[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
This commit is contained in:
parent
62d946e133
commit
5fbd1a333a
|
@ -172,6 +172,9 @@ public:
|
||||||
/// The string to embed in debug information as the current working directory.
|
/// The string to embed in debug information as the current working directory.
|
||||||
std::string DebugCompilationDir;
|
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
|
/// The string to embed in the debug information for the compile unit, if
|
||||||
/// non-empty.
|
/// non-empty.
|
||||||
std::string DwarfDebugFlags;
|
std::string DwarfDebugFlags;
|
||||||
|
|
|
@ -1103,6 +1103,10 @@ def fdebug_compilation_dir_EQ : Joined<["-"], "fdebug-compilation-dir=">,
|
||||||
def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
|
def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
|
||||||
Group<f_Group>, Flags<[CC1Option, CC1AsOption, CoreOption]>,
|
Group<f_Group>, Flags<[CC1Option, CC1AsOption, CoreOption]>,
|
||||||
Alias<fdebug_compilation_dir_EQ>;
|
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",
|
defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
|
||||||
CodeGenOpts<"DebugInfoForProfiling">, DefaultFalse,
|
CodeGenOpts<"DebugInfoForProfiling">, DefaultFalse,
|
||||||
PosFlag<SetTrue, [CC1Option], "Emit extra debug info to make sample profile more accurate">,
|
PosFlag<SetTrue, [CC1Option], "Emit extra debug info to make sample profile more accurate">,
|
||||||
|
|
|
@ -1606,9 +1606,17 @@ CoverageMappingModuleGen::CoverageMappingModuleGen(
|
||||||
ProfilePrefixMap = CGM.getCodeGenOpts().ProfilePrefixMap;
|
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) {
|
std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
|
||||||
llvm::SmallString<256> Path(Filename);
|
llvm::SmallString<256> Path(Filename);
|
||||||
llvm::sys::fs::make_absolute(Path);
|
|
||||||
llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
|
llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
|
||||||
for (const auto &Entry : ProfilePrefixMap) {
|
for (const auto &Entry : ProfilePrefixMap) {
|
||||||
if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
|
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
|
// also processed by the CoverageMappingWriter which performs
|
||||||
// additional minimization operations such as reducing the number of
|
// additional minimization operations such as reducing the number of
|
||||||
// expressions.
|
// expressions.
|
||||||
|
llvm::SmallVector<std::string, 16> FilenameStrs;
|
||||||
std::vector<StringRef> Filenames;
|
std::vector<StringRef> Filenames;
|
||||||
std::vector<CounterExpression> Expressions;
|
std::vector<CounterExpression> Expressions;
|
||||||
std::vector<CounterMappingRegion> Regions;
|
std::vector<CounterMappingRegion> Regions;
|
||||||
llvm::SmallVector<std::string, 16> FilenameStrs;
|
FilenameStrs.resize(FileEntries.size() + 1);
|
||||||
llvm::SmallVector<StringRef, 16> FilenameRefs;
|
FilenameStrs[0] = normalizeFilename(getCurrentDirname());
|
||||||
FilenameStrs.resize(FileEntries.size());
|
|
||||||
FilenameRefs.resize(FileEntries.size());
|
|
||||||
for (const auto &Entry : FileEntries) {
|
for (const auto &Entry : FileEntries) {
|
||||||
auto I = Entry.second;
|
auto I = Entry.second;
|
||||||
FilenameStrs[I] = normalizeFilename(Entry.first->getName());
|
FilenameStrs[I] = normalizeFilename(Entry.first->getName());
|
||||||
FilenameRefs[I] = FilenameStrs[I];
|
|
||||||
}
|
}
|
||||||
|
ArrayRef<std::string> FilenameRefs = llvm::makeArrayRef(FilenameStrs);
|
||||||
RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
|
RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
|
||||||
Expressions, Regions);
|
Expressions, Regions);
|
||||||
if (Reader.read())
|
if (Reader.read())
|
||||||
|
@ -1717,19 +1724,18 @@ void CoverageMappingModuleGen::emit() {
|
||||||
|
|
||||||
// Create the filenames and merge them with coverage mappings
|
// Create the filenames and merge them with coverage mappings
|
||||||
llvm::SmallVector<std::string, 16> FilenameStrs;
|
llvm::SmallVector<std::string, 16> FilenameStrs;
|
||||||
llvm::SmallVector<StringRef, 16> FilenameRefs;
|
FilenameStrs.resize(FileEntries.size() + 1);
|
||||||
FilenameStrs.resize(FileEntries.size());
|
// The first filename is the current working directory.
|
||||||
FilenameRefs.resize(FileEntries.size());
|
FilenameStrs[0] = getCurrentDirname();
|
||||||
for (const auto &Entry : FileEntries) {
|
for (const auto &Entry : FileEntries) {
|
||||||
auto I = Entry.second;
|
auto I = Entry.second;
|
||||||
FilenameStrs[I] = normalizeFilename(Entry.first->getName());
|
FilenameStrs[I] = normalizeFilename(Entry.first->getName());
|
||||||
FilenameRefs[I] = FilenameStrs[I];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Filenames;
|
std::string Filenames;
|
||||||
{
|
{
|
||||||
llvm::raw_string_ostream OS(Filenames);
|
llvm::raw_string_ostream OS(Filenames);
|
||||||
CoverageFilenamesSectionWriter(FilenameRefs).write(OS);
|
CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
|
||||||
}
|
}
|
||||||
auto *FilenamesVal =
|
auto *FilenamesVal =
|
||||||
llvm::ConstantDataArray::getString(Ctx, Filenames, false);
|
llvm::ConstantDataArray::getString(Ctx, Filenames, false);
|
||||||
|
@ -1787,7 +1793,7 @@ unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
|
||||||
auto It = FileEntries.find(File);
|
auto It = FileEntries.find(File);
|
||||||
if (It != FileEntries.end())
|
if (It != FileEntries.end())
|
||||||
return It->second;
|
return It->second;
|
||||||
unsigned FileID = FileEntries.size();
|
unsigned FileID = FileEntries.size() + 1;
|
||||||
FileEntries.insert(std::make_pair(File, FileID));
|
FileEntries.insert(std::make_pair(File, FileID));
|
||||||
return FileID;
|
return FileID;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,7 @@ class CoverageMappingModuleGen {
|
||||||
std::vector<FunctionInfo> FunctionRecords;
|
std::vector<FunctionInfo> FunctionRecords;
|
||||||
std::map<std::string, std::string> ProfilePrefixMap;
|
std::map<std::string, std::string> ProfilePrefixMap;
|
||||||
|
|
||||||
|
std::string getCurrentDirname();
|
||||||
std::string normalizeFilename(StringRef Filename);
|
std::string normalizeFilename(StringRef Filename);
|
||||||
|
|
||||||
/// Emit a function record.
|
/// Emit a function record.
|
||||||
|
|
|
@ -858,6 +858,13 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
|
||||||
CmdArgs.push_back("-fcoverage-mapping");
|
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)) {
|
if (Args.hasArg(options::OPT_fprofile_exclude_files_EQ)) {
|
||||||
auto *Arg = Args.getLastArg(options::OPT_fprofile_exclude_files_EQ);
|
auto *Arg = Args.getLastArg(options::OPT_fprofile_exclude_files_EQ);
|
||||||
if (!Args.hasArg(options::OPT_coverage))
|
if (!Args.hasArg(options::OPT_coverage))
|
||||||
|
|
|
@ -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() {}
|
|
@ -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
|
// 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-NOT: Inputs
|
||||||
// RMDOTS: "
|
// RMDOTS: "
|
||||||
|
|
||||||
// RUN: mkdir -p %t/test && cd %t/test
|
// RUN: mkdir -p %t/test && cd %t/test
|
||||||
// RUN: echo "void f1() {}" > f1.c
|
// 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: @__llvm_coverage_mapping = {{.*}}"\02
|
||||||
// RELPATH: {{[/\\].*(/|\\\\)test(/|\\\\)f1}}.c
|
// RELPATH: {{..(/|\\\\)test(/|\\\\)f1}}.c
|
||||||
// RELPATH: "
|
// RELPATH: "
|
||||||
|
|
||||||
|
// ABSPATH: @__llvm_coverage_mapping = {{.*}}"\02
|
||||||
|
// ABSPATH: {{[/\\].*(/|\\\\)test(/|\\\\)f1}}.c
|
||||||
|
// ABSPATH: "
|
||||||
|
|
||||||
void f1() {}
|
void f1() {}
|
||||||
|
|
|
@ -5,10 +5,14 @@
|
||||||
// RUN: echo "void f1() {}" > %t/root/nested/profile-prefix-map.c
|
// RUN: echo "void f1() {}" > %t/root/nested/profile-prefix-map.c
|
||||||
// RUN: cd %t/root
|
// 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}}
|
||||||
|
|
|
@ -649,7 +649,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
|
||||||
/* Indexed profile format version (start from 1). */
|
/* Indexed profile format version (start from 1). */
|
||||||
#define INSTR_PROF_INDEX_VERSION 7
|
#define INSTR_PROF_INDEX_VERSION 7
|
||||||
/* Coverage mapping format version (start from 0). */
|
/* 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
|
/* 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
|
* version for other variants of profile. We set the lowest bit of the upper 8
|
||||||
|
|
|
@ -266,7 +266,16 @@ too deeply).
|
||||||
[32 x i8] c"..." ; Encoded data (dissected later)
|
[32 x i8] c"..." ; Encoded data (dissected later)
|
||||||
}, section "__llvm_covmap", align 8
|
}, section "__llvm_covmap", align 8
|
||||||
|
|
||||||
The current version of the format is version 5. There is one difference from version 4:
|
The current version of the format is version 6.
|
||||||
|
|
||||||
|
There is one difference 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 difference between versions 5 and 4:
|
||||||
|
|
||||||
* The notion of branch region has been introduced along with a corresponding
|
* The notion of branch region has been introduced along with a corresponding
|
||||||
region kind. Branch regions encode two counters, one to track how many
|
region kind. Branch regions encode two counters, one to track how many
|
||||||
|
|
|
@ -996,7 +996,10 @@ enum CovMapVersion {
|
||||||
Version4 = 3,
|
Version4 = 3,
|
||||||
// Branch regions referring to two counters are added
|
// Branch regions referring to two counters are added
|
||||||
Version5 = 4,
|
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
|
CurrentVersion = INSTR_PROF_COVMAP_VERSION
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -125,14 +125,14 @@ public:
|
||||||
|
|
||||||
/// Reader for the raw coverage mapping data.
|
/// Reader for the raw coverage mapping data.
|
||||||
class RawCoverageMappingReader : public RawCoverageReader {
|
class RawCoverageMappingReader : public RawCoverageReader {
|
||||||
ArrayRef<StringRef> TranslationUnitFilenames;
|
ArrayRef<std::string> &TranslationUnitFilenames;
|
||||||
std::vector<StringRef> &Filenames;
|
std::vector<StringRef> &Filenames;
|
||||||
std::vector<CounterExpression> &Expressions;
|
std::vector<CounterExpression> &Expressions;
|
||||||
std::vector<CounterMappingRegion> &MappingRegions;
|
std::vector<CounterMappingRegion> &MappingRegions;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RawCoverageMappingReader(StringRef MappingData,
|
RawCoverageMappingReader(StringRef MappingData,
|
||||||
ArrayRef<StringRef> TranslationUnitFilenames,
|
ArrayRef<std::string> &TranslationUnitFilenames,
|
||||||
std::vector<StringRef> &Filenames,
|
std::vector<StringRef> &Filenames,
|
||||||
std::vector<CounterExpression> &Expressions,
|
std::vector<CounterExpression> &Expressions,
|
||||||
std::vector<CounterMappingRegion> &MappingRegions)
|
std::vector<CounterMappingRegion> &MappingRegions)
|
||||||
|
@ -174,10 +174,8 @@ public:
|
||||||
FilenamesBegin(FilenamesBegin), FilenamesSize(FilenamesSize) {}
|
FilenamesBegin(FilenamesBegin), FilenamesSize(FilenamesSize) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
using DecompressedData = std::vector<std::unique_ptr<SmallVector<char, 0>>>;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<StringRef> Filenames;
|
std::vector<std::string> Filenames;
|
||||||
std::vector<ProfileMappingRecord> MappingRecords;
|
std::vector<ProfileMappingRecord> MappingRecords;
|
||||||
InstrProfSymtab ProfileNames;
|
InstrProfSymtab ProfileNames;
|
||||||
size_t CurrentRecord = 0;
|
size_t CurrentRecord = 0;
|
||||||
|
@ -190,10 +188,6 @@ private:
|
||||||
// D69471, which can split up function records into multiple sections on ELF.
|
// D69471, which can split up function records into multiple sections on ELF.
|
||||||
std::string FuncRecords;
|
std::string FuncRecords;
|
||||||
|
|
||||||
// Used to tie the lifetimes of decompressed strings to the lifetime of this
|
|
||||||
// BinaryCoverageReader instance.
|
|
||||||
DecompressedData Decompressed;
|
|
||||||
|
|
||||||
BinaryCoverageReader(std::string &&FuncRecords)
|
BinaryCoverageReader(std::string &&FuncRecords)
|
||||||
: FuncRecords(std::move(FuncRecords)) {}
|
: FuncRecords(std::move(FuncRecords)) {}
|
||||||
|
|
||||||
|
@ -216,20 +210,20 @@ public:
|
||||||
|
|
||||||
/// Reader for the raw coverage filenames.
|
/// Reader for the raw coverage filenames.
|
||||||
class RawCoverageFilenamesReader : public RawCoverageReader {
|
class RawCoverageFilenamesReader : public RawCoverageReader {
|
||||||
std::vector<StringRef> &Filenames;
|
std::vector<std::string> &Filenames;
|
||||||
|
|
||||||
// Read an uncompressed sequence of filenames.
|
// Read an uncompressed sequence of filenames.
|
||||||
Error readUncompressed(uint64_t NumFilenames);
|
Error readUncompressed(CovMapVersion Version, uint64_t NumFilenames);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RawCoverageFilenamesReader(StringRef Data, std::vector<StringRef> &Filenames)
|
RawCoverageFilenamesReader(StringRef Data,
|
||||||
|
std::vector<std::string> &Filenames)
|
||||||
: RawCoverageReader(Data), Filenames(Filenames) {}
|
: RawCoverageReader(Data), Filenames(Filenames) {}
|
||||||
RawCoverageFilenamesReader(const RawCoverageFilenamesReader &) = delete;
|
RawCoverageFilenamesReader(const RawCoverageFilenamesReader &) = delete;
|
||||||
RawCoverageFilenamesReader &
|
RawCoverageFilenamesReader &
|
||||||
operator=(const RawCoverageFilenamesReader &) = delete;
|
operator=(const RawCoverageFilenamesReader &) = delete;
|
||||||
|
|
||||||
Error read(CovMapVersion Version,
|
Error read(CovMapVersion Version);
|
||||||
BinaryCoverageReader::DecompressedData &Decompressed);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace coverage
|
} // end namespace coverage
|
||||||
|
|
|
@ -27,10 +27,10 @@ namespace coverage {
|
||||||
/// Writer of the filenames section for the instrumentation
|
/// Writer of the filenames section for the instrumentation
|
||||||
/// based code coverage.
|
/// based code coverage.
|
||||||
class CoverageFilenamesSectionWriter {
|
class CoverageFilenamesSectionWriter {
|
||||||
ArrayRef<StringRef> Filenames;
|
ArrayRef<std::string> Filenames;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CoverageFilenamesSectionWriter(ArrayRef<StringRef> Filenames);
|
CoverageFilenamesSectionWriter(ArrayRef<std::string> Filenames);
|
||||||
|
|
||||||
/// Write encoded filenames to the given output stream. If \p Compress is
|
/// Write encoded filenames to the given output stream. If \p Compress is
|
||||||
/// true, attempt to compress the filenames.
|
/// true, attempt to compress the filenames.
|
||||||
|
|
|
@ -649,7 +649,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
|
||||||
/* Indexed profile format version (start from 1). */
|
/* Indexed profile format version (start from 1). */
|
||||||
#define INSTR_PROF_INDEX_VERSION 7
|
#define INSTR_PROF_INDEX_VERSION 7
|
||||||
/* Coverage mapping format version (start from 0). */
|
/* 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
|
/* 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
|
* version for other variants of profile. We set the lowest bit of the upper 8
|
||||||
|
|
|
@ -97,9 +97,7 @@ Error RawCoverageReader::readString(StringRef &Result) {
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error RawCoverageFilenamesReader::read(
|
Error RawCoverageFilenamesReader::read(CovMapVersion Version) {
|
||||||
CovMapVersion Version,
|
|
||||||
BinaryCoverageReader::DecompressedData &Decompressed) {
|
|
||||||
uint64_t NumFilenames;
|
uint64_t NumFilenames;
|
||||||
if (auto Err = readSize(NumFilenames))
|
if (auto Err = readSize(NumFilenames))
|
||||||
return Err;
|
return Err;
|
||||||
|
@ -107,7 +105,7 @@ Error RawCoverageFilenamesReader::read(
|
||||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||||
|
|
||||||
if (Version < CovMapVersion::Version4)
|
if (Version < CovMapVersion::Version4)
|
||||||
return readUncompressed(NumFilenames);
|
return readUncompressed(Version, NumFilenames);
|
||||||
|
|
||||||
// The uncompressed length may exceed the size of the encoded filenames.
|
// The uncompressed length may exceed the size of the encoded filenames.
|
||||||
// Skip size validation.
|
// Skip size validation.
|
||||||
|
@ -124,11 +122,8 @@ Error RawCoverageFilenamesReader::read(
|
||||||
return make_error<CoverageMapError>(
|
return make_error<CoverageMapError>(
|
||||||
coveragemap_error::decompression_failed);
|
coveragemap_error::decompression_failed);
|
||||||
|
|
||||||
// Allocate memory for the decompressed filenames. Transfer ownership of
|
// Allocate memory for the decompressed filenames.
|
||||||
// the memory to BinaryCoverageReader.
|
SmallVector<char, 0> StorageBuf;
|
||||||
auto DecompressedStorage = std::make_unique<SmallVector<char, 0>>();
|
|
||||||
SmallVectorImpl<char> &StorageBuf = *DecompressedStorage.get();
|
|
||||||
Decompressed.push_back(std::move(DecompressedStorage));
|
|
||||||
|
|
||||||
// Read compressed filenames.
|
// Read compressed filenames.
|
||||||
StringRef CompressedFilenames = Data.substr(0, CompressedLen);
|
StringRef CompressedFilenames = Data.substr(0, CompressedLen);
|
||||||
|
@ -143,19 +138,40 @@ Error RawCoverageFilenamesReader::read(
|
||||||
|
|
||||||
StringRef UncompressedFilenames(StorageBuf.data(), StorageBuf.size());
|
StringRef UncompressedFilenames(StorageBuf.data(), StorageBuf.size());
|
||||||
RawCoverageFilenamesReader Delegate(UncompressedFilenames, Filenames);
|
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.
|
// Read uncompressed filenames.
|
||||||
|
if (Version < CovMapVersion::Version6) {
|
||||||
for (size_t I = 0; I < NumFilenames; ++I) {
|
for (size_t I = 0; I < NumFilenames; ++I) {
|
||||||
StringRef Filename;
|
StringRef Filename;
|
||||||
if (auto Err = readString(Filename))
|
if (auto Err = readString(Filename))
|
||||||
return Err;
|
return Err;
|
||||||
Filenames.push_back(Filename);
|
Filenames.push_back(Filename.str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
StringRef CWD;
|
||||||
|
if (auto Err = readString(CWD))
|
||||||
|
return Err;
|
||||||
|
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();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
@ -481,9 +497,8 @@ struct CovMapFuncRecordReader {
|
||||||
//
|
//
|
||||||
// Returns a pointer to the next \c CovHeader if it exists, or to an address
|
// Returns a pointer to the next \c CovHeader if it exists, or to an address
|
||||||
// greater than \p CovEnd if not.
|
// greater than \p CovEnd if not.
|
||||||
virtual Expected<const char *>
|
virtual Expected<const char *> readCoverageHeader(const char *CovBuf,
|
||||||
readCoverageHeader(const char *CovBuf, const char *CovBufEnd,
|
const char *CovBufEnd) = 0;
|
||||||
BinaryCoverageReader::DecompressedData &Decompressed) = 0;
|
|
||||||
|
|
||||||
// Read function records.
|
// Read function records.
|
||||||
//
|
//
|
||||||
|
@ -505,7 +520,7 @@ struct CovMapFuncRecordReader {
|
||||||
static Expected<std::unique_ptr<CovMapFuncRecordReader>>
|
static Expected<std::unique_ptr<CovMapFuncRecordReader>>
|
||||||
get(CovMapVersion Version, InstrProfSymtab &P,
|
get(CovMapVersion Version, InstrProfSymtab &P,
|
||||||
std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
|
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.
|
// A class for reading coverage mapping function records for a module.
|
||||||
|
@ -519,7 +534,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
|
||||||
// in \c Records.
|
// in \c Records.
|
||||||
DenseMap<NameRefType, size_t> FunctionRecords;
|
DenseMap<NameRefType, size_t> FunctionRecords;
|
||||||
InstrProfSymtab &ProfileNames;
|
InstrProfSymtab &ProfileNames;
|
||||||
std::vector<StringRef> &Filenames;
|
std::vector<std::string> &Filenames;
|
||||||
std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records;
|
std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records;
|
||||||
|
|
||||||
// Maps a hash of the filenames in a TU to a \c FileRange. The range
|
// Maps a hash of the filenames in a TU to a \c FileRange. The range
|
||||||
|
@ -579,14 +594,13 @@ public:
|
||||||
VersionedCovMapFuncRecordReader(
|
VersionedCovMapFuncRecordReader(
|
||||||
InstrProfSymtab &P,
|
InstrProfSymtab &P,
|
||||||
std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
|
std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
|
||||||
std::vector<StringRef> &F)
|
std::vector<std::string> &F)
|
||||||
: ProfileNames(P), Filenames(F), Records(R) {}
|
: ProfileNames(P), Filenames(F), Records(R) {}
|
||||||
|
|
||||||
~VersionedCovMapFuncRecordReader() override = default;
|
~VersionedCovMapFuncRecordReader() override = default;
|
||||||
|
|
||||||
Expected<const char *> readCoverageHeader(
|
Expected<const char *> readCoverageHeader(const char *CovBuf,
|
||||||
const char *CovBuf, const char *CovBufEnd,
|
const char *CovBufEnd) override {
|
||||||
BinaryCoverageReader::DecompressedData &Decompressed) override {
|
|
||||||
using namespace support;
|
using namespace support;
|
||||||
|
|
||||||
if (CovBuf + sizeof(CovMapHeader) > CovBufEnd)
|
if (CovBuf + sizeof(CovMapHeader) > CovBufEnd)
|
||||||
|
@ -615,7 +629,7 @@ public:
|
||||||
size_t FilenamesBegin = Filenames.size();
|
size_t FilenamesBegin = Filenames.size();
|
||||||
StringRef FilenameRegion(CovBuf, FilenamesSize);
|
StringRef FilenameRegion(CovBuf, FilenamesSize);
|
||||||
RawCoverageFilenamesReader Reader(FilenameRegion, Filenames);
|
RawCoverageFilenamesReader Reader(FilenameRegion, Filenames);
|
||||||
if (auto Err = Reader.read(Version, Decompressed))
|
if (auto Err = Reader.read(Version))
|
||||||
return std::move(Err);
|
return std::move(Err);
|
||||||
CovBuf += FilenamesSize;
|
CovBuf += FilenamesSize;
|
||||||
FilenameRange FileRange(FilenamesBegin, Filenames.size() - FilenamesBegin);
|
FilenameRange FileRange(FilenamesBegin, Filenames.size() - FilenamesBegin);
|
||||||
|
@ -721,7 +735,7 @@ template <class IntPtrT, support::endianness Endian>
|
||||||
Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
|
Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
|
||||||
CovMapVersion Version, InstrProfSymtab &P,
|
CovMapVersion Version, InstrProfSymtab &P,
|
||||||
std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
|
std::vector<BinaryCoverageReader::ProfileMappingRecord> &R,
|
||||||
std::vector<StringRef> &F) {
|
std::vector<std::string> &F) {
|
||||||
using namespace coverage;
|
using namespace coverage;
|
||||||
|
|
||||||
switch (Version) {
|
switch (Version) {
|
||||||
|
@ -732,6 +746,7 @@ Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
|
||||||
case CovMapVersion::Version3:
|
case CovMapVersion::Version3:
|
||||||
case CovMapVersion::Version4:
|
case CovMapVersion::Version4:
|
||||||
case CovMapVersion::Version5:
|
case CovMapVersion::Version5:
|
||||||
|
case CovMapVersion::Version6:
|
||||||
// Decompress the name data.
|
// Decompress the name data.
|
||||||
if (Error E = P.create(P.getNameData()))
|
if (Error E = P.create(P.getNameData()))
|
||||||
return std::move(E);
|
return std::move(E);
|
||||||
|
@ -747,6 +762,9 @@ Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
|
||||||
else if (Version == CovMapVersion::Version5)
|
else if (Version == CovMapVersion::Version5)
|
||||||
return std::make_unique<VersionedCovMapFuncRecordReader<
|
return std::make_unique<VersionedCovMapFuncRecordReader<
|
||||||
CovMapVersion::Version5, IntPtrT, Endian>>(P, R, F);
|
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");
|
llvm_unreachable("Unsupported version");
|
||||||
}
|
}
|
||||||
|
@ -755,8 +773,7 @@ template <typename T, support::endianness Endian>
|
||||||
static Error readCoverageMappingData(
|
static Error readCoverageMappingData(
|
||||||
InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords,
|
InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords,
|
||||||
std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,
|
std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,
|
||||||
std::vector<StringRef> &Filenames,
|
std::vector<std::string> &Filenames) {
|
||||||
BinaryCoverageReader::DecompressedData &Decompressed) {
|
|
||||||
using namespace coverage;
|
using namespace coverage;
|
||||||
|
|
||||||
// Read the records in the coverage data section.
|
// Read the records in the coverage data section.
|
||||||
|
@ -782,8 +799,7 @@ static Error readCoverageMappingData(
|
||||||
// header.
|
// header.
|
||||||
//
|
//
|
||||||
// Return a pointer to the next coverage header.
|
// Return a pointer to the next coverage header.
|
||||||
auto NextOrErr =
|
auto NextOrErr = Reader->readCoverageHeader(CovBuf, CovBufEnd);
|
||||||
Reader->readCoverageHeader(CovBuf, CovBufEnd, Decompressed);
|
|
||||||
if (auto E = NextOrErr.takeError())
|
if (auto E = NextOrErr.takeError())
|
||||||
return E;
|
return E;
|
||||||
CovBuf = NextOrErr.get();
|
CovBuf = NextOrErr.get();
|
||||||
|
@ -810,25 +826,23 @@ BinaryCoverageReader::createCoverageReaderFromBuffer(
|
||||||
if (Error E =
|
if (Error E =
|
||||||
readCoverageMappingData<uint32_t, support::endianness::little>(
|
readCoverageMappingData<uint32_t, support::endianness::little>(
|
||||||
Reader->ProfileNames, Coverage, FuncRecordsRef,
|
Reader->ProfileNames, Coverage, FuncRecordsRef,
|
||||||
Reader->MappingRecords, Reader->Filenames,
|
Reader->MappingRecords, Reader->Filenames))
|
||||||
Reader->Decompressed))
|
|
||||||
return std::move(E);
|
return std::move(E);
|
||||||
} else if (BytesInAddress == 4 && Endian == support::endianness::big) {
|
} else if (BytesInAddress == 4 && Endian == support::endianness::big) {
|
||||||
if (Error E = readCoverageMappingData<uint32_t, support::endianness::big>(
|
if (Error E = readCoverageMappingData<uint32_t, support::endianness::big>(
|
||||||
Reader->ProfileNames, Coverage, FuncRecordsRef,
|
Reader->ProfileNames, Coverage, FuncRecordsRef,
|
||||||
Reader->MappingRecords, Reader->Filenames, Reader->Decompressed))
|
Reader->MappingRecords, Reader->Filenames))
|
||||||
return std::move(E);
|
return std::move(E);
|
||||||
} else if (BytesInAddress == 8 && Endian == support::endianness::little) {
|
} else if (BytesInAddress == 8 && Endian == support::endianness::little) {
|
||||||
if (Error E =
|
if (Error E =
|
||||||
readCoverageMappingData<uint64_t, support::endianness::little>(
|
readCoverageMappingData<uint64_t, support::endianness::little>(
|
||||||
Reader->ProfileNames, Coverage, FuncRecordsRef,
|
Reader->ProfileNames, Coverage, FuncRecordsRef,
|
||||||
Reader->MappingRecords, Reader->Filenames,
|
Reader->MappingRecords, Reader->Filenames))
|
||||||
Reader->Decompressed))
|
|
||||||
return std::move(E);
|
return std::move(E);
|
||||||
} else if (BytesInAddress == 8 && Endian == support::endianness::big) {
|
} else if (BytesInAddress == 8 && Endian == support::endianness::big) {
|
||||||
if (Error E = readCoverageMappingData<uint64_t, support::endianness::big>(
|
if (Error E = readCoverageMappingData<uint64_t, support::endianness::big>(
|
||||||
Reader->ProfileNames, Coverage, FuncRecordsRef,
|
Reader->ProfileNames, Coverage, FuncRecordsRef,
|
||||||
Reader->MappingRecords, Reader->Filenames, Reader->Decompressed))
|
Reader->MappingRecords, Reader->Filenames))
|
||||||
return std::move(E);
|
return std::move(E);
|
||||||
} else
|
} else
|
||||||
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
return make_error<CoverageMapError>(coveragemap_error::malformed);
|
||||||
|
@ -1075,10 +1089,9 @@ Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {
|
||||||
Expressions.clear();
|
Expressions.clear();
|
||||||
MappingRegions.clear();
|
MappingRegions.clear();
|
||||||
auto &R = MappingRecords[CurrentRecord];
|
auto &R = MappingRecords[CurrentRecord];
|
||||||
RawCoverageMappingReader Reader(
|
auto F = makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize);
|
||||||
R.CoverageMapping,
|
RawCoverageMappingReader Reader(R.CoverageMapping, F, FunctionsFilenames,
|
||||||
makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize),
|
Expressions, MappingRegions);
|
||||||
FunctionsFilenames, Expressions, MappingRegions);
|
|
||||||
if (auto Err = Reader.read())
|
if (auto Err = Reader.read())
|
||||||
return Err;
|
return Err;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ using namespace llvm;
|
||||||
using namespace coverage;
|
using namespace coverage;
|
||||||
|
|
||||||
CoverageFilenamesSectionWriter::CoverageFilenamesSectionWriter(
|
CoverageFilenamesSectionWriter::CoverageFilenamesSectionWriter(
|
||||||
ArrayRef<StringRef> Filenames)
|
ArrayRef<std::string> Filenames)
|
||||||
: Filenames(Filenames) {
|
: Filenames(Filenames) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
StringSet<> NameSet;
|
StringSet<> NameSet;
|
||||||
|
|
Binary file not shown.
|
@ -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.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.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.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
|
// RUN: llvm-cov export %S/Inputs/binary-formats.macho64l -instr-profile %t.profdata | FileCheck %S/Inputs/binary-formats.canonical.json
|
||||||
|
|
|
@ -129,6 +129,7 @@ struct InputFunctionCoverageData {
|
||||||
struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> {
|
struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> {
|
||||||
bool UseMultipleReaders;
|
bool UseMultipleReaders;
|
||||||
StringMap<unsigned> Files;
|
StringMap<unsigned> Files;
|
||||||
|
std::vector<std::string> Filenames;
|
||||||
std::vector<InputFunctionCoverageData> InputFunctions;
|
std::vector<InputFunctionCoverageData> InputFunctions;
|
||||||
std::vector<OutputFunctionCoverageData> OutputFunctions;
|
std::vector<OutputFunctionCoverageData> OutputFunctions;
|
||||||
|
|
||||||
|
@ -146,7 +147,7 @@ struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> {
|
||||||
auto R = Files.find(Name);
|
auto R = Files.find(Name);
|
||||||
if (R != Files.end())
|
if (R != Files.end())
|
||||||
return R->second;
|
return R->second;
|
||||||
unsigned Index = Files.size();
|
unsigned Index = Files.size() + 1;
|
||||||
Files.try_emplace(Name, Index);
|
Files.try_emplace(Name, Index);
|
||||||
return Index;
|
return Index;
|
||||||
}
|
}
|
||||||
|
@ -200,11 +201,12 @@ struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> {
|
||||||
|
|
||||||
void readCoverageRegions(const std::string &Coverage,
|
void readCoverageRegions(const std::string &Coverage,
|
||||||
OutputFunctionCoverageData &Data) {
|
OutputFunctionCoverageData &Data) {
|
||||||
SmallVector<StringRef, 8> Filenames(Files.size());
|
Filenames.resize(Files.size() + 1);
|
||||||
for (const auto &E : Files)
|
for (const auto &E : Files)
|
||||||
Filenames[E.getValue()] = E.getKey();
|
Filenames[E.getValue()] = E.getKey().str();
|
||||||
std::vector<CounterExpression> Expressions;
|
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);
|
Expressions, Data.Regions);
|
||||||
EXPECT_THAT_ERROR(Reader.read(), Succeeded());
|
EXPECT_THAT_ERROR(Reader.read(), Succeeded());
|
||||||
}
|
}
|
||||||
|
@ -895,7 +897,7 @@ INSTANTIATE_TEST_CASE_P(ParameterizedCovMapTest, CoverageMappingTest,
|
||||||
std::pair<bool, bool>({true, true})),);
|
std::pair<bool, bool>({true, true})),);
|
||||||
|
|
||||||
TEST(CoverageMappingTest, filename_roundtrip) {
|
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}) {
|
for (bool Compress : {false, true}) {
|
||||||
std::string EncodedFilenames;
|
std::string EncodedFilenames;
|
||||||
|
@ -905,16 +907,12 @@ TEST(CoverageMappingTest, filename_roundtrip) {
|
||||||
Writer.write(OS, Compress);
|
Writer.write(OS, Compress);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<StringRef> ReadFilenames;
|
std::vector<std::string> ReadFilenames;
|
||||||
RawCoverageFilenamesReader Reader(EncodedFilenames, ReadFilenames);
|
RawCoverageFilenamesReader Reader(EncodedFilenames, ReadFilenames);
|
||||||
BinaryCoverageReader::DecompressedData Decompressed;
|
EXPECT_THAT_ERROR(Reader.read(CovMapVersion::CurrentVersion), Succeeded());
|
||||||
EXPECT_THAT_ERROR(Reader.read(CovMapVersion::CurrentVersion, Decompressed),
|
|
||||||
Succeeded());
|
|
||||||
if (!Compress)
|
|
||||||
ASSERT_EQ(Decompressed.size(), 0U);
|
|
||||||
|
|
||||||
ASSERT_EQ(ReadFilenames.size(), Paths.size());
|
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]);
|
ASSERT_TRUE(ReadFilenames[I] == Paths[I]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue