zequanwu updated this revision to Diff 556805.
zequanwu added a comment.

Remove profile name section.

Unused coverage function names are stored in debug info as a fake global 
variable info:

  0x0000000b: DW_TAG_compile_unit
  ...
  0x00000071:   DW_TAG_variable
                  DW_AT_name      ("__llvm_coverage_names")
                  DW_AT_type      (0x00000097 "Coverage Type")
                  DW_AT_location  (DW_OP_addr 0x0)
  
  0x00000084:     DW_TAG_LLVM_annotation
                    DW_AT_name    ("Cov Function Name")
                    DW_AT_const_value     ("bar")
  
  0x0000008d:     DW_TAG_LLVM_annotation
                    DW_AT_name    ("Cov Function Name")
                    DW_AT_const_value     ("baz")

llvm-cov will need to retrieve those names from the binary's debug info.

The reasons for not writing those names into the indexed profile file are 
following:

1. llvm-cov always need to read __llvm_covfun and __llvm_covmap from the 
unstripped binary, so it doesn't matter if those names are read from the binary 
or the indexed profile.
2. Since those names are just an array of strings, they don't have counter/data 
info. When llvm-profdata writes indexed profile, it iterates profile data to 
write records, so those unreferenced names are skipped even if I append them to 
the end of profile symtab. I'm not sure how we can simply append those names 
into the end of function name strings at indexed profile.

Overall, there are basically two types of function names:

1. Instrumented function names, which are stored in dwarf and later copied to 
indexed profile. llvm-cov reads them from indexed profile.
2. Unused function names(could be empty), which are stored in dwarf. llvm-cov 
reads them from the debug info.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D157913/new/

https://reviews.llvm.org/D157913

Files:
  clang/lib/CodeGen/CoverageMappingGen.cpp
  clang/test/CodeGen/coverage-profile-raw-version.c
  compiler-rt/lib/profile/InstrProfilingWriter.c
  compiler-rt/test/profile/Darwin/coverage-debug-info-correlate.cpp
  compiler-rt/test/profile/Linux/coverage-debug-info-correlate.cpp
  llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
  llvm/include/llvm/ProfileData/InstrProf.h
  llvm/include/llvm/ProfileData/InstrProfCorrelator.h
  llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
  llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
  llvm/lib/ProfileData/InstrProfCorrelator.cpp
  llvm/lib/ProfileData/InstrProfReader.cpp
  llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
  llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-byte-coverage.ll
  
llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-clang-coverage.ll
  llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll

Index: llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-clang-coverage.ll
===================================================================
--- /dev/null
+++ llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-clang-coverage.ll
@@ -0,0 +1,66 @@
+; Test if unused function names are correctly emitted as dwarf variable debug info under DW_TAG_compile_unit
+
+; RUN: opt < %s -passes=instrprof -debug-info-correlate -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 %s --check-prefix=CHECK-DWARF
+
+; REQUIRES: system-linux, object-emission
+
+
+
+@__profn_foo = private constant [3 x i8] c"foo"
+@__profn_bar = private constant [3 x i8] c"bar"
+@__profn_baz = private constant [3 x i8] c"baz"
+@__llvm_coverage_names = internal constant [2 x ptr] [ptr @__profn_bar, ptr @__profn_baz]
+; CHECK: @__llvm_coverage_names = internal constant [2 x ptr] [ptr @__profn_bar, ptr @__profn_baz], !dbg ![[DBG:[0-9]+]]
+; CHECK: ![[DBG]] = !DIGlobalVariableExpression(var: ![[VAR:[0-9]+]], expr: !DIExpression())
+; CHECK: ![[VAR]] = {{.*}} !DIGlobalVariable(name: "__llvm_coverage_names"
+; CHECK-SAME: scope: ![[SCOPE:[0-9]+]]
+; CHECK-SAME: annotations: ![[ANNOTATIONS:[0-9]+]]
+; CHECK: ![[SCOPE]] = {{.*}} !DICompileUnit(
+; CHECK: ![[ANNOTATIONS]] = !{![[FUNC_NAME1:[0-9]+]], ![[FUNC_NAME2:[0-9]+]]}
+; CHECK: ![[FUNC_NAME1]] = !{!"Cov Function Name", !"bar"}
+; CHECK: ![[FUNC_NAME2]] = !{!"Cov Function Name", !"baz"}
+
+define void @_Z3foov() !dbg !12 {
+  call void @llvm.instrprof.increment(ptr @__profn_foo, i64 12345678, i32 2, i32 0)
+  ret void
+}
+
+declare void @llvm.instrprof.increment(ptr, i64, i32, i32)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8, !9, !10}
+!llvm.ident = !{!11}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "debug-info-correlate.cpp", directory: "")
+!2 = !{i32 7, !"Dwarf Version", i32 4}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"branch-target-enforcement", i32 0}
+!6 = !{i32 8, !"sign-return-address", i32 0}
+!7 = !{i32 8, !"sign-return-address-all", i32 0}
+!8 = !{i32 8, !"sign-return-address-with-bkey", i32 0}
+!9 = !{i32 7, !"uwtable", i32 1}
+!10 = !{i32 7, !"frame-pointer", i32 1}
+!11 = !{!"clang version 14.0.0"}
+!12 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !13, file: !13, line: 1, type: !14, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !16)
+!13 = !DIFile(filename: "debug-info-correlate.cpp", directory: "")
+!14 = !DISubroutineType(types: !15)
+!15 = !{null}
+!16 = !{}
+
+; CHECK-DWARF: DW_TAG_compile_unit
+; CHECK-DWARF:   DW_TAG_variable
+; CHECK-DWARF:     DW_AT_name	("__llvm_coverage_names")
+; CHECK-DWARF:     DW_AT_type	({{.*}} "Coverage Type")
+; CHECK-DWARF:     DW_TAG_LLVM_annotation
+; CHECK-DWARF:       DW_AT_name	("Cov Function Name")
+; CHECK-DWARF:       DW_AT_const_value	("bar")
+; CHECK-DWARF:     DW_TAG_LLVM_annotation
+; CHECK-DWARF:       DW_AT_name	("Cov Function Name")
+; CHECK-DWARF:       DW_AT_const_value	("baz")
+; CHECK-DWARF:   DW_TAG_unspecified_type
+; CHECK-DWARF:     DW_AT_name ("Coverage Type")
+; CHECK-DWARF:   NULL
Index: llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll
===================================================================
--- /dev/null
+++ llvm/test/Instrumentation/InstrProfiling/debug-info-correlate-coverage.ll
@@ -1,34 +0,0 @@
-; RUN: opt < %s -passes=instrprof -debug-info-correlate -S | opt -O2 -S | FileCheck %s
-
-@__profn_foo = private constant [3 x i8] c"foo"
-; CHECK:      @__profc_foo
-
-define  void @_Z3foov() !dbg !12 {
-  call void @llvm.instrprof.cover(ptr @__profn_foo, i64 12345678, i32 1, i32 0)
-  ; CHECK: store i8 0, ptr @__profc_foo, align 1
-  ret void
-}
-
-declare void @llvm.instrprof.cover(ptr, i64, i32, i32)
-
-!llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8, !9, !10}
-!llvm.ident = !{!11}
-
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
-!1 = !DIFile(filename: "debug-info-correlate-coverage.cpp", directory: "")
-!2 = !{i32 7, !"Dwarf Version", i32 4}
-!3 = !{i32 2, !"Debug Info Version", i32 3}
-!4 = !{i32 1, !"wchar_size", i32 4}
-!5 = !{i32 8, !"branch-target-enforcement", i32 0}
-!6 = !{i32 8, !"sign-return-address", i32 0}
-!7 = !{i32 8, !"sign-return-address-all", i32 0}
-!8 = !{i32 8, !"sign-return-address-with-bkey", i32 0}
-!9 = !{i32 7, !"uwtable", i32 1}
-!10 = !{i32 7, !"frame-pointer", i32 1}
-!11 = !{!"clang version 14.0.0"}
-!12 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !13, file: !13, line: 1, type: !14, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !16)
-!13 = !DIFile(filename: "debug-info-correlate-coverage.cpp", directory: "")
-!14 = !DISubroutineType(types: !15)
-!15 = !{null}
-!16 = !{}
Index: llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
===================================================================
--- llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
+++ llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
@@ -766,6 +766,34 @@
     if (isa<ConstantExpr>(NC))
       NC->dropAllReferences();
   }
+  if (DebugInfoCorrelate && !ReferencedNames.empty()) {
+    MDNode *Node = *M->debug_compile_units_begin();
+    DICompileUnit *CU = cast<DICompileUnit>(Node);
+    DIBuilder DB(*M, true, CU);
+    LLVMContext &Ctx = M->getContext();
+    SmallVector<llvm::Metadata *> Annots;
+    for (auto *NameVar: ReferencedNames) {
+      Metadata *CovFunctionNameAnnotation[] = {
+          MDString::get(Ctx, InstrProfCorrelator::CovFunctionNameAttributeName),
+          MDString::get(Ctx,
+                        std::string(getPGOFuncNameVarInitializer(NameVar))),
+      };
+      Annots.push_back(MDNode::get(Ctx, CovFunctionNameAnnotation));
+    }
+    auto Annotations = DB.getOrCreateArray(Annots);
+    auto *DICovName = DB.createGlobalVariableExpression(
+        CU, CoverageNamesVar->getName(), /*LinkageName=*/StringRef(),
+        CU->getFile(),
+        /*LineNo=*/0, DB.createUnspecifiedType("Coverage Type"),
+        /*IsLocalToUnit=*/true, /*IsDefined=*/true, /*Expr=*/nullptr,
+        /*Decl=*/nullptr, /*TemplateParams=*/nullptr, /*AlignInBits=*/0,
+        Annotations);
+    CoverageNamesVar->addDebugInfo(DICovName);
+    DB.finalize();
+    ReferencedNames.clear();
+    return;
+  }
+
   CoverageNamesVar->eraseFromParent();
 }
 
Index: llvm/lib/ProfileData/InstrProfReader.cpp
===================================================================
--- llvm/lib/ProfileData/InstrProfReader.cpp
+++ llvm/lib/ProfileData/InstrProfReader.cpp
@@ -574,8 +574,8 @@
   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);
+    assert(DataSize == 0 && (!isIRLevelProfile() || NamesSize == 0));
+    assert(CountersDelta == 0 && (!isIRLevelProfile() || NamesDelta == 0));
     Data = Correlator->getDataPointer();
     DataEnd = Data + Correlator->getDataSize();
     NamesStart = Correlator->getNamesPointer();
Index: llvm/lib/ProfileData/InstrProfCorrelator.cpp
===================================================================
--- llvm/lib/ProfileData/InstrProfCorrelator.cpp
+++ llvm/lib/ProfileData/InstrProfCorrelator.cpp
@@ -38,6 +38,8 @@
 const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name";
 const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash";
 const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters";
+const char *InstrProfCorrelator::CovFunctionNameAttributeName =
+    "Cov Function Name";
 
 llvm::Expected<std::unique_ptr<InstrProfCorrelator::Context>>
 InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
@@ -361,3 +363,80 @@
     WithColor::warning() << format("Suppressed %d additional warnings\n",
                                    NumSuppressedWarnings);
 }
