This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG5fbd1a333aa1: [Coverage] Store compilation dir separately in coverage mapping (authored by phosek).
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D95753/new/ https://reviews.llvm.org/D95753 Files: 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/CodeGen/profile-compilation-dir.c 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/Inputs/binary-formats.v6.linux64l llvm/test/tools/llvm-cov/binary-formats.c llvm/unittests/ProfileData/CoverageMappingTest.cpp
Index: llvm/unittests/ProfileData/CoverageMappingTest.cpp =================================================================== --- llvm/unittests/ProfileData/CoverageMappingTest.cpp +++ llvm/unittests/ProfileData/CoverageMappingTest.cpp @@ -129,6 +129,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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]); } } Index: llvm/test/tools/llvm-cov/binary-formats.c =================================================================== --- llvm/test/tools/llvm-cov/binary-formats.c +++ llvm/test/tools/llvm-cov/binary-formats.c @@ -8,5 +8,6 @@ // 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 Index: llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp =================================================================== --- llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp +++ llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp @@ -27,7 +27,7 @@ using namespace coverage; CoverageFilenamesSectionWriter::CoverageFilenamesSectionWriter( - ArrayRef<StringRef> Filenames) + ArrayRef<std::string> Filenames) : Filenames(Filenames) { #ifndef NDEBUG StringSet<> NameSet; Index: llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp =================================================================== --- llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ 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; @@ -107,7 +105,7 @@ 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 @@ 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 @@ 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 @@ // // 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 @@ 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 @@ // 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ 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; Index: llvm/include/llvm/ProfileData/InstrProfData.inc =================================================================== --- llvm/include/llvm/ProfileData/InstrProfData.inc +++ llvm/include/llvm/ProfileData/InstrProfData.inc @@ -649,7 +649,7 @@ /* 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 Index: llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h =================================================================== --- llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h +++ llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h @@ -27,10 +27,10 @@ /// 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. Index: llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h =================================================================== --- llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h +++ llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h @@ -125,14 +125,14 @@ /// 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 @@ 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 @@ // 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<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 Index: llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h =================================================================== --- llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -996,7 +996,10 @@ 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 }; Index: llvm/docs/CoverageMappingFormat.rst =================================================================== --- llvm/docs/CoverageMappingFormat.rst +++ llvm/docs/CoverageMappingFormat.rst @@ -266,7 +266,16 @@ [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 Index: compiler-rt/include/profile/InstrProfData.inc =================================================================== --- compiler-rt/include/profile/InstrProfData.inc +++ compiler-rt/include/profile/InstrProfData.inc @@ -649,7 +649,7 @@ /* 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 Index: clang/test/Profile/profile-prefix-map.c =================================================================== --- clang/test/Profile/profile-prefix-map.c +++ 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}} Index: clang/test/CoverageMapping/abspath.cpp =================================================================== --- clang/test/CoverageMapping/abspath.cpp +++ 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() {} Index: clang/test/CodeGen/profile-compilation-dir.c =================================================================== --- /dev/null +++ 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() {} Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -858,6 +858,13 @@ 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)) Index: clang/lib/CodeGen/CoverageMappingGen.h =================================================================== --- clang/lib/CodeGen/CoverageMappingGen.h +++ clang/lib/CodeGen/CoverageMappingGen.h @@ -95,6 +95,7 @@ std::vector<FunctionInfo> FunctionRecords; std::map<std::string, std::string> ProfilePrefixMap; + std::string getCurrentDirname(); std::string normalizeFilename(StringRef Filename); /// Emit a function record. Index: clang/lib/CodeGen/CoverageMappingGen.cpp =================================================================== --- clang/lib/CodeGen/CoverageMappingGen.cpp +++ clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1606,9 +1606,17 @@ 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 @@ // 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 @@ // 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 @@ 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; } Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1103,6 +1103,10 @@ 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">, Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -172,6 +172,9 @@ /// 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;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits