[clang] [Profile] Add binary profile correlation to offload profile metadata at runtime. (PR #69493)

Zequan Wu via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 18 11:23:14 PDT 2023


https://github.com/ZequanWu created https://github.com/llvm/llvm-project/pull/69493

This is similar to debug info correlation. The motivation is that debug info correlation doesn't work on Windows because it's hard to make codeview contains those artificial debug info. 

The idea is to offload profile metadata(profile name and data sections) from binary by marking them as metadata sections, so that they can be stripped away as a post-linking step. The generated raw profiles will contains only headers + counters. llvm-profdata will use the unstripped binary to correlate the raw profiles to generate indexed profile.

A few things to note:
1. This new mode and debug info correlation mode are under `-profile-correlate=` flag, since they are similar.
2. llvm-profdata doesn't support filter raw profiles by binary id yet, so when a raw profile doesn't belongs to the binary being digested by llvm-profdata, merging will fail. Once this is implemented, llvm-profdata should be able to only merge raw profiles with the same binary id as the binary and discard the rest (with mismatched/missing binary id). The workflow I have in mind is to have scripts invoke llvm-profdata to get all binary ids for all raw profiles, and selectively choose the raw profiles with matching binary id and the binary to llvm-profdata for merging.

>From 3a394ce5d4d7d91251337bd0a2c1c1a074eb37e6 Mon Sep 17 00:00:00 2001
From: Zequan Wu <zequanwu at google.com>
Date: Tue, 17 Oct 2023 19:24:12 -0400
Subject: [PATCH 1/3] [Profile] Add binary profile correlation.

---
 clang/lib/CodeGen/BackendUtil.cpp             |  10 +-
 clang/lib/CodeGen/CoverageMappingGen.cpp      |  20 ++
 .../CodeGen/coverage-profile-raw-version.c    |   9 +
 compiler-rt/include/profile/InstrProfData.inc |   2 +
 compiler-rt/lib/profile/InstrProfiling.h      |   3 +
 .../lib/profile/InstrProfilingBuffer.c        |  14 ++
 compiler-rt/lib/profile/InstrProfilingMerge.c |   8 +-
 .../profile/InstrProfilingPlatformWindows.c   |   2 -
 .../lib/profile/InstrProfilingWriter.c        |  24 +--
 compiler-rt/test/CMakeLists.txt               |   5 +-
 .../Darwin/instrprof-debug-info-correlate.c   |   4 +-
 .../instrprof-debug-info-correlate-warnings.c |   2 +-
 .../Linux/instrprof-debug-info-correlate.c    |   6 +-
 .../instrprof-show-debug-info-correlation.c   |   6 +-
 .../test/profile/instrprof-binary-correlate.c |  29 +++
 llvm/include/llvm/ProfileData/InstrProf.h     |   6 +-
 .../llvm/ProfileData/InstrProfCorrelator.h    |  59 ++++-
 .../llvm/ProfileData/InstrProfData.inc        |   2 +
 .../llvm/ProfileData/InstrProfReader.h        |  10 +
 .../Instrumentation/PGOInstrumentation.h      |   2 -
 .../CodeGen/TargetLoweringObjectFileImpl.cpp  |  23 +-
 .../Coverage/CoverageMappingReader.cpp        |  28 ++-
 llvm/lib/ProfileData/InstrProf.cpp            |   8 +-
 llvm/lib/ProfileData/InstrProfCorrelator.cpp  | 203 ++++++++++++++----
 llvm/lib/ProfileData/InstrProfReader.cpp      |   8 +-
 .../Instrumentation/InstrProfiling.cpp        |  31 +--
 .../Instrumentation/PGOInstrumentation.cpp    |   3 +-
 .../debug-info-correlate-coverage.ll          |   2 +-
 .../InstrProfiling/debug-info-correlate.ll    |   2 +-
 llvm/tools/llvm-profdata/llvm-profdata.cpp    |  37 +++-
 30 files changed, 436 insertions(+), 132 deletions(-)
 create mode 100644 clang/test/CodeGen/coverage-profile-raw-version.c
 create mode 100644 compiler-rt/test/profile/instrprof-binary-correlate.c

diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 70accce456d3c07..dad3c9a145b5049 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -42,6 +42,7 @@
 #include "llvm/Passes/PassBuilder.h"
 #include "llvm/Passes/PassPlugin.h"
 #include "llvm/Passes/StandardInstrumentations.h"
+#include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/Support/BuryPointer.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -98,13 +99,16 @@ extern cl::opt<bool> PrintPipelinePasses;
 static cl::opt<bool> ClSanitizeOnOptimizerEarlyEP(
     "sanitizer-early-opt-ep", cl::Optional,
     cl::desc("Insert sanitizers on OptimizerEarlyEP."), cl::init(false));
-}
+
+extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;
+} // namespace llvm
 
 namespace {
 
 // Default filename used for profile generation.
 std::string getDefaultProfileGenName() {
-  return DebugInfoCorrelate ? "default_%m.proflite" : "default_%m.profraw";
+  return ProfileCorrelate.getNumOccurrences() ? "default_%m.proflite"
+                                              : "default_%m.profraw";
 }
 
 class EmitAssemblyHelper {
@@ -197,7 +201,7 @@ class EmitAssemblyHelper {
   void EmitAssembly(BackendAction Action,
                     std::unique_ptr<raw_pwrite_stream> OS);
 };
-}
+} // namespace
 
 static SanitizerCoverageOptions
 getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) {
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 76ed10091b025be..daff0d1d50923f5 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -31,6 +31,10 @@
 // is textually included.
 #define COVMAP_V3
 
+namespace llvm {
+extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;
+} // namespace llvm
+
 static llvm::cl::opt<bool> EmptyLineCommentCoverage(
     "emptyline-comment-coverage",
     llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
@@ -1831,6 +1835,22 @@ void CoverageMappingModuleGen::emit() {
                              llvm::GlobalValue::InternalLinkage, NamesArrVal,
                              llvm::getCoverageUnusedNamesVarName());
   }
+  const StringRef VarName(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR));
+  llvm::Type *IntTy64 = llvm::Type::getInt64Ty(Ctx);
+  uint64_t ProfileVersion = INSTR_PROF_RAW_VERSION;
+  if (llvm::ProfileCorrelate == llvm::InstrProfCorrelator::BINARY)
+    ProfileVersion |= VARIANT_MASK_BIN_CORRELATE;
+  auto *VersionVariable = new llvm::GlobalVariable(
+      CGM.getModule(), llvm::Type::getInt64Ty(Ctx), true,
+      llvm::GlobalValue::WeakAnyLinkage,
+      llvm::Constant::getIntegerValue(IntTy64, llvm::APInt(64, ProfileVersion)),
+      VarName);
+  VersionVariable->setVisibility(llvm::GlobalValue::HiddenVisibility);
+  llvm::Triple TT(CGM.getModule().getTargetTriple());
+  if (TT.supportsCOMDAT()) {
+    VersionVariable->setLinkage(llvm::GlobalValue::ExternalLinkage);
+    VersionVariable->setComdat(CGM.getModule().getOrInsertComdat(VarName));
+  }
 }
 
 unsigned CoverageMappingModuleGen::getFileID(FileEntryRef File) {
diff --git a/clang/test/CodeGen/coverage-profile-raw-version.c b/clang/test/CodeGen/coverage-profile-raw-version.c
new file mode 100644
index 000000000000000..fc81179e1a33e06
--- /dev/null
+++ b/clang/test/CodeGen/coverage-profile-raw-version.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1  -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -mllvm -profile-correlate=binary -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -o - %s | FileCheck %s --check-prefix=BIN-CORRELATE
+
+// CHECK: @__llvm_profile_raw_version = {{.*}} i64 8
+// BIN-CORRELATE: @__llvm_profile_raw_version = {{.*}} i64 4294967304
+
+int main() {
+    return 0;
+}
diff --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc
index 8ba7e186d4fb1a6..1841ef348a70061 100644
--- a/compiler-rt/include/profile/InstrProfData.inc
+++ b/compiler-rt/include/profile/InstrProfData.inc
@@ -655,6 +655,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
  * version for other variants of profile. We set the 8th most significant bit 
  * (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentation
  * generated profile, and 0 if this is a Clang FE generated profile.
+ * 1 in bit 32 indicates there is no profile name and data sections.
  * 1 in bit 57 indicates there are context-sensitive records in the profile.
  * The 59th bit indicates whether to use debug info to correlate profiles.
  * The 60th bit indicates single byte coverage instrumentation.
@@ -664,6 +665,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
  */
 #define VARIANT_MASKS_ALL 0xffffffff00000000ULL
 #define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
+#define VARIANT_MASK_BIN_CORRELATE (0x1ULL << 32)
 #define VARIANT_MASK_IR_PROF (0x1ULL << 56)
 #define VARIANT_MASK_CSIR_PROF (0x1ULL << 57)
 #define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 58)
diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h
index 4433d7bd48871fc..8b9e029ee8baee5 100644
--- a/compiler-rt/lib/profile/InstrProfiling.h
+++ b/compiler-rt/lib/profile/InstrProfiling.h
@@ -267,6 +267,9 @@ uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin,
 uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
                                       const __llvm_profile_data *End);
 
+/*! \brief Get the size of the profile name section in bytes. */
+uint64_t __llvm_profile_get_name_size(const char *Begin, const char *End);
+
 /*! \brief Get the size in bytes of a single counter entry. */
 size_t __llvm_profile_counter_entry_size(void);
 
diff --git a/compiler-rt/lib/profile/InstrProfilingBuffer.c b/compiler-rt/lib/profile/InstrProfilingBuffer.c
index 61ac5d9c0285002..e60aa9fc04e7fac 100644
--- a/compiler-rt/lib/profile/InstrProfilingBuffer.c
+++ b/compiler-rt/lib/profile/InstrProfilingBuffer.c
@@ -53,6 +53,9 @@ uint64_t __llvm_profile_get_size_for_buffer(void) {
 COMPILER_RT_VISIBILITY
 uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin,
                                      const __llvm_profile_data *End) {
+  if ((__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) ||
+      (__llvm_profile_get_version() & VARIANT_MASK_BIN_CORRELATE))
+    return 0;
   intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End;
   return ((EndI + sizeof(__llvm_profile_data) - 1) - BeginI) /
          sizeof(__llvm_profile_data);
@@ -61,9 +64,20 @@ uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin,
 COMPILER_RT_VISIBILITY
 uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
                                       const __llvm_profile_data *End) {
+  if ((__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) ||
+      (__llvm_profile_get_version() & VARIANT_MASK_BIN_CORRELATE))
+    return 0;
   return __llvm_profile_get_num_data(Begin, End) * sizeof(__llvm_profile_data);
 }
 
+COMPILER_RT_VISIBILITY
+uint64_t __llvm_profile_get_name_size(const char *Begin, const char *End) {
+  if ((__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) ||
+      (__llvm_profile_get_version() & VARIANT_MASK_BIN_CORRELATE))
+    return 0;
+  return End - Begin;
+}
+
 COMPILER_RT_VISIBILITY size_t __llvm_profile_counter_entry_size(void) {
   if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE)
     return sizeof(uint8_t);
diff --git a/compiler-rt/lib/profile/InstrProfilingMerge.c b/compiler-rt/lib/profile/InstrProfilingMerge.c
index 9cf12f251f7262d..554ce3693b6e464 100644
--- a/compiler-rt/lib/profile/InstrProfilingMerge.c
+++ b/compiler-rt/lib/profile/InstrProfilingMerge.c
@@ -66,8 +66,9 @@ int __llvm_profile_check_compatibility(const char *ProfileData,
       Header->NumCounters !=
           __llvm_profile_get_num_counters(__llvm_profile_begin_counters(),
                                           __llvm_profile_end_counters()) ||
-      Header->NamesSize != (uint64_t)(__llvm_profile_end_names() -
-                                      __llvm_profile_begin_names()) ||
+      Header->NamesSize !=
+          __llvm_profile_get_name_size(__llvm_profile_begin_names(),
+                                       __llvm_profile_end_names()) ||
       Header->ValueKindLast != IPVK_Last)
     return 1;
 
@@ -132,7 +133,8 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData,
 
   // Merge counters by iterating the entire counter section when debug info
   // correlation is enabled.
-  if (__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) {
+  if ((__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) ||
+      (__llvm_profile_get_version() & VARIANT_MASK_BIN_CORRELATE)) {
     for (SrcCounter = SrcCountersStart,
         DstCounter = __llvm_profile_begin_counters();
          SrcCounter < SrcCountersEnd;) {
diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c b/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c
index dd576b2f8357dbb..23a7739355e2ed6 100644
--- a/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c
+++ b/compiler-rt/lib/profile/InstrProfilingPlatformWindows.c
@@ -13,8 +13,6 @@
 
 #if defined(_MSC_VER)
 /* Merge read-write sections into .data. */
-#pragma comment(linker, "/MERGE:.lprfc=.data")
-#pragma comment(linker, "/MERGE:.lprfd=.data")
 #pragma comment(linker, "/MERGE:.lprfv=.data")
 #pragma comment(linker, "/MERGE:.lprfnd=.data")
 /* Do *NOT* merge .lprfn and .lcovmap into .rdata. llvm-cov must be able to find
diff --git a/compiler-rt/lib/profile/InstrProfilingWriter.c b/compiler-rt/lib/profile/InstrProfilingWriter.c
index 1e22398a4c0f64a..f3709694427d5c8 100644
--- a/compiler-rt/lib/profile/InstrProfilingWriter.c
+++ b/compiler-rt/lib/profile/InstrProfilingWriter.c
@@ -259,19 +259,19 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
                    const char *CountersBegin, const char *CountersEnd,
                    VPDataReaderType *VPDataReader, const char *NamesBegin,
                    const char *NamesEnd, int SkipNameDataWrite) {
-  int DebugInfoCorrelate =
-      (__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) != 0ULL;
+  int ProfileCorrelation =
+      (__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) ||
+      (__llvm_profile_get_version() & VARIANT_MASK_BIN_CORRELATE);
 
   /* Calculate size of sections. */
   const uint64_t DataSectionSize =
-      DebugInfoCorrelate ? 0 : __llvm_profile_get_data_size(DataBegin, DataEnd);
-  const uint64_t NumData =
-      DebugInfoCorrelate ? 0 : __llvm_profile_get_num_data(DataBegin, DataEnd);
+      __llvm_profile_get_data_size(DataBegin, DataEnd);
+  const uint64_t NumData = __llvm_profile_get_num_data(DataBegin, DataEnd);
   const uint64_t CountersSectionSize =
       __llvm_profile_get_counters_size(CountersBegin, CountersEnd);
   const uint64_t NumCounters =
       __llvm_profile_get_num_counters(CountersBegin, CountersEnd);
-  const uint64_t NamesSize = DebugInfoCorrelate ? 0 : NamesEnd - NamesBegin;
+  const uint64_t NamesSize = __llvm_profile_get_name_size(NamesBegin, NamesEnd);
 
   /* Create the header. */
   __llvm_profile_header Header;
@@ -298,7 +298,7 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
 #endif
 
   /* The data and names sections are omitted in lightweight mode. */
-  if (DebugInfoCorrelate) {
+  if (ProfileCorrelation) {
     Header.CountersDelta = 0;
     Header.NamesDelta = 0;
   }
@@ -314,19 +314,19 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
 
   /* Write the profile data. */
   ProfDataIOVec IOVecData[] = {
-      {DebugInfoCorrelate ? NULL : DataBegin, sizeof(uint8_t), DataSectionSize,
+      {ProfileCorrelation ? NULL : DataBegin, sizeof(uint8_t), DataSectionSize,
        0},
       {NULL, sizeof(uint8_t), PaddingBytesBeforeCounters, 1},
       {CountersBegin, sizeof(uint8_t), CountersSectionSize, 0},
       {NULL, sizeof(uint8_t), PaddingBytesAfterCounters, 1},
-      {(SkipNameDataWrite || DebugInfoCorrelate) ? NULL : NamesBegin,
+      {(SkipNameDataWrite || ProfileCorrelation) ? NULL : NamesBegin,
        sizeof(uint8_t), NamesSize, 0},
       {NULL, sizeof(uint8_t), PaddingBytesAfterNames, 1}};
   if (Writer->Write(Writer, IOVecData, sizeof(IOVecData) / sizeof(*IOVecData)))
     return -1;
-
-  /* Value profiling is not yet supported in continuous mode. */
-  if (__llvm_profile_is_continuous_mode_enabled())
+  /* Value profiling is not yet supported in continuous mode and profile
+   * correlation mode. */
+  if (__llvm_profile_is_continuous_mode_enabled() || ProfileCorrelation)
     return 0;
 
   return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd);
diff --git a/compiler-rt/test/CMakeLists.txt b/compiler-rt/test/CMakeLists.txt
index f9b01b15b0e62c6..7357604b1f651eb 100644
--- a/compiler-rt/test/CMakeLists.txt
+++ b/compiler-rt/test/CMakeLists.txt
@@ -37,8 +37,9 @@ if(NOT ANDROID)
   if(NOT COMPILER_RT_STANDALONE_BUILD AND NOT LLVM_RUNTIMES_BUILD)
     # Use LLVM utils and Clang from the same build tree.
     list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS
-      clang clang-resource-headers FileCheck count not llvm-config llvm-nm llvm-objdump
-      llvm-readelf llvm-readobj llvm-size llvm-symbolizer compiler-rt-headers sancov split-file)
+      clang clang-resource-headers FileCheck count not llvm-config llvm-nm 
+      llvm-objdump llvm-readelf llvm-readobj llvm-size llvm-symbolizer 
+      compiler-rt-headers sancov split-file llvm-strip)
     if (WIN32)
       list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS KillTheDoctor)
     endif()
diff --git a/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c b/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c
index f347d439e2e0671..46d25a4e386dc3a 100644
--- a/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c
+++ b/compiler-rt/test/profile/Darwin/instrprof-debug-info-correlate.c
@@ -1,5 +1,5 @@
 // Value profiling is currently not supported in lightweight mode.
-// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: %clang_pgogen -o %t -g -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
 // RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
 // RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.proflite
 
@@ -9,7 +9,7 @@
 
 // RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
 
-// RUN: %clang_pgogen -o %t.cov -g -mllvm --debug-info-correlate -mllvm -pgo-function-entry-coverage -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: %clang_pgogen -o %t.cov -g -mllvm --profile-correlate=debug-info -mllvm -pgo-function-entry-coverage -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
 // RUN: env LLVM_PROFILE_FILE=%t.cov.proflite %run %t.cov
 // RUN: llvm-profdata merge -o %t.cov.profdata --debug-info=%t.cov.dSYM %t.cov.proflite
 
diff --git a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate-warnings.c b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate-warnings.c
index 5069c6340b64fd2..25022f241a6d281 100644
--- a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate-warnings.c
+++ b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate-warnings.c
@@ -1,6 +1,6 @@
 // Disable full debug info and verify that we get warnings during merging
 
-// RUN: %clang_pgogen -o %t -gline-tables-only -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: %clang_pgogen -o %t -gline-tables-only -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
 // RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
 // RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.proflite --max-debug-info-correlation-warnings=2 2>&1 >/dev/null | FileCheck %s --check-prefixes=CHECK,LIMIT --implicit-check-not=warning
 // RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.proflite --max-debug-info-correlation-warnings=0 2>&1 >/dev/null | FileCheck %s --check-prefixes=CHECK,NOLIMIT --implicit-check-not=warning
diff --git a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
index a918d7b6299005e..ccfd65b6f4c4b16 100644
--- a/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
+++ b/compiler-rt/test/profile/Linux/instrprof-debug-info-correlate.c
@@ -3,19 +3,19 @@
 // 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.d4 -g -gdwarf-4 -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: %clang_pgogen -o %t.d4 -g -gdwarf-4 -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
 // RUN: env LLVM_PROFILE_FILE=%t.d4.proflite %run %t.d4
 // RUN: llvm-profdata merge -o %t.d4.profdata --debug-info=%t.d4 %t.d4.proflite
 
 // RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.d4.profdata)
 
-// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: %clang_pgogen -o %t -g -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
 // RUN: env LLVM_PROFILE_FILE=%t.proflite %run %t
 // RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.proflite
 
 // RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
 
-// RUN: %clang_pgogen -o %t.cov -g -mllvm --debug-info-correlate -mllvm -pgo-function-entry-coverage -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: %clang_pgogen -o %t.cov -g -mllvm --profile-correlate=debug-info -mllvm -pgo-function-entry-coverage -mllvm --disable-vp=true %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp
 // RUN: env LLVM_PROFILE_FILE=%t.cov.proflite %run %t.cov
 // RUN: llvm-profdata merge -o %t.cov.profdata --debug-info=%t.cov %t.cov.proflite
 
diff --git a/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c b/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c
index 226d678aca347a4..93bf40f98d3ab62 100644
--- a/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c
+++ b/compiler-rt/test/profile/Linux/instrprof-show-debug-info-correlation.c
@@ -1,10 +1,10 @@
-// RUN: %clang_pgogen -o %t -g -mllvm --debug-info-correlate -mllvm --disable-vp=true %s
+// RUN: %clang_pgogen -o %t -g -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %s
 // RUN: llvm-profdata show --debug-info=%t --detailed-summary --show-prof-sym-list | FileCheck %s
 // RUN: llvm-profdata show --debug-info=%t --show-format=yaml | FileCheck %s --match-full-lines --check-prefix YAML
 
-// RUN: %clang_pgogen -o %t.no.dbg -mllvm --debug-info-correlate -mllvm --disable-vp=true %s
+// RUN: %clang_pgogen -o %t.no.dbg -mllvm --profile-correlate=debug-info -mllvm --disable-vp=true %s
 // RUN: not llvm-profdata show --debug-info=%t.no.dbg 2>&1 | FileCheck %s --check-prefix NO-DBG
-// NO-DBG: unable to correlate profile: could not find any profile metadata in debug info
+// NO-DBG: unable to correlate profile: could not find any profile data metadata in correlated file
 
 // YAML: Probes:
 // YAML:   - Function Name:   a
diff --git a/compiler-rt/test/profile/instrprof-binary-correlate.c b/compiler-rt/test/profile/instrprof-binary-correlate.c
new file mode 100644
index 000000000000000..2154c13027e286b
--- /dev/null
+++ b/compiler-rt/test/profile/instrprof-binary-correlate.c
@@ -0,0 +1,29 @@
+// REQUIRES: linux || windows
+// Default
+// RUN: %clang -o %t.normal -fprofile-instr-generate -fcoverage-mapping -fuse-ld=lld %S/Inputs/instrprof-debug-info-correlate-main.cpp %S/Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw
+
+// With -profile-correlate=binary flag
+// RUN: %clang -o %t-1.exe -fprofile-instr-generate -fcoverage-mapping -mllvm -profile-correlate=binary -fuse-ld=lld %S/Inputs/instrprof-debug-info-correlate-main.cpp %S/Inputs/instrprof-debug-info-correlate-foo.cpp
+// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t-1.exe
+// RUN: llvm-profdata merge -o %t-1.profdata --object-file=%t-1.exe %t-1.profraw 
+// RUN: diff %t.normal.profdata %t-1.profdata 
+
+// Strip above binary and run
+// RUN: llvm-strip %t-1.exe -o %t-2.exe
+// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t-2.exe
+// RUN: llvm-profdata merge -o %t-2.profdata --object-file=%t-1.exe %t-2.profraw 
+// RUN: diff %t.normal.profdata %t-2.profdata 
+
+// Online merging.
+// RUN: env LLVM_PROFILE_FILE=%t-3.profraw %run %t.normal
+// RUN: env LLVM_PROFILE_FILE=%t-4.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.merged.profdata %t-3.profraw %t-4.profraw
+// RUN: rm -rf %t.profdir && mkdir %t.profdir
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m-4.profraw %run %t-2.exe
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m-4.profraw %run %t-2.exe
+// RUN: llvm-profdata merge -o %t-4.profdata --object-file=%t-1.exe  %t.profdir
+// RUN: diff %t.normal.merged.profdata %t-4.profdata
+
+// TODO: After adding support for binary ID, test binaries with different binary IDs.
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index 9239c1a691eca19..00a7bafb54e89ea 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -328,8 +328,8 @@ enum class instrprof_error {
   too_large,
   truncated,
   malformed,
-  missing_debug_info_for_correlation,
-  unexpected_debug_info_for_correlation,
+  missing_correlation_info,
+  unexpected_correlation_info,
   unable_to_correlate_profile,
   unknown_function,
   invalid_prof,
@@ -460,7 +460,7 @@ class InstrProfSymtab {
   /// only initialize the symtab with reference to the data and
   /// the section base address. The decompression will be delayed
   /// until before it is used. See also \c create(StringRef) method.
-  Error create(object::SectionRef &Section);
+  Error create(object::SectionRef &Section, bool MightHasNullByte = false);
 
   /// This interface is used by reader of CoverageMapping test
   /// format.
diff --git a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
index dd062951f277c1c..661570eaee11300 100644
--- a/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
+++ b/llvm/include/llvm/ProfileData/InstrProfCorrelator.h
@@ -5,8 +5,8 @@
 // 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.
+// This file defines InstrProfCorrelator used to generate PGO/coverage profiles 
+// from raw profile data and debug info/binary file.
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_PROFILEDATA_INSTRPROFCORRELATOR_H
@@ -31,8 +31,12 @@ class ObjectFile;
 /// to their functions.
 class InstrProfCorrelator {
 public:
+  /// Indicate if we should use the debug info or profile metadata sections to
+  /// correlate.
+  enum ProfCorrelatorKind { NONE, DEBUG_INFO, BINARY };
+
   static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
-  get(StringRef DebugInfoFilename);
+  get(StringRef Filename, ProfCorrelatorKind FileKind);
 
   /// Construct a ProfileData vector used to correlate raw instrumentation data
   /// to their functions.
@@ -68,11 +72,18 @@ class InstrProfCorrelator {
 protected:
   struct Context {
     static llvm::Expected<std::unique_ptr<Context>>
-    get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj);
+    get(std::unique_ptr<MemoryBuffer> Buffer, const object::ObjectFile &Obj,
+        ProfCorrelatorKind FileKind);
     std::unique_ptr<MemoryBuffer> Buffer;
     /// The address range of the __llvm_prf_cnts section.
     uint64_t CountersSectionStart;
     uint64_t CountersSectionEnd;
+    /// The pointer points to start/end of profile data/name sections if
+    /// FileKind is Binary.
+    const char *DataStart;
+    const char *DataEnd;
+    const char *NameStart;
+    size_t NameSize;
     /// True if target and host have different endian orders.
     bool ShouldSwapBytes;
   };
@@ -104,7 +115,7 @@ class InstrProfCorrelator {
 
 private:
   static llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
-  get(std::unique_ptr<MemoryBuffer> Buffer);
+  get(std::unique_ptr<MemoryBuffer> Buffer, ProfCorrelatorKind FileKind);
 
   const InstrProfCorrelatorKind Kind;
 };
@@ -128,7 +139,7 @@ class InstrProfCorrelatorImpl : public InstrProfCorrelator {
 
   static llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
   get(std::unique_ptr<InstrProfCorrelator::Context> Ctx,
-      const object::ObjectFile &Obj);
+      const object::ObjectFile &Obj, ProfCorrelatorKind FileKind);
 
 protected:
   std::vector<RawInstrProf::ProfileData<IntPtrT>> Data;
@@ -138,21 +149,23 @@ class InstrProfCorrelatorImpl : public InstrProfCorrelator {
       int MaxWarnings,
       InstrProfCorrelator::CorrelationData *Data = nullptr) = 0;
 
+  virtual Error correlateProfileNameImpl() = 0;
+
   Error dumpYaml(int MaxWarnings, raw_ostream &OS) override;
 
   void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset,
                 IntPtrT FunctionPtr, uint32_t NumCounters);
 
+  // Byte-swap the value if necessary.
+  template <class T> T maybeSwap(T Value) const {
+    return Ctx->ShouldSwapBytes ? llvm::byteswap(Value) : Value;
+  }
+
 private:
   InstrProfCorrelatorImpl(InstrProfCorrelatorKind Kind,
                           std::unique_ptr<InstrProfCorrelator::Context> Ctx)
       : InstrProfCorrelator(Kind, std::move(Ctx)){};
   llvm::DenseSet<IntPtrT> CounterOffsets;
-
-  // Byte-swap the value if necessary.
-  template <class T> T maybeSwap(T Value) const {
-    return Ctx->ShouldSwapBytes ? llvm::byteswap(Value) : Value;
-  }
 };
 
 /// DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes
@@ -205,6 +218,30 @@ class DwarfInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
   void correlateProfileDataImpl(
       int MaxWarnings,
       InstrProfCorrelator::CorrelationData *Data = nullptr) override;
+
+  Error correlateProfileNameImpl() override;
+};
+
+/// BinaryInstrProfCorrelator - A child of InstrProfCorrelatorImpl that
+/// takes an object file as input to correlate profiles.
+template <class IntPtrT>
+class BinaryInstrProfCorrelator : public InstrProfCorrelatorImpl<IntPtrT> {
+public:
+  BinaryInstrProfCorrelator(std::unique_ptr<InstrProfCorrelator::Context> Ctx)
+      : InstrProfCorrelatorImpl<IntPtrT>(std::move(Ctx)) {}
+
+  /// Return a pointer to the names string that this class constructs.
+  const char *getNamesPointer() const { return this->Ctx.NameStart; }
+
+  /// Return the number of bytes in the names string.
+  size_t getNamesSize() const { return this->Ctx.NameSize; }
+
+private:
+  void correlateProfileDataImpl(
+      int MaxWarnings,
+      InstrProfCorrelator::CorrelationData *Data = nullptr) override;
+
+  Error correlateProfileNameImpl() override;
 };
 
 } // end namespace llvm
diff --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc
index 13be2753e514efe..f6c5f2b3fa17301 100644
--- a/llvm/include/llvm/ProfileData/InstrProfData.inc
+++ b/llvm/include/llvm/ProfileData/InstrProfData.inc
@@ -655,6 +655,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
  * version for other variants of profile. We set the 8th most significant bit 
  * (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentation
  * generated profile, and 0 if this is a Clang FE generated profile.
+ * 1 in bit 32 indicates whether to use binary to correlate profiles.
  * 1 in bit 57 indicates there are context-sensitive records in the profile.
  * The 59th bit indicates whether to use debug info to correlate profiles.
  * The 60th bit indicates single byte coverage instrumentation.
@@ -664,6 +665,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
  */
 #define VARIANT_MASKS_ALL 0xffffffff00000000ULL
 #define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
+#define VARIANT_MASK_BIN_CORRELATE (0x1ULL << 32)
 #define VARIANT_MASK_IR_PROF (0x1ULL << 56)
 #define VARIANT_MASK_CSIR_PROF (0x1ULL << 57)
 #define VARIANT_MASK_INSTR_ENTRY (0x1ULL << 58)
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index 5f54cbeb1b01eda..d5eb009087d9f9b 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -126,6 +126,8 @@ class InstrProfReader {
   /// Return true if we must provide debug info to create PGO profiles.
   virtual bool useDebugInfoCorrelate() const { return false; }
 
+  virtual bool useBinaryCorrelate() const { return false; }
+
   /// Return true if the profile has single byte counters representing coverage.
   virtual bool hasSingleByteCoverage() const = 0;
 
@@ -374,6 +376,14 @@ class RawInstrProfReader : public InstrProfReader {
     return (Version & VARIANT_MASK_DBG_CORRELATE) != 0;
   }
 
+  bool useBinaryCorrelate() const override {
+    return (Version & VARIANT_MASK_BIN_CORRELATE) != 0;
+  }
+
+  bool useCorrelate() const {
+    return useDebugInfoCorrelate() || useBinaryCorrelate();
+  }
+
   bool hasSingleByteCoverage() const override {
     return (Version & VARIANT_MASK_BYTE_COVERAGE) != 0;
   }
diff --git a/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h
index 5b1977b7de9a2ae..3d8f3bd9235451f 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h
@@ -24,8 +24,6 @@
 
 namespace llvm {
 
-extern cl::opt<bool> DebugInfoCorrelate;
-
 class Function;
 class Instruction;
 class Module;
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 6210e7fc128a30c..fd785ff2629932e 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -57,6 +57,7 @@
 #include "llvm/MC/MCValue.h"
 #include "llvm/MC/SectionKind.h"
 #include "llvm/ProfileData/InstrProf.h"
+#include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/Support/Base64.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CodeGen.h"
@@ -71,6 +72,10 @@
 using namespace llvm;
 using namespace dwarf;
 
+namespace llvm {
+extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;
+} // namespace llvm
+
 static cl::opt<bool> JumpTableInFunctionSection(
     "jumptable-in-function-section", cl::Hidden, cl::init(false),
     cl::desc("Putting Jump Table in function section"));
@@ -472,7 +477,15 @@ static SectionKind getELFKindForNamedSection(StringRef Name, SectionKind K) {
                                       /*AddSegmentInfo=*/false) ||
       Name == getInstrProfSectionName(IPSK_covfun, Triple::ELF,
                                       /*AddSegmentInfo=*/false) ||
-      Name == ".llvmbc" || Name == ".llvmcmd")
+      Name == ".llvmbc" || Name == ".llvmcmd" ||
+      // Instead of checking the flag, maybe we should check if
+      // VARIANT_MASK_BIN_CORRELATE flag is set at the profile version global
+      // variable.
+      (ProfileCorrelate == InstrProfCorrelator::BINARY &&
+       (Name == getInstrProfSectionName(llvm::IPSK_name, Triple::ELF,
+                                        /*AddSegmentInfo=*/false) ||
+        Name == getInstrProfSectionName(llvm::IPSK_data, Triple::ELF,
+                                        /*AddSegmentInfo=*/false))))
     return SectionKind::getMetadata();
 
   if (Name.empty() || Name[0] != '.') return K;
@@ -1674,9 +1687,15 @@ static int getSelectionForCOFF(const GlobalValue *GV) {
 
 MCSection *TargetLoweringObjectFileCOFF::getExplicitSectionGlobal(
     const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
+  StringRef Name = GO->getSection();
+  if (ProfileCorrelate == InstrProfCorrelator::BINARY &&
+      (Name == getInstrProfSectionName(llvm::IPSK_name, Triple::COFF,
+                                       /*AddSegmentInfo=*/false) ||
+       Name == getInstrProfSectionName(llvm::IPSK_data, Triple::COFF,
+                                       /*AddSegmentInfo=*/false)))
+    Kind = SectionKind::getMetadata();
   int Selection = 0;
   unsigned Characteristics = getCOFFSectionFlags(Kind, TM);
-  StringRef Name = GO->getSection();
   StringRef COMDATSymName = "";
   if (GO->hasComdat()) {
     Selection = getSelectionForCOFF(GO);
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index 857498256ec54c4..a56e4c90911141b 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -457,7 +457,7 @@ Expected<bool> RawCoverageMappingDummyChecker::isDummy() {
   return Tag == Counter::Zero;
 }
 
-Error InstrProfSymtab::create(SectionRef &Section) {
+Error InstrProfSymtab::create(SectionRef &Section, bool MightHasNullByte) {
   Expected<StringRef> DataOrErr = Section.getContents();
   if (!DataOrErr)
     return DataOrErr.takeError();
@@ -467,7 +467,8 @@ Error InstrProfSymtab::create(SectionRef &Section) {
   // If this is a linked PE/COFF file, then we have to skip over the null byte
   // that is allocated in the .lprfn$A section in the LLVM profiling runtime.
   const ObjectFile *Obj = Section.getObject();
-  if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject())
+  if (MightHasNullByte && isa<COFFObjectFile>(Obj) &&
+      !Obj->isRelocatableObject())
     Data = Data.drop_front(1);
 
   return Error::success();
@@ -1070,11 +1071,24 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
 
   InstrProfSymtab ProfileNames;
   std::vector<SectionRef> NamesSectionRefs = *NamesSection;
-  if (NamesSectionRefs.size() != 1)
-    return make_error<CoverageMapError>(
-        coveragemap_error::malformed,
-        "the size of coverage mapping section is not one");
-  if (Error E = ProfileNames.create(NamesSectionRefs.back()))
+  bool MightHasNullByte = true;
+  if (NamesSectionRefs.size() != 1) {
+    // By default, the profile name section in the binary starts with a null
+    // byte and followed by names. But if binary correlation is enabled, there
+    // will be 2 name sections. One contains only two null bytes, and another
+    // one contains the names without the dummy null byte at the beginning.
+    if (ObjFormat == Triple::COFF) {
+      NamesSectionRefs.erase(
+          std::remove_if(NamesSectionRefs.begin(), NamesSectionRefs.end(),
+                         [](const SectionRef &S) { return S.isData(); }));
+      MightHasNullByte = false;
+    }
+    if (NamesSectionRefs.size() != 1)
+      return make_error<CoverageMapError>(
+          coveragemap_error::malformed,
+          "the size of coverage mapping section is not one");
+  }
+  if (Error E = ProfileNames.create(NamesSectionRefs.back(), MightHasNullByte))
     return std::move(E);
 
   // Look for the coverage records section (Version4 only).
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index ddc11304742df76..349ebf3762df40a 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -113,11 +113,11 @@ 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";
+  case instrprof_error::missing_correlation_info:
+    OS << "debug info/binary for correlation is required";
     break;
-  case instrprof_error::unexpected_debug_info_for_correlation:
-    OS << "debug info for correlation is not necessary";
+  case instrprof_error::unexpected_correlation_info:
+    OS << "debug info/binary for correlation is not necessary";
     break;
   case instrprof_error::unable_to_correlate_profile:
     OS << "unable to correlate profile";
diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
index 71787c9bd8577b4..347879e71bbda18 100644
--- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp
+++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
@@ -24,15 +24,43 @@
 
 using namespace llvm;
 
-/// Get the __llvm_prf_cnts section.
-Expected<object::SectionRef> getCountersSection(const object::ObjectFile &Obj) {
+namespace llvm {
+cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate(
+    "profile-correlate",
+    cl::desc("Use debug info or binary file to correlate profiles."),
+    cl::init(InstrProfCorrelator::NONE),
+    cl::values(clEnumValN(InstrProfCorrelator::NONE, "",
+                          "No profile correlation"),
+               clEnumValN(InstrProfCorrelator::DEBUG_INFO, "debug-info",
+                          "Use debug info to correlate"),
+               clEnumValN(InstrProfCorrelator::BINARY, "binary",
+                          "Use binary to correlate")));
+} // namespace llvm
+
+/// Get profile section.
+Expected<object::SectionRef> getInstrProfSection(const object::ObjectFile &Obj,
+                                                 InstrProfSectKind IPSK) {
+  // On COFF, the object file section name may end in "$M". This tells the
+  // linker to sort these sections between "$A" and "$Z". The linker removes the
+  // dollar and everything after it in the final binary. Do the same to match.
+  Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat();
+  std::string ExpectedSectionName =
+      getInstrProfSectionName(IPSK, ObjFormat,
+                              /*AddSegmentInfo=*/false);
   for (auto &Section : Obj.sections())
     if (auto SectionName = Section.getName())
-      if (SectionName.get() == INSTR_PROF_CNTS_SECT_NAME)
+      if (SectionName.get() == ExpectedSectionName) {
+        // There will be extra profile name and data sections in COFF used for
+        // runtime to detect start/stop of those sections, skipping them.
+        // (details at compiler-rt/lib/profile/InstrProfilingPlatformWindows.c)
+        if (ObjFormat == Triple::COFF && IPSK != IPSK_cnts && Section.isData())
+          continue;
         return Section;
+      }
+
   return make_error<InstrProfError>(
       instrprof_error::unable_to_correlate_profile,
-      "could not find counter section (" INSTR_PROF_CNTS_SECT_NAME ")");
+      "could not find section (" + Twine(ExpectedSectionName) + ")");
 }
 
 const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name";
@@ -41,56 +69,84 @@ 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);
+                                  const object::ObjectFile &Obj,
+                                  ProfCorrelatorKind FileKind) {
+  auto C = std::make_unique<Context>();
+  auto CountersSection = getInstrProfSection(Obj, IPSK_cnts);
   if (auto Err = CountersSection.takeError())
     return std::move(Err);
-  auto C = std::make_unique<Context>();
+  if (FileKind == InstrProfCorrelator::BINARY) {
+    auto DataSection = getInstrProfSection(Obj, IPSK_data);
+    if (auto Err = DataSection.takeError())
+      return std::move(Err);
+    auto DataOrErr = DataSection->getContents();
+    if (!DataOrErr)
+      return DataOrErr.takeError();
+    auto NameSection = getInstrProfSection(Obj, IPSK_name);
+    if (auto Err = NameSection.takeError())
+      return std::move(Err);
+    auto NameOrErr = NameSection->getContents();
+    if (!NameOrErr)
+      return NameOrErr.takeError();
+    C->DataStart = DataOrErr->data();
+    C->DataEnd = DataOrErr->data() + DataOrErr->size();
+    C->NameStart = NameOrErr->data();
+    C->NameSize = NameOrErr->size();
+  }
   C->Buffer = std::move(Buffer);
   C->CountersSectionStart = CountersSection->getAddress();
   C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize();
+  // In COFF object file, there's a null byte at the beginning of the counter
+  // section which doesn't exist in raw profile.
+  if (Obj.getTripleObjectFormat() == Triple::COFF)
+    C->CountersSectionStart++;
+
   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 make_error<InstrProfError>(
-          instrprof_error::unable_to_correlate_profile,
-          "using multiple objects is not yet supported");
-    DebugInfoFilename = *DsymObjectsOrErr->begin();
+InstrProfCorrelator::get(StringRef Filename, ProfCorrelatorKind FileKind) {
+  if (FileKind == DEBUG_INFO) {
+    auto DsymObjectsOrErr =
+        object::MachOObjectFile::findDsymObjectMembers(Filename);
+    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 make_error<InstrProfError>(
+            instrprof_error::unable_to_correlate_profile,
+            "using multiple objects is not yet supported");
+      Filename = *DsymObjectsOrErr->begin();
+    }
   }
-  auto BufferOrErr =
-      errorOrToExpected(MemoryBuffer::getFile(DebugInfoFilename));
+  auto BufferOrErr = errorOrToExpected(MemoryBuffer::getFile(Filename));
   if (auto Err = BufferOrErr.takeError())
     return std::move(Err);
 
-  return get(std::move(*BufferOrErr));
+  return get(std::move(*BufferOrErr), FileKind);
 }
 
 llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
-InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer) {
+InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer,
+                         ProfCorrelatorKind FileKind) {
   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);
+    auto CtxOrErr = Context::get(std::move(Buffer), *Obj, FileKind);
     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);
+      return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj,
+                                                    FileKind);
     if (T.isArch32Bit())
-      return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj);
+      return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj,
+                                                    FileKind);
   }
   return make_error<InstrProfError>(
       instrprof_error::unable_to_correlate_profile, "not an object file");
