[compiler-rt] 65d7fd0 - [Try2][InstrProf] Add Correlator class to read debug info

Ellis Hoag via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 17 10:46:04 PST 2021


Author: Ellis Hoag
Date: 2021-12-17T10:45:59-08:00
New Revision: 65d7fd0239bf301c5dcaa26ed474200845966136

URL: https://github.com/llvm/llvm-project/commit/65d7fd0239bf301c5dcaa26ed474200845966136
DIFF: https://github.com/llvm/llvm-project/commit/65d7fd0239bf301c5dcaa26ed474200845966136.diff

LOG: [Try2][InstrProf] Add Correlator class to read debug info

Extend `llvm-profdata` to read in a `.proflite` file and also a debug info file to generate a normal `.profdata` profile. This reduces the binary size by 8.4% when building an instrumented Clang binary without value profiling (164 MB vs 179 MB).

This work is part of the "lightweight instrumentation" RFC: https://groups.google.com/g/llvm-dev/c/r03Z6JoN7d4

This was first landed in https://reviews.llvm.org/D114566 but had to be reverted due to build errors.

Reviewed By: kyulee

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

Added: 
    compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c
    compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
    llvm/include/llvm/ProfileData/InstrProfCorrelator.h
    llvm/lib/ProfileData/InstrProfCorrelator.cpp

Modified: 
    llvm/include/llvm/ProfileData/InstrProf.h
    llvm/include/llvm/ProfileData/InstrProfReader.h
    llvm/lib/ProfileData/CMakeLists.txt
    llvm/lib/ProfileData/InstrProf.cpp
    llvm/lib/ProfileData/InstrProfReader.cpp
    llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
    llvm/tools/llvm-profdata/CMakeLists.txt
    llvm/tools/llvm-profdata/llvm-profdata.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c b/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c
new file mode 100644
index 0000000000000..1a361841e885d
--- /dev/null
+++ b/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c
@@ -0,0 +1,31 @@
+// Value profiling is currently not supported in lightweight mode.
+// RUN: %clang_pgogen -o %t.normal -mllvm --disable-vp=true %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw
+
+// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %s
+// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.proflite
+
+// RUN: 
diff  %t.normal.profdata %t.profdata
+
+int foo(int a) {
+  if (a % 2)
+    return 4 * a + 1;
+  return 0;
+}
+
+int bar(int a) {
+  while (a > 100)
+    a /= 2;
+  return a;
+}
+
+typedef int (*FP)(int);
+FP Fps[3] = {foo, bar};
+
+int main() {
+  for (int i = 0; i < 5; i++)
+    Fps[i % 2](i);
+  return 0;
+}

diff  --git a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
new file mode 100644
index 0000000000000..ed2739f7a7a19
--- /dev/null
+++ b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
@@ -0,0 +1,31 @@
+// Value profiling is currently not supported in lightweight mode.
+// RUN: %clang_pgogen -o %t.normal -mllvm --disable-vp=true %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw
+
+// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %s
+// RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.proflite
+
+// RUN: 
diff  %t.normal.profdata %t.profdata
+
+int foo(int a) {
+  if (a % 2)
+    return 4 * a + 1;
+  return 0;
+}
+
+int bar(int a) {
+  while (a > 100)
+    a /= 2;
+  return a;
+}
+
+typedef int (*FP)(int);
+FP Fps[3] = {foo, bar};
+
+int main() {
+  for (int i = 0; i < 5; i++)
+    Fps[i % 2](i);
+  return 0;
+}

