[llvm] 97ec8fa - [Coverage] Store compilation dir separately in coverage mapping

Petr Hosek via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 18 12:28:43 PST 2021


Author: Petr Hosek
Date: 2021-02-18T12:27:42-08:00
New Revision: 97ec8fa5bb07e3f5bf25ddcb216b545cd3d03b65

URL: https://github.com/llvm/llvm-project/commit/97ec8fa5bb07e3f5bf25ddcb216b545cd3d03b65
DIFF: https://github.com/llvm/llvm-project/commit/97ec8fa5bb07e3f5bf25ddcb216b545cd3d03b65.diff

LOG: [Coverage] Store compilation dir separately in coverage mapping

We currently always store absolute filenames in coverage mapping.  This
is problematic for several reasons. It poses a problem for distributed
compilation as source location might vary across machines.  We are also
duplicating the path prefix potentially wasting space.

This change modifies how we store filenames in coverage mapping. Rather
than absolute paths, it stores the compilation directory and file paths
as given to the compiler, either relative or absolute. Later when
reading the coverage mapping information, we recombine relative paths
with the working directory. This approach is similar to handling
ofDW_AT_comp_dir in DWARF.

Finally, we also provide a new option, -fprofile-compilation-dir akin
to -fdebug-compilation-dir which can be used to manually override the
compilation directory which is useful in distributed compilation cases.

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

Added: 
    clang/test/CodeGen/profile-compilation-dir.c
    llvm/test/tools/llvm-cov/Inputs/binary-formats.v6.linux64l

Modified: 
    clang/include/clang/Basic/CodeGenOptions.h
    clang/include/clang/Driver/Options.td
    clang/lib/CodeGen/CoverageMappingGen.cpp
    clang/lib/CodeGen/CoverageMappingGen.h
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/test/CoverageMapping/abspath.cpp
    clang/test/Profile/profile-prefix-map.c
    compiler-rt/include/profile/InstrProfData.inc
    llvm/docs/CoverageMappingFormat.rst
    llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
    llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
    llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h
    llvm/include/llvm/ProfileData/InstrProfData.inc
    llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
    llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
    llvm/test/tools/llvm-cov/binary-formats.c
    llvm/unittests/ProfileData/CoverageMappingTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index efcb6b16b0f7..bf260c444b2e 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -172,6 +172,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
   /// The string to embed in debug information as the current working directory.
   std::string DebugCompilationDir;
 
+  /// The string to embed in coverage mapping as the current working directory.
+  std::string ProfileCompilationDir;
+
   /// The string to embed in the debug information for the compile unit, if
   /// non-empty.
   std::string DwarfDebugFlags;

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index efb1f2e2288f..c7003437472e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1103,6 +1103,10 @@ def fdebug_compilation_dir_EQ : Joined<["-"], "fdebug-compilation-dir=">,
 def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
     Group<f_Group>, Flags<[CC1Option, CC1AsOption, CoreOption]>,
     Alias<fdebug_compilation_dir_EQ>;
+def fprofile_compilation_dir_EQ : Joined<["-"], "fprofile-compilation-dir=">,
+    Group<f_Group>, Flags<[CC1Option, CC1AsOption, CoreOption]>,
+    HelpText<"The compilation directory to embed in the coverage mapping.">,
+    MarshallingInfoString<CodeGenOpts<"ProfileCompilationDir">>;
 defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
   CodeGenOpts<"DebugInfoForProfiling">, DefaultFalse,
   PosFlag<SetTrue, [CC1Option], "Emit extra debug info to make sample profile more accurate">,

diff  --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index ce2cb380e0c1..ebbd6aad2cd7 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1606,9 +1606,17 @@ CoverageMappingModuleGen::CoverageMappingModuleGen(
   ProfilePrefixMap = CGM.getCodeGenOpts().ProfilePrefixMap;
 }
 
+std::string CoverageMappingModuleGen::getCurrentDirname() {
+  if (!CGM.getCodeGenOpts().ProfileCompilationDir.empty())
+    return CGM.getCodeGenOpts().ProfileCompilationDir;
+
+  SmallString<256> CWD;
+  llvm::sys::fs::current_path(CWD);
+  return CWD.str().str();
+}
+
 std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
   llvm::SmallString<256> Path(Filename);
