diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -160,6 +160,9 @@ /// The version string to put into coverage files. char CoverageVersion[4]; + /// The string to embed in coverage mapping as the current working directory. + std::string CoverageCompilationDir; + /// Enable additional debugging information. std::string DebugPass; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1104,6 +1104,13 @@ CodeGenOpts<"CoverageMapping">, DefaultFalse, PosFlag, NegFlag, BothFlags<[CoreOption]>>; +def fcoverage_compilation_dir : Separate<["-"], "fcoverage-compilation-dir">, + Group, Flags<[CC1Option, CC1AsOption, CoreOption]>, + HelpText<"The compilation directory to embed in the coverage mapping.">, + MarshallingInfoString>; +def fcoverage_compilation_dir_EQ : Joined<["-"], "fcoverage-compilation-dir=">, + Group, Flags<[CC1Option, CC1AsOption, CoreOption]>, + Alias; def fprofile_generate : Flag<["-"], "fprofile-generate">, Group, Flags<[CoreOption]>, HelpText<"Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM_PROFILE_FILE env var)">; diff --git a/clang/lib/CodeGen/CoverageMappingGen.h b/clang/lib/CodeGen/CoverageMappingGen.h --- a/clang/lib/CodeGen/CoverageMappingGen.h +++ b/clang/lib/CodeGen/CoverageMappingGen.h @@ -95,6 +95,7 @@ std::vector FunctionRecords; std::map ProfilePrefixMap; + std::string getCurrentDirname(); std::string normalizeFilename(StringRef Filename); /// Emit a function record. diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1591,9 +1591,17 @@ ProfilePrefixMap = CGM.getCodeGenOpts().ProfilePrefixMap; } +std::string CoverageMappingModuleGen::getCurrentDirname() { + if (!CGM.getCodeGenOpts().CoverageCompilationDir.empty()) + return CGM.getCodeGenOpts().CoverageCompilationDir; + + 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)) @@ -1677,15 +1685,14 @@ std::vector Filenames; std::vector Expressions; std::vector Regions; - llvm::SmallVector FilenameStrs; - llvm::SmallVector FilenameRefs; - FilenameStrs.resize(FileEntries.size()); - FilenameRefs.resize(FileEntries.size()); + std::vector FilenameStrs; + FilenameStrs.resize(FileEntries.size() + 1); + FilenameStrs[0] = 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()) @@ -1703,8 +1710,11 @@ // 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); + FilenameRefs.resize(FileEntries.size() + 1); + // The first filename is the current working directory. + FilenameStrs[0] = getCurrentDirname(); + FilenameRefs[0] = FilenameStrs[0]; for (const auto &Entry : FileEntries) { auto I = Entry.second; FilenameStrs[I] = normalizeFilename(Entry.first->getName()); @@ -1772,7 +1782,7 @@ 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/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -614,6 +614,19 @@ return CodeGenOptions::FramePointerKind::None; } +/// Add a CC1 option to specify the coverage compilation directory. +static void addCoverageCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, + const llvm::vfs::FileSystem &VFS) { + if (Arg *A = Args.getLastArg(options::OPT_fcoverage_compilation_dir)) { + CmdArgs.push_back("-fcoverage-compilation-dir"); + CmdArgs.push_back(A->getValue()); + } else if (llvm::ErrorOr CWD = + VFS.getCurrentWorkingDirectory()) { + CmdArgs.push_back("-fcoverage-compilation-dir"); + CmdArgs.push_back(Args.MakeArgString(*CWD)); + } +} + /// Add a CC1 option to specify the debug compilation directory. static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, const llvm::vfs::FileSystem &VFS) { @@ -5285,6 +5298,10 @@ if (!ShouldEnableAutolink(Args, TC, JA)) CmdArgs.push_back("-fno-autolink"); + // Add in -fcoverage-compilation-dir if necessary. + if (!Triple.isNVPTX() && !Triple.isAMDGCN()) + addCoverageCompDirArg(Args, CmdArgs, D.getVFS()); + // Add in -fdebug-compilation-dir if necessary. addDebugCompDirArg(Args, CmdArgs, D.getVFS()); diff --git a/clang/test/CoverageMapping/abspath.cpp b/clang/test/CoverageMapping/abspath.cpp --- a/clang/test/CoverageMapping/abspath.cpp +++ b/clang/test/CoverageMapping/abspath.cpp @@ -6,10 +6,14 @@ // 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 --- 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 // +// 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 = {{.*"\\01[^/]*}}.{{/|\\+}}nested{{.*profile-prefix-map\.c}} diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h @@ -125,14 +125,14 @@ /// 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 @@ 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 @@ // 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 @@ /// 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); 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/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -97,9 +97,7 @@ 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; @@ -124,11 +122,8 @@ 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); @@ -150,13 +145,24 @@ } Error RawCoverageFilenamesReader::readUncompressed(uint64_t NumFilenames) { - // Read uncompressed filenames. - for (size_t I = 0; I < NumFilenames; ++I) { + 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; - Filenames.push_back(Filename); + 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 +487,8 @@ // // 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 +510,7 @@ 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 +524,7 @@ // 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 +584,13 @@ 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 +619,7 @@ 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 +725,7 @@ Expected> CovMapFuncRecordReader::get( CovMapVersion Version, InstrProfSymtab &P, std::vector &R, - std::vector &F) { + std::vector &F) { using namespace coverage; switch (Version) { @@ -755,8 +759,7 @@ 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 +785,7 @@ // 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 +812,23 @@ 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 +1075,9 @@ 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;