diff  --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 398a18448dd12..6c5efb2f6d5de 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -290,6 +290,10 @@ enum class instrprof_error {
   too_large,
   truncated,
   malformed,
+  missing_debug_info_for_correlation,
+  unexpected_debug_info_for_correlation,
+  unable_to_correlate_profile,
+  unsupported_debug_format,
   unknown_function,
   invalid_prof,
   hash_mismatch,

diff  --git a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
new file mode 100644
index 0000000000000..eae7b4e0322c9
--- /dev/null
+++ b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
@@ -0,0 +1,170 @@
+//===- InstrProfCorrelator.h ------------------------------------*- 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 defines InstrProfCorrelator used to generate PGO profiles from
+// raw profile data and debug info.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
+#define LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
+
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <vector>
+
+namespace llvm {
+
+/// InstrProfCorrelator - A base class used to create raw instrumentation data
+/// to their functions.
+class InstrProfCorrelator {
+public:
+  static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
+  get(StringRef DebugInfoFilename);
+
+  /// Construct a ProfileData vector used to correlate raw instrumentation data
+  /// to their functions.
+  virtual Error correlateProfileData() = 0;
+
+  static const char *FunctionNameAttributeName;
+  static const char *CFGHashAttributeName;
+  static const char *NumCountersAttributeName;
+
+  enum InstrProfCorrelatorKind { CK_32Bit, CK_64Bit };
+  InstrProfCorrelatorKind getKind() const { return Kind; }
+  virtual ~InstrProfCorrelator() {}
+
+protected:
+  struct Context {
+    static llvm::Expected<std::unique_ptr<Context>>
+    get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj);
+    std::unique_ptr<MemoryBuffer> Buffer;
+    /// The address range of the __llvm_prf_cnts section.
+    uint64_t CountersSectionStart;
+    uint64_t CountersSectionEnd;
+    /// True if target and host have 
diff erent endian orders.
+    bool ShouldSwapBytes;
+  };
+  const std::unique_ptr<InstrProfCorrelator::Context> Ctx;
+
+  InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr<Context> Ctx)
+      : Ctx(std::move(Ctx)), Kind(K) {}
+
+private:
+  static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
+  get(std::unique_ptr<MemoryBuffer> Buffer);
+
+  const InstrProfCorrelatorKind Kind;
+};
+
+/// InstrProfCorrelatorImpl - A child of InstrProfCorrelator with a template
+/// pointer type so that the ProfileData vector can be materialized.
+template <class IntPtrT>
+class InstrProfCorrelatorImpl : public InstrProfCorrelator {
+public:
+  InstrProfCorrelatorImpl(std::unique_ptr<InstrProfCorrelator::Context> Ctx);
+  static bool classof(const InstrProfCorrelator *C);
+
+  /// Return a pointer to the underlying ProfileData vector that this class
+  /// constructs.
+  const RawInstrProf::ProfileData<IntPtrT> *getDataPointer() const {
+    return Data.empty() ? nullptr : Data.data();
+  }
+
+  /// Return the number of ProfileData elements.
+  size_t getDataSize() const { return Data.size(); }
+
+  /// Return a pointer to the compressed names string that this class
+  /// constructs.
+  const char *getCompressedNamesPointer() const {
+    return CompressedNames.c_str();
+  }
+
+  /// Return the number of bytes in the compressed names string.
+  size_t getCompressedNamesSize() const { return CompressedNames.size(); }
+
+  static llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
+  get(std::unique_ptr<InstrProfCorrelator::Context> Ctx,
+      const object::ObjectFile &Obj);
+
+protected:
+  std::vector<RawInstrProf::ProfileData<IntPtrT>> Data;
+  std::string CompressedNames;
+
+  Error correlateProfileData() override;
+  virtual void correlateProfileDataImpl() = 0;
+
+  void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset,
+                IntPtrT FunctionPtr, uint32_t NumCounters);
+
+private:
+  InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind,
+                          std::unique_ptr<InstrProfCorrelator::Context> Ctx)
+      : InstrProfCorrelator(Kind, std::move(Ctx)){};
+  std::vector<std::string> Names;
+
+  // Byte-swap the value if necessary.
+  template <class T> T maybeSwap(T Value) const {
+    return Ctx->ShouldSwapBytes ? sys::getSwappedBytes(Value) : Value;
+  }
+};
+
+/// DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes
+/// DWARF debug info as input to correlate profiles.
+template <class IntPtrT>
+class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
+public:
+  DwarfInstrProfCorrelator(std::unique_ptr<DWARFContext> DICtx,
+                           std::unique_ptr<InstrProfCorrelator::Context> Ctx)
+      : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)),
+        DICtx(std::move(DICtx)) {}
+
+private:
+  std::unique_ptr<DWARFContext> DICtx;
+
+  /// Return the address of the object that the provided DIE symbolizes.
+  llvm::Optional<uint64_t> getLocation(const DWARFDie &Die) const;
+
+  /// Returns true if the provided DIE symbolizes an instrumentation probe
+  /// symbol.
+  static bool isDIEOfProbe(const DWARFDie &Die);
+
+  /// Iterate over DWARF DIEs to find those that symbolize instrumentation
+  /// probes and construct the ProfileData vector and CompressedNames string.
+  ///
+  /// Here is some example DWARF for an instrumentation probe we are looking
+  /// for:
+  /// \code
+  ///   DW_TAG_subprogram
+  ///   DW_AT_low_pc	(0x0000000000000000)
+  ///   DW_AT_high_pc	(0x0000000000000014)
+  ///   DW_AT_name	("foo")
+  ///     DW_TAG_variable
+  ///       DW_AT_name	("__profc_foo")
+  ///       DW_AT_location	(DW_OP_addr 0x0)
+  ///       DW_TAG_LLVM_annotation
+  ///         DW_AT_name	("Function Name")
+  ///         DW_AT_const_value	("foo")
+  ///       DW_TAG_LLVM_annotation
+  ///         DW_AT_name	("CFG Hash")
+  ///         DW_AT_const_value	(12345678)
+  ///       DW_TAG_LLVM_annotation
+  ///         DW_AT_name	("Num Counters")
+  ///         DW_AT_const_value	(2)
+  ///       NULL
+  ///     NULL
+  /// \endcode
+  void correlateProfileDataImpl() override;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H

diff  --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index b62d4ff044a35..c615e85331781 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -18,6 +18,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/ProfileSummary.h"
 #include "llvm/ProfileData/InstrProf.h"