-  llvm::sys::fs::make_absolute(Path);
   llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
   for (const auto &Entry : ProfilePrefixMap) {
     if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
@@ -1689,18 +1697,17 @@ void CoverageMappingModuleGen::addFunctionMappingRecord(
     // also processed by the CoverageMappingWriter which performs
     // additional minimization operations such as reducing the number of
     // expressions.
+    llvm::SmallVector<std::string, 16> FilenameStrs;
     std::vector<StringRef> Filenames;
     std::vector<CounterExpression> Expressions;
     std::vector<CounterMappingRegion> Regions;
-    llvm::SmallVector<std::string, 16> FilenameStrs;
-    llvm::SmallVector<StringRef, 16> FilenameRefs;
-    FilenameStrs.resize(FileEntries.size());
-    FilenameRefs.resize(FileEntries.size());
+    FilenameStrs.resize(FileEntries.size() + 1);
+    FilenameStrs[0] = normalizeFilename(getCurrentDirname());
     for (const auto &Entry : FileEntries) {
       auto I = Entry.second;
       FilenameStrs[I] = normalizeFilename(Entry.first->getName());
-      FilenameRefs[I] = FilenameStrs[I];
     }
+    ArrayRef<std::string> FilenameRefs = llvm::makeArrayRef(FilenameStrs);
     RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
                                     Expressions, Regions);
     if (Reader.read())
@@ -1717,19 +1724,18 @@ void CoverageMappingModuleGen::emit() {
 
   // Create the filenames and merge them with coverage mappings
   llvm::SmallVector<std::string, 16> FilenameStrs;
-  llvm::SmallVector<StringRef, 16> FilenameRefs;
-  FilenameStrs.resize(FileEntries.size());
-  FilenameRefs.resize(FileEntries.size());
+  FilenameStrs.resize(FileEntries.size() + 1);
+  // The first filename is the current working directory.
+  FilenameStrs[0] = getCurrentDirname();
   for (const auto &Entry : FileEntries) {
     auto I = Entry.second;
     FilenameStrs[I] = normalizeFilename(Entry.first->getName());
-    FilenameRefs[I] = FilenameStrs[I];
   }
 
   std::string Filenames;
   {
     llvm::raw_string_ostream OS(Filenames);
-    CoverageFilenamesSectionWriter(FilenameRefs).write(OS);
+    CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
   }
   auto *FilenamesVal =
       llvm::ConstantDataArray::getString(Ctx, Filenames, false);
@@ -1787,7 +1793,7 @@ unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
   auto It = FileEntries.find(File);
   if (It != FileEntries.end())
     return It->second;
-  unsigned FileID = FileEntries.size();
+  unsigned FileID = FileEntries.size() + 1;
   FileEntries.insert(std::make_pair(File, FileID));
   return FileID;
 }

diff  --git a/clang/lib/CodeGen/CoverageMappingGen.h b/clang/lib/CodeGen/CoverageMappingGen.h
index b26f79be5316..abf12e58def6 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.h
+++ b/clang/lib/CodeGen/CoverageMappingGen.h
@@ -95,6 +95,7 @@ class CoverageMappingModuleGen {
   std::vector<FunctionInfo> FunctionRecords;
   std::map<std::string, std::string> ProfilePrefixMap;
 
+  std::string getCurrentDirname();
   std::string normalizeFilename(StringRef Filename);
 
   /// Emit a function record.

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index ae7a8227d304..180d9cfec225 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -858,6 +858,13 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
     CmdArgs.push_back("-fcoverage-mapping");
   }
 
+  if (Arg *A = Args.getLastArg(options::OPT_fprofile_compilation_dir_EQ)) {
+    A->render(Args, CmdArgs);
+  } else if (llvm::ErrorOr<std::string> CWD =
+                 D.getVFS().getCurrentWorkingDirectory()) {
+    Args.MakeArgString("-fprofile-compilation-dir=" + *CWD);
+  }
+
   if (Args.hasArg(options::OPT_fprofile_exclude_files_EQ)) {
     auto *Arg = Args.getLastArg(options::OPT_fprofile_exclude_files_EQ);
     if (!Args.hasArg(options::OPT_coverage))

diff  --git a/clang/test/CodeGen/profile-compilation-dir.c b/clang/test/CodeGen/profile-compilation-dir.c
new file mode 100644
index 000000000000..6d66581bc702
--- /dev/null
+++ b/clang/test/CodeGen/profile-compilation-dir.c
@@ -0,0 +1,7 @@
+// RUN: mkdir -p %t.dir && cd %t.dir
+// RUN: cp %s rel.c
+// RUN: %clang_cc1 -fprofile-instrument=clang -fprofile-compilation-dir=/nonsense -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false rel.c -o - | FileCheck -check-prefix=CHECK-NONSENSE %s
+
+// CHECK-NONSENSE: nonsense
+
+void f() {}

diff  --git a/clang/test/CoverageMapping/abspath.cpp b/clang/test/CoverageMapping/abspath.cpp
index 3c593f40b7dd..4fa8eb9467f3 100644
--- a/clang/test/CoverageMapping/abspath.cpp
+++ b/clang/test/CoverageMapping/abspath.cpp
@@ -1,15 +1,19 @@
 // RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -emit-llvm -main-file-name abspath.cpp %S/Inputs/../abspath.cpp -o - | FileCheck -check-prefix=RMDOTS %s
 
-// RMDOTS: @__llvm_coverage_mapping = {{.*}}"\01
+// RMDOTS: @__llvm_coverage_mapping = {{.*}}"\02
 // RMDOTS-NOT: Inputs
 // RMDOTS: "
 
 // RUN: mkdir -p %t/test && cd %t/test
 // RUN: echo "void f1() {}" > f1.c
-// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -emit-llvm -main-file-name abspath.cpp ../test/f1.c -o - | FileCheck -check-prefix=RELPATH %s
+// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -emit-llvm -main-file-name abspath.cpp %t/test/f1.c -o - | FileCheck -check-prefix=ABSPATH %s
 
-// RELPATH: @__llvm_coverage_mapping = {{.*}}"\01
-// RELPATH: {{[/\\].*(/|\\\\)test(/|\\\\)f1}}.c
+// RELPATH: @__llvm_coverage_mapping = {{.*}}"\02
+// RELPATH: {{..(/|\\\\)test(/|\\\\)f1}}.c
 // RELPATH: "
 
+// ABSPATH: @__llvm_coverage_mapping = {{.*}}"\02
+// ABSPATH: {{[/\\].*(/|\\\\)test(/|\\\\)f1}}.c
+// ABSPATH: "
+
 void f1() {}

diff  --git a/clang/test/Profile/profile-prefix-map.c b/clang/test/Profile/profile-prefix-map.c
index 1b316d0149c2..9c7718e901d0 100644
--- a/clang/test/Profile/profile-prefix-map.c
+++ b/clang/test/Profile/profile-prefix-map.c
@@ -5,10 +5,14 @@
 // RUN: echo "void f1() {}" > %t/root/nested/profile-prefix-map.c
 // RUN: cd %t/root
 
-// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c nested/profile-prefix-map.c -o - | FileCheck --check-prefix=ABSOLUTE %s
+// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c %t/root/nested/profile-prefix-map.c -o - | FileCheck --check-prefix=ABSOLUTE %s
 //
-// ABSOLUTE: @__llvm_coverage_mapping = {{.*"\\01.*root.*nested.*profile-prefix-map\.c}}
+// ABSOLUTE: @__llvm_coverage_mapping = {{.*"\\02.*root.*nested.*profile-prefix-map\.c}}
 
-// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c nested/profile-prefix-map.c -fprofile-prefix-map=%/t/root=. -o - | FileCheck --check-prefix=PROFILE-PREFIX-MAP %s --implicit-check-not=root
+// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c ../root/nested/profile-prefix-map.c -o - | FileCheck --check-prefix=RELATIVE %s
 //
-// PROFILE-PREFIX-MAP: @__llvm_coverage_mapping = {{.*"\\01[^/]*}}.{{/|\\+}}nested{{.*profile-prefix-map\.c}}
+// RELATIVE: @__llvm_coverage_mapping = {{.*"\\02.*}}..{{/|\\+}}root{{/|\\+}}nested{{.*profile-prefix-map\.c}}
+
+// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c %t/root/nested/profile-prefix-map.c -fprofile-prefix-map=%/t/root=. -o - | FileCheck --check-prefix=PROFILE-PREFIX-MAP %s
+// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c ../root/nested/profile-prefix-map.c -fprofile-prefix-map=../root=. -o - | FileCheck --check-prefix=PROFILE-PREFIX-MAP %s
+// PROFILE-PREFIX-MAP: @__llvm_coverage_mapping = {{.*"\\02.*}}.{{/|\\+}}nested{{.*profile-prefix-map\.c}}

diff  --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc
index 3ee7af712872..9112c9fa12b2 100644
--- a/compiler-rt/include/profile/InstrProfData.inc
+++ b/compiler-rt/include/profile/InstrProfData.inc
@@ -649,7 +649,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
 /* Indexed profile format version (start from 1). */
 #define INSTR_PROF_INDEX_VERSION 7
 /* Coverage mapping format version (start from 0). */
-#define INSTR_PROF_COVMAP_VERSION 4
+#define INSTR_PROF_COVMAP_VERSION 5
 
 /* Profile version is always of type uint64_t. Reserve the upper 8 bits in the
  * version for other variants of profile. We set the lowest bit of the upper 8

diff  --git a/llvm/docs/CoverageMappingFormat.rst b/llvm/docs/CoverageMappingFormat.rst
index 4dc9dc380b98..0dc5ce6e808a 100644
--- a/llvm/docs/CoverageMappingFormat.rst
+++ b/llvm/docs/CoverageMappingFormat.rst
@@ -266,7 +266,16 @@ too deeply).
    [32 x i8] c"..." ; Encoded data (dissected later)
   }, section "__llvm_covmap", align 8
 
-The current version of the format is version 5. There is one 
diff erence from version 4:
+The current version of the format is version 6.
+
+There is one 
diff erence between versions 6 and 5:
+
+* The first entry in the filename list is the compilation directory. When the
+  filename is relative, the compilation directory is combined with the relative
+  path to get an absolute path. This can reduce size by omitting the duplicate
+  prefix in filenames.
+
+There is one 
diff erence between versions 5 and 4:
 
 * The notion of branch region has been introduced along with a corresponding
   region kind.  Branch regions encode two counters, one to track how many

diff  --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 09f21677ec54..957dfe9f1503 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -996,7 +996,10 @@ enum CovMapVersion {
   Version4 = 3,
   // Branch regions referring to two counters are added
   Version5 = 4,
-  // The current version is Version5.
+  // Compilation directory is stored separately and combined with relative
+  // filenames to produce an absolute file path.
+  Version6 = 5,
+  // The current version is Version6.
   CurrentVersion = INSTR_PROF_COVMAP_VERSION
 };
 

diff  --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
index 3a611bcb8cd1..86a3c4af9c3c 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
@@ -125,14 +125,14 @@ class RawCoverageMappingDummyChecker : public RawCoverageReader {
 
 /// Reader for the raw coverage mapping data.
 class RawCoverageMappingReader : public RawCoverageReader {
-  ArrayRef<StringRef> TranslationUnitFilenames;
+  ArrayRef<std::string> &TranslationUnitFilenames;
   std::vector<StringRef> &Filenames;
   std::vector<CounterExpression> &Expressions;
   std::vector<CounterMappingRegion> &MappingRegions;
 
 public:
   RawCoverageMappingReader(StringRef MappingData,
-                           ArrayRef<StringRef> TranslationUnitFilenames,
+                           ArrayRef<std::string> &TranslationUnitFilenames,
                            std::vector<StringRef> &Filenames,
                            std::vector<CounterExpression> &Expressions,
                            std::vector<CounterMappingRegion> &MappingRegions)
@@ -174,10 +174,8 @@ class BinaryCoverageReader : public CoverageMappingReader {
           FilenamesBegin(FilenamesBegin), FilenamesSize(FilenamesSize) {}
   };
 
-  using DecompressedData = std::vector<std::unique_ptr<SmallVector<char, 0>>>;
-
 private:
-  std::vector<StringRef> Filenames;
+  std::vector<std::string> Filenames;
   std::vector<ProfileMappingRecord> MappingRecords;
   InstrProfSymtab ProfileNames;
   size_t CurrentRecord = 0;
@@ -190,10 +188,6 @@ class BinaryCoverageReader : public CoverageMappingReader {
   // D69471, which can split up function records into multiple sections on ELF.
   std::string FuncRecords;
 
-  // Used to tie the lifetimes of decompressed strings to the lifetime of this
-  // BinaryCoverageReader instance.
-  DecompressedData Decompressed;
-
   BinaryCoverageReader(std::string &&FuncRecords)
       : FuncRecords(std::move(FuncRecords)) {}
 
@@ -216,20 +210,20 @@ class BinaryCoverageReader : public CoverageMappingReader {
 
 /// Reader for the raw coverage filenames.
 class RawCoverageFilenamesReader : public RawCoverageReader {
-  std::vector<StringRef> &Filenames;
+  std::vector<std::string> &Filenames;
 
   // Read an uncompressed sequence of filenames.
-  Error readUncompressed(uint64_t NumFilenames);
+  Error readUncompressed(CovMapVersion Version, uint64_t NumFilenames);
 
 public:
-  RawCoverageFilenamesReader(StringRef Data, std::vector<StringRef> &Filenames)
+  RawCoverageFilenamesReader(StringRef Data,
+                             std::vector<std::string> &Filenames)
       : RawCoverageReader(Data), Filenames(Filenames) {}
   RawCoverageFilenamesReader(const RawCoverageFilenamesReader &) = delete;
   RawCoverageFilenamesReader &
   operator=(const RawCoverageFilenamesReader &) = delete;
 
-  Error read(CovMapVersion Version,
-             BinaryCoverageReader::DecompressedData &Decompressed);
+  Error read(CovMapVersion Version);
 };
 
 } // end namespace coverage

diff  --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h
index 303e5184d493..14206755881b 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h
@@ -27,10 +27,10 @@ namespace coverage {
 /// Writer of the filenames section for the instrumentation
 /// based code coverage.
 class CoverageFilenamesSectionWriter {
-  ArrayRef<StringRef> Filenames;
+  ArrayRef<std::string> Filenames;
 
 public:
-  CoverageFilenamesSectionWriter(ArrayRef<StringRef> Filenames);
+  CoverageFilenamesSectionWriter(ArrayRef<std::string> Filenames);
 
   /// Write encoded filenames to the given output stream. If \p Compress is
   /// true, attempt to compress the filenames.

diff  --git a/llvm/include/llvm/ProfileData/InstrProfData.inc b/llvm/include/llvm/ProfileData/InstrProfData.inc
index 3ee7af712872..9112c9fa12b2 100644
--- a/llvm/include/llvm/ProfileData/InstrProfData.inc
+++ b/llvm/include/llvm/ProfileData/InstrProfData.inc
@@ -649,7 +649,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
 /* Indexed profile format version (start from 1). */
 #define INSTR_PROF_INDEX_VERSION 7
 /* Coverage mapping format version (start from 0). */
-#define INSTR_PROF_COVMAP_VERSION 4
+#define INSTR_PROF_COVMAP_VERSION 5
 
 /* Profile version is always of type uint64_t. Reserve the upper 8 bits in the
  * version for other variants of profile. We set the lowest bit of the upper 8

diff  --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index 1acdcb4bebb9..942f8e7957f3 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -97,9 +97,7 @@ Error RawCoverageReader::readString(StringRef &Result) {
   return Error::success();
 }
 
-Error RawCoverageFilenamesReader::read(
-    CovMapVersion Version,
-    BinaryCoverageReader::DecompressedData &Decompressed) {
+Error RawCoverageFilenamesReader::read(CovMapVersion Version) {
   uint64_t NumFilenames;
   if (auto Err = readSize(NumFilenames))
     return Err;
@@ -107,7 +105,7 @@ Error RawCoverageFilenamesReader::read(
     return make_error<CoverageMapError>(coveragemap_error::malformed);
 
   if (Version < CovMapVersion::Version4)
-    return readUncompressed(NumFilenames);
+    return readUncompressed(Version, NumFilenames);
 
   // The uncompressed length may exceed the size of the encoded filenames.
   // Skip size validation.
@@ -124,11 +122,8 @@ Error RawCoverageFilenamesReader::read(
       return make_error<CoverageMapError>(
           coveragemap_error::decompression_failed);
 
-    // Allocate memory for the decompressed filenames. Transfer ownership of
-    // the memory to BinaryCoverageReader.
-    auto DecompressedStorage = std::make_unique<SmallVector<char, 0>>();
-    SmallVectorImpl<char> &StorageBuf = *DecompressedStorage.get();
-    Decompressed.push_back(std::move(DecompressedStorage));
+    // Allocate memory for the decompressed filenames.
+    SmallVector<char, 0> StorageBuf;
 
     // Read compressed filenames.
     StringRef CompressedFilenames = Data.substr(0, CompressedLen);
@@ -143,19 +138,40 @@ Error RawCoverageFilenamesReader::read(
 
     StringRef UncompressedFilenames(StorageBuf.data(), StorageBuf.size());
     RawCoverageFilenamesReader Delegate(UncompressedFilenames, Filenames);
-    return Delegate.readUncompressed(NumFilenames);
+    return Delegate.readUncompressed(Version, NumFilenames);
   }
 
-  return readUncompressed(NumFilenames);
+  return readUncompressed(Version, NumFilenames);
 }
 
-Error RawCoverageFilenamesReader::readUncompressed(uint64_t NumFilenames) {
+Error RawCoverageFilenamesReader::readUncompressed(CovMapVersion Version,
+                                                   uint64_t NumFilenames) {
   // Read uncompressed filenames.
-  for (size_t I = 0; I < NumFilenames; ++I) {
-    StringRef Filename;
-    if (auto Err = readString(Filename))
+  if (Version < CovMapVersion::Version6) {
+    for (size_t I = 0; I < NumFilenames; ++I) {
+      StringRef Filename;
+      if (auto Err = readString(Filename))
+        return Err;
+      Filenames.push_back(Filename.str());
+    }
+  } else {
+    StringRef CWD;
+    if (auto Err = readString(CWD))
       return Err;
-    Filenames.push_back(Filename);
+    Filenames.push_back(CWD.str());
+
+    for (size_t I = 1; I < NumFilenames; ++I) {
+      StringRef Filename;
+      if (auto Err = readString(Filename))
+        return Err;
+      if (sys::path::is_absolute(Filename)) {
+        Filenames.push_back(Filename.str());
+      } else {
+        SmallString<256> P(CWD);
+        llvm::sys::path::append(P, Filename);
+        Filenames.push_back(static_cast<std::string>(P));
+      }
+    }
   }
   return Error::success();
 }
@@ -481,9 +497,8 @@ struct CovMapFuncRecordReader {
   //
   // Returns a pointer to the next \c CovHeader if it exists, or to an address
   // greater than \p CovEnd if not.
-  virtual Expected<const char *>
-  readCoverageHeader(const char *CovBuf, const char *CovBufEnd,
-                     BinaryCoverageReader::DecompressedData &Decompressed) = 0;
+  virtual Expected<const char *> readCoverageHeader(const char *CovBuf,
+                                                    const char *CovBufEnd) = 0;
 
   // Read function records.
   //
@@ -505,7 +520,7 @@ struct CovMapFuncRecordReader {
   static Expected<std::unique_ptr<CovMapFuncRecordReader>>
   get(CovMapVersion Version, InstrProfSymtab &P,
       std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
-      std::vector<StringRef> &F);
+      std::vector<std::string> &F);
 };
 
 // A class for reading coverage mapping function records for a module.
@@ -519,7 +534,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
   // in \c Records.
   DenseMap<NameRefType, size_t> FunctionRecords;
   InstrProfSymtab &ProfileNames;
-  std::vector<StringRef> &Filenames;
+  std::vector<std::string> &Filenames;
   std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records;
 
   // Maps a hash of the filenames in a TU to a \c FileRange. The range
@@ -579,14 +594,13 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
   VersionedCovMapFuncRecordReader(
       InstrProfSymtab &P,
       std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
-      std::vector<StringRef> &F)
+      std::vector<std::string> &F)
       : ProfileNames(P), Filenames(F), Records(R) {}
 
   ~VersionedCovMapFuncRecordReader() override = default;
 
-  Expected<const char *> readCoverageHeader(
-      const char *CovBuf, const char *CovBufEnd,
-      BinaryCoverageReader::DecompressedData &Decompressed) override {
+  Expected<const char *> readCoverageHeader(const char *CovBuf,
+                                            const char *CovBufEnd) override {
     using namespace support;
 
     if (CovBuf + sizeof(CovMapHeader) > CovBufEnd)
@@ -615,7 +629,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
     size_t FilenamesBegin = Filenames.size();
     StringRef FilenameRegion(CovBuf, FilenamesSize);
     RawCoverageFilenamesReader Reader(FilenameRegion, Filenames);
-    if (auto Err = Reader.read(Version, Decompressed))
+    if (auto Err = Reader.read(Version))
       return std::move(Err);
     CovBuf += FilenamesSize;
     FilenameRange FileRange(FilenamesBegin, Filenames.size() - FilenamesBegin);
@@ -721,7 +735,7 @@ template <class IntPtrT, support::endianness Endian>
 Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
     CovMapVersion Version, InstrProfSymtab &P,
     std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
-    std::vector<StringRef> &F) {
+    std::vector<std::string> &F) {
   using namespace coverage;
 
   switch (Version) {
@@ -732,6 +746,7 @@ Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
   case CovMapVersion::Version3:
   case CovMapVersion::Version4:
   case CovMapVersion::Version5:
+  case CovMapVersion::Version6:
     // Decompress the name data.
     if (Error E = P.create(P.getNameData()))
       return std::move(E);
@@ -747,6 +762,9 @@ Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
     else if (Version == CovMapVersion::Version5)
       return std::make_unique<VersionedCovMapFuncRecordReader<
           CovMapVersion::Version5, IntPtrT, Endian>>(P, R, F);
+    else if (Version == CovMapVersion::Version6)
+      return std::make_unique<VersionedCovMapFuncRecordReader<
+          CovMapVersion::Version6, IntPtrT, Endian>>(P, R, F);
   }
   llvm_unreachable("Unsupported version");
 }
@@ -755,8 +773,7 @@ template <typename T, support::endianness Endian>
 static Error readCoverageMappingData(
     InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords,
     std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,
-    std::vector<StringRef> &Filenames,
-    BinaryCoverageReader::DecompressedData &Decompressed) {
+    std::vector<std::string> &Filenames) {
   using namespace coverage;
 
   // Read the records in the coverage data section.
@@ -782,8 +799,7 @@ static Error readCoverageMappingData(
     // header.
     //
     // Return a pointer to the next coverage header.
-    auto NextOrErr =
-        Reader->readCoverageHeader(CovBuf, CovBufEnd, Decompressed);
+    auto NextOrErr = Reader->readCoverageHeader(CovBuf, CovBufEnd);
     if (auto E = NextOrErr.takeError())
       return E;
     CovBuf = NextOrErr.get();
@@ -810,25 +826,23 @@ BinaryCoverageReader::createCoverageReaderFromBuffer(
     if (Error E =
             readCoverageMappingData<uint32_t, support::endianness::little>(
                 Reader->ProfileNames, Coverage, FuncRecordsRef,
-                Reader->MappingRecords, Reader->Filenames,
-                Reader->Decompressed))
+                Reader->MappingRecords, Reader->Filenames))
       return std::move(E);
   } else if (BytesInAddress == 4 && Endian == support::endianness::big) {
     if (Error E = readCoverageMappingData<uint32_t, support::endianness::big>(
             Reader->ProfileNames, Coverage, FuncRecordsRef,
-            Reader->MappingRecords, Reader->Filenames, Reader->Decompressed))
+            Reader->MappingRecords, Reader->Filenames))
       return std::move(E);
   } else if (BytesInAddress == 8 && Endian == support::endianness::little) {
     if (Error E =
             readCoverageMappingData<uint64_t, support::endianness::little>(
                 Reader->ProfileNames, Coverage, FuncRecordsRef,
-                Reader->MappingRecords, Reader->Filenames,
-                Reader->Decompressed))
+                Reader->MappingRecords, Reader->Filenames))
       return std::move(E);
   } else if (BytesInAddress == 8 && Endian == support::endianness::big) {
     if (Error E = readCoverageMappingData<uint64_t, support::endianness::big>(
             Reader->ProfileNames, Coverage, FuncRecordsRef,
-            Reader->MappingRecords, Reader->Filenames, Reader->Decompressed))
+            Reader->MappingRecords, Reader->Filenames))
       return std::move(E);
   } else
     return make_error<CoverageMapError>(coveragemap_error::malformed);
@@ -1075,10 +1089,9 @@ Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {
   Expressions.clear();
   MappingRegions.clear();
   auto &R = MappingRecords[CurrentRecord];
-  RawCoverageMappingReader Reader(
-      R.CoverageMapping,
-      makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize),
-      FunctionsFilenames, Expressions, MappingRegions);
+  auto F = makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize);
+  RawCoverageMappingReader Reader(R.CoverageMapping, F, FunctionsFilenames,
+                                  Expressions, MappingRegions);
   if (auto Err = Reader.read())
     return Err;
 

diff  --git a/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
index 65b83d1f4197..6a9258fee5ee 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
@@ -27,7 +27,7 @@ using namespace llvm;
 using namespace coverage;
 
 CoverageFilenamesSectionWriter::CoverageFilenamesSectionWriter(
-    ArrayRef<StringRef> Filenames)
+    ArrayRef<std::string> Filenames)
     : Filenames(Filenames) {
 #ifndef NDEBUG
   StringSet<> NameSet;

diff  --git a/llvm/test/tools/llvm-cov/Inputs/binary-formats.v6.linux64l b/llvm/test/tools/llvm-cov/Inputs/binary-formats.v6.linux64l
new file mode 100755
index 000000000000..bd00cd0f1373
Binary files /dev/null and b/llvm/test/tools/llvm-cov/Inputs/binary-formats.v6.linux64l 
diff er

diff  --git a/llvm/test/tools/llvm-cov/binary-formats.c b/llvm/test/tools/llvm-cov/binary-formats.c
index 009583c00bce..a5bfc012860e 100644
--- a/llvm/test/tools/llvm-cov/binary-formats.c
+++ b/llvm/test/tools/llvm-cov/binary-formats.c
@@ -8,5 +8,6 @@ int main(int argc, const char *argv[]) {}
 // RUN: llvm-cov show %S/Inputs/binary-formats.macho64l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s
 // RUN: llvm-cov show %S/Inputs/binary-formats.macho32b -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s
 // RUN: llvm-cov show %S/Inputs/binary-formats.v3.macho64l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s
+// RUN: llvm-cov show %S/Inputs/binary-formats.v6.linux64l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s
 
 // RUN: llvm-cov export %S/Inputs/binary-formats.macho64l -instr-profile %t.profdata | FileCheck %S/Inputs/binary-formats.canonical.json

diff  --git a/llvm/unittests/ProfileData/CoverageMappingTest.cpp b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
index cbe9c1e823b7..44b7a13334d4 100644
--- a/llvm/unittests/ProfileData/CoverageMappingTest.cpp
+++ b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
@@ -129,6 +129,7 @@ struct InputFunctionCoverageData {
 struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> {
   bool UseMultipleReaders;
   StringMap<unsigned> Files;
+  std::vector<std::string> Filenames;
   std::vector<InputFunctionCoverageData> InputFunctions;
   std::vector<OutputFunctionCoverageData> OutputFunctions;
 
@@ -146,7 +147,7 @@ struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> {
     auto R = Files.find(Name);
     if (R != Files.end())
       return R->second;
-    unsigned Index = Files.size();
+    unsigned Index = Files.size() + 1;
     Files.try_emplace(Name, Index);
     return Index;
   }
@@ -200,11 +201,12 @@ struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> {
 
   void readCoverageRegions(const std::string &Coverage,
                            OutputFunctionCoverageData &Data) {
-    SmallVector<StringRef, 8> Filenames(Files.size());
+    Filenames.resize(Files.size() + 1);
     for (const auto &E : Files)
-      Filenames[E.getValue()] = E.getKey();
+      Filenames[E.getValue()] = E.getKey().str();
     std::vector<CounterExpression> Expressions;
-    RawCoverageMappingReader Reader(Coverage, Filenames, Data.Filenames,
+    ArrayRef<std::string> FilenameRefs = llvm::makeArrayRef(Filenames);
+    RawCoverageMappingReader Reader(Coverage, FilenameRefs, Data.Filenames,
                                     Expressions, Data.Regions);
     EXPECT_THAT_ERROR(Reader.read(), Succeeded());
   }
@@ -895,7 +897,7 @@ INSTANTIATE_TEST_CASE_P(ParameterizedCovMapTest, CoverageMappingTest,
                                           std::pair<bool, bool>({true, true})),);
 
 TEST(CoverageMappingTest, filename_roundtrip) {
-  std::vector<StringRef> Paths({"a", "b", "c", "d", "e"});
+  std::vector<std::string> Paths({"", "a", "b", "c", "d", "e"});
 
   for (bool Compress : {false, true}) {
     std::string EncodedFilenames;
@@ -905,16 +907,12 @@ TEST(CoverageMappingTest, filename_roundtrip) {
       Writer.write(OS, Compress);
     }
 
-    std::vector<StringRef> ReadFilenames;
+    std::vector<std::string> ReadFilenames;
     RawCoverageFilenamesReader Reader(EncodedFilenames, ReadFilenames);
-    BinaryCoverageReader::DecompressedData Decompressed;
-    EXPECT_THAT_ERROR(Reader.read(CovMapVersion::CurrentVersion, Decompressed),
-                      Succeeded());
-    if (!Compress)
-      ASSERT_EQ(Decompressed.size(), 0U);
+    EXPECT_THAT_ERROR(Reader.read(CovMapVersion::CurrentVersion), Succeeded());
 
     ASSERT_EQ(ReadFilenames.size(), Paths.size());
-    for (unsigned I = 0; I < Paths.size(); ++I)
+    for (unsigned I = 1; I < Paths.size(); ++I)
       ASSERT_TRUE(ReadFilenames[I] == Paths[I]);
   }
 }


        


More information about the llvm-commits mailing list