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 @@ -31,6 +31,10 @@ // is textually included. #define COVMAP_V3 +namespace llvm { +extern cl::opt DebugInfoCorrelate; +} // namespace llvm + static llvm::cl::opt EmptyLineCommentCoverage( "emptyline-comment-coverage", llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only " @@ -1821,6 +1825,22 @@ llvm::GlobalValue::InternalLinkage, NamesArrVal, llvm::getCoverageUnusedNamesVarName()); } + const StringRef VarName(INSTR_PROF_QUOTE(INSTR_PROF_RAW_VERSION_VAR)); + llvm::Type *IntTy64 = llvm::Type::getInt64Ty(Ctx); + uint64_t ProfileVersion = INSTR_PROF_RAW_VERSION; + if (llvm::DebugInfoCorrelate) + ProfileVersion |= VARIANT_MASK_DBG_CORRELATE; + auto *VersionVariable = new llvm::GlobalVariable( + CGM.getModule(), llvm::Type::getInt64Ty(Ctx), true, + llvm::GlobalValue::WeakAnyLinkage, + llvm::Constant::getIntegerValue(IntTy64, llvm::APInt(64, ProfileVersion)), + VarName); + VersionVariable->setVisibility(llvm::GlobalValue::HiddenVisibility); + llvm::Triple TT(CGM.getModule().getTargetTriple()); + if (TT.supportsCOMDAT()) { + VersionVariable->setLinkage(llvm::GlobalValue::ExternalLinkage); + VersionVariable->setComdat(CGM.getModule().getOrInsertComdat(VarName)); + } } unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) { diff --git a/clang/test/CodeGen/coverage-debug-info-correlate.c b/clang/test/CodeGen/coverage-debug-info-correlate.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/coverage-debug-info-correlate.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -debug-info-kind=standalone -mllvm -debug-info-correlate -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -o - %s | FileCheck %s + +// CHECK: @__llvm_profile_raw_version = hidden constant i64 576460752303423496, comdat +int main() { + return 0; +} diff --git a/compiler-rt/test/profile/Darwin/coverage-debug-info-correlate.c b/compiler-rt/test/profile/Darwin/coverage-debug-info-correlate.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/profile/Darwin/coverage-debug-info-correlate.c @@ -0,0 +1,37 @@ +// Test debug info correlate with clang coverage. + +// RUN: %clang_profgen -o %t.normal -fcoverage-mapping %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal +// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw + +// RUN: %clang_profgen -o %t -g -mllvm --debug-info-correlate -fcoverage-mapping %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.profraw + +// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata) + +// RUN: llvm-cov report --instr-profile=%t.profdata %t | FileCheck %s + +// Test debug info correlate with clang coverage (online merging). + +// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t.normal +// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t.normal +// RUN: llvm-profdata merge -o %t.normal.profdata %t-1.profraw %t-2.profraw + +// RUN: rm -rf %t.profdir && mkdir %t.profdir +// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t +// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t +// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t.dSYM %t.profdir + +// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata) + +// RUN: llvm-cov report --instr-profile=%t.profdata %t | FileCheck %s + + +// CHECK: Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover +// CHECK-NEXT: -- +// CHECK-NEXT: instrprof-debug-info-correlate-bar.h 3 1 66.67% 1 0 100.00% 5 1 80.00% 2 1 50.00% +// CHECK-NEXT: instrprof-debug-info-correlate-foo.cpp 5 2 60.00% 2 1 50.00% 6 2 66.67% 2 1 50.00% +// CHECK-NEXT: instrprof-debug-info-correlate-main.cpp 4 0 100.00% 1 0 100.00% 5 0 100.00% 2 0 100.00% +// CHECK-NEXT: -- +// CHECK-NEXT: TOTAL 12 3 75.00% 4 1 75.00% 16 3 81.25% 6 2 66.67% diff --git a/compiler-rt/test/profile/Linux/coverage-debug-info-correlate.c b/compiler-rt/test/profile/Linux/coverage-debug-info-correlate.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-debug-info-correlate.c @@ -0,0 +1,37 @@ +// Test debug info correlate with clang coverage. + +// RUN: %clang_profgen -o %t.normal -fcoverage-mapping %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.normal +// RUN: llvm-profdata merge -o %t.normal.profdata %t.profraw + +// RUN: %clang_profgen -o %t -g -mllvm --debug-info-correlate -fcoverage-mapping %S/../Inputs/instrprof-debug-info-correlate-main.cpp %S/../Inputs/instrprof-debug-info-correlate-foo.cpp +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.profraw + +// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata) + +// RUN: llvm-cov report --instr-profile=%t.profdata %t + +// Test debug info correlate with clang coverage (online merging). + +// RUN: env LLVM_PROFILE_FILE=%t-1.profraw %run %t.normal +// RUN: env LLVM_PROFILE_FILE=%t-2.profraw %run %t.normal +// RUN: llvm-profdata merge -o %t.normal.profdata %t-1.profraw %t-2.profraw + +// RUN: rm -rf %t.profdir && mkdir %t.profdir +// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t +// RUN: env LLVM_PROFILE_FILE=%t.profdir/%m.proflite %run %t +// RUN: llvm-profdata merge -o %t.profdata --debug-info=%t %t.profdir + +// RUN: diff <(llvm-profdata show --all-functions --counts %t.normal.profdata) <(llvm-profdata show --all-functions --counts %t.profdata) + +// RUN: llvm-cov report --instr-profile=%t.profdata %t + + +// CHECK: Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover +// CHECK-NEXT: -- +// CHECK-NEXT: instrprof-debug-info-correlate-bar.h 3 1 66.67% 1 0 100.00% 5 1 80.00% 2 1 50.00% +// CHECK-NEXT: instrprof-debug-info-correlate-foo.cpp 5 2 60.00% 2 1 50.00% 6 2 66.67% 2 1 50.00% +// CHECK-NEXT: instrprof-debug-info-correlate-main.cpp 4 0 100.00% 1 0 100.00% 5 0 100.00% 2 0 100.00% +// CHECK-NEXT: -- +// CHECK-NEXT: TOTAL 12 3 75.00% 4 1 75.00% 16 3 81.25% 6 2 66.67% 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 @@ -203,7 +203,8 @@ BinaryCoverageReader &operator=(const BinaryCoverageReader &) = delete; static Expected>> - create(MemoryBufferRef ObjectBuffer, StringRef Arch, + create(MemoryBufferRef ObjectBuffer, IndexedInstrProfReader &ProfileReader, + StringRef Arch, SmallVectorImpl> &ObjectFileBuffers, StringRef CompilationDir = "", SmallVectorImpl *BinaryIDs = nullptr); diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -360,7 +360,7 @@ SmallVector BinaryIDs; auto CoverageReadersOrErr = BinaryCoverageReader::create( - CovMappingBufRef, Arch, Buffers, CompilationDir, + CovMappingBufRef, ProfileReader, Arch, Buffers, CompilationDir, FoundBinaryIDs ? &BinaryIDs : nullptr); if (Error E = CoverageReadersOrErr.takeError()) { E = handleMaybeNoDataFoundError(std::move(E)); 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 @@ -25,6 +25,7 @@ #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/ProfileData/InstrProf.h" +#include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Debug.h" @@ -953,7 +954,8 @@ } static Expected> -loadBinaryFormat(std::unique_ptr Bin, StringRef Arch, +loadBinaryFormat(std::unique_ptr Bin, + IndexedInstrProfReader &ProfileReader, StringRef Arch, StringRef CompilationDir = "", object::BuildIDRef *BinaryID = nullptr) { std::unique_ptr OF; @@ -982,11 +984,20 @@ // Look for the sections that we are interested in. auto ObjFormat = OF->getTripleObjectFormat(); + InstrProfSymtab ProfileNames; auto NamesSection = lookupSections(*OF, getInstrProfSectionName(IPSK_name, ObjFormat, /*AddSegmentInfo=*/false)); - if (auto E = NamesSection.takeError()) - return std::move(E); + if (auto E = NamesSection.takeError()) { + consumeError(std::move(E)); + ProfileNames = ProfileReader.getSymtab(); + } else { + std::vector NamesSectionRefs = *NamesSection; + if (NamesSectionRefs.size() != 1) + return make_error(coveragemap_error::malformed); + if (Error E = ProfileNames.create(NamesSectionRefs.back())) + return std::move(E); + } auto CoverageSection = lookupSections(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false)); @@ -1000,13 +1011,6 @@ return CoverageMappingOrErr.takeError(); StringRef CoverageMapping = CoverageMappingOrErr.get(); - InstrProfSymtab ProfileNames; - std::vector NamesSectionRefs = *NamesSection; - if (NamesSectionRefs.size() != 1) - return make_error(coveragemap_error::malformed); - if (Error E = ProfileNames.create(NamesSectionRefs.back())) - return std::move(E); - // Look for the coverage records section (Version4 only). auto CoverageRecordsSections = lookupSections(*OF, getInstrProfSectionName(IPSK_covfun, ObjFormat, @@ -1076,7 +1080,8 @@ Expected>> BinaryCoverageReader::create( - MemoryBufferRef ObjectBuffer, StringRef Arch, + MemoryBufferRef ObjectBuffer, IndexedInstrProfReader &ProfileReader, + StringRef Arch, SmallVectorImpl> &ObjectFileBuffers, StringRef CompilationDir, SmallVectorImpl *BinaryIDs) { std::vector> Readers; @@ -1117,8 +1122,8 @@ } return BinaryCoverageReader::create( - ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers, - CompilationDir, BinaryIDs); + ArchiveOrErr.get()->getMemoryBufferRef(), ProfileReader, Arch, + ObjectFileBuffers, CompilationDir, BinaryIDs); } } @@ -1131,8 +1136,8 @@ return ChildBufOrErr.takeError(); auto ChildReadersOrErr = BinaryCoverageReader::create( - ChildBufOrErr.get(), Arch, ObjectFileBuffers, CompilationDir, - BinaryIDs); + ChildBufOrErr.get(), ProfileReader, Arch, ObjectFileBuffers, + CompilationDir, BinaryIDs); if (!ChildReadersOrErr) return ChildReadersOrErr.takeError(); for (auto &Reader : ChildReadersOrErr.get()) @@ -1152,8 +1157,9 @@ } object::BuildIDRef BinaryID; - auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch, CompilationDir, - BinaryIDs ? &BinaryID : nullptr); + auto ReaderOrErr = + loadBinaryFormat(std::move(Bin), ProfileReader, Arch, CompilationDir, + BinaryIDs ? &BinaryID : nullptr); if (!ReaderOrErr) return ReaderOrErr.takeError(); Readers.push_back(std::move(ReaderOrErr.get()));