+#include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/LineIterator.h"
@@ -96,6 +97,9 @@ class InstrProfReader {
 
   virtual bool instrEntryBBEnabled() const = 0;
 
+  /// Return true if we must provide debug info to create PGO profiles.
+  virtual bool useDebugInfoCorrelate() const { return false; }
+
   /// Return the PGO symtab. There are three 
diff erent readers:
   /// Raw, Text, and Indexed profile readers. The first two types
   /// of readers are used only by llvm-profdata tool, while the indexed
@@ -150,10 +154,12 @@ class InstrProfReader {
 
   /// Factory method to create an appropriately typed reader for the given
   /// instrprof file.
-  static Expected<std::unique_ptr<InstrProfReader>> create(const Twine &Path);
+  static Expected<std::unique_ptr<InstrProfReader>>
+  create(const Twine &Path, const InstrProfCorrelator *Correlator = nullptr);
 
   static Expected<std::unique_ptr<InstrProfReader>>
-  create(std::unique_ptr<MemoryBuffer> Buffer);
+  create(std::unique_ptr<MemoryBuffer> Buffer,
+         const InstrProfCorrelator *Correlator = nullptr);
 };
 
 /// Reader for the simple text based instrprof format.
@@ -215,6 +221,9 @@ class RawInstrProfReader : public InstrProfReader {
 private:
   /// The profile data file contents.
   std::unique_ptr<MemoryBuffer> DataBuffer;
+  /// If available, this hold the ProfileData array used to correlate raw
+  /// instrumentation data to their functions.
+  const InstrProfCorrelatorImpl<IntPtrT> *Correlator;
   bool ShouldSwapBytes;
   // The value of the version field of the raw profile data header. The lower 56
   // bits specifies the format version and the most significant 8 bits specify
@@ -226,7 +235,7 @@ class RawInstrProfReader : public InstrProfReader {
   const RawInstrProf::ProfileData<IntPtrT> *DataEnd;
   const uint64_t *CountersStart;
   const char *NamesStart;
-  uint64_t NamesSize;
+  const char *NamesEnd;
   // After value profile is all read, this pointer points to
   // the header of next profile data (if exists)
   const uint8_t *ValueDataStart;
@@ -237,8 +246,11 @@ class RawInstrProfReader : public InstrProfReader {
   const uint8_t *BinaryIdsStart;
 
 public:
-  RawInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer)
-      : DataBuffer(std::move(DataBuffer)) {}
+  RawInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer,
+                     const InstrProfCorrelator *Correlator)
+      : DataBuffer(std::move(DataBuffer)),
+        Correlator(dyn_cast_or_null<const InstrProfCorrelatorImpl<IntPtrT>>(
+            Correlator)) {}
   RawInstrProfReader(const RawInstrProfReader &) = delete;
   RawInstrProfReader &operator=(const RawInstrProfReader &) = delete;
 
@@ -259,6 +271,10 @@ class RawInstrProfReader : public InstrProfReader {
     return (Version & VARIANT_MASK_INSTR_ENTRY) != 0;
   }
 
+  bool useDebugInfoCorrelate() const override {
+    return (Version & VARIANT_MASK_DBG_CORRELATE) != 0;
+  }
+
   InstrProfSymtab &getSymtab() override {
     assert(Symtab.get());
     return *Symtab.get();

diff  --git a/llvm/lib/ProfileData/CMakeLists.txt b/llvm/lib/ProfileData/CMakeLists.txt
index eec2392aef428..1237bf77983fc 100644
--- a/llvm/lib/ProfileData/CMakeLists.txt
+++ b/llvm/lib/ProfileData/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_llvm_component_library(LLVMProfileData
   GCOV.cpp
   InstrProf.cpp
+  InstrProfCorrelator.cpp
   InstrProfReader.cpp
   InstrProfWriter.cpp
   ProfileSummaryBuilder.cpp
@@ -19,6 +20,8 @@ add_llvm_component_library(LLVMProfileData
   Core
   Support
   Demangle
+  Object
+  DebugInfoDWARF
   )
 
 add_subdirectory(Coverage)

diff  --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 187e97851247d..34e0c5ebcd584 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -110,6 +110,18 @@ static std::string getInstrProfErrString(instrprof_error Err,
   case instrprof_error::malformed:
     OS << "malformed instrumentation profile data";
     break;
+  case instrprof_error::missing_debug_info_for_correlation:
+    OS << "debug info for correlation is required";
+    break;
+  case instrprof_error::unexpected_debug_info_for_correlation:
+    OS << "debug info for correlation is not necessary";
+    break;
+  case instrprof_error::unable_to_correlate_profile:
+    OS << "unable to correlate profile";
+    break;
+  case instrprof_error::unsupported_debug_format:
+    OS << "unsupported debug info format (only DWARF is supported)";
+    break;
   case instrprof_error::invalid_prof:
     OS << "invalid profile created. Please file a bug "
           "at: " BUG_REPORT_URL

diff  --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
new file mode 100644
index 0000000000000..f9c113027da2b
--- /dev/null
+++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
@@ -0,0 +1,264 @@
+//===-- InstrProfCorrelator.cpp -------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ProfileData/InstrProfCorrelator.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+#define DEBUG_TYPE "correlator"
+
+using namespace llvm;
+
+/// Get the __llvm_prf_cnts section.
+Expected<object::SectionRef> getCountersSection(const object::ObjectFile &Obj) {
+  for (auto &Section : Obj.sections())
+    if (auto SectionName = Section.getName())
+      if (SectionName.get() == INSTR_PROF_CNTS_SECT_NAME)
+        return Section;
+  return make_error<InstrProfError>(
+      instrprof_error::unable_to_correlate_profile);
+}
+
+const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name";
+const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash";
+const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters";
+
+llvm::Expected<std::unique_ptr<InstrProfCorrelator::Context>>
+InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
+                                  const object::ObjectFile &Obj) {
+  auto CountersSection = getCountersSection(Obj);
+  if (auto Err = CountersSection.takeError())
+    return std::move(Err);
+  auto C = std::make_unique<Context>();
+  C->Buffer = std::move(Buffer);
+  C->CountersSectionStart = CountersSection->getAddress();
+  C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize();
+  C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost;
+  return Expected<std::unique_ptr<Context>>(std::move(C));
+}
+
+llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
+InstrProfCorrelator::get(StringRef DebugInfoFilename) {
+  auto DsymObjectsOrErr =
+      object::MachOObjectFile::findDsymObjectMembers(DebugInfoFilename);
+  if (auto Err = DsymObjectsOrErr.takeError())
+    return std::move(Err);
+  if (!DsymObjectsOrErr->empty()) {
+    // TODO: Enable profile correlation when there are multiple objects in a
+    // dSYM bundle.
+    if (DsymObjectsOrErr->size() > 1)
+      return createStringError(
+          std::error_code(),
+          "Profile correlation using multiple objects is not yet supported");
+    DebugInfoFilename = *DsymObjectsOrErr->begin();
+  }
+  auto BufferOrErr =
+      errorOrToExpected(MemoryBuffer::getFile(DebugInfoFilename));
+  if (auto Err = BufferOrErr.takeError())
+    return std::move(Err);
+
+  return get(std::move(*BufferOrErr));
+}
+
+llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
+InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer) {
+  auto BinOrErr = object::createBinary(*Buffer);
+  if (auto Err = BinOrErr.takeError())
+    return std::move(Err);
+
+  if (auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
+    auto CtxOrErr = Context::get(std::move(Buffer), *Obj);
+    if (auto Err = CtxOrErr.takeError())
+      return std::move(Err);
+    auto T = Obj->makeTriple();
+    if (T.isArch64Bit())
+      return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj);
+    if (T.isArch32Bit())
+      return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj);
+  }
+  return make_error<InstrProfError>(
+      instrprof_error::unable_to_correlate_profile);
+}
+
+namespace llvm {
+
+template <>
+InstrProfCorrelatorImpl<uint32_t>::InstrProfCorrelatorImpl(
+    std::unique_ptr<InstrProfCorrelator::Context> Ctx)
+    : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_32Bit,
+                              std::move(Ctx)) {}
+template <>
+InstrProfCorrelatorImpl<uint64_t>::InstrProfCorrelatorImpl(
+    std::unique_ptr<InstrProfCorrelator::Context> Ctx)
+    : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_64Bit,
+                              std::move(Ctx)) {}
+template <>
+bool InstrProfCorrelatorImpl<uint32_t>::classof(const InstrProfCorrelator *C) {
+  return C->getKind() == InstrProfCorrelatorKind::CK_32Bit;
+}
+template <>
+bool InstrProfCorrelatorImpl<uint64_t>::classof(const InstrProfCorrelator *C) {
+  return C->getKind() == InstrProfCorrelatorKind::CK_64Bit;
+}
+
+} // end namespace llvm
+
+template <class IntPtrT>
+llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
+InstrProfCorrelatorImpl<IntPtrT>::get(
+    std::unique_ptr<InstrProfCorrelator::Context> Ctx,
+    const object::ObjectFile &Obj) {
+  if (Obj.isELF() || Obj.isMachO()) {
+    auto DICtx = DWARFContext::create(Obj);
+    return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(std::move(DICtx),
+                                                               std::move(Ctx));
+  }
+  return make_error<InstrProfError>(instrprof_error::unsupported_debug_format);
+}
+
+template <class IntPtrT>
+Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData() {
+  assert(Data.empty() && CompressedNames.empty() && Names.empty());
+  correlateProfileDataImpl();
+  auto Result =
+      collectPGOFuncNameStrings(Names, /*doCompression=*/true, CompressedNames);
+  Names.clear();
+  return Result;
+}
+
+template <class IntPtrT>
+void InstrProfCorrelatorImpl<IntPtrT>::addProbe(StringRef FunctionName,
+                                                uint64_t CFGHash,
+                                                IntPtrT CounterOffset,
+                                                IntPtrT FunctionPtr,
+                                                uint32_t NumCounters) {
+  Data.push_back({
+      maybeSwap<uint64_t>(IndexedInstrProf::ComputeHash(FunctionName)),
+      maybeSwap<uint64_t>(CFGHash),
+      // In this mode, CounterPtr actually stores the section relative address
+      // of the counter.
+      maybeSwap<IntPtrT>(CounterOffset),
+      maybeSwap<IntPtrT>(FunctionPtr),
+      // TODO: Value profiling is not yet supported.
+      /*ValuesPtr=*/maybeSwap<IntPtrT>(0),
+      maybeSwap<uint32_t>(NumCounters),
+      /*NumValueSites=*/{maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
+  });
+  Names.push_back(FunctionName.str());
+}
+
+template <class IntPtrT>
+llvm::Optional<uint64_t>
+DwarfInstrProfCorrelator<IntPtrT>::getLocation(const DWARFDie &Die) const {
+  auto Locations = Die.getLocations(dwarf::DW_AT_location);
+  if (!Locations) {
+    consumeError(Locations.takeError());
+    return {};
+  }
+  auto &DU = *Die.getDwarfUnit();
+  for (auto &Location : *Locations) {
+    auto AddressSize = DU.getAddressByteSize();
+    DataExtractor Data(Location.Expr, DICtx->isLittleEndian(), AddressSize);
+    DWARFExpression Expr(Data, AddressSize);
+    for (auto &Op : Expr)
+      if (Op.getCode() == dwarf::DW_OP_addr)
+        return Op.getRawOperand(0);
+  }
+  return {};
+}
+
+template <class IntPtrT>
+bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die) {
+  const auto &ParentDie = Die.getParent();
+  if (!Die.isValid() || !ParentDie.isValid() || Die.isNULL())
+    return false;
+  if (Die.getTag() != dwarf::DW_TAG_variable)
+    return false;
+  if (!ParentDie.isSubprogramDIE())
+    return false;
+  if (!Die.hasChildren())
+    return false;
+  if (const char *Name = Die.getName(DINameKind::ShortName))
+    return StringRef(Name).startswith(getInstrProfCountersVarPrefix());
+  return false;
+}
+
+template <class IntPtrT>
+void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl() {
+  auto maybeAddProbe = [&](DWARFDie Die) {
+    if (!isDIEOfProbe(Die))
+      return;
+    Optional<const char *> FunctionName;
+    Optional<uint64_t> CFGHash;
+    Optional<uint64_t> CounterPtr = getLocation(Die);
+    auto FunctionPtr =
+        dwarf::toAddress(Die.getParent().find(dwarf::DW_AT_low_pc));
+    Optional<uint64_t> NumCounters;
+    for (const DWARFDie &Child : Die.children()) {
+      if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
+        continue;
+      auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
+      auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
+      if (!AnnotationFormName || !AnnotationFormValue)
+        continue;
+      auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
+      if (auto Err = AnnotationNameOrErr.takeError()) {
+        consumeError(std::move(Err));
+        continue;
+      }
+      StringRef AnnotationName = *AnnotationNameOrErr;
+      if (AnnotationName.compare(
+              InstrProfCorrelator::FunctionNameAttributeName) == 0) {
+        if (auto EC =
+                AnnotationFormValue->getAsCString().moveInto(FunctionName))
+          consumeError(std::move(EC));
+      } else if (AnnotationName.compare(
+                     InstrProfCorrelator::CFGHashAttributeName) == 0) {
+        CFGHash = AnnotationFormValue->getAsUnsignedConstant();
+      } else if (AnnotationName.compare(
+                     InstrProfCorrelator::NumCountersAttributeName) == 0) {
+        NumCounters = AnnotationFormValue->getAsUnsignedConstant();
+      }
+    }
+    if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
+      LLVM_DEBUG(dbgs() << "Incomplete DIE for probe\n\tFunctionName: "
+                        << FunctionName << "\n\tCFGHash: " << CFGHash
+                        << "\n\tCounterPtr: " << CounterPtr
+                        << "\n\tNumCounters: " << NumCounters);
+      LLVM_DEBUG(Die.dump(dbgs()));
+      return;
+    }
+    uint64_t CountersStart = this->Ctx->CountersSectionStart;
+    uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
+    if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
+      LLVM_DEBUG(
+          dbgs() << "CounterPtr out of range for probe\n\tFunction Name: "
+                 << FunctionName << "\n\tExpected: [0x"
+                 << Twine::utohexstr(CountersStart) << ", 0x"
+                 << Twine::utohexstr(CountersEnd) << ")\n\tActual: 0x"
+                 << Twine::utohexstr(*CounterPtr));
+      LLVM_DEBUG(Die.dump(dbgs()));
+      return;
+    }
+    if (!FunctionPtr) {
+      LLVM_DEBUG(dbgs() << "Could not find address of " << *FunctionName
+                        << "\n");
+      LLVM_DEBUG(Die.dump(dbgs()));
+    }
+    this->addProbe(*FunctionName, *CFGHash, *CounterPtr - CountersStart,
+                   FunctionPtr.getValueOr(0), *NumCounters);
+  };
+  for (auto &CU : DICtx->normal_units())
+    for (const auto &Entry : CU->dies())
+      maybeAddProbe(DWARFDie(CU.get(), &Entry));
+  for (auto &CU : DICtx->dwo_units())
+    for (const auto &Entry : CU->dies())
+      maybeAddProbe(DWARFDie(CU.get(), &Entry));
+}