@@ -132,29 +188,35 @@ 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));
+    const object::ObjectFile &Obj, ProfCorrelatorKind FileKind) {
+  if (FileKind == DEBUG_INFO) {
+    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::unable_to_correlate_profile,
+        "unsupported debug info format (only DWARF is supported)");
   }
+  if (Obj.isELF() || Obj.isCOFF())
+    return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx));
   return make_error<InstrProfError>(
-      instrprof_error::unable_to_correlate_profile,
-      "unsupported debug info format (only DWARF is supported)");
+        instrprof_error::unable_to_correlate_profile,
+        "unsupported binary format (only ELF and COFF are supported)");
 }
 
 template <class IntPtrT>
 Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData(int MaxWarnings) {
   assert(Data.empty() && Names.empty() && NamesVec.empty());
   correlateProfileDataImpl(MaxWarnings);
-  if (Data.empty() || NamesVec.empty())
+  if (this->Data.empty())
     return make_error<InstrProfError>(
         instrprof_error::unable_to_correlate_profile,
-        "could not find any profile metadata in debug info");
-  auto Result =
-      collectPGOFuncNameStrings(NamesVec, /*doCompression=*/false, Names);
-  CounterOffsets.clear();
-  NamesVec.clear();
+        "could not find any profile data metadata in correlated file");
+  Error Result = correlateProfileNameImpl();
+  this->CounterOffsets.clear();
+  this->NamesVec.clear();
   return Result;
 }
 
