Index: cfe/trunk/include/clang/Driver/CC1Options.td =================================================================== --- cfe/trunk/include/clang/Driver/CC1Options.td +++ cfe/trunk/include/clang/Driver/CC1Options.td @@ -179,6 +179,8 @@ HelpText<"Four-byte version string for gcov files.">; def test_coverage : Flag<["-"], "test-coverage">, HelpText<"Do not generate coverage files or remove coverage changes from IR">; +def dump_coverage_mapping : Flag<["-"], "dump-coverage-mapping">, + HelpText<"Dump the coverage mapping records, for testing">; def fuse_register_sized_bitfield_access: Flag<["-"], "fuse-register-sized-bitfield-access">, HelpText<"Use register sized accesses to bit-fields, when possible.">; def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">, Index: cfe/trunk/include/clang/Frontend/CodeGenOptions.def =================================================================== --- cfe/trunk/include/clang/Frontend/CodeGenOptions.def +++ cfe/trunk/include/clang/Frontend/CodeGenOptions.def @@ -90,6 +90,8 @@ ///< execution counts to use with PGO. CODEGENOPT(CoverageMapping , 1, 0) ///< Generate coverage mapping regions to ///< enable code coverage analysis. +CODEGENOPT(DumpCoverageMapping , 1, 0) ///< Dump the generated coverage mapping + ///< regions. /// If -fpcc-struct-return or -freg-struct-return is specified. ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default) Index: cfe/trunk/lib/CodeGen/CodeGenModule.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp @@ -3198,10 +3198,20 @@ } void CodeGenModule::EmitDeferredUnusedCoverageMappings() { + std::vector DeferredDecls; for (const auto I : DeferredEmptyCoverageMappingDecls) { if (!I.second) continue; - const auto *D = I.first; + DeferredDecls.push_back(I.first); + } + // Sort the declarations by their location to make sure that the tests get a + // predictable order for the coverage mapping for the unused declarations. + if (CodeGenOpts.DumpCoverageMapping) + std::sort(DeferredDecls.begin(), DeferredDecls.end(), + [] (const Decl *LHS, const Decl *RHS) { + return LHS->getLocStart() < RHS->getLocStart(); + }); + for (const auto *D : DeferredDecls) { switch (D->getKind()) { case Decl::CXXConversion: case Decl::CXXMethod: Index: cfe/trunk/lib/CodeGen/CodeGenPGO.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenPGO.cpp +++ cfe/trunk/lib/CodeGen/CodeGenPGO.cpp @@ -169,7 +169,7 @@ // Create coverage mapping data variable. if (!CoverageMapping.empty()) CGM.getCoverageMapping()->addFunctionMappingRecord(Name, - getFuncName().size(), + getFuncName(), CoverageMapping); // Hide all these symbols so that we correctly get a copy for each Index: cfe/trunk/lib/CodeGen/CoverageMappingGen.h =================================================================== --- cfe/trunk/lib/CodeGen/CoverageMappingGen.h +++ cfe/trunk/lib/CodeGen/CoverageMappingGen.h @@ -68,7 +68,7 @@ /// \brief Add a function's coverage mapping record to the collection of the /// function mapping records. void addFunctionMappingRecord(llvm::GlobalVariable *FunctionName, - unsigned FunctionNameSize, + StringRef FunctionNameValue, const std::string &CoverageMapping); /// \brief Emit the coverage mapping data for a translation unit. Index: cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp +++ cfe/trunk/lib/CodeGen/CoverageMappingGen.cpp @@ -18,6 +18,7 @@ #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/ProfileData/CoverageMapping.h" #include "llvm/ProfileData/CoverageMappingWriter.h" +#include "llvm/ProfileData/CoverageMappingReader.h" #include "llvm/Support/FileSystem.h" using namespace clang; @@ -1052,8 +1053,36 @@ return isMachO(CGM) ? "__DATA,__llvm_covmap" : "__llvm_covmap"; } +static void dump(llvm::raw_ostream &OS, const CoverageMappingRecord &Function) { + OS << Function.FunctionName << ":\n"; + CounterMappingContext Ctx(Function.Expressions); + for (const auto &R : Function.MappingRegions) { + OS.indent(2); + switch (R.Kind) { + case CounterMappingRegion::CodeRegion: + break; + case CounterMappingRegion::ExpansionRegion: + OS << "Expansion,"; + break; + case CounterMappingRegion::SkippedRegion: + OS << "Skipped,"; + break; + } + + OS << "File " << R.FileID << ", " << R.LineStart << ":" + << R.ColumnStart << " -> " << R.LineEnd << ":" << R.ColumnEnd + << " = "; + Ctx.dump(R.Count); + OS << " (HasCodeBefore = " << R.HasCodeBefore; + if (R.Kind == CounterMappingRegion::ExpansionRegion) + OS << ", Expanded file = " << R.ExpandedFileID; + + OS << ")\n"; + } +} + void CoverageMappingModuleGen::addFunctionMappingRecord( - llvm::GlobalVariable *FunctionName, unsigned FunctionNameSize, + llvm::GlobalVariable *FunctionName, StringRef FunctionNameValue, const std::string &CoverageMapping) { llvm::LLVMContext &Ctx = CGM.getLLVMContext(); auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); @@ -1066,11 +1095,33 @@ llvm::Constant *FunctionRecordVals[] = { llvm::ConstantExpr::getBitCast(FunctionName, Int8PtrTy), - llvm::ConstantInt::get(Int32Ty, FunctionNameSize), + llvm::ConstantInt::get(Int32Ty, FunctionNameValue.size()), llvm::ConstantInt::get(Int32Ty, CoverageMapping.size())}; FunctionRecords.push_back(llvm::ConstantStruct::get( FunctionRecordTy, makeArrayRef(FunctionRecordVals))); CoverageMappings += CoverageMapping; + + if (CGM.getCodeGenOpts().DumpCoverageMapping) { + // Dump the coverage mapping data for this function by decoding the + // encoded data. This allows us to dump the mapping regions which were + // also processed by the CoverageMappingWriter which performs + // additional minimization operations such as reducing the number of + // expressions. + std::vector Filenames; + std::vector Expressions; + std::vector Regions; + llvm::SmallVector FilenameRefs; + FilenameRefs.resize(FileEntries.size()); + for (const auto &Entry : FileEntries) + FilenameRefs[Entry.second] = Entry.first->getName(); + RawCoverageMappingReader Reader(FunctionNameValue, CoverageMapping, + FilenameRefs, + Filenames, Expressions, Regions); + CoverageMappingRecord FunctionRecord; + if (Reader.read(FunctionRecord)) + return; + dump(llvm::outs(), FunctionRecord); + } } void CoverageMappingModuleGen::emit() { Index: cfe/trunk/lib/Frontend/CompilerInvocation.cpp =================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp @@ -400,6 +400,7 @@ Opts.ProfileInstrGenerate = Args.hasArg(OPT_fprofile_instr_generate); Opts.InstrProfileInput = Args.getLastArgValue(OPT_fprofile_instr_use_EQ); Opts.CoverageMapping = Args.hasArg(OPT_fcoverage_mapping); + Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping); Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device);