diff  --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index b4a4681df7345..37cdf4dd1fe24 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -52,16 +52,19 @@ static Error initializeReader(InstrProfReader &Reader) {
 }
 
 Expected<std::unique_ptr<InstrProfReader>>
-InstrProfReader::create(const Twine &Path) {
+InstrProfReader::create(const Twine &Path,
+                        const InstrProfCorrelator *Correlator) {
   // Set up the buffer to read.
   auto BufferOrError = setupMemoryBuffer(Path);
   if (Error E = BufferOrError.takeError())
     return std::move(E);
-  return InstrProfReader::create(std::move(BufferOrError.get()));
+  return InstrProfReader::create(std::move(BufferOrError.get()), Correlator);
 }
 
 Expected<std::unique_ptr<InstrProfReader>>
-InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
+InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
+                        const InstrProfCorrelator *Correlator) {
+  // Sanity check the buffer.
   if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint64_t>::max())
     return make_error<InstrProfError>(instrprof_error::too_large);
 
@@ -73,9 +76,9 @@ InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
   if (IndexedInstrProfReader::hasFormat(*Buffer))
     Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
   else if (RawInstrProfReader64::hasFormat(*Buffer))
-    Result.reset(new RawInstrProfReader64(std::move(Buffer)));
+    Result.reset(new RawInstrProfReader64(std::move(Buffer), Correlator));
   else if (RawInstrProfReader32::hasFormat(*Buffer))