+
+template <class IntPtrT>
+Error DwarfInstrProfCorrelator<IntPtrT>::correlateCovUnusedFuncNames(
+    int MaxWarnings) {
+  bool UnlimitedWarnings = (MaxWarnings == 0);
+  // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
+  int NumSuppressedWarnings = -MaxWarnings;
+  std::vector<std::string> UnusedFuncNames;
+  auto IsDIEOfCovName = [](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.getParent().isValid())
+      return false;
+    if (!Die.hasChildren())
+      return false;
+    if (const char *Name = Die.getName(DINameKind::ShortName))
+      return StringRef(Name).startswith(getCoverageUnusedNamesVarName());
+    return false;
+  };
+  auto MaybeAddCovFuncName = [&](DWARFDie Die) {
+    if (!IsDIEOfCovName(Die))
+      return;
+    if (StringRef(Die.getName(DINameKind::ShortName))
+            .startswith(getCoverageUnusedNamesVarName())) {
+      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;
+        }
+        std::optional<const char *> FunctionName;
+        StringRef AnnotationName = *AnnotationNameOrErr;
+        if (AnnotationName.compare(
+                InstrProfCorrelator::CovFunctionNameAttributeName) == 0) {
+          if (auto EC =
+                  AnnotationFormValue->getAsCString().moveInto(FunctionName))
+            consumeError(std::move(EC));
+        }
+        if (!FunctionName) {
+          if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
+            WithColor::warning() << format(
+                "Missing coverage function name value at DIE 0x%08" PRIx64,
+                Child.getOffset());
+          }
+          return;
+        }
+        UnusedFuncNames.push_back(*FunctionName);
+      }
+      return;
+    }
+  };
+  for (auto &CU : DICtx->normal_units())
+    for (const auto &Entry : CU->dies())
+      MaybeAddCovFuncName(DWARFDie(CU.get(), &Entry));
+  for (auto &CU : DICtx->dwo_units())
+    for (const auto &Entry : CU->dies())
+      MaybeAddCovFuncName(DWARFDie(CU.get(), &Entry));
+
+  if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
+    WithColor::warning() << format("Suppressed %d additional warnings\n",
+                                   NumSuppressedWarnings);
+  if (!UnusedFuncNames.empty()) {
+    auto Result = collectPGOFuncNameStrings(
+        UnusedFuncNames, /*doCompression=*/false, this->CovUnusedFuncNames);
+    return Result;
+  }
+  return Error::success();
+}
\ No newline at end of file
Index: llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
===================================================================
--- llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -25,6 +25,7 @@
 #include "llvm/Object/MachOUniversal.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/ProfileData/InstrProf.h"
+#include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Compression.h"
 #include "llvm/Support/Debug.h"
@@ -980,8 +981,23 @@
   return Sections;
 }
 
+static Error getProfileNamesFromDebugInfo(StringRef FileName,
+                                          InstrProfSymtab &ProfileNames) {
+  std::unique_ptr<InstrProfCorrelator> Correlator;
+  if (auto E = InstrProfCorrelator::get(FileName).moveInto(Correlator))
+    return E;
+  if (auto E = Correlator->correlateCovUnusedFuncNames(0))
+    return E;
+  if (auto E = ProfileNames.create(
+          StringRef(Correlator->getCovUnusedFuncNamesPointer(),
+                    Correlator->getCovUnusedFuncNamesSize())))
+    return E;
+  return Error::success();
+}
+
 static Expected<std::unique_ptr<BinaryCoverageReader>>
-loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
+loadBinaryFormat(std::unique_ptr<Binary> Bin,
+                 IndexedInstrProfReader &ProfileReader, StringRef Arch,
                  StringRef CompilationDir = "",
                  object::BuildIDRef *BinaryID = nullptr) {
   std::unique_ptr<ObjectFile> OF;
@@ -1010,11 +1026,24 @@
 
   // Look for the sections that we are interested in.
   auto ObjFormat = OF->getTripleObjectFormat();
+  InstrProfSymtab ProfileNames = ProfileReader.getSymtab();
   auto NamesSection =
       lookupSections(*OF, getInstrProfSectionName(IPSK_name, ObjFormat,
-                                                 /*AddSegmentInfo=*/false));
-  if (auto E = NamesSection.takeError())
-    return std::move(E);
+                                                  /*AddSegmentInfo=*/false));
+  if (auto E = NamesSection.takeError()) {
+    if (OF->hasDebugInfo()) {
+      if (auto E =
+              getProfileNamesFromDebugInfo(OF->getFileName(), ProfileNames))
+        return make_error<CoverageMapError>(coveragemap_error::malformed);
+    }
+    consumeError(std::move(E));
+  } else {
+    std::vector<SectionRef> NamesSectionRefs = *NamesSection;
+    if (NamesSectionRefs.size() != 1)
+      return make_error<CoverageMapError>(coveragemap_error::malformed);
+    if (Error E = ProfileNames.create(NamesSectionRefs.back()))
+      return std::move(E);
+  }
   auto CoverageSection =
       lookupSections(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat,
                                                   /*AddSegmentInfo=*/false));