@@ -361,3 +423,64 @@ void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
     WithColor::warning() << format("Suppressed %d additional warnings\n",
                                    NumSuppressedWarnings);
 }
+
+template <class IntPtrT>
+Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
+  if (this->NamesVec.empty()) {
+    return make_error<InstrProfError>(
+        instrprof_error::unable_to_correlate_profile,
+        "could not find any profile name metadata in debug info");
+  }
+  auto Result = collectPGOFuncNameStrings(this->NamesVec,
+                                          /*doCompression=*/false, this->Names);
+  return Result;
+}
+
+template <class IntPtrT>
+void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
+    int MaxWarnings, InstrProfCorrelator::CorrelationData *CorrelateData) {
+  bool UnlimitedWarnings = (MaxWarnings == 0);
+  // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
+  int NumSuppressedWarnings = -MaxWarnings;
+
+  const RawInstrProf::ProfileData<IntPtrT> *DataStart =
+      (const RawInstrProf::ProfileData<IntPtrT> *)this->Ctx->DataStart;
+  const RawInstrProf::ProfileData<IntPtrT> *DataEnd =
+      (const RawInstrProf::ProfileData<IntPtrT> *)this->Ctx->DataEnd;
+  // We need to use < here because the last data record may have no padding.
+  for (const RawInstrProf::ProfileData<IntPtrT> *I = DataStart; I < DataEnd;
+       ++I) {
+    uint64_t CounterPtr = this->template maybeSwap<IntPtrT>(I->CounterPtr);
+    uint64_t CountersStart = this->Ctx->CountersSectionStart;
+    uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
+    if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
+      if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+        WithColor::warning() << format(
+            "CounterPtr out of range for function: Actual=0x%x "
+            "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
+            CounterPtr, CountersStart, CountersEnd,
+            (I - DataStart) * sizeof(RawInstrProf::ProfileData<IntPtrT>));
+      }
+    }
+    IntPtrT CounterOffset = CounterPtr - CountersStart;
+    this->Data.push_back({I->NameRef,
+                          I->FuncHash,
+                          this->template maybeSwap<IntPtrT>(CounterOffset),
+                          I->FunctionPointer,
+                          // Value profiling is not supported.
+                          0,
+                          I->NumCounters,
+                          {0, 0}});
+  }
+}
+
+template <class IntPtrT>
+Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
+  if (this->Ctx->NameSize == 0) {
+    return make_error<InstrProfError>(
+        instrprof_error::unable_to_correlate_profile,
+        "could not find any profile data metadata in object file");
+  }
+  this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
+  return Error::success();
+}
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index a920a31d0a4b229..2b5181e6b34043c 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -540,10 +540,10 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
                   "\nPLEASE update this tool to version in the raw profile, or "
                   "regenerate raw profile with expected version.")
                      .str());