-    Result.reset(new RawInstrProfReader32(std::move(Buffer)));
+    Result.reset(new RawInstrProfReader32(std::move(Buffer), Correlator));
   else if (TextInstrProfReader::hasFormat(*Buffer))
     Result.reset(new TextInstrProfReader(std::move(Buffer)));
   else
@@ -352,7 +355,7 @@ Error RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
 
 template <class IntPtrT>
 Error RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) {
-  if (Error E = Symtab.create(StringRef(NamesStart, NamesSize)))
+  if (Error E = Symtab.create(StringRef(NamesStart, NamesEnd - NamesStart)))
     return error(std::move(E));
   for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) {
     const IntPtrT FPtr = swap(I->FunctionPointer);
@@ -369,6 +372,10 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
   Version = swap(Header.Version);
   if (GET_VERSION(Version) != RawInstrProf::Version)
     return error(instrprof_error::unsupported_version);
+  if (useDebugInfoCorrelate() && !Correlator)
+    return error(instrprof_error::missing_debug_info_for_correlation);
+  if (!useDebugInfoCorrelate() && Correlator)
+    return error(instrprof_error::unexpected_debug_info_for_correlation);
 
   BinaryIdsSize = swap(Header.BinaryIdsSize);
   if (BinaryIdsSize % sizeof(uint64_t))
@@ -380,7 +387,7 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
   auto PaddingBytesBeforeCounters = swap(Header.PaddingBytesBeforeCounters);
   auto CountersSize = swap(Header.CountersSize);
   auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
-  NamesSize = swap(Header.NamesSize);
+  auto NamesSize = swap(Header.NamesSize);
   ValueKindLast = swap(Header.ValueKindLast);
 
   auto DataSizeInBytes = DataSize * sizeof(RawInstrProf::ProfileData<IntPtrT>);
@@ -398,15 +405,27 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
   if (Start + ValueDataOffset > DataBuffer->getBufferEnd())
     return error(instrprof_error::bad_header);
 
-  Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
-      Start + DataOffset);
-  DataEnd = Data + DataSize;
+  if (Correlator) {
+    // These sizes in the raw file are zero because we constructed them in the
+    // Correlator.
+    assert(DataSize == 0 && NamesSize == 0);
+    assert(CountersDelta == 0 && NamesDelta == 0);
+    Data = Correlator->getDataPointer();
+    DataEnd = Data + Correlator->getDataSize();
+    NamesStart = Correlator->getCompressedNamesPointer();
+    NamesEnd = NamesStart + Correlator->getCompressedNamesSize();
+  } else {
+    Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>(
+        Start + DataOffset);
+    DataEnd = Data + DataSize;
+    NamesStart = Start + NamesOffset;
+    NamesEnd = NamesStart + NamesSize;
+  }
 
   // Binary ids start just after the header.
   BinaryIdsStart =
       reinterpret_cast<const uint8_t *>(&Header) + sizeof(RawInstrProf::Header);
   CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