@@ -1028,13 +1057,6 @@
     return CoverageMappingOrErr.takeError();
   StringRef CoverageMapping = CoverageMappingOrErr.get();
 
-  InstrProfSymtab ProfileNames;
-  std::vector<SectionRef> NamesSectionRefs = *NamesSection;
-  if (NamesSectionRefs.size() != 1)
-    return make_error<CoverageMapError>(coveragemap_error::malformed);
-  if (Error E = ProfileNames.create(NamesSectionRefs.back()))
-    return std::move(E);
-
   // Look for the coverage records section (Version4 only).
   auto CoverageRecordsSections =
       lookupSections(*OF, getInstrProfSectionName(IPSK_covfun, ObjFormat,
@@ -1104,7 +1126,8 @@
 
 Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>>
 BinaryCoverageReader::create(
-    MemoryBufferRef ObjectBuffer, StringRef Arch,
+    MemoryBufferRef ObjectBuffer, IndexedInstrProfReader &ProfileReader,
+    StringRef Arch,
     SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers,
     StringRef CompilationDir, SmallVectorImpl<object::BuildIDRef> *BinaryIDs) {
   std::vector<std::unique_ptr<BinaryCoverageReader>> Readers;
@@ -1150,8 +1173,8 @@
       }
 
       return BinaryCoverageReader::create(
-          ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers,
-          CompilationDir, BinaryIDs);
+          ArchiveOrErr.get()->getMemoryBufferRef(), ProfileReader, Arch,
+          ObjectFileBuffers, CompilationDir, BinaryIDs);
     }
   }
 
@@ -1164,8 +1187,8 @@
         return ChildBufOrErr.takeError();
 
       auto ChildReadersOrErr = BinaryCoverageReader::create(
-          ChildBufOrErr.get(), Arch, ObjectFileBuffers, CompilationDir,
-          BinaryIDs);
+          ChildBufOrErr.get(), ProfileReader, Arch, ObjectFileBuffers,
+          CompilationDir, BinaryIDs);
       if (!ChildReadersOrErr)
         return ChildReadersOrErr.takeError();
       for (auto &Reader : ChildReadersOrErr.get())
@@ -1185,8 +1208,9 @@
   }
 
   object::BuildIDRef BinaryID;
-  auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch, CompilationDir,
-                                      BinaryIDs ? &BinaryID : nullptr);
+  auto ReaderOrErr =
+      loadBinaryFormat(std::move(Bin), ProfileReader, Arch, CompilationDir,
+                       BinaryIDs ? &BinaryID : nullptr);
   if (!ReaderOrErr)
     return ReaderOrErr.takeError();
   Readers.push_back(std::move(ReaderOrErr.get()));
