diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index efcb6b16b0f7ac..bf260c444b2e81 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 efb1f2e2288fef..c7003437472e57 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, Flags<[CC1Option, CC1AsOption, CoreOption]>, Alias; +def fprofile_compilation_dir_EQ : Joined<["-"], "fprofile-compilation-dir=">, + Group, Flags<[CC1Option, CC1AsOption, CoreOption]>, + HelpText<"The compilation directory to embed in the coverage mapping.">, + MarshallingInfoString>; defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling", CodeGenOpts<"DebugInfoForProfiling">, DefaultFalse, PosFlag, diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index ce2cb380e0c1dc..ebbd6aad2cd7b3 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 FilenameStrs; std::vector Filenames; std::vector Expressions; std::vector Regions; - llvm::SmallVector FilenameStrs; - llvm::SmallVector 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 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 FilenameStrs; - llvm::SmallVector 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 b26f79be53166e..abf12e58def6c6 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.h +++ b/clang/lib/CodeGen/CoverageMappingGen.h @@ -95,6 +95,7 @@ class CoverageMappingModuleGen { std::vector FunctionRecords; std::map 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 ae7a8227d304ef..180d9cfec225a3 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 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 00000000000000..6d66581bc70245 --- /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 3c593f40b7dd73..4fa8eb9467f368 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 1b316d0149c2da..9c7718e901d038 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 3ee7af71287227..9112c9fa12b290 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 4dc9dc380b9808..0dc5ce6e808ada 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 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 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 09f21677ec5412..957dfe9f1503f7 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 3a611bcb8cd112..86a3c4af9c3c89 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 TranslationUnitFilenames; + ArrayRef &TranslationUnitFilenames; std::vector &Filenames; std::vector &Expressions; std::vector &MappingRegions; public: RawCoverageMappingReader(StringRef MappingData, - ArrayRef TranslationUnitFilenames, + ArrayRef &TranslationUnitFilenames, std::vector &Filenames, std::vector &Expressions, std::vector &MappingRegions) @@ -174,10 +174,8 @@ class BinaryCoverageReader : public CoverageMappingReader { FilenamesBegin(FilenamesBegin), FilenamesSize(FilenamesSize) {} }; - using DecompressedData = std::vector>>; - private: - std::vector Filenames; + std::vector Filenames; std::vector 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 &Filenames; + std::vector &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 &Filenames) + RawCoverageFilenamesReader(StringRef Data, + std::vector &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 303e5184d4937a..14206755881b92 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 Filenames; + ArrayRef Filenames; public: - CoverageFilenamesSectionWriter(ArrayRef Filenames); + CoverageFilenamesSectionWriter(ArrayRef 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 3ee7af71287227..9112c9fa12b290 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 1acdcb4bebb9b1..942f8e7957f3f2 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(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( coveragemap_error::decompression_failed); - // Allocate memory for the decompressed filenames. Transfer ownership of - // the memory to BinaryCoverageReader. - auto DecompressedStorage = std::make_unique>(); - SmallVectorImpl &StorageBuf = *DecompressedStorage.get(); - Decompressed.push_back(std::move(DecompressedStorage)); + // Allocate memory for the decompressed filenames. + SmallVector 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(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 - readCoverageHeader(const char *CovBuf, const char *CovBufEnd, - BinaryCoverageReader::DecompressedData &Decompressed) = 0; + virtual Expected readCoverageHeader(const char *CovBuf, + const char *CovBufEnd) = 0; // Read function records. // @@ -505,7 +520,7 @@ struct CovMapFuncRecordReader { static Expected> get(CovMapVersion Version, InstrProfSymtab &P, std::vector &R, - std::vector &F); + std::vector &F); }; // A class for reading coverage mapping function records for a module. @@ -519,7 +534,7 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader { // in \c Records. DenseMap FunctionRecords; InstrProfSymtab &ProfileNames; - std::vector &Filenames; + std::vector &Filenames; std::vector &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 &R, - std::vector &F) + std::vector &F) : ProfileNames(P), Filenames(F), Records(R) {} ~VersionedCovMapFuncRecordReader() override = default; - Expected readCoverageHeader( - const char *CovBuf, const char *CovBufEnd, - BinaryCoverageReader::DecompressedData &Decompressed) override { + Expected 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 Expected> CovMapFuncRecordReader::get( CovMapVersion Version, InstrProfSymtab &P, std::vector &R, - std::vector &F) { + std::vector &F) { using namespace coverage; switch (Version) { @@ -732,6 +746,7 @@ Expected> 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> CovMapFuncRecordReader::get( else if (Version == CovMapVersion::Version5) return std::make_unique>(P, R, F); + else if (Version == CovMapVersion::Version6) + return std::make_unique>(P, R, F); } llvm_unreachable("Unsupported version"); } @@ -755,8 +773,7 @@ template static Error readCoverageMappingData( InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords, std::vector &Records, - std::vector &Filenames, - BinaryCoverageReader::DecompressedData &Decompressed) { + std::vector &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( 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( 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( 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( Reader->ProfileNames, Coverage, FuncRecordsRef, - Reader->MappingRecords, Reader->Filenames, Reader->Decompressed)) + Reader->MappingRecords, Reader->Filenames)) return std::move(E); } else return make_error(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 65b83d1f41979f..6a9258fee5ee0f 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 Filenames) + ArrayRef 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 00000000000000..bd00cd0f137321 Binary files /dev/null and b/llvm/test/tools/llvm-cov/Inputs/binary-formats.v6.linux64l differ diff --git a/llvm/test/tools/llvm-cov/binary-formats.c b/llvm/test/tools/llvm-cov/binary-formats.c index 009583c00bce7c..a5bfc012860ec3 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 cbe9c1e823b72f..44b7a13334d4a5 100644 --- a/llvm/unittests/ProfileData/CoverageMappingTest.cpp +++ b/llvm/unittests/ProfileData/CoverageMappingTest.cpp @@ -129,6 +129,7 @@ struct InputFunctionCoverageData { struct CoverageMappingTest : ::testing::TestWithParam> { bool UseMultipleReaders; StringMap Files; + std::vector Filenames; std::vector InputFunctions; std::vector OutputFunctions; @@ -146,7 +147,7 @@ struct CoverageMappingTest : ::testing::TestWithParam> { 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> { void readCoverageRegions(const std::string &Coverage, OutputFunctionCoverageData &Data) { - SmallVector 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 Expressions; - RawCoverageMappingReader Reader(Coverage, Filenames, Data.Filenames, + ArrayRef 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({true, true})),); TEST(CoverageMappingTest, filename_roundtrip) { - std::vector Paths({"a", "b", "c", "d", "e"}); + std::vector 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 ReadFilenames; + std::vector 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]); } }