X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FProfileData%2FCoverageMapping.cpp;h=f5d477bd139aa5954209be21a8b04dc69e35d66a;hb=12d60e9e7c149a7d333e277dfbe25a720c88c585;hp=06a950c2e40b4f124fc59fa5070555a961d804c8;hpb=aacc919bfd62dd0503f394326f458dfbe39218f8;p=oota-llvm.git diff --git a/lib/ProfileData/CoverageMapping.cpp b/lib/ProfileData/CoverageMapping.cpp index 06a950c2e40..f5d477bd139 100644 --- a/lib/ProfileData/CoverageMapping.cpp +++ b/lib/ProfileData/CoverageMapping.cpp @@ -13,77 +13,100 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/CoverageMapping.h" - #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/ProfileData/CoverageMappingReader.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace coverage; #define DEBUG_TYPE "coverage-mapping" -CounterExpressionBuilder::CounterExpressionBuilder(unsigned NumCounterValues) { - Terms.resize(NumCounterValues); -} - Counter CounterExpressionBuilder::get(const CounterExpression &E) { - for (unsigned I = 0, S = Expressions.size(); I < S; ++I) { - if (Expressions[I] == E) - return Counter::getExpression(I); - } + auto It = ExpressionIndices.find(E); + if (It != ExpressionIndices.end()) + return Counter::getExpression(It->second); + unsigned I = Expressions.size(); Expressions.push_back(E); - return Counter::getExpression(Expressions.size() - 1); + ExpressionIndices[E] = I; + return Counter::getExpression(I); } -void CounterExpressionBuilder::extractTerms(Counter C, int Sign) { +void CounterExpressionBuilder::extractTerms( + Counter C, int Sign, SmallVectorImpl> &Terms) { switch (C.getKind()) { case Counter::Zero: break; case Counter::CounterValueReference: - Terms[C.getCounterID()] += Sign; + Terms.push_back(std::make_pair(C.getCounterID(), Sign)); break; case Counter::Expression: const auto &E = Expressions[C.getExpressionID()]; - extractTerms(E.LHS, Sign); - extractTerms(E.RHS, E.Kind == CounterExpression::Subtract ? -Sign : Sign); + extractTerms(E.LHS, Sign, Terms); + extractTerms(E.RHS, E.Kind == CounterExpression::Subtract ? -Sign : Sign, + Terms); break; } } Counter CounterExpressionBuilder::simplify(Counter ExpressionTree) { // Gather constant terms. - for (auto &I : Terms) - I = 0; - extractTerms(ExpressionTree); + llvm::SmallVector, 32> Terms; + extractTerms(ExpressionTree, +1, Terms); + + // If there are no terms, this is just a zero. The algorithm below assumes at + // least one term. + if (Terms.size() == 0) + return Counter::getZero(); + + // Group the terms by counter ID. + std::sort(Terms.begin(), Terms.end(), + [](const std::pair &LHS, + const std::pair &RHS) { + return LHS.first < RHS.first; + }); + + // Combine terms by counter ID to eliminate counters that sum to zero. + auto Prev = Terms.begin(); + for (auto I = Prev + 1, E = Terms.end(); I != E; ++I) { + if (I->first == Prev->first) { + Prev->second += I->second; + continue; + } + ++Prev; + *Prev = *I; + } + Terms.erase(++Prev, Terms.end()); Counter C; - // Create additions. - // Note: the additions are created first - // to avoid creation of a tree like ((0 - X) + Y) instead of (Y - X). - for (unsigned I = 0, S = Terms.size(); I < S; ++I) { - if (Terms[I] <= 0) + // Create additions. We do this before subtractions to avoid constructs like + // ((0 - X) + Y), as opposed to (Y - X). + for (auto Term : Terms) { + if (Term.second <= 0) continue; - for (int J = 0; J < Terms[I]; ++J) { + for (int I = 0; I < Term.second; ++I) if (C.isZero()) - C = Counter::getCounter(I); + C = Counter::getCounter(Term.first); else C = get(CounterExpression(CounterExpression::Add, C, - Counter::getCounter(I))); - } + Counter::getCounter(Term.first))); } // Create subtractions. - for (unsigned I = 0, S = Terms.size(); I < S; ++I) { - if (Terms[I] >= 0) + for (auto Term : Terms) { + if (Term.second >= 0) continue; - for (int J = 0; J < (-Terms[I]); ++J) + for (int I = 0; I < -Term.second; ++I) C = get(CounterExpression(CounterExpression::Subtract, C, - Counter::getCounter(I))); + Counter::getCounter(Term.first))); } return C; } @@ -132,11 +155,11 @@ ErrorOr CounterMappingContext::evaluate(const Counter &C) const { return 0; case Counter::CounterValueReference: if (C.getCounterID() >= CounterValues.size()) - return std::make_error_code(std::errc::argument_out_of_domain); + return make_error_code(errc::argument_out_of_domain); return CounterValues[C.getCounterID()]; case Counter::Expression: { if (C.getExpressionID() >= Expressions.size()) - return std::make_error_code(std::errc::argument_out_of_domain); + return make_error_code(errc::argument_out_of_domain); const auto &E = Expressions[C.getExpressionID()]; ErrorOr LHS = evaluate(E.LHS); if (!LHS) @@ -150,54 +173,75 @@ ErrorOr CounterMappingContext::evaluate(const Counter &C) const { llvm_unreachable("Unhandled CounterKind"); } +void FunctionRecordIterator::skipOtherFiles() { + while (Current != Records.end() && !Filename.empty() && + Filename != Current->Filenames[0]) + ++Current; + if (Current == Records.end()) + *this = FunctionRecordIterator(); +} + ErrorOr> -CoverageMapping::load(ObjectFileCoverageMappingReader &CoverageReader, +CoverageMapping::load(CoverageMappingReader &CoverageReader, IndexedInstrProfReader &ProfileReader) { auto Coverage = std::unique_ptr(new CoverageMapping()); std::vector Counts; for (const auto &Record : CoverageReader) { + CounterMappingContext Ctx(Record.Expressions); + Counts.clear(); if (std::error_code EC = ProfileReader.getFunctionCounts( Record.FunctionName, Record.FunctionHash, Counts)) { - if (EC != instrprof_error::hash_mismatch && - EC != instrprof_error::unknown_function) + if (EC == instrprof_error::hash_mismatch) { + Coverage->MismatchedFunctionCount++; + continue; + } else if (EC != instrprof_error::unknown_function) return EC; - Coverage->MismatchedFunctionCount++; - continue; + Counts.assign(Record.MappingRegions.size(), 0); } + Ctx.setCounts(Counts); - FunctionRecord Function(Record.FunctionName, Record.Filenames); - CounterMappingContext Ctx(Record.Expressions, Counts); + assert(!Record.MappingRegions.empty() && "Function has no regions"); + + StringRef OrigFuncName = Record.FunctionName; + if (!Record.Filenames.empty()) + OrigFuncName = + getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]); + FunctionRecord Function(OrigFuncName, Record.Filenames); for (const auto &Region : Record.MappingRegions) { ErrorOr ExecutionCount = Ctx.evaluate(Region.Count); if (!ExecutionCount) break; - Function.CountedRegions.push_back(CountedRegion(Region, *ExecutionCount)); + Function.pushRegion(Region, *ExecutionCount); } if (Function.CountedRegions.size() != Record.MappingRegions.size()) { Coverage->MismatchedFunctionCount++; continue; } - Coverage->Functions.push_back(Function); + Coverage->Functions.push_back(std::move(Function)); } return std::move(Coverage); } ErrorOr> -CoverageMapping::load(StringRef ObjectFilename, StringRef ProfileFilename) { +CoverageMapping::load(StringRef ObjectFilename, StringRef ProfileFilename, + StringRef Arch) { auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename); - if (auto EC = CounterMappingBuff.getError()) + if (std::error_code EC = CounterMappingBuff.getError()) return EC; - ObjectFileCoverageMappingReader CoverageReader(CounterMappingBuff.get()); - if (auto EC = CoverageReader.readHeader()) + auto CoverageReaderOrErr = + BinaryCoverageReader::create(CounterMappingBuff.get(), Arch); + if (std::error_code EC = CoverageReaderOrErr.getError()) return EC; - std::unique_ptr ProfileReader; - if (auto EC = IndexedInstrProfReader::create(ProfileFilename, ProfileReader)) + auto CoverageReader = std::move(CoverageReaderOrErr.get()); + auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename); + if (auto EC = ProfileReaderOrErr.getError()) return EC; - return load(CoverageReader, *ProfileReader); + auto ProfileReader = std::move(ProfileReaderOrErr.get()); + return load(*CoverageReader, *ProfileReader); } namespace { @@ -275,20 +319,22 @@ class SegmentBuilder { public: /// Build a list of CoverageSegments from a sorted list of Regions. std::vector buildSegments(ArrayRef Regions) { + const CountedRegion *PrevRegion = nullptr; for (const auto &Region : Regions) { // Pop any regions that end before this one starts. while (!ActiveRegions.empty() && ActiveRegions.back()->endLoc() <= Region.startLoc()) popRegion(); - if (Segments.size() && Segments.back().Line == Region.LineStart && - Segments.back().Col == Region.ColumnStart) { - if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion) + if (PrevRegion && PrevRegion->startLoc() == Region.startLoc() && + PrevRegion->endLoc() == Region.endLoc()) { + if (Region.Kind == coverage::CounterMappingRegion::CodeRegion) Segments.back().addCount(Region.ExecutionCount); } else { // Add this region to the stack. ActiveRegions.push_back(&Region); startSegment(Region); } + PrevRegion = &Region; } // Pop any regions that are left in the stack. while (!ActiveRegions.empty()) @@ -298,53 +344,50 @@ public: }; } -std::vector CoverageMapping::getUniqueSourceFiles() { +std::vector CoverageMapping::getUniqueSourceFiles() const { std::vector Filenames; for (const auto &Function : getCoveredFunctions()) - for (const auto &Filename : Function.Filenames) - Filenames.push_back(Filename); + Filenames.insert(Filenames.end(), Function.Filenames.begin(), + Function.Filenames.end()); std::sort(Filenames.begin(), Filenames.end()); auto Last = std::unique(Filenames.begin(), Filenames.end()); Filenames.erase(Last, Filenames.end()); return Filenames; } -static Optional findMainViewFileID(StringRef SourceFile, - const FunctionRecord &Function) { - llvm::SmallVector IsExpandedFile(Function.Filenames.size(), false); - llvm::SmallVector FilenameEquivalence(Function.Filenames.size(), - false); +static SmallBitVector gatherFileIDs(StringRef SourceFile, + const FunctionRecord &Function) { + SmallBitVector FilenameEquivalence(Function.Filenames.size(), false); for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) if (SourceFile == Function.Filenames[I]) FilenameEquivalence[I] = true; + return FilenameEquivalence; +} + +static Optional findMainViewFileID(StringRef SourceFile, + const FunctionRecord &Function) { + SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true); + SmallBitVector FilenameEquivalence = gatherFileIDs(SourceFile, Function); for (const auto &CR : Function.CountedRegions) if (CR.Kind == CounterMappingRegion::ExpansionRegion && FilenameEquivalence[CR.FileID]) - IsExpandedFile[CR.ExpandedFileID] = true; - for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) - if (FilenameEquivalence[I] && !IsExpandedFile[I]) - return I; - return None; + IsNotExpandedFile[CR.ExpandedFileID] = false; + IsNotExpandedFile &= FilenameEquivalence; + int I = IsNotExpandedFile.find_first(); + if (I == -1) + return None; + return I; } static Optional findMainViewFileID(const FunctionRecord &Function) { - llvm::SmallVector IsExpandedFile(Function.Filenames.size(), false); + SmallBitVector IsNotExpandedFile(Function.Filenames.size(), true); for (const auto &CR : Function.CountedRegions) if (CR.Kind == CounterMappingRegion::ExpansionRegion) - IsExpandedFile[CR.ExpandedFileID] = true; - for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) - if (!IsExpandedFile[I]) - return I; - return None; -} - -static SmallSet gatherFileIDs(StringRef SourceFile, - const FunctionRecord &Function) { - SmallSet IDs; - for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) - if (SourceFile == Function.Filenames[I]) - IDs.insert(I); - return IDs; + IsNotExpandedFile[CR.ExpandedFileID] = false; + int I = IsNotExpandedFile.find_first(); + if (I == -1) + return None; + return I; } /// Sort a nested sequence of regions from a single file. @@ -372,7 +415,7 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) { continue; auto FileIDs = gatherFileIDs(Filename, Function); for (const auto &CR : Function.CountedRegions) - if (FileIDs.count(CR.FileID)) { + if (FileIDs.test(CR.FileID)) { Regions.push_back(CR); if (isExpansion(CR, *MainFileID)) FileCoverage.Expansions.emplace_back(CR, Function); @@ -380,6 +423,7 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) { } sortNestedRegions(Regions.begin(), Regions.end()); + DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n"); FileCoverage.Segments = SegmentBuilder().buildSegments(Regions); return FileCoverage; @@ -399,8 +443,8 @@ CoverageMapping::getInstantiations(StringRef Filename) { for (const auto &InstantiationSet : InstantiationSetCollector) { if (InstantiationSet.second.size() < 2) continue; - for (auto Function : InstantiationSet.second) - Result.push_back(Function); + Result.insert(Result.end(), InstantiationSet.second.begin(), + InstantiationSet.second.end()); } return Result; } @@ -421,6 +465,7 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) { } sortNestedRegions(Regions.begin(), Regions.end()); + DEBUG(dbgs() << "Emitting segments for function: " << Function.Name << "\n"); FunctionCoverage.Segments = SegmentBuilder().buildSegments(Regions); return FunctionCoverage; @@ -439,7 +484,39 @@ CoverageMapping::getCoverageForExpansion(const ExpansionRecord &Expansion) { } sortNestedRegions(Regions.begin(), Regions.end()); + DEBUG(dbgs() << "Emitting segments for expansion of file " << Expansion.FileID + << "\n"); ExpansionCoverage.Segments = SegmentBuilder().buildSegments(Regions); return ExpansionCoverage; } + +namespace { +class CoverageMappingErrorCategoryType : public std::error_category { + const char *name() const LLVM_NOEXCEPT override { return "llvm.coveragemap"; } + std::string message(int IE) const override { + auto E = static_cast(IE); + switch (E) { + case coveragemap_error::success: + return "Success"; + case coveragemap_error::eof: + return "End of File"; + case coveragemap_error::no_data_found: + return "No coverage data found"; + case coveragemap_error::unsupported_version: + return "Unsupported coverage format version"; + case coveragemap_error::truncated: + return "Truncated coverage data"; + case coveragemap_error::malformed: + return "Malformed coverage data"; + } + llvm_unreachable("A value of coveragemap_error has no message."); + } +}; +} + +static ManagedStatic ErrorCategory; + +const std::error_category &llvm::coverage::coveragemap_category() { + return *ErrorCategory; +}