Index: llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
===================================================================
--- llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -360,7 +360,7 @@
 
   SmallVector<object::BuildIDRef> BinaryIDs;
   auto CoverageReadersOrErr = BinaryCoverageReader::create(
-      CovMappingBufRef, Arch, Buffers, CompilationDir,
+      CovMappingBufRef, ProfileReader, Arch, Buffers, CompilationDir,
       FoundBinaryIDs ? &BinaryIDs : nullptr);
   if (Error E = CoverageReadersOrErr.takeError()) {
     E = handleMaybeNoDataFoundError(std::move(E));
Index: llvm/include/llvm/ProfileData/InstrProfCorrelator.h
===================================================================
--- llvm/include/llvm/ProfileData/InstrProfCorrelator.h
+++ llvm/include/llvm/ProfileData/InstrProfCorrelator.h
@@ -39,6 +39,8 @@
   /// \param MaxWarnings the maximum number of warnings to emit (0 = no limit)
   virtual Error correlateProfileData(int MaxWarnings) = 0;
 
+  virtual Error correlateCovUnusedFuncNames(int MaxWarnings) = 0;
+
   /// Process debug info and dump the correlation data.
   /// \param MaxWarnings the maximum number of warnings to emit (0 = no limit)
   virtual Error dumpYaml(int MaxWarnings, raw_ostream &OS) = 0;
@@ -52,6 +54,12 @@
   /// Return the number of bytes in the names string.
   size_t getNamesSize() const { return Names.size(); }
 
+  const char *getCovUnusedFuncNamesPointer() const {
+    return CovUnusedFuncNames.c_str();
+  }
+
+  size_t getCovUnusedFuncNamesSize() const { return CovUnusedFuncNames.size(); }
+
   /// Return the size of the counters section in bytes.
   uint64_t getCountersSectionSize() const {
     return Ctx->CountersSectionEnd - Ctx->CountersSectionStart;
@@ -60,6 +68,7 @@
   static const char *FunctionNameAttributeName;
   static const char *CFGHashAttributeName;
   static const char *NumCountersAttributeName;
+  static const char *CovFunctionNameAttributeName;
 
   enum InstrProfCorrelatorKind { CK_32Bit, CK_64Bit };
   InstrProfCorrelatorKind getKind() const { return Kind; }
@@ -83,6 +92,7 @@
 
   std::string Names;
   std::vector<std::string> NamesVec;
+  std::string CovUnusedFuncNames;
 
   struct Probe {
     std::string FunctionName;
@@ -205,6 +215,8 @@
   void correlateProfileDataImpl(
       int MaxWarnings,
       InstrProfCorrelator::CorrelationData *Data = nullptr) override;
+
+  Error correlateCovUnusedFuncNames(int MaxWarnings) override;
 };
 
 } // end namespace llvm
Index: llvm/include/llvm/ProfileData/InstrProf.h
===================================================================
--- llvm/include/llvm/ProfileData/InstrProf.h
+++ llvm/include/llvm/ProfileData/InstrProf.h
@@ -532,6 +532,11 @@
 
   /// Dump the symbols in this table.
   void dumpNames(raw_ostream &OS) const;
+
+  /// True if symbol table is empty.
+  bool isEmpty() {
+    return Data.empty() && NameTab.empty();
+  }
 };
 
 Error InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) {
Index: llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
===================================================================
--- llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
+++ llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
@@ -203,7 +203,8 @@
   BinaryCoverageReader &operator=(const BinaryCoverageReader &) = delete;
 
   static Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>>
-  create(MemoryBufferRef ObjectBuffer, StringRef Arch,
+  create(MemoryBufferRef ObjectBuffer, IndexedInstrProfReader &ProfileReader,
+         StringRef Arch,
          SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers,
          StringRef CompilationDir = "",
          SmallVectorImpl<object::BuildIDRef> *BinaryIDs = nullptr);
Index: compiler-rt/test/profile/Linux/coverage-debug-info-correlate.cpp
===================================================================
--- /dev/null
+++ compiler-rt/test/profile/Linux/coverage-debug-info-correlate.cpp
@@ -0,0 +1,78 @@
+// Test debug info correlate with clang coverage.
+
+// Test the case when there is no __llvm_prf_names in the binary.
+// RUN: %clang_profgen -o %t.normal -fcoverage-mapping %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
+
+// RUN: %clang_profgen -o %t -g -mllvm --debug-info-correlate -fcoverage-mapping %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: llvm-cov report --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NONAME
+
+// Test debug info correlate with clang coverage (online merging).
+
+// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t.normal
+// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t-1.profraw %t-2.profraw
+
+// RUN: rm -rf %t.profdir && mkdir %t.profdir
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.profdir
+
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// RUN: llvm-cov report --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NONAME
+// RUN: llvm-cov report --instr-profile=%t.normal.profdata %t | FileCheck %s -check-prefix=NONAME
+
+// NONAME:      Filename                                    Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
+// NONAME-NEXT: --
+// NONAME-NEXT: instrprof-debug-info-correlate-bar.h              3                 1    66.67%           1                 0   100.00%           5                 1    80.00%           2                 1    50.00%
+// NONAME-NEXT: instrprof-debug-info-correlate-foo.cpp            5                 2    60.00%           2                 1    50.00%           6                 2    66.67%           2                 1    50.00%
+// NONAME-NEXT: instrprof-debug-info-correlate-main.cpp           4                 0   100.00%           1                 0   100.00%           5                 0   100.00%           2                 0   100.00%
+// NONAME-NEXT: --
+// NONAME-NEXT: TOTAL                                            12                 3    75.00%           4                 1    75.00%          16                 3    81.25%           6                 2    66.67%
+
+// Test the case when there is __llvm_prf_names in the binary (those are names of uninstrumented functions).
+// RUN: %clang_profgen -o %t.normal -fcoverage-mapping -mllvm -enable-name-compression=false %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw
+
+// RUN: %clang_profgen -o %t -g -mllvm --debug-info-correlate -fcoverage-mapping -mllvm -enable-name-compression=false %s
+// 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: llvm-cov export --format=lcov --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NAME
+
+// Test debug info correlate with clang coverage (online merging).
+
+// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t.normal
+// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t-1.profraw %t-2.profraw
+
+// RUN: rm -rf %t.profdir && mkdir %t.profdir
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.profdir
+
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// RUN: llvm-cov export --format=lcov --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NAME
+// NAME: _Z9used_funcv
+// NAME: main
+// NAME: _ZN1A11unused_funcEv
+
+struct A {
+  void unused_func() {}
+};
+void used_func() {}
+int main() {
+  used_func();
+  return 0;
+}
Index: compiler-rt/test/profile/Darwin/coverage-debug-info-correlate.cpp
===================================================================
--- /dev/null
+++ compiler-rt/test/profile/Darwin/coverage-debug-info-correlate.cpp
@@ -0,0 +1,78 @@
+// Test debug info correlate with clang coverage.
+
+// Test the case when there is no __llvm_prf_names in the binary.
+// RUN: %clang_profgen -o %t.normal -fcoverage-mapping %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
+
+// RUN: %clang_profgen -o %t -g -mllvm --debug-info-correlate -fcoverage-mapping %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
+
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// RUN: llvm-cov report --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NONAME
+
+// Test debug info correlate with clang coverage (online merging).
+
+// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t.normal
+// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t-1.profraw %t-2.profraw
+
+// RUN: rm -rf %t.profdir && mkdir %t.profdir
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.profdir
+
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// RUN: llvm-cov report --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NONAME
+// RUN: llvm-cov report --instr-profile=%t.normal.profdata %t | FileCheck %s -check-prefix=NONAME
+
+// NONAME:      Filename                                    Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
+// NONAME-NEXT: --
+// NONAME-NEXT: instrprof-debug-info-correlate-bar.h              3                 1    66.67%           1                 0   100.00%           5                 1    80.00%           2                 1    50.00%
+// NONAME-NEXT: instrprof-debug-info-correlate-foo.cpp            5                 2    60.00%           2                 1    50.00%           6                 2    66.67%           2                 1    50.00%
+// NONAME-NEXT: instrprof-debug-info-correlate-main.cpp           4                 0   100.00%           1                 0   100.00%           5                 0   100.00%           2                 0   100.00%
+// NONAME-NEXT: --
+// NONAME-NEXT: TOTAL                                            12                 3    75.00%           4                 1    75.00%          16                 3    81.25%           6                 2    66.67%
+
+// Test the case when there is __llvm_prf_names in the binary (those are names of uninstrumented functions).
+// RUN: %clang_profgen -o %t.normal -fcoverage-mapping -mllvm -enable-name-compression=false %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw
+
+// RUN: %clang_profgen -o %t -g -mllvm --debug-info-correlate -fcoverage-mapping -mllvm -enable-name-compression=false %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 <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// RUN: llvm-cov export --format=lcov --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NAME
+
+// Test debug info correlate with clang coverage (online merging).
+
+// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t.normal
+// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t.normal
+// RUN: llvm-profdata merge -o %t.normal.profdata %t-1.profraw %t-2.profraw
+
+// RUN: rm -rf %t.profdir && mkdir %t.profdir
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t
+// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.profdir
+
+// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata)
+
+// RUN: llvm-cov export --format=lcov --instr-profile=%t.profdata %t | FileCheck %s -check-prefix=NAME
+// NAME: _Z9used_funcv
+// NAME: main
+// NAME: _ZN1A11unused_funcEv
+
+struct A {
+  void unused_func() {}
+};
+void used_func() {}
+int main() {
+  used_func();
+  return 0;
+}
Index: compiler-rt/lib/profile/InstrProfilingWriter.c
===================================================================
--- compiler-rt/lib/profile/InstrProfilingWriter.c
+++ compiler-rt/lib/profile/InstrProfilingWriter.c
@@ -261,7 +261,9 @@
                    const char *NamesEnd, int SkipNameDataWrite) {
   int DebugInfoCorrelate =
       (__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) != 0ULL;
-
+  int IRLevelProfile =
+      (__llvm_profile_get_version() & VARIANT_MASK_IR_PROF) != 0ULL;
+  
   /* Calculate size of sections. */
   const uint64_t DataSectionSize =
       DebugInfoCorrelate ? 0 : __llvm_profile_get_data_size(DataBegin, DataEnd);
@@ -271,7 +273,8 @@
       __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 =
+      DebugInfoCorrelate && IRLevelProfile ? 0 : NamesEnd - NamesBegin;
 
   /* Create the header. */
   __llvm_profile_header Header;
@@ -297,10 +300,12 @@
   Header.CountersDelta = (uint32_t)Header.CountersDelta;
 #endif
 
-  /* The data and names sections are omitted in lightweight mode. */
+  /* The data section is omitted in lightweight mode. */
   if (DebugInfoCorrelate) {
     Header.CountersDelta = 0;
-    Header.NamesDelta = 0;
+    if (IRLevelProfile) {
+      Header.NamesDelta = 0;
+    }
   }
 
   /* Write the profile header. */
@@ -319,7 +324,9 @@
       {NULL, sizeof(uint8_t), PaddingBytesBeforeCounters, 1},
       {CountersBegin, sizeof(uint8_t), CountersSectionSize, 0},
       {NULL, sizeof(uint8_t), PaddingBytesAfterCounters, 1},
-      {(SkipNameDataWrite || DebugInfoCorrelate) ? NULL : NamesBegin,
+      {(SkipNameDataWrite || (DebugInfoCorrelate && IRLevelProfile))
+           ? NULL
+           : NamesBegin,
        sizeof(uint8_t), NamesSize, 0},
       {NULL, sizeof(uint8_t), PaddingBytesAfterNames, 1}};
   if (Writer->Write(Writer, IOVecData, sizeof(IOVecData) / sizeof(*IOVecData)))
Index: clang/test/CodeGen/coverage-profile-raw-version.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/coverage-profile-raw-version.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -debug-info-kind=standalone -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -debug-info-kind=standalone -mllvm -debug-info-correlate -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -o - %s | FileCheck %s --check-prefix=DEBUG_INFO
+
+// CHECK: @__llvm_profile_raw_version = hidden constant i64 8, comdat
+// DEBUG_INFO: @__llvm_profile_raw_version = hidden constant i64 576460752303423496, comdat
+
+int main() {
+    return 0;
+}
Index: clang/lib/CodeGen/CoverageMappingGen.cpp
===================================================================
--- clang/lib/CodeGen/CoverageMappingGen.cpp
+++ clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -31,6 +31,10 @@
 // is textually included.
 #define COVMAP_V3
 
+namespace llvm {
+extern cl::opt<bool> DebugInfoCorrelate;
+} // namespace llvm
+
 static llvm::cl::opt<bool> EmptyLineCommentCoverage(
     "emptyline-comment-coverage",
     llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
@@ -1821,6 +1825,22 @@
                              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::DebugInfoCorrelate)
+    ProfileVersion |= VARIANT_MASK_DBG_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(const FileEntry *File) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to