-  if (useDebugInfoCorrelate() && !Correlator)
-    return error(instrprof_error::missing_debug_info_for_correlation);
-  if (!useDebugInfoCorrelate() && Correlator)
-    return error(instrprof_error::unexpected_debug_info_for_correlation);
+  if (useCorrelate() && !Correlator)
+    return error(instrprof_error::missing_correlation_info);
+  if (!useCorrelate() && Correlator)
+    return error(instrprof_error::unexpected_correlation_info);
 
   BinaryIdsSize = swap(Header.BinaryIdsSize);
   if (BinaryIdsSize % sizeof(uint64_t))
diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
index 57fcfd53836911b..7eaa92bfe842e16 100644
--- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
@@ -60,10 +60,7 @@ using namespace llvm;
 #define DEBUG_TYPE "instrprof"
 
 namespace llvm {
-cl::opt<bool>
-    DebugInfoCorrelate("debug-info-correlate",
-                       cl::desc("Use debug info to correlate profiles."),
-                       cl::init(false));
+extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;
 } // namespace llvm
 
 namespace {
@@ -627,7 +624,7 @@ void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) {
   // in lightweight mode. We need to move the value profile pointer to the
   // Counter struct to get this working.
   assert(
-      !DebugInfoCorrelate &&
+      ProfileCorrelate == InstrProfCorrelator::NONE &&
       "Value profiling is not yet supported with lightweight instrumentation");
   GlobalVariable *Name = Ind->getName();
   auto It = ProfileDataMap.find(Name);
@@ -965,8 +962,8 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
 
   // Use internal rather than private linkage so the counter variable shows up
   // in the symbol table when using debug info for correlation.
-  if (DebugInfoCorrelate && TT.isOSBinFormatMachO() &&
-      Linkage == GlobalValue::PrivateLinkage)
+  if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO &&
+      TT.isOSBinFormatMachO() && Linkage == GlobalValue::PrivateLinkage)
     Linkage = GlobalValue::InternalLinkage;
 
   // Due to the limitation of binder as of 2021/09/28, the duplicate weak