-  NamesStart = Start + NamesOffset;
   ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset);
 
   const uint8_t *BufferEnd = (const uint8_t *)DataBuffer->getBufferEnd();
@@ -440,45 +459,50 @@ Error RawInstrProfReader<IntPtrT>::readRawCounts(
   if (NumCounters == 0)
     return error(instrprof_error::malformed, "number of counters is zero");
 
-  IntPtrT CounterPtr = Data->CounterPtr;
-  auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
-  ptr
diff _t MaxNumCounters = NamesStartAsCounter - CountersStart;
-
-  // Check bounds. Note that the counter pointer embedded in the data record
-  // may itself be corrupt.
-  if (MaxNumCounters < 0 || NumCounters > (uint32_t)MaxNumCounters)
-    return error(instrprof_error::malformed,
-                 "counter pointer is out of bounds");
-
-  // We need to compute the in-buffer counter offset from the in-memory address
-  // distance. The initial CountersDelta is the in-memory address 
diff erence
-  // start(__llvm_prf_cnts)-start(__llvm_prf_data), so SrcData->CounterPtr -
-  // CountersDelta computes the offset into the in-buffer counter section.
-  //
-  // CountersDelta decreases as we advance to the next data record.
-  ptr
diff _t CounterOffset = getCounterOffset(CounterPtr);
-  CountersDelta -= sizeof(*Data);
-  if (CounterOffset < 0)
-    return error(
-        instrprof_error::malformed,
-        ("counter offset " + Twine(CounterOffset) + " is negative").str());
-
-  if (CounterOffset > MaxNumCounters)
-    return error(instrprof_error::malformed,
-                 ("counter offset " + Twine(CounterOffset) +
-                  " is greater than the maximum number of counters " +
-                  Twine((uint32_t)MaxNumCounters))
-                     .str());
-
-  if (((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters)
-    return error(instrprof_error::malformed,
-                 ("number of counters " +
-                  Twine(((uint32_t)CounterOffset + NumCounters)) +
-                  " is greater than the maximum number of counters " +
-                  Twine((uint32_t)MaxNumCounters))
-                     .str());
-
-  auto RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters);
+  ArrayRef<uint64_t> RawCounts;
+  if (Correlator) {
+    uint64_t CounterOffset = swap<IntPtrT>(Data->CounterPtr) / sizeof(uint64_t);
+    RawCounts =
+        makeArrayRef<uint64_t>(CountersStart + CounterOffset, NumCounters);
+  } else {
+    IntPtrT CounterPtr = Data->CounterPtr;
+    ptr
diff _t CounterOffset = getCounterOffset(CounterPtr);
+    if (CounterOffset < 0)
+      return error(
+          instrprof_error::malformed,
+          ("counter offset " + Twine(CounterOffset) + " is negative").str());
+
+    // Check bounds. Note that the counter pointer embedded in the data record
+    // may itself be corrupt.
+    auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
+    ptr
diff _t MaxNumCounters = NamesStartAsCounter - CountersStart;
+    if (MaxNumCounters < 0 || NumCounters > (uint32_t)MaxNumCounters)
+      return error(instrprof_error::malformed,
+                   "counter pointer is out of bounds");
+    // We need to compute the in-buffer counter offset from the in-memory
+    // address distance. The initial CountersDelta is the in-memory address
+    // 
diff erence start(__llvm_prf_cnts)-start(__llvm_prf_data), so
+    // SrcData->CounterPtr - CountersDelta computes the offset into the
+    // in-buffer counter section.
+    if (CounterOffset > MaxNumCounters)
+      return error(instrprof_error::malformed,
+                   ("counter offset " + Twine(CounterOffset) +
+                    " is greater than the maximum number of counters " +
+                    Twine((uint32_t)MaxNumCounters))
+                       .str());
+
+    if (((uint32_t)CounterOffset + NumCounters) > (uint32_t)MaxNumCounters)
+      return error(instrprof_error::malformed,
+                   ("number of counters " +
+                    Twine(((uint32_t)CounterOffset + NumCounters)) +
+                    " is greater than the maximum number of counters " +
+                    Twine((uint32_t)MaxNumCounters))
+                       .str());
+    // CountersDelta decreases as we advance to the next data record.
+    CountersDelta -= sizeof(*Data);
+
+    RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters);
+  }
 
   if (ShouldSwapBytes) {
     Record.Counts.clear();

diff  --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
index 38ed291fd1a27..de34348606efc 100644
--- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
@@ -42,6 +42,7 @@
 #include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
 #include "llvm/ProfileData/InstrProf.h"
+#include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Error.h"
@@ -941,15 +942,15 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfIncrementInst *Inc) {
     if (auto *SP = Fn->getSubprogram()) {
       DIBuilder DB(*M, true, SP->getUnit());
       Metadata *FunctionNameAnnotation[] = {
-          MDString::get(Ctx, "Function Name"),
+          MDString::get(Ctx, InstrProfCorrelator::FunctionNameAttributeName),
           MDString::get(Ctx, getPGOFuncNameVarInitializer(NamePtr)),
       };
       Metadata *CFGHashAnnotation[] = {
-          MDString::get(Ctx, "CFG Hash"),
+          MDString::get(Ctx, InstrProfCorrelator::CFGHashAttributeName),
           ConstantAsMetadata::get(Inc->getHash()),
       };
       Metadata *NumCountersAnnotation[] = {
-          MDString::get(Ctx, "Num Counters"),
+          MDString::get(Ctx, InstrProfCorrelator::NumCountersAttributeName),
           ConstantAsMetadata::get(Inc->getNumCounters()),
       };
       auto Annotations = DB.getOrCreateArray({

diff  --git a/llvm/tools/llvm-profdata/CMakeLists.txt b/llvm/tools/llvm-profdata/CMakeLists.txt
index 49641c482f29f..3545bde5c4042 100644
--- a/llvm/tools/llvm-profdata/CMakeLists.txt
+++ b/llvm/tools/llvm-profdata/CMakeLists.txt
@@ -1,6 +1,8 @@
 set(LLVM_LINK_COMPONENTS
   Core
   ProfileData
+  Object
+  DebugInfoDWARF
   Support
   )
 

diff  --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 8f45629d7d56b..285b41f57147d 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -13,7 +13,10 @@
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
 #include "llvm/IR/LLVMContext.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/ProfileData/InstrProfWriter.h"
 #include "llvm/ProfileData/ProfileCommon.h"
@@ -233,6 +236,7 @@ static void overlapInput(const std::string &BaseFilename,
 
 /// Load an input into a writer context.
 static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
+                      const InstrProfCorrelator *Correlator,
                       WriterContext *WC) {
   std::unique_lock<std::mutex> CtxGuard{WC->Lock};
 
@@ -241,7 +245,7 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
   // invalid outside of this packaged task.
   std::string Filename = Input.Filename;
 
-  auto ReaderOrErr = InstrProfReader::create(Input.Filename);
+  auto ReaderOrErr = InstrProfReader::create(Input.Filename, Correlator);
   if (Error E = ReaderOrErr.takeError()) {
     // Skip the empty profiles by returning sliently.
     instrprof_error IPE = InstrProfError::take(std::move(E));
@@ -325,6 +329,7 @@ static void writeInstrProfile(StringRef OutputFilename,
 }
 
 static void mergeInstrProfile(const WeightedFileVector &Inputs,
+                              StringRef DebugInfoFilename,
                               SymbolRemapper *Remapper,
                               StringRef OutputFilename,
                               ProfileFormat OutputFormat, bool OutputSparse,
@@ -333,6 +338,15 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
       OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text)
     exitWithError("unknown format is specified");
 
+  std::unique_ptr<InstrProfCorrelator> Correlator;
+  if (!DebugInfoFilename.empty()) {
+    if (auto Err =
+            InstrProfCorrelator::get(DebugInfoFilename).moveInto(Correlator))
+      exitWithError(std::move(Err), DebugInfoFilename);
+    if (auto Err = Correlator->correlateProfileData())
+      exitWithError(std::move(Err), DebugInfoFilename);
+  }
+
   std::mutex ErrorLock;
   SmallSet<instrprof_error, 4> WriterErrorCodes;
 
@@ -352,14 +366,15 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
 
   if (NumThreads == 1) {
     for (const auto &Input : Inputs)
-      loadInput(Input, Remapper, Contexts[0].get());
+      loadInput(Input, Remapper, Correlator.get(), Contexts[0].get());
   } else {
     ThreadPool Pool(hardware_concurrency(NumThreads));
 
     // Load the inputs in parallel (N/NumThreads serial steps).
     unsigned Ctx = 0;
     for (const auto &Input : Inputs) {
-      Pool.async(loadInput, Input, Remapper, Contexts[Ctx].get());
+      Pool.async(loadInput, Input, Remapper, Correlator.get(),
+                 Contexts[Ctx].get());
       Ctx = (Ctx + 1) % NumThreads;
     }
     Pool.wait();
@@ -575,7 +590,7 @@ static void supplementInstrProfile(
   SmallSet<instrprof_error, 4> WriterErrorCodes;
   auto WC = std::make_unique<WriterContext>(OutputSparse, ErrorLock,
                                             WriterErrorCodes);
-  loadInput(Inputs[0], nullptr, WC.get());
+  loadInput(Inputs[0], nullptr, nullptr, WC.get());
   if (WC->Errors.size() > 0)
     exitWithError(std::move(WC->Errors[0].first), InstrFilename);
 
@@ -952,6 +967,9 @@ static int merge_main(int argc, const char *argv[]) {
   cl::opt<bool> GenCSNestedProfile(
       "gen-cs-nested-profile", cl::Hidden, cl::init(false),
       cl::desc("Generate nested function profiles for CSSPGO"));
+  cl::opt<std::string> DebugInfoFilename(
+      "debug-info", cl::init(""), cl::Hidden,
+      cl::desc("Use the provided debug info to correlate the raw profile."));
 
   cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
 
@@ -992,8 +1010,9 @@ static int merge_main(int argc, const char *argv[]) {
   }
 
   if (ProfileKind == instr)
-    mergeInstrProfile(WeightedInputs, Remapper.get(), OutputFilename,
-                      OutputFormat, OutputSparse, NumThreads, FailureMode);
+    mergeInstrProfile(WeightedInputs, DebugInfoFilename, Remapper.get(),
+                      OutputFilename, OutputFormat, OutputSparse, NumThreads,
+                      FailureMode);
   else
     mergeSampleProfile(WeightedInputs, Remapper.get(), OutputFilename,
                        OutputFormat, ProfileSymbolListFile, CompressAllSections,
@@ -1024,7 +1043,7 @@ static void overlapInstrProfile(const std::string &BaseFilename,
     OS << "Sum of edge counts for profile " << TestFilename << " is 0.\n";
     exit(0);
   }
-  loadInput(WeightedInput, nullptr, &Context);
+  loadInput(WeightedInput, nullptr, nullptr, &Context);
   overlapInput(BaseFilename, TestFilename, &Context, Overlap, FuncFilter, OS,
                IsCS);
   Overlap.dump(OS);


        


More information about the llvm-commits mailing list