@@ -1030,7 +1027,7 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
   CounterPtr->setLinkage(Linkage);
   MaybeSetComdat(CounterPtr);
   PD.RegionCounters = CounterPtr;
-  if (DebugInfoCorrelate) {
+  if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) {
     if (auto *SP = Fn->getSubprogram()) {
       DIBuilder DB(*M, true, SP->getUnit());
       Metadata *FunctionNameAnnotation[] = {
@@ -1083,7 +1080,7 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
         ConstantExpr::getBitCast(ValuesVar, Type::getInt8PtrTy(Ctx));
   }
 
-  if (DebugInfoCorrelate) {
+  if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO) {
     // Mark the counter variable as used so that it isn't optimized out.
     CompilerUsedVars.push_back(PD.RegionCounters);
     return PD.RegionCounters;
@@ -1124,11 +1121,17 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfInstBase *Inc) {
   }
   auto *Data =
       new GlobalVariable(*M, DataTy, false, Linkage, nullptr, DataVarName);
-  // Reference the counter variable with a label difference (link-time
-  // constant).
-  auto *RelativeCounterPtr =
-      ConstantExpr::getSub(ConstantExpr::getPtrToInt(CounterPtr, IntPtrTy),
-                           ConstantExpr::getPtrToInt(Data, IntPtrTy));
+  Constant *RelativeCounterPtr;
+  if (ProfileCorrelate == InstrProfCorrelator::BINARY) {
+    // CounterPtr needs to be absolute when we make data section strippable.
+    RelativeCounterPtr = ConstantExpr::getPtrToInt(CounterPtr, IntPtrTy);
+  } else {
+    // Reference the counter variable with a label difference (link-time
+    // constant).
+    RelativeCounterPtr =
+        ConstantExpr::getSub(ConstantExpr::getPtrToInt(CounterPtr, IntPtrTy),
+                             ConstantExpr::getPtrToInt(Data, IntPtrTy));
+  }
 
   Constant *DataVals[] = {
 #define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Init,
diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
index 7ad1c9bc54f3780..6dcbf3ada5f0c72 100644
--- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
+++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
@@ -327,6 +327,7 @@ extern cl::opt<PGOViewCountsType> PGOViewCounts;
 // Defined in Analysis/BlockFrequencyInfo.cpp:  -view-bfi-func-name=
 extern cl::opt<std::string> ViewBlockFreqFuncName;
 
+extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;
 } // namespace llvm
 
 static cl::opt<bool>
@@ -381,7 +382,7 @@ static GlobalVariable *createIRLevelProfileFlagVar(Module &M, bool IsCS) {
     ProfileVersion |= VARIANT_MASK_CSIR_PROF;
   if (PGOInstrumentEntry)
     ProfileVersion |= VARIANT_MASK_INSTR_ENTRY;
-  if (DebugInfoCorrelate)
+  if (ProfileCorrelate == InstrProfCorrelator::DEBUG_INFO)
     ProfileVersion |= VARIANT_MASK_DBG_CORRELATE;
   if (PGOFunctionEntryCoverage)
     ProfileVersion |=
diff --git a/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll b/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll
index 192bac6e503a07b..dd6461533817050 100644
--- a/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll
+++ b/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -passes=instrprof -debug-info-correlate -S | opt -O2 -S | FileCheck %s
+; RUN: opt < %s -passes=instrprof -profile-correlate=debug-info -S | opt -O2 -S | FileCheck %s
 
 @__profn_foo = private constant [3 x i8] c"foo"
 ; CHECK:      @__profc_foo
diff --git a/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll b/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll
index fd868ead5b78d21..84eaab33701a487 100644
--- a/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll
+++ b/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -passes=instrprof -debug-info-correlate -S > %t.ll
+; RUN: opt < %s -passes=instrprof -profile-correlate=debug-info -S > %t.ll
 ; RUN: FileCheck < %t.ll --implicit-check-not "{{__llvm_prf_data|__llvm_prf_names}}" %s
 ; RUN: %llc_dwarf -O0 -filetype=obj < %t.ll | llvm-dwarfdump - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s --check-prefix CHECK-DWARF
 
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 7d665a8005b0d62..c0db32e8343d820 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -413,10 +413,11 @@ static void writeInstrProfile(StringRef OutputFilename,
 
 static void
 mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename,
-                  SymbolRemapper *Remapper, StringRef OutputFilename,
-                  ProfileFormat OutputFormat, uint64_t TraceReservoirSize,
-                  uint64_t MaxTraceLength, int MaxDbgCorrelationWarnings,
-                  bool OutputSparse, unsigned NumThreads, FailureMode FailMode,
+                  StringRef ObjectFilename, SymbolRemapper *Remapper,
+                  StringRef OutputFilename, ProfileFormat OutputFormat,
+                  uint64_t TraceReservoirSize, uint64_t MaxTraceLength,
+                  int MaxDbgCorrelationWarnings, bool OutputSparse,
+                  unsigned NumThreads, FailureMode FailMode,
                   const StringRef ProfiledBinary) {
   if (OutputFormat == PF_Compact_Binary)
     exitWithError("Compact Binary is deprecated");
@@ -425,12 +426,17 @@ mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename,
     exitWithError("unknown format is specified");
 
   std::unique_ptr<InstrProfCorrelator> Correlator;
-  if (!DebugInfoFilename.empty()) {
+  if (!DebugInfoFilename.empty() || !ObjectFilename.empty()) {
+    InstrProfCorrelator::ProfCorrelatorKind Kind =
+        DebugInfoFilename.empty() ? InstrProfCorrelator::BINARY
+                                  : InstrProfCorrelator::DEBUG_INFO;
+    StringRef FileName =
+        DebugInfoFilename.empty() ? ObjectFilename : DebugInfoFilename;
     if (auto Err =
-            InstrProfCorrelator::get(DebugInfoFilename).moveInto(Correlator))
-      exitWithError(std::move(Err), DebugInfoFilename);
+            InstrProfCorrelator::get(FileName, Kind).moveInto(Correlator))
+      exitWithError(std::move(Err), FileName);
     if (auto Err = Correlator->correlateProfileData(MaxDbgCorrelationWarnings))
-      exitWithError(std::move(Err), DebugInfoFilename);
+      exitWithError(std::move(Err), FileName);
   }
 
   std::mutex ErrorLock;
@@ -1279,6 +1285,10 @@ static int merge_main(int argc, const char *argv[]) {
   cl::opt<std::string> DebugInfoFilename(
       "debug-info", cl::init(""),
       cl::desc("Use the provided debug info to correlate the raw profile."));
+  cl::opt<std::string> ObjectFilename(
+      "object-file", cl::init(""),
+      cl::desc("Read and extract profile metadata from object file and show "
+               "the functions it found."));
   cl::opt<unsigned> MaxDbgCorrelationWarnings(
       "max-debug-info-correlation-warnings",
       cl::desc("The maximum number of warnings to emit when correlating "
@@ -1304,6 +1314,9 @@ static int merge_main(int argc, const char *argv[]) {
                "(default: 10000)"));
 
   cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
+  if (!DebugInfoFilename.empty() && !ObjectFilename.empty()) {
+    exitWithError("Expected only one of -debug-info, -object-file");
+  }
 
   WeightedFileVector WeightedInputs;
   for (StringRef Filename : InputFilenames)
@@ -1342,8 +1355,8 @@ static int merge_main(int argc, const char *argv[]) {
   }
 
   if (ProfileKind == instr)
-    mergeInstrProfile(WeightedInputs, DebugInfoFilename, Remapper.get(),
-                      OutputFilename, OutputFormat,
+    mergeInstrProfile(WeightedInputs, DebugInfoFilename, ObjectFilename,
+                      Remapper.get(), OutputFilename, OutputFormat,
                       TemporalProfTraceReservoirSize,
                       TemporalProfMaxTraceLength, MaxDbgCorrelationWarnings,
                       OutputSparse, NumThreads, FailureMode, ProfiledBinary);
@@ -2893,7 +2906,9 @@ static int showDebugInfoCorrelation(const std::string &Filename,
   if (SFormat == ShowFormat::Json)
     exitWithError("JSON output is not supported for debug info correlation");
   std::unique_ptr<InstrProfCorrelator> Correlator;
-  if (auto Err = InstrProfCorrelator::get(Filename).moveInto(Correlator))
+  if (auto Err =
+          InstrProfCorrelator::get(Filename, InstrProfCorrelator::DEBUG_INFO)
+              .moveInto(Correlator))
     exitWithError(std::move(Err), Filename);
   if (SFormat == ShowFormat::Yaml) {
     if (auto Err = Correlator->dumpYaml(MaxDbgCorrelationWarnings, OS))

>From 776784459f67f44c0455ab0f3b216f7d9c6a6376 Mon Sep 17 00:00:00 2001
From: My Name <zequanwu at google.com>
Date: Wed, 18 Oct 2023 13:30:21 -0400
Subject: [PATCH 2/3] fix correlator for coff.

---
 llvm/lib/ProfileData/InstrProfCorrelator.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/ProfileData/InstrProfCorrelator.cpp b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
index 347879e71bbda18..168c2803145f1ff 100644
--- a/llvm/lib/ProfileData/InstrProfCorrelator.cpp
+++ b/llvm/lib/ProfileData/InstrProfCorrelator.cpp
@@ -44,12 +44,16 @@ Expected<object::SectionRef> getInstrProfSection(const object::ObjectFile &Obj,
   // linker to sort these sections between "$A" and "$Z". The linker removes the
   // dollar and everything after it in the final binary. Do the same to match.
   Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat();
+  auto StripSuffix = [ObjFormat](StringRef N) {
+    return ObjFormat == Triple::COFF ? N.split('$').first : N;
+  };
   std::string ExpectedSectionName =
       getInstrProfSectionName(IPSK, ObjFormat,
                               /*AddSegmentInfo=*/false);
+  ExpectedSectionName = StripSuffix(ExpectedSectionName);
   for (auto &Section : Obj.sections())
     if (auto SectionName = Section.getName())
-      if (SectionName.get() == ExpectedSectionName) {
+      if (StripSuffix(*SectionName) == ExpectedSectionName) {
         // There will be extra profile name and data sections in COFF used for
         // runtime to detect start/stop of those sections, skipping them.
         // (details at compiler-rt/lib/profile/InstrProfilingPlatformWindows.c)

>From c5cca07062572077c4140b4eb9a4bdbb22a385a6 Mon Sep 17 00:00:00 2001
From: Zequan Wu <zequanwu at google.com>
Date: Wed, 18 Oct 2023 13:59:04 -0400
Subject: [PATCH 3/3] update docs and renaming option

---
 .../test/profile/instrprof-binary-correlate.c  |  6 +++---
 llvm/docs/CommandGuide/llvm-profdata.rst       | 13 +++++++++----
 llvm/tools/llvm-profdata/llvm-profdata.cpp     | 18 +++++++++---------
 3 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/compiler-rt/test/profile/instrprof-binary-correlate.c b/compiler-rt/test/profile/instrprof-binary-correlate.c
index 2154c13027e286b..bc05dbd99b82516 100644
--- a/compiler-rt/test/profile/instrprof-binary-correlate.c
+++ b/compiler-rt/test/profile/instrprof-binary-correlate.c
@@ -7,13 +7,13 @@
 // With -profile-correlate=binary flag
 // RUN: %clang -o %t-1.exe -fprofile-instr-generate -fcoverage-mapping -mllvm -profile-correlate=binary -fuse-ld=lld %S/Inputs/instrprof-debug-info-correlate-main.cpp %S/Inputs/instrprof-debug-info-correlate-foo.cpp
 // RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t-1.exe
-// RUN: llvm-profdata merge -o %t-1.profdata --object-file=%t-1.exe %t-1.profraw 
+// RUN: llvm-profdata merge -o %t-1.profdata --binary-file=%t-1.exe %t-1.profraw 
 // RUN: diff %t.normal.profdata %t-1.profdata 
 
 // Strip above binary and run
 // RUN: llvm-strip %t-1.exe -o %t-2.exe
 // RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t-2.exe
-// RUN: llvm-profdata merge -o %t-2.profdata --object-file=%t-1.exe %t-2.profraw 
+// RUN: llvm-profdata merge -o %t-2.profdata --binary-file=%t-1.exe %t-2.profraw 
 // RUN: diff %t.normal.profdata %t-2.profdata 
 
 // Online merging.
@@ -23,7 +23,7 @@
 // RUN: rm -rf %t.profdir && mkdir %t.profdir
 // RUN: env LLVM_PROFILE_FILE=%t.profdir/%m-4.profraw %run %t-2.exe
 // RUN: env LLVM_PROFILE_FILE=%t.profdir/%m-4.profraw %run %t-2.exe
-// RUN: llvm-profdata merge -o %t-4.profdata --object-file=%t-1.exe  %t.profdir
+// RUN: llvm-profdata merge -o %t-4.profdata --binary-file=%t-1.exe  %t.profdir
 // RUN: diff %t.normal.merged.profdata %t-4.profdata
 
 // TODO: After adding support for binary ID, test binaries with different binary IDs.
diff --git a/llvm/docs/CommandGuide/llvm-profdata.rst b/llvm/docs/CommandGuide/llvm-profdata.rst
index be42733ca140567..f81c80601e98a11 100644
--- a/llvm/docs/CommandGuide/llvm-profdata.rst
+++ b/llvm/docs/CommandGuide/llvm-profdata.rst
@@ -195,8 +195,13 @@ OPTIONS
 .. option:: --debug-info=<path>
 
  Specify the executable or ``.dSYM`` that contains debug info for the raw profile.
- When ``-debug-info-correlate`` was used for instrumentation, use this option
- to correlate the raw profile.
+ When ``-profile-correlate=debug-info`` was used for instrumentation, use this
+ option to correlate the raw profile.
+
+.. option:: --binary-file=<path>
+Specify the executable that contains profile data and profile name sections for 
+the raw profile. When ``-profile-correlate=binary`` was used for 
+instrumentation, use this option to correlate the raw profile.
 
 .. option:: --temporal-profile-trace-reservoir-size
 
@@ -346,8 +351,8 @@ OPTIONS
 .. option:: --debug-info=<path>
 
  Specify the executable or ``.dSYM`` that contains debug info for the raw profile.
- When ``-debug-info-correlate`` was used for instrumentation, use this option
- to show the correlated functions from the raw profile.
+ When ``-profile-correlate=debug-info`` was used for instrumentation, use this 
+ option to show the correlated functions from the raw profile.
 
 .. option:: --covered
 
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index c0db32e8343d820..068504228d97d3f 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -413,7 +413,7 @@ static void writeInstrProfile(StringRef OutputFilename,
 
 static void
 mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename,
-                  StringRef ObjectFilename, SymbolRemapper *Remapper,
+                  StringRef BinaryFilename, SymbolRemapper *Remapper,
                   StringRef OutputFilename, ProfileFormat OutputFormat,
                   uint64_t TraceReservoirSize, uint64_t MaxTraceLength,
                   int MaxDbgCorrelationWarnings, bool OutputSparse,
@@ -426,12 +426,12 @@ mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename,
     exitWithError("unknown format is specified");
 
   std::unique_ptr<InstrProfCorrelator> Correlator;
-  if (!DebugInfoFilename.empty() || !ObjectFilename.empty()) {
+  if (!DebugInfoFilename.empty() || !BinaryFilename.empty()) {
     InstrProfCorrelator::ProfCorrelatorKind Kind =
         DebugInfoFilename.empty() ? InstrProfCorrelator::BINARY
                                   : InstrProfCorrelator::DEBUG_INFO;
     StringRef FileName =
-        DebugInfoFilename.empty() ? ObjectFilename : DebugInfoFilename;
+        DebugInfoFilename.empty() ? BinaryFilename : DebugInfoFilename;
     if (auto Err =
             InstrProfCorrelator::get(FileName, Kind).moveInto(Correlator))
       exitWithError(std::move(Err), FileName);
@@ -1285,9 +1285,9 @@ static int merge_main(int argc, const char *argv[]) {
   cl::opt<std::string> DebugInfoFilename(
       "debug-info", cl::init(""),
       cl::desc("Use the provided debug info to correlate the raw profile."));
-  cl::opt<std::string> ObjectFilename(
-      "object-file", cl::init(""),
-      cl::desc("Read and extract profile metadata from object file and show "
+  cl::opt<std::string> BinaryFilename(
+      "binary-file", cl::init(""),
+      cl::desc("Read and extract profile metadata from binary file and show "
                "the functions it found."));
   cl::opt<unsigned> MaxDbgCorrelationWarnings(
       "max-debug-info-correlation-warnings",
@@ -1314,8 +1314,8 @@ static int merge_main(int argc, const char *argv[]) {
                "(default: 10000)"));
 
   cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
-  if (!DebugInfoFilename.empty() && !ObjectFilename.empty()) {
-    exitWithError("Expected only one of -debug-info, -object-file");
+  if (!DebugInfoFilename.empty() && !BinaryFilename.empty()) {
+    exitWithError("Expected only one of -debug-info, -binary-file");
   }
 
   WeightedFileVector WeightedInputs;
@@ -1355,7 +1355,7 @@ static int merge_main(int argc, const char *argv[]) {
   }
 
   if (ProfileKind == instr)
-    mergeInstrProfile(WeightedInputs, DebugInfoFilename, ObjectFilename,
+    mergeInstrProfile(WeightedInputs, DebugInfoFilename, BinaryFilename,
                       Remapper.get(), OutputFilename, OutputFormat,
                       TemporalProfTraceReservoirSize,
                       TemporalProfMaxTraceLength, MaxDbgCorrelationWarnings,



More information about the cfe-commits mailing list