[llvm] r216300 - llvm-cov: add code coverage tool that's based on coverage mapping format and clang's pgo.

Alex Lorenz arphaman at gmail.com
Fri Aug 22 15:56:03 PDT 2014


Author: arphaman
Date: Fri Aug 22 17:56:03 2014
New Revision: 216300

URL: http://llvm.org/viewvc/llvm-project?rev=216300&view=rev
Log:
llvm-cov: add code coverage tool that's based on coverage mapping format and clang's pgo.

This commit expands llvm-cov's functionality by adding support for a new code coverage
tool that uses LLVM's coverage mapping format and clang's instrumentation based profiling.
The gcov compatible tool can be invoked by supplying the 'gcov' command as the first argument,
or by modifying the tool's name to end with 'gcov'.

Differential Revision: http://reviews.llvm.org/D4445

Added:
    llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.covmapping   (with props)
    llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata   (with props)
    llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping   (with props)
    llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata   (with props)
    llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping   (with props)
    llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata   (with props)
    llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp
    llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp
    llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp
    llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
    llvm/trunk/tools/llvm-cov/CoverageFilters.cpp
    llvm/trunk/tools/llvm-cov/CoverageFilters.h
    llvm/trunk/tools/llvm-cov/CoverageReport.cpp
    llvm/trunk/tools/llvm-cov/CoverageReport.h
    llvm/trunk/tools/llvm-cov/CoverageSummary.cpp
    llvm/trunk/tools/llvm-cov/CoverageSummary.h
    llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp
    llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h
    llvm/trunk/tools/llvm-cov/CoverageViewOptions.h
    llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h
    llvm/trunk/tools/llvm-cov/RenderingSupport.h
    llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp
    llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h
    llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp
    llvm/trunk/tools/llvm-cov/SourceCoverageView.h
    llvm/trunk/tools/llvm-cov/TestingSupport.cpp
Modified:
    llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp
    llvm/trunk/test/tools/llvm-cov/Inputs/README
    llvm/trunk/tools/llvm-cov/CMakeLists.txt
    llvm/trunk/tools/llvm-cov/LLVMBuild.txt
    llvm/trunk/tools/llvm-cov/Makefile
    llvm/trunk/tools/llvm-cov/llvm-cov.cpp

Modified: llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp?rev=216300&r1=216299&r2=216300&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp (original)
+++ llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp Fri Aug 22 17:56:03 2014
@@ -289,18 +289,6 @@ ObjectFileCoverageMappingReader::ObjectF
     Object = std::move(File.get());
 }
 
-ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader(
-    std::unique_ptr<MemoryBuffer> &ObjectBuffer, sys::fs::file_magic Type)
-    : CurrentRecord(0) {
-  auto File = object::ObjectFile::createObjectFile(
-      ObjectBuffer->getMemBufferRef(), Type);
-  if (!File)
-    error(File.getError());
-  else
-    Object = OwningBinary<ObjectFile>(std::move(File.get()),
-                                      std::move(ObjectBuffer));
-}
-
 namespace {
 /// \brief The coverage mapping data for a single function.
 /// It points to the function's name.
@@ -347,19 +335,11 @@ struct SectionData {
 
 template <typename T>
 std::error_code readCoverageMappingData(
-    SectionRef &ProfileNames, SectionRef &CoverageMapping,
+    SectionData &ProfileNames, StringRef Data,
     std::vector<ObjectFileCoverageMappingReader::ProfileMappingRecord> &Records,
     std::vector<StringRef> &Filenames) {
   llvm::DenseSet<T> UniqueFunctionMappingData;
 
-  // Get the contents of the given sections.
-  StringRef Data;
-  if (auto Err = CoverageMapping.getContents(Data))
-    return Err;
-  SectionData ProfileNamesData;
-  if (auto Err = ProfileNamesData.load(ProfileNames))
-    return Err;
-
   // Read the records in the coverage data section.
   while (!Data.empty()) {
     if (Data.size() < sizeof(CoverageMappingTURecord<T>))
@@ -418,9 +398,9 @@ std::error_code readCoverageMappingData(
         continue;
       UniqueFunctionMappingData.insert(MappingRecord.FunctionNamePtr);
       StringRef FunctionName;
-      if (auto Err = ProfileNamesData.get(MappingRecord.FunctionNamePtr,
-                                          MappingRecord.FunctionNameSize,
-                                          FunctionName))
+      if (auto Err =
+              ProfileNames.get(MappingRecord.FunctionNamePtr,
+                               MappingRecord.FunctionNameSize, FunctionName))
         return Err;
       Records.push_back(ObjectFileCoverageMappingReader::ProfileMappingRecord(
           Version, FunctionName, MappingRecord.FunctionHash, Mapping,
@@ -431,6 +411,63 @@ std::error_code readCoverageMappingData(
   return instrprof_error::success;
 }
 
+static const char *TestingFormatMagic = "llvmcovmtestdata";
+
+static std::error_code decodeTestingFormat(StringRef Data,
+                                           SectionData &ProfileNames,
+                                           StringRef &CoverageMapping) {
+  Data = Data.substr(StringRef(TestingFormatMagic).size());
+  if (Data.size() < 1)
+    return instrprof_error::truncated;
+  unsigned N = 0;
+  auto ProfileNamesSize =
+      decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
+  if (N > Data.size())
+    return instrprof_error::malformed;
+  Data = Data.substr(N);
+  if (Data.size() < 1)
+    return instrprof_error::truncated;
+  N = 0;
+  ProfileNames.Address =
+      decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
+  if (N > Data.size())
+    return instrprof_error::malformed;
+  Data = Data.substr(N);
+  if (Data.size() < ProfileNamesSize)
+    return instrprof_error::malformed;
+  ProfileNames.Data = Data.substr(0, ProfileNamesSize);
+  CoverageMapping = Data.substr(ProfileNamesSize);
+  return instrprof_error::success;
+}
+
+ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader(
+    std::unique_ptr<MemoryBuffer> &ObjectBuffer, sys::fs::file_magic Type)
+    : CurrentRecord(0) {
+  if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic)) {
+    // This is a special format used for testing.
+    SectionData ProfileNames;
+    StringRef CoverageMapping;
+    if (auto Err = decodeTestingFormat(ObjectBuffer->getBuffer(), ProfileNames,
+                                       CoverageMapping)) {
+      error(Err);
+      return;
+    }
+    error(readCoverageMappingData<uint64_t>(ProfileNames, CoverageMapping,
+                                            MappingRecords, Filenames));
+    Object = OwningBinary<ObjectFile>(std::unique_ptr<ObjectFile>(),
+                                      std::move(ObjectBuffer));
+    return;
+  }
+
+  auto File = object::ObjectFile::createObjectFile(
+      ObjectBuffer->getMemBufferRef(), Type);
+  if (!File)
+    error(File.getError());
+  else
+    Object = OwningBinary<ObjectFile>(std::move(File.get()),
+                                      std::move(ObjectBuffer));
+}
+
 std::error_code ObjectFileCoverageMappingReader::readHeader() {
   ObjectFile *OF = Object.getBinary().get();
   if (!OF)
@@ -457,13 +494,21 @@ std::error_code ObjectFileCoverageMappin
   if (FoundSectionCount != 2)
     return error(instrprof_error::bad_header);
 
+  // Get the contents of the given sections.
+  StringRef Data;
+  if (auto Err = CoverageMapping.getContents(Data))
+    return Err;
+  SectionData ProfileNamesData;
+  if (auto Err = ProfileNamesData.load(ProfileNames))
+    return Err;
+
   // Load the data from the found sections.
   std::error_code Err;
   if (BytesInAddress == 4)
-    Err = readCoverageMappingData<uint32_t>(ProfileNames, CoverageMapping,
+    Err = readCoverageMappingData<uint32_t>(ProfileNamesData, Data,
                                             MappingRecords, Filenames);
   else
-    Err = readCoverageMappingData<uint64_t>(ProfileNames, CoverageMapping,
+    Err = readCoverageMappingData<uint64_t>(ProfileNamesData, Data,
                                             MappingRecords, Filenames);
   if (Err)
     return error(Err);

Modified: llvm/trunk/test/tools/llvm-cov/Inputs/README
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/README?rev=216300&r1=216299&r2=216300&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/Inputs/README (original)
+++ llvm/trunk/test/tools/llvm-cov/Inputs/README Fri Aug 22 17:56:03 2014
@@ -1,7 +1,21 @@
 These inputs were pre-generated to allow for easier testing of llvm-cov.
 
-test.gcno and test.gcda were create by running clang:
-  clang++ -g -ftest-coverage -fprofile-arcs test.cpp
+The files used to test the gcov compatible code coverage tool were generated
+using the following method:
 
-test.cpp.gcov was created by running gcov 4.2.1:
-  gcov test.cpp
+  test.gcno and test.gcda were create by running clang:
+    clang++ -g -ftest-coverage -fprofile-arcs test.cpp
+
+  test.cpp.gcov was created by running gcov 4.2.1:
+    gcov test.cpp
+
+The 'covmapping' files that are used to test llvm-cov contain raw sections
+with the coverage mapping data generated by the compiler and linker. They are
+created by running clang and llvm-cov:
+  clang++ -fprofile-instr-generate -fcoverage-mapping -o test test.cpp
+  llvm-cov convert-for-testing -o test.covmapping test
+
+The 'profdata' files were generated by running an instrumented version of the
+program and merging the raw profile data using llvm-profdata.
+  ./test
+  llvm-profdata merge -o test.profdata default.profraw

Added: llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.covmapping
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.covmapping?rev=216300&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.covmapping
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata?rev=216300&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping?rev=216300&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata?rev=216300&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping?rev=216300&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata?rev=216300&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp (added)
+++ llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,45 @@
+// RUN: llvm-cov show %S/Inputs/highlightedRanges.covmapping -instr-profile %S/Inputs/highlightedRanges.profdata -dump -filename-equivalence %s | FileCheck %s
+
+void func() {
+  return;
+  int i = 0;                     // CHECK: Highlighted line [[@LINE]], 3 -> 12
+}
+
+void func2(int x) {
+  if(x > 5) {
+    while(x >= 9) {
+      return;
+      --x;                       // CHECK: Highlighted line [[@LINE]], 7 -> 10
+    }
+    int i = 0;                   // CHECK: Highlighted line [[@LINE]], 5 -> 14
+  }
+}
+
+void test() {
+  int x = 0;
+
+  if (x) {                       // CHECK: Highlighted line [[@LINE]], 10 -> ?
+    x = 0;                       // CHECK: Highlighted line [[@LINE]], 1 -> ?
+  } else {                       // CHECK: Highlighted line [[@LINE]], 1 -> 4
+    x = 1;
+  }
+
+                                  // CHECK: Highlighted line [[@LINE+1]], 26 -> 29
+  for (int i = 0; i < 0; ++i) {   // CHECK: Highlighted line [[@LINE]], 31 -> ?
+    x = 1;                        // CHECK: Highlighted line [[@LINE]], 1 -> ?
+  }                               // CHECK: Highlighted line [[@LINE]], 1 -> 4
+
+  x = x < 10 ? x +
+               1
+             : x - 1;             // CHECK: Highlighted line [[@LINE]], 16 -> 21
+  x = x > 10 ? x +                // CHECK: Highlighted line [[@LINE]], 16 -> ?
+               1                  // CHECK: Highlighted line [[@LINE]], 1 -> 17
+             : x - 1;
+}
+
+int main() {
+  test();
+  func();
+  func2(9);
+  return 0;
+}

Added: llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp (added)
+++ llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,22 @@
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %S/Inputs/lineExecutionCounts.profdata -no-colors -filename-equivalence %s | FileCheck %s
+
+int main() {                             // CHECK:   1| [[@LINE]]|int main(
+  int x = 0;                             // CHECK:   1| [[@LINE]]|  int x
+                                         // CHECK:   1| [[@LINE]]|
+  if (x) {                               // CHECK:   0| [[@LINE]]|  if (x)
+    x = 0;                               // CHECK:   0| [[@LINE]]|    x = 0
+  } else {                               // CHECK:   1| [[@LINE]]|  } else
+    x = 1;                               // CHECK:   1| [[@LINE]]|    x = 1
+  }                                      // CHECK:   1| [[@LINE]]|  }
+                                         // CHECK:   1| [[@LINE]]|
+  for (int i = 0; i < 100; ++i) {        // CHECK: 100| [[@LINE]]|  for (
+    x = 1;                               // CHECK: 100| [[@LINE]]|    x = 1
+  }                                      // CHECK: 100| [[@LINE]]|  }
+                                         // CHECK:   1| [[@LINE]]|
+  x = x < 10 ? x + 1 : x - 1;            // CHECK:   0| [[@LINE]]|  x =
+  x = x > 10 ?                           // CHECK:   1| [[@LINE]]|  x =
+        x - 1:                           // CHECK:   0| [[@LINE]]|        x
+        x + 1;                           // CHECK:   1| [[@LINE]]|        x
+                                         // CHECK:   1| [[@LINE]]|
+  return 0;                              // CHECK:   1| [[@LINE]]|  return
+}                                        // CHECK:   1| [[@LINE]]|}

Added: llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp (added)
+++ llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,23 @@
+// RUN: llvm-cov show %S/Inputs/regionMarkers.covmapping -instr-profile %S/Inputs/regionMarkers.profdata -show-regions -dump -filename-equivalence %s | FileCheck %s
+
+int main() {                      // CHECK: Marker at [[@LINE]]:12 = 1
+  int x = 0;
+
+  if (x) {                        // CHECK: Marker at [[@LINE]]:10 = 0
+    x = 0;
+  } else {                        // CHECK: Marker at [[@LINE]]:10 = 1
+    x = 1;
+  }
+                                  // CHECK: Marker at [[@LINE+2]]:19 = 101
+                                  // CHECK: Marker at [[@LINE+1]]:28 = 100
+  for (int i = 0; i < 100; ++i) { // CHECK: Marker at [[@LINE]]:33 = 100
+    x = 1;
+  }
+                                  // CHECK: Marker at [[@LINE+1]]:16 = 1
+  x = x < 10 ? x + 1 : x - 1;     // CHECK: Marker at [[@LINE]]:24 = 0
+  x = x > 10 ?
+        x - 1:                    // CHECK: Marker at [[@LINE]]:9 = 0
+        x + 1;                    // CHECK: Marker at [[@LINE]]:9 = 1
+
+  return 0;
+}

Modified: llvm/trunk/tools/llvm-cov/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CMakeLists.txt?rev=216300&r1=216299&r2=216300&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-cov/CMakeLists.txt Fri Aug 22 17:56:03 2014
@@ -1,6 +1,14 @@
-set(LLVM_LINK_COMPONENTS core support )
+set(LLVM_LINK_COMPONENTS core support object profiledata)
 
 add_llvm_tool(llvm-cov
   llvm-cov.cpp
   gcov.cpp
+  CodeCoverage.cpp
+  CoverageFilters.cpp
+  CoverageReport.cpp
+  CoverageSummary.cpp
+  CoverageSummaryInfo.cpp
+  SourceCoverageDataManager.cpp
+  SourceCoverageView.cpp
+  TestingSupport.cpp
   )

Added: llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CodeCoverage.cpp (added)
+++ llvm/trunk/tools/llvm-cov/CodeCoverage.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,709 @@
+//===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The 'CodeCoverageTool' class implements a command line tool to analyze and
+// report coverage information using the profiling instrumentation and code
+// coverage mapping.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FunctionCoverageMapping.h"
+#include "RenderingSupport.h"
+#include "CoverageViewOptions.h"
+#include "CoverageFilters.h"
+#include "SourceCoverageDataManager.h"
+#include "SourceCoverageView.h"
+#include "CoverageSummary.h"
+#include "CoverageReport.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/ProfileData/CoverageMappingReader.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryObject.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include <system_error>
+#include <functional>
+
+using namespace llvm;
+using namespace coverage;
+
+namespace {
+/// \brief Distribute the functions into instantiation sets.
+/// An instantiation set is a collection of functions
+/// that have the same source code, e.g.
+/// template functions specializations.
+class FunctionInstantiationSetCollector {
+  ArrayRef<FunctionCoverageMapping> FunctionMappings;
+  typedef uint64_t KeyType;
+  typedef std::vector<const FunctionCoverageMapping *> SetType;
+  std::unordered_map<uint64_t, SetType> InstantiatedFunctions;
+
+  static KeyType getKey(const MappingRegion &R) {
+    return uint64_t(R.LineStart) | uint64_t(R.ColumnStart) << 32;
+  }
+
+public:
+  void insert(const FunctionCoverageMapping &Function, unsigned FileID) {
+    KeyType Key = 0;
+    for (const auto &R : Function.MappingRegions) {
+      if (R.FileID == FileID) {
+        Key = getKey(R);
+        break;
+      }
+    }
+    auto I = InstantiatedFunctions.find(Key);
+    if (I == InstantiatedFunctions.end()) {
+      SetType Set;
+      Set.push_back(&Function);
+      InstantiatedFunctions.insert(std::make_pair(Key, Set));
+    } else
+      I->second.push_back(&Function);
+  }
+
+  std::unordered_map<KeyType, SetType>::iterator begin() {
+    return InstantiatedFunctions.begin();
+  }
+
+  std::unordered_map<KeyType, SetType>::iterator end() {
+    return InstantiatedFunctions.end();
+  }
+};
+
+/// \brief The implementation of the coverage tool.
+class CodeCoverageTool {
+public:
+  enum Command {
+    /// \brief The show command.
+    Show,
+    /// \brief The report command.
+    Report
+  };
+
+  /// \brief Print the error message to the error output stream.
+  void error(const Twine &Message, StringRef Whence = "");
+
+  /// \brief Return a memory buffer for the given source file.
+  ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
+
+  /// \brief Return true if two filepaths refer to the same file.
+  bool equivalentFiles(StringRef A, StringRef B);
+
+  /// \brief Collect a set of function's file ids which correspond to the
+  /// given source file. Return false if the set is empty.
+  bool gatherInterestingFileIDs(StringRef SourceFile,
+                                const FunctionCoverageMapping &Function,
+                                SmallSet<unsigned, 8> &InterestingFileIDs);
+
+  /// \brief Find the file id which is not an expanded file id.
+  bool findMainViewFileID(StringRef SourceFile,
+                          const FunctionCoverageMapping &Function,
+                          unsigned &MainViewFileID);
+
+  bool findMainViewFileID(const FunctionCoverageMapping &Function,
+                          unsigned &MainViewFileID);
+
+  /// \brief Create a source view which shows coverage for an expansion
+  /// of a file.
+  void createExpansionSubView(const MappingRegion &ExpandedRegion,
+                              const FunctionCoverageMapping &Function,
+                              SourceCoverageView &Parent);
+
+  void createExpansionSubViews(SourceCoverageView &View, unsigned ViewFileID,
+                               const FunctionCoverageMapping &Function);
+
+  /// \brief Create a source view which shows coverage for an instantiation
+  /// of a funciton.
+  void createInstantiationSubView(StringRef SourceFile,
+                                  const FunctionCoverageMapping &Function,
+                                  SourceCoverageView &View);
+
+  /// \brief Create the main source view of a particular source file.
+  /// Return true if this particular source file is not covered.
+  bool
+  createSourceFileView(StringRef SourceFile, SourceCoverageView &View,
+                       ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
+                       bool UseOnlyRegionsInMainFile = false);
+
+  /// \brief Load the coverage mapping data. Return true if an error occured.
+  bool load();
+
+  int run(Command Cmd, int argc, const char **argv);
+
+  typedef std::function<int(int, const char **)> CommandLineParserType;
+
+  int show(int argc, const char **argv,
+           CommandLineParserType commandLineParser);
+
+  int report(int argc, const char **argv,
+             CommandLineParserType commandLineParser);
+
+  StringRef ObjectFilename;
+  CoverageViewOptions ViewOpts;
+  std::unique_ptr<IndexedInstrProfReader> PGOReader;
+  CoverageFiltersMatchAll Filters;
+  std::vector<std::string> SourceFiles;
+  std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
+      LoadedSourceFiles;
+  std::vector<FunctionCoverageMapping> FunctionMappingRecords;
+  bool CompareFilenamesOnly;
+};
+}
+
+void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
+  errs() << "error: ";
+  if (!Whence.empty())
+    errs() << Whence << ": ";
+  errs() << Message << "\n";
+}
+
+ErrorOr<const MemoryBuffer &>
+CodeCoverageTool::getSourceFile(StringRef SourceFile) {
+  SmallString<256> Path(SourceFile);
+  sys::fs::make_absolute(Path);
+  for (const auto &Files : LoadedSourceFiles) {
+    if (sys::fs::equivalent(Path.str(), Files.first)) {
+      return *Files.second;
+    }
+  }
+  auto Buffer = MemoryBuffer::getFile(SourceFile);
+  if (auto EC = Buffer.getError()) {
+    error(EC.message(), SourceFile);
+    return EC;
+  }
+  LoadedSourceFiles.push_back(std::make_pair(
+      std::string(Path.begin(), Path.end()), std::move(Buffer.get())));
+  return *LoadedSourceFiles.back().second;
+}
+
+/// \brief Return a line start - line end range which contains
+/// all the mapping regions of a given function with a particular file id.
+std::pair<unsigned, unsigned>
+findExpandedFileInterestingLineRange(unsigned FileID,
+                                     const FunctionCoverageMapping &Function) {
+  unsigned LineStart = std::numeric_limits<unsigned>::max();
+  unsigned LineEnd = 0;
+  for (const auto &Region : Function.MappingRegions) {
+    if (Region.FileID != FileID)
+      continue;
+    LineStart = std::min(Region.LineStart, LineStart);
+    LineEnd = std::max(Region.LineEnd, LineEnd);
+  }
+  return std::make_pair(LineStart, LineEnd);
+}
+
+bool CodeCoverageTool::equivalentFiles(StringRef A, StringRef B) {
+  if (CompareFilenamesOnly)
+    return sys::path::filename(A).equals_lower(sys::path::filename(B));
+  return sys::fs::equivalent(A, B);
+}
+
+bool CodeCoverageTool::gatherInterestingFileIDs(
+    StringRef SourceFile, const FunctionCoverageMapping &Function,
+    SmallSet<unsigned, 8> &InterestingFileIDs) {
+  bool Interesting = false;
+  for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
+    if (equivalentFiles(SourceFile, Function.Filenames[I])) {
+      InterestingFileIDs.insert(I);
+      Interesting = true;
+    }
+  }
+  return Interesting;
+}
+
+bool
+CodeCoverageTool::findMainViewFileID(StringRef SourceFile,
+                                     const FunctionCoverageMapping &Function,
+                                     unsigned &MainViewFileID) {
+  llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
+  llvm::SmallVector<bool, 8> FilenameEquivalence(Function.Filenames.size(),
+                                                 false);
+  for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
+    if (equivalentFiles(SourceFile, Function.Filenames[I]))
+      FilenameEquivalence[I] = true;
+  }
+  for (const auto &Region : Function.MappingRegions) {
+    if (Region.Kind == MappingRegion::ExpansionRegion &&
+        FilenameEquivalence[Region.FileID])
+      IsExpandedFile[Region.ExpandedFileID] = true;
+  }
+  for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
+    if (!FilenameEquivalence[I] || IsExpandedFile[I])
+      continue;
+    MainViewFileID = I;
+    return false;
+  }
+  return true;
+}
+
+bool
+CodeCoverageTool::findMainViewFileID(const FunctionCoverageMapping &Function,
+                                     unsigned &MainViewFileID) {
+  llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
+  for (const auto &Region : Function.MappingRegions) {
+    if (Region.Kind == MappingRegion::ExpansionRegion)
+      IsExpandedFile[Region.ExpandedFileID] = true;
+  }
+  for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
+    if (IsExpandedFile[I])
+      continue;
+    MainViewFileID = I;
+    return false;
+  }
+  return true;
+}
+
+void CodeCoverageTool::createExpansionSubView(
+    const MappingRegion &ExpandedRegion,
+    const FunctionCoverageMapping &Function, SourceCoverageView &Parent) {
+  auto ExpandedLines = findExpandedFileInterestingLineRange(
+      ExpandedRegion.ExpandedFileID, Function);
+  if (ViewOpts.Debug)
+    llvm::outs() << "Expansion of " << ExpandedRegion.ExpandedFileID << ":"
+                 << ExpandedLines.first << " -> " << ExpandedLines.second
+                 << " @ " << ExpandedRegion.FileID << ", "
+                 << ExpandedRegion.LineStart << ":"
+                 << ExpandedRegion.ColumnStart << "\n";
+  auto SourceBuffer =
+      getSourceFile(Function.Filenames[ExpandedRegion.ExpandedFileID]);
+  if (!SourceBuffer)
+    return;
+  auto SubView = llvm::make_unique<SourceCoverageView>(
+      SourceBuffer.get(), Parent.getOptions(), ExpandedLines.first,
+      ExpandedLines.second, ExpandedRegion);
+  SourceCoverageDataManager RegionManager;
+  for (const auto &Region : Function.MappingRegions) {
+    if (Region.FileID == ExpandedRegion.ExpandedFileID)
+      RegionManager.insert(Region);
+  }
+  SubView->load(RegionManager);
+  createExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function);
+  Parent.addChild(std::move(SubView));
+}
+
+void CodeCoverageTool::createExpansionSubViews(
+    SourceCoverageView &View, unsigned ViewFileID,
+    const FunctionCoverageMapping &Function) {
+  if (!ViewOpts.ShowExpandedRegions)
+    return;
+  for (const auto &Region : Function.MappingRegions) {
+    if (Region.Kind != CounterMappingRegion::ExpansionRegion)
+      continue;
+    if (Region.FileID != ViewFileID)
+      continue;
+    createExpansionSubView(Region, Function, View);
+  }
+}
+
+void CodeCoverageTool::createInstantiationSubView(
+    StringRef SourceFile, const FunctionCoverageMapping &Function,
+    SourceCoverageView &View) {
+  SourceCoverageDataManager RegionManager;
+  SmallSet<unsigned, 8> InterestingFileIDs;
+  if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs))
+    return;
+  // Get the interesting regions
+  for (const auto &Region : Function.MappingRegions) {
+    if (InterestingFileIDs.count(Region.FileID))
+      RegionManager.insert(Region);
+  }
+  View.load(RegionManager);
+  unsigned MainFileID;
+  if (findMainViewFileID(SourceFile, Function, MainFileID))
+    return;
+  createExpansionSubViews(View, MainFileID, Function);
+}
+
+bool CodeCoverageTool::createSourceFileView(
+    StringRef SourceFile, SourceCoverageView &View,
+    ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
+    bool UseOnlyRegionsInMainFile) {
+  SourceCoverageDataManager RegionManager;
+  FunctionInstantiationSetCollector InstantiationSetCollector;
+
+  for (const auto &Function : FunctionMappingRecords) {
+    unsigned MainFileID;
+    if (findMainViewFileID(SourceFile, Function, MainFileID))
+      continue;
+    SmallSet<unsigned, 8> InterestingFileIDs;
+    if (UseOnlyRegionsInMainFile) {
+      InterestingFileIDs.insert(MainFileID);
+    } else if (!gatherInterestingFileIDs(SourceFile, Function,
+                                         InterestingFileIDs))
+      continue;
+    // Get the interesting regions
+    for (const auto &Region : Function.MappingRegions) {
+      if (InterestingFileIDs.count(Region.FileID))
+        RegionManager.insert(Region);
+    }
+    InstantiationSetCollector.insert(Function, MainFileID);
+    createExpansionSubViews(View, MainFileID, Function);
+  }
+  if (RegionManager.getSourceRegions().empty())
+    return true;
+  View.load(RegionManager);
+  // Show instantiations
+  if (!ViewOpts.ShowFunctionInstantiations)
+    return false;
+  for (const auto &InstantiationSet : InstantiationSetCollector) {
+    if (InstantiationSet.second.size() < 2)
+      continue;
+    auto InterestingRange = findExpandedFileInterestingLineRange(
+        InstantiationSet.second.front()->MappingRegions.front().FileID,
+        *InstantiationSet.second.front());
+    for (auto Function : InstantiationSet.second) {
+      auto SubView = llvm::make_unique<SourceCoverageView>(
+          View, InterestingRange.first, InterestingRange.second,
+          Function->PrettyName);
+      createInstantiationSubView(SourceFile, *Function, *SubView);
+      View.addChild(std::move(SubView));
+    }
+  }
+  return false;
+}
+
+bool CodeCoverageTool::load() {
+  auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
+  if (auto EC = CounterMappingBuff.getError()) {
+    error(EC.message(), ObjectFilename);
+    return true;
+  }
+  ObjectFileCoverageMappingReader MappingReader(CounterMappingBuff.get());
+  if (auto EC = MappingReader.readHeader()) {
+    error(EC.message(), ObjectFilename);
+    return true;
+  }
+
+  std::vector<uint64_t> Counts;
+  for (const auto &I : MappingReader) {
+    FunctionCoverageMapping Function(I.FunctionName, I.Filenames);
+
+    // Create the mapping regions with evaluated execution counts
+    Counts.clear();
+    PGOReader->getFunctionCounts(Function.Name, I.FunctionHash, Counts);
+
+    // Get the biggest referenced counters
+    bool RegionError = false;
+    CounterMappingContext Ctx(I.Expressions, Counts);
+    for (const auto &R : I.MappingRegions) {
+      // Compute the values of mapped regions
+      if (ViewOpts.Debug) {
+        outs() << "File " << R.FileID << "| " << R.LineStart << ":"
+               << R.ColumnStart << " -> " << R.LineEnd << ":" << R.ColumnEnd
+               << " = ";
+        Ctx.dump(R.Count);
+        if (R.Kind == CounterMappingRegion::ExpansionRegion) {
+          outs() << " (Expanded file id = " << R.ExpandedFileID << ") ";
+        }
+        outs() << "\n";
+      }
+      std::error_code Error;
+      Function.MappingRegions.push_back(
+          MappingRegion(R, Ctx.evaluate(R.Count, Error)));
+      if (Error && !RegionError) {
+        colored_ostream(errs(), raw_ostream::RED)
+            << "error: Regions and counters don't match in a function '"
+            << Function.PrettyName << "' (re-run the instrumented binary).";
+        errs() << "\n";
+        RegionError = true;
+      }
+    }
+
+    if (RegionError || !Filters.matches(Function))
+      continue;
+
+    FunctionMappingRecords.push_back(Function);
+  }
+  return false;
+}
+
+int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
+  // Print a stack trace if we signal out.
+  sys::PrintStackTraceOnErrorSignal();
+  PrettyStackTraceProgram X(argc, argv);
+  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+  cl::list<std::string> InputSourceFiles(
+      cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
+
+  cl::opt<std::string> PGOFilename(
+      "instr-profile", cl::Required,
+      cl::desc(
+          "File with the profile data obtained after an instrumented run"));
+
+  cl::opt<bool> DebugDump("dump", cl::Optional,
+                          cl::desc("Show internal debug dump"));
+
+  cl::opt<bool> FilenameEquivalence(
+      "filename-equivalence", cl::Optional,
+      cl::desc("Compare the filenames instead of full filepaths"));
+
+  cl::OptionCategory FilteringCategory("Function filtering options");
+
+  cl::list<std::string> NameFilters(
+      "name", cl::Optional,
+      cl::desc("Show code coverage only for functions with the given name"),
+      cl::ZeroOrMore, cl::cat(FilteringCategory));
+
+  cl::list<std::string> NameRegexFilters(
+      "name-regex", cl::Optional,
+      cl::desc("Show code coverage only for functions that match the given "
+               "regular expression"),
+      cl::ZeroOrMore, cl::cat(FilteringCategory));
+
+  cl::opt<double> RegionCoverageLtFilter(
+      "region-coverage-lt", cl::Optional,
+      cl::desc("Show code coverage only for functions with region coverage "
+               "less than the given threshold"),
+      cl::cat(FilteringCategory));
+
+  cl::opt<double> RegionCoverageGtFilter(
+      "region-coverage-gt", cl::Optional,
+      cl::desc("Show code coverage only for functions with region coverage "
+               "greater than the given threshold"),
+      cl::cat(FilteringCategory));
+
+  cl::opt<double> LineCoverageLtFilter(
+      "line-coverage-lt", cl::Optional,
+      cl::desc("Show code coverage only for functions with line coverage less "
+               "than the given threshold"),
+      cl::cat(FilteringCategory));
+
+  cl::opt<double> LineCoverageGtFilter(
+      "line-coverage-gt", cl::Optional,
+      cl::desc("Show code coverage only for functions with line coverage "
+               "greater than the given threshold"),
+      cl::cat(FilteringCategory));
+
+  auto commandLineParser = [&, this](int argc, const char **argv) -> int {
+    cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
+    ViewOpts.Debug = DebugDump;
+    CompareFilenamesOnly = FilenameEquivalence;
+
+    if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader)) {
+      error(EC.message(), PGOFilename);
+      return 1;
+    }
+
+    // Create the function filters
+    if (!NameFilters.empty() || !NameRegexFilters.empty()) {
+      auto NameFilterer = new CoverageFilters;
+      for (const auto &Name : NameFilters)
+        NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
+      for (const auto &Regex : NameRegexFilters)
+        NameFilterer->push_back(
+            llvm::make_unique<NameRegexCoverageFilter>(Regex));
+      Filters.push_back(std::unique_ptr<CoverageFilter>(NameFilterer));
+    }
+    if (RegionCoverageLtFilter.getNumOccurrences() ||
+        RegionCoverageGtFilter.getNumOccurrences() ||
+        LineCoverageLtFilter.getNumOccurrences() ||
+        LineCoverageGtFilter.getNumOccurrences()) {
+      auto StatFilterer = new CoverageFilters;
+      if (RegionCoverageLtFilter.getNumOccurrences())
+        StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
+            RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
+      if (RegionCoverageGtFilter.getNumOccurrences())
+        StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
+            RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
+      if (LineCoverageLtFilter.getNumOccurrences())
+        StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
+            LineCoverageFilter::LessThan, LineCoverageLtFilter));
+      if (LineCoverageGtFilter.getNumOccurrences())
+        StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
+            RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
+      Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
+    }
+
+    SourceFiles = InputSourceFiles;
+    return 0;
+  };
+
+  // Parse the object filename
+  if (argc > 1) {
+    StringRef Arg(argv[1]);
+    if (Arg.equals_lower("-help") || Arg.equals_lower("-version")) {
+      cl::ParseCommandLineOptions(2, argv, "LLVM code coverage tool\n");
+      return 0;
+    }
+    ObjectFilename = Arg;
+
+    argv[1] = argv[0];
+    --argc;
+    ++argv;
+  } else {
+    errs() << sys::path::filename(argv[0]) << ": No executable file given!\n";
+    return 1;
+  }
+
+  switch (Cmd) {
+  case Show:
+    return show(argc, argv, commandLineParser);
+  case Report:
+    return report(argc, argv, commandLineParser);
+  }
+  return 0;
+}
+
+int CodeCoverageTool::show(int argc, const char **argv,
+                           CommandLineParserType commandLineParser) {
+
+  cl::OptionCategory ViewCategory("Viewing options");
+
+  cl::opt<bool> ShowLineExecutionCounts(
+      "show-line-counts", cl::Optional,
+      cl::desc("Show the execution counts for each line"), cl::init(true),
+      cl::cat(ViewCategory));
+
+  cl::opt<bool> ShowRegions(
+      "show-regions", cl::Optional,
+      cl::desc("Show the execution counts for each region"),
+      cl::cat(ViewCategory));
+
+  cl::opt<bool> ShowBestLineRegionsCounts(
+      "show-line-counts-or-regions", cl::Optional,
+      cl::desc("Show the execution counts for each line, or the execution "
+               "counts for each region on lines that have multiple regions"),
+      cl::cat(ViewCategory));
+
+  cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
+                               cl::desc("Show expanded source regions"),
+                               cl::cat(ViewCategory));
+
+  cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
+                                   cl::desc("Show function instantiations"),
+                                   cl::cat(ViewCategory));
+
+  cl::opt<bool> NoColors("no-colors", cl::Optional,
+                         cl::desc("Don't show text colors"), cl::init(false),
+                         cl::cat(ViewCategory));
+
+  auto Err = commandLineParser(argc, argv);
+  if (Err)
+    return Err;
+
+  ViewOpts.Colors = !NoColors;
+  ViewOpts.ShowLineNumbers = true;
+  ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
+                           !ShowRegions || ShowBestLineRegionsCounts;
+  ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
+  ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
+  ViewOpts.ShowExpandedRegions = ShowExpansions;
+  ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
+
+  if (load())
+    return 1;
+
+  if (!Filters.empty()) {
+    // Show functions
+    for (const auto &Function : FunctionMappingRecords) {
+      unsigned MainFileID;
+      if (findMainViewFileID(Function, MainFileID))
+        continue;
+      StringRef SourceFile = Function.Filenames[MainFileID];
+      std::unique_ptr<SourceCoverageView> mainView;
+      auto SourceBuffer = getSourceFile(SourceFile);
+      if (!SourceBuffer)
+        return 1;
+      auto Range = findExpandedFileInterestingLineRange(MainFileID, Function);
+      mainView.reset(new SourceCoverageView(SourceBuffer.get(), ViewOpts,
+                                            Range.first, Range.second));
+      createSourceFileView(SourceFile, *mainView, Function, true);
+      ViewOpts.colored_ostream(outs(), raw_ostream::CYAN)
+          << Function.PrettyName << " from " << SourceFile << ":";
+      outs() << "\n";
+      mainView->render(outs());
+      if (FunctionMappingRecords.size() > 1)
+        outs() << "\n";
+    }
+    return 0;
+  }
+
+  // Show files
+  bool ShowFilenames = SourceFiles.size() != 1;
+
+  if (SourceFiles.empty()) {
+    // Get the source files from the function coverage mapping
+    std::set<StringRef> UniqueFilenames;
+    for (const auto &Function : FunctionMappingRecords) {
+      for (const auto &Filename : Function.Filenames)
+        UniqueFilenames.insert(Filename);
+    }
+    for (const auto &Filename : UniqueFilenames)
+      SourceFiles.push_back(Filename);
+  }
+
+  for (const auto &SourceFile : SourceFiles) {
+    std::unique_ptr<SourceCoverageView> mainView;
+    auto SourceBuffer = getSourceFile(SourceFile);
+    if (!SourceBuffer)
+      return 1;
+    mainView.reset(new SourceCoverageView(SourceBuffer.get(), ViewOpts));
+    if (createSourceFileView(SourceFile, *mainView, FunctionMappingRecords)) {
+      ViewOpts.colored_ostream(outs(), raw_ostream::RED)
+          << "warning: The file '" << SourceFile << "' isn't covered.";
+      outs() << "\n";
+      continue;
+    }
+
+    if (ShowFilenames) {
+      ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":";
+      outs() << "\n";
+    }
+    mainView->render(outs());
+    if (SourceFiles.size() > 1)
+      outs() << "\n";
+  }
+
+  return 0;
+}
+
+int CodeCoverageTool::report(int argc, const char **argv,
+                             CommandLineParserType commandLineParser) {
+  cl::opt<bool> NoColors("no-colors", cl::Optional,
+                         cl::desc("Don't show text colors"), cl::init(false));
+
+  auto Err = commandLineParser(argc, argv);
+  if (Err)
+    return Err;
+
+  ViewOpts.Colors = !NoColors;
+
+  if (load())
+    return 1;
+
+  CoverageSummary Summarizer;
+  Summarizer.createSummaries(FunctionMappingRecords);
+  CoverageReport Report(ViewOpts, Summarizer);
+  if (SourceFiles.empty() && Filters.empty()) {
+    Report.renderFileReports(llvm::outs());
+    return 0;
+  }
+
+  Report.renderFunctionReports(llvm::outs());
+  return 0;
+}
+
+int show_main(int argc, const char **argv) {
+  CodeCoverageTool Tool;
+  return Tool.run(CodeCoverageTool::Show, argc, argv);
+}
+
+int report_main(int argc, const char **argv) {
+  CodeCoverageTool Tool;
+  return Tool.run(CodeCoverageTool::Report, argc, argv);
+}

Added: llvm/trunk/tools/llvm-cov/CoverageFilters.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageFilters.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageFilters.cpp (added)
+++ llvm/trunk/tools/llvm-cov/CoverageFilters.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,57 @@
+//===- CoverageFilters.cpp - Function coverage mapping filters ------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes provide filtering for function coverage mapping records.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageFilters.h"
+#include "CoverageSummaryInfo.h"
+#include "llvm/Support/Regex.h"
+
+using namespace llvm;
+
+bool NameCoverageFilter::matches(const FunctionCoverageMapping &Function) {
+  StringRef FuncName = Function.PrettyName;
+  return FuncName.find(Name) != StringRef::npos;
+}
+
+bool NameRegexCoverageFilter::matches(const FunctionCoverageMapping &Function) {
+  return llvm::Regex(Regex).match(Function.PrettyName);
+}
+
+bool RegionCoverageFilter::matches(const FunctionCoverageMapping &Function) {
+  return PassesThreshold(FunctionCoverageSummary::get(Function)
+                             .RegionCoverage.getPercentCovered());
+}
+
+bool LineCoverageFilter::matches(const FunctionCoverageMapping &Function) {
+  return PassesThreshold(
+      FunctionCoverageSummary::get(Function).LineCoverage.getPercentCovered());
+}
+
+void CoverageFilters::push_back(std::unique_ptr<CoverageFilter> Filter) {
+  Filters.push_back(std::move(Filter));
+}
+
+bool CoverageFilters::matches(const FunctionCoverageMapping &Function) {
+  for (const auto &Filter : Filters) {
+    if (Filter->matches(Function))
+      return true;
+  }
+  return false;
+}
+
+bool CoverageFiltersMatchAll::matches(const FunctionCoverageMapping &Function) {
+  for (const auto &Filter : Filters) {
+    if (!Filter->matches(Function))
+      return false;
+  }
+  return true;
+}

Added: llvm/trunk/tools/llvm-cov/CoverageFilters.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageFilters.h?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageFilters.h (added)
+++ llvm/trunk/tools/llvm-cov/CoverageFilters.h Fri Aug 22 17:56:03 2014
@@ -0,0 +1,125 @@
+//===- CoverageFilters.h - Function coverage mapping filters --------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes provide filtering for function coverage mapping records.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_COVERAGEFILTERS_H
+#define LLVM_COV_COVERAGEFILTERS_H
+
+#include "FunctionCoverageMapping.h"
+#include <vector>
+#include <memory>
+
+namespace llvm {
+
+/// \brief Matches specific functions that pass the requirement of this filter.
+class CoverageFilter {
+public:
+  virtual ~CoverageFilter() {}
+
+  /// \brief Return true if the function passes the requirements of this filter.
+  virtual bool matches(const FunctionCoverageMapping &Function) { return true; }
+};
+
+/// \brief Matches functions that contain a specific string in their name.
+class NameCoverageFilter : public CoverageFilter {
+  StringRef Name;
+
+public:
+  NameCoverageFilter(StringRef Name) : Name(Name) {}
+
+  bool matches(const FunctionCoverageMapping &Function) override;
+};
+
+/// \brief Matches functions whose name matches a certain regular expression.
+class NameRegexCoverageFilter : public CoverageFilter {
+  StringRef Regex;
+
+public:
+  NameRegexCoverageFilter(StringRef Regex) : Regex(Regex) {}
+
+  bool matches(const FunctionCoverageMapping &Function) override;
+};
+
+/// \brief Matches numbers that pass a certain threshold.
+template <typename T> class StatisticThresholdFilter {
+public:
+  enum Operation { LessThan, GreaterThan };
+
+protected:
+  Operation Op;
+  T Threshold;
+
+  StatisticThresholdFilter(Operation Op, T Threshold)
+      : Op(Op), Threshold(Threshold) {}
+
+  /// \brief Return true if the given number is less than
+  /// or greater than the certain threshold.
+  bool PassesThreshold(T Value) const {
+    switch (Op) {
+    case LessThan:
+      return Value < Threshold;
+    case GreaterThan:
+      return Value > Threshold;
+    }
+    return false;
+  }
+};
+
+/// \brief Matches functions whose region coverage percentage
+/// is above/below a certain percentage.
+class RegionCoverageFilter : public CoverageFilter,
+                             public StatisticThresholdFilter<double> {
+public:
+  RegionCoverageFilter(Operation Op, double Threshold)
+      : StatisticThresholdFilter(Op, Threshold) {}
+
+  bool matches(const FunctionCoverageMapping &Function) override;
+};
+
+/// \brief Matches functions whose line coverage percentage
+/// is above/below a certain percentage.
+class LineCoverageFilter : public CoverageFilter,
+                           public StatisticThresholdFilter<double> {
+public:
+  LineCoverageFilter(Operation Op, double Threshold)
+      : StatisticThresholdFilter(Op, Threshold) {}
+
+  bool matches(const FunctionCoverageMapping &Function) override;
+};
+
+/// \brief A collection of filters.
+/// Matches functions that match any filters contained
+/// in an instance of this class.
+class CoverageFilters : public CoverageFilter {
+protected:
+  std::vector<std::unique_ptr<CoverageFilter>> Filters;
+
+public:
+  /// \brief Append a filter to this collection.
+  void push_back(std::unique_ptr<CoverageFilter> Filter);
+
+  bool empty() const { return Filters.empty(); }
+
+  bool matches(const FunctionCoverageMapping &Function) override;
+};
+
+/// \brief A collection of filters.
+/// Matches functions that match all of the filters contained
+/// in an instance of this class.
+class CoverageFiltersMatchAll : public CoverageFilters {
+public:
+  bool matches(const FunctionCoverageMapping &Function) override;
+};
+
+} // namespace llvm
+
+#endif // LLVM_COV_COVERAGEFILTERS_H

Added: llvm/trunk/tools/llvm-cov/CoverageReport.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageReport.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageReport.cpp (added)
+++ llvm/trunk/tools/llvm-cov/CoverageReport.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,201 @@
+//===- CoverageReport.cpp - Code coverage report -------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements rendering of a code coverage report.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageReport.h"
+#include "CoverageSummary.h"
+#include "RenderingSupport.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FileSystem.h"
+
+using namespace llvm;
+namespace {
+/// \brief Helper struct which prints trimmed and aligned columns.
+struct Column {
+  enum TrimKind { NoTrim, LeftTrim, RightTrim };
+
+  enum AlignmentKind { LeftAlignment, RightAlignment };
+
+  StringRef Str;
+  unsigned Width;
+  TrimKind Trim;
+  AlignmentKind Alignment;
+
+  Column(StringRef Str, unsigned Width)
+      : Str(Str), Width(Width), Trim(NoTrim), Alignment(LeftAlignment) {}
+
+  Column &set(TrimKind Value) {
+    Trim = Value;
+    return *this;
+  }
+
+  Column &set(AlignmentKind Value) {
+    Alignment = Value;
+    return *this;
+  }
+
+  void render(raw_ostream &OS) const;
+};
+raw_ostream &operator<<(raw_ostream &OS, const Column &Value) {
+  Value.render(OS);
+  return OS;
+}
+}
+
+void Column::render(raw_ostream &OS) const {
+  if (Str.size() <= Width) {
+    if (Alignment == RightAlignment) {
+      OS.indent(Width - Str.size());
+      OS << Str;
+      return;
+    }
+    OS << Str;
+    OS.indent(Width - Str.size());
+    return;
+  }
+
+  switch (Trim) {
+  case NoTrim:
+    OS << Str.substr(0, Width);
+    break;
+  case LeftTrim:
+    OS << "..." << Str.substr(Str.size() - Width + 3);
+    break;
+  case RightTrim:
+    OS << Str.substr(0, Width - 3) << "...";
+    break;
+  }
+}
+
+static Column column(StringRef Str, unsigned Width) {
+  return Column(Str, Width);
+}
+
+template <typename T>
+static Column column(StringRef Str, unsigned Width, const T &Value) {
+  return Column(Str, Width).set(Value);
+}
+
+static const unsigned FileReportColumns[] = {25, 10, 8, 8, 10, 8};
+static const unsigned FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8};
+
+/// \brief Prints a horizontal divider which spans across the given columns.
+template <typename T, size_t N>
+static void renderDivider(T (&Columns)[N], raw_ostream &OS) {
+  unsigned Length = 0;
+  for (unsigned I = 0; I < N; ++I)
+    Length += Columns[I];
+  for (unsigned I = 0; I < Length; ++I)
+    OS << '-';
+}
+
+/// \brief Return the color which correponds to the coverage
+/// percentage of a certain metric.
+template <typename T>
+static raw_ostream::Colors determineCoveragePercentageColor(const T &Info) {
+  if (Info.isFullyCovered())
+    return raw_ostream::GREEN;
+  return Info.getPercentCovered() >= 80.0 ? raw_ostream::YELLOW
+                                          : raw_ostream::RED;
+}
+
+void CoverageReport::render(const FileCoverageSummary &File, raw_ostream &OS) {
+  OS << column(File.Name, FileReportColumns[0], Column::LeftTrim)
+     << format("%*zd", FileReportColumns[1], File.RegionCoverage.NumRegions);
+  Options.colored_ostream(OS, File.RegionCoverage.isFullyCovered()
+                                  ? raw_ostream::GREEN
+                                  : raw_ostream::RED)
+      << format("%*zd", FileReportColumns[2], File.RegionCoverage.NotCovered);
+  Options.colored_ostream(OS,
+                          determineCoveragePercentageColor(File.RegionCoverage))
+      << format("%*.2f", FileReportColumns[3] - 1,
+                File.RegionCoverage.getPercentCovered()) << '%';
+  OS << format("%*zd", FileReportColumns[4],
+               File.FunctionCoverage.NumFunctions);
+  Options.colored_ostream(
+      OS, determineCoveragePercentageColor(File.FunctionCoverage))
+      << format("%*.2f", FileReportColumns[5] - 1,
+                File.FunctionCoverage.getPercentCovered()) << '%';
+  OS << "\n";
+}
+
+void CoverageReport::render(const FunctionCoverageSummary &Function,
+                            raw_ostream &OS) {
+  OS << column(Function.Name, FunctionReportColumns[0], Column::RightTrim)
+     << format("%*zd", FunctionReportColumns[1],
+               Function.RegionCoverage.NumRegions);
+  Options.colored_ostream(OS, Function.RegionCoverage.isFullyCovered()
+                                  ? raw_ostream::GREEN
+                                  : raw_ostream::RED)
+      << format("%*zd", FunctionReportColumns[2],
+                Function.RegionCoverage.NotCovered);
+  Options.colored_ostream(
+      OS, determineCoveragePercentageColor(Function.RegionCoverage))
+      << format("%*.2f", FunctionReportColumns[3] - 1,
+                Function.RegionCoverage.getPercentCovered()) << '%';
+  OS << format("%*zd", FunctionReportColumns[4],
+               Function.LineCoverage.NumLines);
+  Options.colored_ostream(OS, Function.LineCoverage.isFullyCovered()
+                                  ? raw_ostream::GREEN
+                                  : raw_ostream::RED)
+      << format("%*zd", FunctionReportColumns[5],
+                Function.LineCoverage.NotCovered);
+  Options.colored_ostream(
+      OS, determineCoveragePercentageColor(Function.LineCoverage))
+      << format("%*.2f", FunctionReportColumns[6] - 1,
+                Function.LineCoverage.getPercentCovered()) << '%';
+  OS << "\n";
+}
+
+void CoverageReport::renderFunctionReports(raw_ostream &OS) {
+  bool isFirst = true;
+  for (const auto &File : Summary.getFileSummaries()) {
+    if (isFirst)
+      isFirst = false;
+    else
+      OS << "\n";
+    OS << "File '" << File.Name << "':\n";
+    OS << column("Name", FunctionReportColumns[0])
+       << column("Regions", FunctionReportColumns[1], Column::RightAlignment)
+       << column("Miss", FunctionReportColumns[2], Column::RightAlignment)
+       << column("Cover", FunctionReportColumns[3], Column::RightAlignment)
+       << column("Lines", FunctionReportColumns[4], Column::RightAlignment)
+       << column("Miss", FunctionReportColumns[5], Column::RightAlignment)
+       << column("Cover", FunctionReportColumns[6], Column::RightAlignment);
+    OS << "\n";
+    renderDivider(FunctionReportColumns, OS);
+    OS << "\n";
+    for (const auto &Function : File.FunctionSummaries)
+      render(Function, OS);
+    renderDivider(FunctionReportColumns, OS);
+    OS << "\n";
+    render(FunctionCoverageSummary("TOTAL", File.RegionCoverage,
+                                   File.LineCoverage),
+           OS);
+  }
+}
+
+void CoverageReport::renderFileReports(raw_ostream &OS) {
+  OS << column("Filename", FileReportColumns[0])
+     << column("Regions", FileReportColumns[1], Column::RightAlignment)
+     << column("Miss", FileReportColumns[2], Column::RightAlignment)
+     << column("Cover", FileReportColumns[3], Column::RightAlignment)
+     << column("Functions", FileReportColumns[4], Column::RightAlignment)
+     << column("Cover", FileReportColumns[5], Column::RightAlignment) << "\n";
+  renderDivider(FileReportColumns, OS);
+  OS << "\n";
+  for (const auto &File : Summary.getFileSummaries())
+    render(File, OS);
+  renderDivider(FileReportColumns, OS);
+  OS << "\n";
+  render(Summary.getCombinedFileSummaries(), OS);
+}

Added: llvm/trunk/tools/llvm-cov/CoverageReport.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageReport.h?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageReport.h (added)
+++ llvm/trunk/tools/llvm-cov/CoverageReport.h Fri Aug 22 17:56:03 2014
@@ -0,0 +1,40 @@
+//===- CoverageReport.h - Code coverage report ---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements rendering of a code coverage report.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_COVERAGEREPORT_H
+#define LLVM_COV_COVERAGEREPORT_H
+
+#include "CoverageViewOptions.h"
+#include "CoverageSummary.h"
+
+namespace llvm {
+
+/// \brief Displays the code coverage report.
+class CoverageReport {
+  const CoverageViewOptions &Options;
+  CoverageSummary &Summary;
+
+  void render(const FileCoverageSummary &File, raw_ostream &OS);
+  void render(const FunctionCoverageSummary &Function, raw_ostream &OS);
+
+public:
+  CoverageReport(const CoverageViewOptions &Options, CoverageSummary &Summary)
+      : Options(Options), Summary(Summary) {}
+
+  void renderFunctionReports(raw_ostream &OS);
+
+  void renderFileReports(raw_ostream &OS);
+};
+}
+
+#endif // LLVM_COV_COVERAGEREPORT_H

Added: llvm/trunk/tools/llvm-cov/CoverageSummary.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageSummary.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageSummary.cpp (added)
+++ llvm/trunk/tools/llvm-cov/CoverageSummary.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,92 @@
+//===- CoverageSummary.cpp - Code coverage summary ------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements data management and rendering for the code coverage
+// summaries of all files and functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageSummary.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+
+unsigned CoverageSummary::getFileID(StringRef Filename) {
+  for (unsigned I = 0, E = Filenames.size(); I < E; ++I) {
+    if (sys::fs::equivalent(Filenames[I], Filename))
+      return I;
+  }
+  Filenames.push_back(Filename);
+  return Filenames.size() - 1;
+}
+
+void
+CoverageSummary::createSummaries(ArrayRef<FunctionCoverageMapping> Functions) {
+  std::vector<std::pair<unsigned, size_t>> FunctionFileIDs;
+
+  FunctionFileIDs.resize(Functions.size());
+  for (size_t I = 0, E = Functions.size(); I < E; ++I) {
+    StringRef Filename = Functions[I].Filenames[0];
+    FunctionFileIDs[I] = std::make_pair(getFileID(Filename), I);
+  }
+
+  // Sort the function records by file ids
+  std::sort(FunctionFileIDs.begin(), FunctionFileIDs.end(),
+            [](const std::pair<unsigned, size_t> &lhs,
+               const std::pair<unsigned, size_t> &rhs) {
+    return lhs.first < rhs.first;
+  });
+
+  // Create function summaries in a sorted order (by file ids)
+  FunctionSummaries.reserve(Functions.size());
+  for (size_t I = 0, E = Functions.size(); I < E; ++I)
+    FunctionSummaries.push_back(
+        FunctionCoverageSummary::get(Functions[FunctionFileIDs[I].second]));
+
+  // Create file summaries
+  size_t CurrentSummary = 0;
+  for (unsigned FileID = 0; FileID < Filenames.size(); ++FileID) {
+    // Gather the relevant functions summaries
+    auto PrevSummary = CurrentSummary;
+    while (CurrentSummary < FunctionSummaries.size() &&
+           FunctionFileIDs[CurrentSummary].first == FileID)
+      ++CurrentSummary;
+    ArrayRef<FunctionCoverageSummary> LocalSummaries(
+        FunctionSummaries.data() + PrevSummary,
+        FunctionSummaries.data() + CurrentSummary);
+    if (LocalSummaries.empty())
+      continue;
+
+    FileSummaries.push_back(
+        FileCoverageSummary::get(Filenames[FileID], LocalSummaries));
+  }
+}
+
+FileCoverageSummary CoverageSummary::getCombinedFileSummaries() {
+  size_t NumRegions = 0, CoveredRegions = 0;
+  size_t NumLines = 0, NonCodeLines = 0, CoveredLines = 0;
+  size_t NumFunctionsCovered = 0, NumFunctions = 0;
+  for (const auto &File : FileSummaries) {
+    NumRegions += File.RegionCoverage.NumRegions;
+    CoveredRegions += File.RegionCoverage.Covered;
+
+    NumLines += File.LineCoverage.NumLines;
+    NonCodeLines += File.LineCoverage.NonCodeLines;
+    CoveredLines += File.LineCoverage.Covered;
+
+    NumFunctionsCovered += File.FunctionCoverage.FullyCovered;
+    NumFunctions += File.FunctionCoverage.NumFunctions;
+  }
+  return FileCoverageSummary(
+      "TOTAL", RegionCoverageInfo(CoveredRegions, NumRegions),
+      LineCoverageInfo(CoveredLines, NonCodeLines, NumLines),
+      FunctionCoverageInfo(NumFunctionsCovered, NumFunctions),
+      ArrayRef<FunctionCoverageSummary>());
+}

Added: llvm/trunk/tools/llvm-cov/CoverageSummary.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageSummary.h?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageSummary.h (added)
+++ llvm/trunk/tools/llvm-cov/CoverageSummary.h Fri Aug 22 17:56:03 2014
@@ -0,0 +1,45 @@
+//===- CoverageSummary.h - Code coverage summary --------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements data management and rendering for the code coverage
+// summaries of all files and functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_COVERAGESUMMARY_H
+#define LLVM_COV_COVERAGESUMMARY_H
+
+#include "CoverageSummaryInfo.h"
+#include <vector>
+
+namespace llvm {
+
+/// \brief Manager for the function and file code coverage summaries.
+class CoverageSummary {
+  std::vector<StringRef> Filenames;
+  std::vector<FunctionCoverageSummary> FunctionSummaries;
+  std::vector<std::pair<unsigned, unsigned>> FunctionSummariesFileIDs;
+  std::vector<FileCoverageSummary> FileSummaries;
+
+  unsigned getFileID(StringRef Filename);
+
+public:
+  void createSummaries(ArrayRef<FunctionCoverageMapping> Functions);
+
+  ArrayRef<FileCoverageSummary> getFileSummaries() { return FileSummaries; }
+
+  FileCoverageSummary getCombinedFileSummaries();
+
+  void render(const FunctionCoverageSummary &Summary, raw_ostream &OS);
+
+  void render(raw_ostream &OS);
+};
+}
+
+#endif // LLVM_COV_COVERAGESUMMARY_H

Added: llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp (added)
+++ llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,95 @@
+//===- CoverageSummaryInfo.cpp - Coverage summary for function/file -------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These structures are used to represent code coverage metrics
+// for functions/files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageSummaryInfo.h"
+
+using namespace llvm;
+using namespace coverage;
+
+FunctionCoverageSummary
+FunctionCoverageSummary::get(const FunctionCoverageMapping &Function) {
+  // Compute the region coverage
+  size_t NumCodeRegions = 0, CoveredRegions = 0;
+  for (auto &Region : Function.MappingRegions) {
+    if (Region.Kind != CounterMappingRegion::CodeRegion)
+      continue;
+    ++NumCodeRegions;
+    if (Region.ExecutionCount != 0)
+      ++CoveredRegions;
+  }
+
+  // Compute the line coverage
+  size_t NumLines = 0, CoveredLines = 0;
+  for (unsigned FileID = 0, E = Function.Filenames.size(); FileID < E;
+       ++FileID) {
+    // Find the line start and end of the function's source code
+    // in that particular file
+    unsigned LineStart = std::numeric_limits<unsigned>::max();
+    unsigned LineEnd = 0;
+    for (auto &Region : Function.MappingRegions) {
+      if (Region.FileID != FileID)
+        continue;
+      LineStart = std::min(LineStart, Region.LineStart);
+      LineEnd = std::max(LineEnd, Region.LineEnd);
+    }
+    unsigned LineCount = LineEnd - LineStart + 1;
+
+    // Get counters
+    llvm::SmallVector<uint64_t, 16> ExecutionCounts;
+    ExecutionCounts.resize(LineCount, 0);
+    for (auto &Region : Function.MappingRegions) {
+      if (Region.FileID != FileID)
+        continue;
+      // Ignore the lines that were skipped by the preprocessor.
+      auto ExecutionCount = Region.ExecutionCount;
+      if (Region.Kind == MappingRegion::SkippedRegion) {
+        LineCount -= Region.LineEnd - Region.LineStart + 1;
+        ExecutionCount = 1;
+      }
+      for (unsigned I = Region.LineStart; I <= Region.LineEnd; ++I)
+        ExecutionCounts[I - LineStart] = ExecutionCount;
+    }
+    CoveredLines += LineCount - std::count(ExecutionCounts.begin(),
+                                           ExecutionCounts.end(), 0);
+    NumLines += LineCount;
+  }
+  return FunctionCoverageSummary(
+      Function.PrettyName, RegionCoverageInfo(CoveredRegions, NumCodeRegions),
+      LineCoverageInfo(CoveredLines, 0, NumLines));
+}
+
+FileCoverageSummary
+FileCoverageSummary::get(StringRef Name,
+                         ArrayRef<FunctionCoverageSummary> FunctionSummaries) {
+  size_t NumRegions = 0, CoveredRegions = 0;
+  size_t NumLines = 0, NonCodeLines = 0, CoveredLines = 0;
+  size_t NumFunctionsCovered = 0;
+  for (const auto &Func : FunctionSummaries) {
+    CoveredRegions += Func.RegionCoverage.Covered;
+    NumRegions += Func.RegionCoverage.NumRegions;
+
+    CoveredLines += Func.LineCoverage.Covered;
+    NonCodeLines += Func.LineCoverage.NonCodeLines;
+    NumLines += Func.LineCoverage.NumLines;
+
+    if (Func.RegionCoverage.isFullyCovered())
+      ++NumFunctionsCovered;
+  }
+
+  return FileCoverageSummary(
+      Name, RegionCoverageInfo(CoveredRegions, NumRegions),
+      LineCoverageInfo(CoveredLines, NonCodeLines, NumLines),
+      FunctionCoverageInfo(NumFunctionsCovered, FunctionSummaries.size()),
+      FunctionSummaries);
+}

Added: llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h (added)
+++ llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h Fri Aug 22 17:56:03 2014
@@ -0,0 +1,131 @@
+//===- CoverageSummaryInfo.h - Coverage summary for function/file ---------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These structures are used to represent code coverage metrics
+// for functions/files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_COVERAGESUMMARYINFO_H
+#define LLVM_COV_COVERAGESUMMARYINFO_H
+
+#include "FunctionCoverageMapping.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+/// \brief Provides information about region coverage for a function/file.
+struct RegionCoverageInfo {
+  /// \brief The number of regions that were executed at least once.
+  size_t Covered;
+
+  /// \brief The number of regions that weren't executed.
+  size_t NotCovered;
+
+  /// \brief The total number of regions in a function/file.
+  size_t NumRegions;
+
+  RegionCoverageInfo(size_t Covered, size_t NumRegions)
+      : Covered(Covered), NotCovered(NumRegions - Covered),
+        NumRegions(NumRegions) {}
+
+  bool isFullyCovered() const { return Covered == NumRegions; }
+
+  double getPercentCovered() const {
+    return double(Covered) / double(NumRegions) * 100.0;
+  }
+};
+
+/// \brief Provides information about line coverage for a function/file.
+struct LineCoverageInfo {
+  /// \brief The number of lines that were executed at least once.
+  size_t Covered;
+
+  /// \brief The number of lines that weren't executed.
+  size_t NotCovered;
+
+  /// \brief The number of lines that aren't code.
+  size_t NonCodeLines;
+
+  /// \brief The total number of lines in a function/file.
+  size_t NumLines;
+
+  LineCoverageInfo(size_t Covered, size_t NumNonCodeLines, size_t NumLines)
+      : Covered(Covered), NotCovered(NumLines - NumNonCodeLines - Covered),
+        NonCodeLines(NumNonCodeLines), NumLines(NumLines) {}
+
+  bool isFullyCovered() const { return Covered == (NumLines - NonCodeLines); }
+
+  double getPercentCovered() const {
+    return double(Covered) / double(NumLines - NonCodeLines) * 100.0;
+  }
+};
+
+/// \brief Provides information about function coverage for a file.
+struct FunctionCoverageInfo {
+  /// \brief The number of functions that have full
+  /// region coverage.
+  size_t FullyCovered;
+
+  /// \brief The total number of functions in this file.
+  size_t NumFunctions;
+
+  FunctionCoverageInfo(size_t FullyCovered, size_t NumFunctions)
+      : FullyCovered(FullyCovered), NumFunctions(NumFunctions) {}
+
+  bool isFullyCovered() const { return FullyCovered == NumFunctions; }
+
+  double getPercentCovered() const {
+    return double(FullyCovered) / double(NumFunctions) * 100.0;
+  }
+};
+
+/// \brief A summary of function's code coverage.
+struct FunctionCoverageSummary {
+  StringRef Name;
+  RegionCoverageInfo RegionCoverage;
+  LineCoverageInfo LineCoverage;
+
+  FunctionCoverageSummary(StringRef Name,
+                          const RegionCoverageInfo &RegionCoverage,
+                          const LineCoverageInfo &LineCoverage)
+      : Name(Name), RegionCoverage(RegionCoverage), LineCoverage(LineCoverage) {
+  }
+
+  /// \brief Compute the code coverage summary for the given function coverage
+  /// mapping record.
+  static FunctionCoverageSummary get(const FunctionCoverageMapping &Function);
+};
+
+/// \brief A summary of file's code coverage.
+struct FileCoverageSummary {
+  StringRef Name;
+  RegionCoverageInfo RegionCoverage;
+  LineCoverageInfo LineCoverage;
+  FunctionCoverageInfo FunctionCoverage;
+  /// \brief The summary of every function
+  /// in this file.
+  ArrayRef<FunctionCoverageSummary> FunctionSummaries;
+
+  FileCoverageSummary(StringRef Name, const RegionCoverageInfo &RegionCoverage,
+                      const LineCoverageInfo &LineCoverage,
+                      const FunctionCoverageInfo &FunctionCoverage,
+                      ArrayRef<FunctionCoverageSummary> FunctionSummaries)
+      : Name(Name), RegionCoverage(RegionCoverage), LineCoverage(LineCoverage),
+        FunctionCoverage(FunctionCoverage),
+        FunctionSummaries(FunctionSummaries) {}
+
+  /// \brief Compute the code coverage summary for a file.
+  static FileCoverageSummary
+  get(StringRef Name, ArrayRef<FunctionCoverageSummary> FunctionSummaries);
+};
+
+} // namespace llvm
+
+#endif // LLVM_COV_COVERAGESUMMARYINFO_H

Added: llvm/trunk/tools/llvm-cov/CoverageViewOptions.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageViewOptions.h?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageViewOptions.h (added)
+++ llvm/trunk/tools/llvm-cov/CoverageViewOptions.h Fri Aug 22 17:56:03 2014
@@ -0,0 +1,36 @@
+//===- CoverageViewOptions.h - Code coverage display options -------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_COVERAGEVIEWOPTIONS_H
+#define LLVM_COV_COVERAGEVIEWOPTIONS_H
+
+#include "RenderingSupport.h"
+
+namespace llvm {
+
+/// \brief The options for displaying the code coverage information.
+struct CoverageViewOptions {
+  bool Debug;
+  bool Colors;
+  bool ShowLineNumbers;
+  bool ShowLineStats;
+  bool ShowRegionMarkers;
+  bool ShowLineStatsOrRegionMarkers;
+  bool ShowExpandedRegions;
+  bool ShowFunctionInstantiations;
+
+  /// \brief Change the output's stream color if the colors are enabled.
+  ColoredRawOstream colored_ostream(raw_ostream &OS,
+                                    raw_ostream::Colors Color) const {
+    return llvm::colored_ostream(OS, Color, Colors);
+  }
+};
+}
+
+#endif // LLVM_COV_COVERAGEVIEWOPTIONS_H

Added: llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h (added)
+++ llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h Fri Aug 22 17:56:03 2014
@@ -0,0 +1,50 @@
+//===- FunctionCoverageMapping.h - Function coverage mapping record -------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A structure that stores the coverage mapping record for a single function.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_FUNCTIONCOVERAGEMAPPING_H
+#define LLVM_COV_FUNCTIONCOVERAGEMAPPING_H
+
+#include <string>
+#include <vector>
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ProfileData/CoverageMapping.h"
+
+namespace llvm {
+
+/// \brief Associates a source range with an execution count.
+struct MappingRegion : public coverage::CounterMappingRegion {
+  uint64_t ExecutionCount;
+
+  MappingRegion(const CounterMappingRegion &R, uint64_t ExecutionCount)
+      : CounterMappingRegion(R), ExecutionCount(ExecutionCount) {}
+};
+
+/// \brief Stores all the required information
+/// about code coverage for a single function.
+struct FunctionCoverageMapping {
+  /// \brief Raw function name.
+  std::string Name;
+  /// \brief Demangled function name.
+  std::string PrettyName;
+  std::vector<std::string> Filenames;
+  std::vector<MappingRegion> MappingRegions;
+
+  FunctionCoverageMapping(StringRef Name, ArrayRef<StringRef> Filenames)
+      : Name(Name), PrettyName(Name),
+        Filenames(Filenames.begin(), Filenames.end()) {}
+};
+
+} // namespace llvm
+
+#endif // LLVM_COV_FUNCTIONCOVERAGEMAPPING_H

Modified: llvm/trunk/tools/llvm-cov/LLVMBuild.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/LLVMBuild.txt?rev=216300&r1=216299&r2=216300&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/LLVMBuild.txt (original)
+++ llvm/trunk/tools/llvm-cov/LLVMBuild.txt Fri Aug 22 17:56:03 2014
@@ -19,4 +19,4 @@
 type = Tool
 name = llvm-cov
 parent = Tools
-required_libraries = Instrumentation
+required_libraries = ProfileData Support Instrumentation

Modified: llvm/trunk/tools/llvm-cov/Makefile
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/Makefile?rev=216300&r1=216299&r2=216300&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/Makefile (original)
+++ llvm/trunk/tools/llvm-cov/Makefile Fri Aug 22 17:56:03 2014
@@ -9,7 +9,7 @@
 
 LEVEL := ../..
 TOOLNAME := llvm-cov
-LINK_COMPONENTS := core support
+LINK_COMPONENTS := core support profiledata object
 
 # This tool has no plugins, optimize startup time.
 TOOL_NO_EXPORTS := 1

Added: llvm/trunk/tools/llvm-cov/RenderingSupport.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/RenderingSupport.h?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/RenderingSupport.h (added)
+++ llvm/trunk/tools/llvm-cov/RenderingSupport.h Fri Aug 22 17:56:03 2014
@@ -0,0 +1,59 @@
+//===- RenderingSupport.h - output stream rendering support functions  ----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_RENDERINGSUPPORT_H
+#define LLVM_COV_RENDERINGSUPPORT_H
+
+#include "llvm/Support/raw_ostream.h"
+#include <utility>
+
+namespace llvm {
+
+/// \brief A helper class that resets the output stream's color if needed
+/// when destroyed.
+class ColoredRawOstream {
+  ColoredRawOstream(const ColoredRawOstream &OS) LLVM_DELETED_FUNCTION;
+
+public:
+  raw_ostream &OS;
+  bool IsColorUsed;
+
+  ColoredRawOstream(raw_ostream &OS, bool IsColorUsed)
+      : OS(OS), IsColorUsed(IsColorUsed) {}
+
+  ColoredRawOstream(ColoredRawOstream &&Other)
+      : OS(Other.OS), IsColorUsed(Other.IsColorUsed) {
+    // Reset the other IsColorUsed so that the other object won't reset the
+    // color when destroyed.
+    Other.IsColorUsed = false;
+  }
+
+  ~ColoredRawOstream() {
+    if (IsColorUsed)
+      OS.resetColor();
+  }
+};
+
+template <typename T>
+inline raw_ostream &operator<<(const ColoredRawOstream &OS, T &&Value) {
+  return OS.OS << std::forward<T>(Value);
+}
+
+/// \brief Change the color of the output stream if the `IsColorUsed` flag
+/// is true. Returns an object that resets the color when destroyed.
+inline ColoredRawOstream colored_ostream(raw_ostream &OS,
+                                         raw_ostream::Colors Color,
+                                         bool IsColorUsed = false) {
+  if (IsColorUsed)
+    OS.changeColor(Color);
+  return ColoredRawOstream(OS, IsColorUsed);
+}
+}
+
+#endif // LLVM_COV_RENDERINGSUPPORT_H

Added: llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp (added)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,57 @@
+//===- SourceCoverageDataManager.cpp - Manager for source file coverage
+// data-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class separates and merges mapping regions for a specific source file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SourceCoverageDataManager.h"
+
+using namespace llvm;
+using namespace coverage;
+
+void SourceCoverageDataManager::insert(const MappingRegion &Region) {
+  SourceRange Range(Region.LineStart, Region.ColumnStart, Region.LineEnd,
+                    Region.ColumnEnd);
+  if (Region.Kind == CounterMappingRegion::SkippedRegion) {
+    SkippedRegions.push_back(Range);
+    return;
+  }
+  Regions.push_back(std::make_pair(Range, Region.ExecutionCount));
+}
+
+ArrayRef<std::pair<SourceCoverageDataManager::SourceRange, uint64_t>>
+SourceCoverageDataManager::getSourceRegions() {
+  if (Uniqued || Regions.size() <= 1)
+    return Regions;
+
+  // Sort.
+  std::sort(Regions.begin(), Regions.end(),
+            [](const std::pair<SourceRange, uint64_t> &LHS,
+               const std::pair<SourceRange, uint64_t> &RHS) {
+    return LHS.first < RHS.first;
+  });
+
+  // Merge duplicate source ranges and sum their execution counts.
+  auto Prev = Regions.begin();
+  for (auto I = Prev + 1, E = Regions.end(); I != E; ++I) {
+    if (I->first == Prev->first) {
+      Prev->second += I->second;
+      continue;
+    }
+    ++Prev;
+    *Prev = *I;
+  }
+  ++Prev;
+  Regions.erase(Prev, Regions.end());
+
+  Uniqued = true;
+  return Regions;
+}

Added: llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h (added)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h Fri Aug 22 17:56:03 2014
@@ -0,0 +1,79 @@
+//===- SourceCoverageDataManager.h - Manager for source file coverage data-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class separates and merges mapping regions for a specific source file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_SOURCECOVERAGEDATAMANAGER_H
+#define LLVM_COV_SOURCECOVERAGEDATAMANAGER_H
+
+#include "FunctionCoverageMapping.h"
+#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/ADT/Hashing.h"
+#include <vector>
+#include <unordered_map>
+
+namespace llvm {
+
+/// \brief Partions mapping regions by their kind and sums
+/// the execution counts of the regions that start at the same location.
+class SourceCoverageDataManager {
+public:
+  struct SourceRange {
+    unsigned LineStart, ColumnStart, LineEnd, ColumnEnd;
+
+    SourceRange(unsigned LineStart, unsigned ColumnStart, unsigned LineEnd,
+                unsigned ColumnEnd)
+        : LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd),
+          ColumnEnd(ColumnEnd) {}
+
+    bool operator==(const SourceRange &Other) const {
+      return LineStart == Other.LineStart && ColumnStart == Other.ColumnStart &&
+             LineEnd == Other.LineEnd && ColumnEnd == Other.ColumnEnd;
+    }
+
+    bool operator<(const SourceRange &Other) const {
+      if (LineStart == Other.LineStart)
+        return ColumnStart < Other.ColumnStart;
+      return LineStart < Other.LineStart;
+    }
+
+    bool contains(const SourceRange &Other) {
+      if (LineStart > Other.LineStart ||
+          (LineStart == Other.LineStart && ColumnStart > Other.ColumnStart))
+        return false;
+      if (LineEnd < Other.LineEnd ||
+          (LineEnd == Other.LineEnd && ColumnEnd < Other.ColumnEnd))
+        return false;
+      return true;
+    }
+  };
+
+protected:
+  std::vector<std::pair<SourceRange, uint64_t>> Regions;
+  std::vector<SourceRange> SkippedRegions;
+  bool Uniqued;
+
+public:
+  SourceCoverageDataManager() : Uniqued(false) {}
+
+  void insert(const MappingRegion &Region);
+
+  /// \brief Return the source ranges and execution counts
+  /// obtained from the non-skipped mapping regions.
+  ArrayRef<std::pair<SourceRange, uint64_t>> getSourceRegions();
+
+  /// \brief Return the source ranges obtained from the skipped mapping regions.
+  ArrayRef<SourceRange> getSkippedRegions() const { return SkippedRegions; }
+};
+
+} // namespace llvm
+
+#endif // LLVM_COV_SOURCECOVERAGEDATAMANAGER_H

Added: llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp (added)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,411 @@
+//===- SourceCoverageView.cpp - Code coverage view for source code --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements rendering for code coverage of source code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SourceCoverageView.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/LineIterator.h"
+
+using namespace llvm;
+
+void SourceCoverageView::renderLine(raw_ostream &OS, StringRef Line,
+                                    ArrayRef<HighlightRange> Ranges) {
+  if (Ranges.empty()) {
+    OS << Line << "\n";
+    return;
+  }
+  if (Line.empty())
+    Line = " ";
+
+  unsigned PrevColumnStart = 0;
+  unsigned Start = 1;
+  for (const auto &Range : Ranges) {
+    if (PrevColumnStart == Range.ColumnStart)
+      continue;
+
+    // Show the unhighlighted part
+    unsigned ColumnStart = PrevColumnStart = Range.ColumnStart;
+    OS << Line.substr(Start - 1, ColumnStart - Start);
+
+    // Show the highlighted part
+    auto Color = Range.Kind == HighlightRange::NotCovered ? raw_ostream::RED
+                                                          : raw_ostream::CYAN;
+    OS.changeColor(Color, false, true);
+    unsigned ColumnEnd = std::min(Range.ColumnEnd, (unsigned)Line.size() + 1);
+    OS << Line.substr(ColumnStart - 1, ColumnEnd - ColumnStart);
+    Start = ColumnEnd;
+    OS.resetColor();
+  }
+
+  // Show the rest of the line
+  OS << Line.substr(Start - 1, Line.size() - Start + 1);
+  OS << "\n";
+}
+
+void SourceCoverageView::renderOffset(raw_ostream &OS, unsigned I) {
+  for (unsigned J = 0; J < I; ++J)
+    OS << "  |";
+}
+
+void SourceCoverageView::renderViewDivider(unsigned Offset, unsigned Length,
+                                           raw_ostream &OS) {
+  for (unsigned J = 1; J < Offset; ++J)
+    OS << "  |";
+  if (Offset != 0)
+    OS.indent(2);
+  for (unsigned I = 0; I < Length; ++I)
+    OS << "-";
+}
+
+void
+SourceCoverageView::renderLineCoverageColumn(raw_ostream &OS,
+                                             const LineCoverageInfo &Line) {
+  if (!Line.isMapped()) {
+    OS.indent(LineCoverageColumnWidth) << '|';
+    return;
+  }
+  SmallString<32> Buffer;
+  raw_svector_ostream BufferOS(Buffer);
+  BufferOS << Line.ExecutionCount;
+  auto Str = BufferOS.str();
+  // Trim
+  Str = Str.substr(0, std::min(Str.size(), (size_t)LineCoverageColumnWidth));
+  // Align to the right
+  OS.indent(LineCoverageColumnWidth - Str.size());
+  colored_ostream(OS, raw_ostream::MAGENTA,
+                  Line.hasMultipleRegions() && Options.Colors)
+      << Str;
+  OS << '|';
+}
+
+void SourceCoverageView::renderLineNumberColumn(raw_ostream &OS,
+                                                unsigned LineNo) {
+  SmallString<32> Buffer;
+  raw_svector_ostream BufferOS(Buffer);
+  BufferOS << LineNo;
+  auto Str = BufferOS.str();
+  // Trim and align to the right
+  Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth));
+  OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
+}
+
+void SourceCoverageView::renderRegionMarkers(raw_ostream &OS,
+                                             ArrayRef<RegionMarker> Regions) {
+  SmallString<32> Buffer;
+  raw_svector_ostream BufferOS(Buffer);
+
+  unsigned PrevColumn = 1;
+  for (const auto &Region : Regions) {
+    // Skip to the new region
+    if (Region.Column > PrevColumn)
+      OS.indent(Region.Column - PrevColumn);
+    PrevColumn = Region.Column + 1;
+    BufferOS << Region.ExecutionCount;
+    StringRef Str = BufferOS.str();
+    // Trim the execution count
+    Str = Str.substr(0, std::min(Str.size(), (size_t)7));
+    PrevColumn += Str.size();
+    OS << '^' << Str;
+    Buffer.clear();
+  }
+  OS << "\n";
+}
+
+/// \brief Insert a new highlighting range into the line's highlighting ranges
+/// Return line's new highlighting ranges in result.
+static void insertHighlightRange(
+    ArrayRef<SourceCoverageView::HighlightRange> Ranges,
+    SourceCoverageView::HighlightRange RangeToInsert,
+    SmallVectorImpl<SourceCoverageView::HighlightRange> &Result) {
+  Result.clear();
+  size_t I = 0;
+  auto E = Ranges.size();
+  for (; I < E; ++I) {
+    if (RangeToInsert.ColumnStart < Ranges[I].ColumnEnd) {
+      const auto &Range = Ranges[I];
+      bool NextRangeContainsInserted = false;
+      // If the next range starts before the inserted range, move the end of the
+      // next range to the start of the inserted range.
+      if (Range.ColumnStart < RangeToInsert.ColumnStart) {
+        if (RangeToInsert.ColumnStart != Range.ColumnStart)
+          Result.push_back(SourceCoverageView::HighlightRange(
+              Range.Line, Range.ColumnStart, RangeToInsert.ColumnStart,
+              Range.Kind));
+        // If the next range also ends after the inserted range, keep this range
+        // and create a new range that starts at the inserted range and ends
+        // at the next range later.
+        if (Range.ColumnEnd > RangeToInsert.ColumnEnd)
+          NextRangeContainsInserted = true;
+      }
+      if (!NextRangeContainsInserted) {
+        ++I;
+        // Ignore ranges that are contained in inserted range
+        while (I < E && RangeToInsert.contains(Ranges[I]))
+          ++I;
+      }
+      break;
+    }
+    Result.push_back(Ranges[I]);
+  }
+  Result.push_back(RangeToInsert);
+  // If the next range starts before the inserted range end, move the start
+  // of the next range to the end of the inserted range.
+  if (I < E && Ranges[I].ColumnStart < RangeToInsert.ColumnEnd) {
+    const auto &Range = Ranges[I];
+    if (RangeToInsert.ColumnEnd != Range.ColumnEnd)
+      Result.push_back(SourceCoverageView::HighlightRange(
+          Range.Line, RangeToInsert.ColumnEnd, Range.ColumnEnd, Range.Kind));
+    ++I;
+  }
+  // Add the remaining ranges that are located after the inserted range
+  for (; I < E; ++I)
+    Result.push_back(Ranges[I]);
+}
+
+void SourceCoverageView::sortChildren() {
+  for (auto &I : Children)
+    I->sortChildren();
+  std::sort(Children.begin(), Children.end(),
+            [](const std::unique_ptr<SourceCoverageView> &LHS,
+               const std::unique_ptr<SourceCoverageView> &RHS) {
+    return LHS->ExpansionRegion < RHS->ExpansionRegion;
+  });
+}
+
+SourceCoverageView::HighlightRange
+SourceCoverageView::getExpansionHighlightRange() const {
+  return HighlightRange(ExpansionRegion.LineStart, ExpansionRegion.ColumnStart,
+                        ExpansionRegion.ColumnEnd, HighlightRange::Expanded);
+}
+
+template <typename T>
+ArrayRef<T> gatherLineItems(size_t &CurrentIdx, const std::vector<T> &Items,
+                            unsigned LineNo) {
+  auto PrevIdx = CurrentIdx;
+  auto E = Items.size();
+  while (CurrentIdx < E && Items[CurrentIdx].Line == LineNo)
+    ++CurrentIdx;
+  return ArrayRef<T>(Items.data() + PrevIdx, CurrentIdx - PrevIdx);
+}
+
+ArrayRef<std::unique_ptr<SourceCoverageView>>
+gatherLineSubViews(size_t &CurrentIdx,
+                   ArrayRef<std::unique_ptr<SourceCoverageView>> Items,
+                   unsigned LineNo) {
+  auto PrevIdx = CurrentIdx;
+  auto E = Items.size();
+  while (CurrentIdx < E &&
+         Items[CurrentIdx]->getSubViewsExpansionLine() == LineNo)
+    ++CurrentIdx;
+  return ArrayRef<std::unique_ptr<SourceCoverageView>>(Items.data() + PrevIdx,
+                                                       CurrentIdx - PrevIdx);
+}
+
+void SourceCoverageView::render(raw_ostream &OS, unsigned Offset) {
+  // Make sure that the children are in sorted order.
+  sortChildren();
+
+  SmallVector<HighlightRange, 8> AdjustedLineHighlightRanges;
+  size_t CurrentChild = 0;
+  size_t CurrentHighlightRange = 0;
+  size_t CurrentRegionMarker = 0;
+
+  line_iterator Lines(File);
+  // Advance the line iterator to the first line.
+  while (Lines.line_number() < LineStart)
+    ++Lines;
+
+  // The width of the leading columns
+  unsigned CombinedColumnWidth =
+      (Options.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
+      (Options.ShowLineNumbers ? LineNumberColumnWidth + 1 : 0);
+  // The width of the line that is used to divide between the view and the
+  // subviews.
+  unsigned DividerWidth = CombinedColumnWidth + 4;
+
+  for (size_t I = 0; I < LineCount; ++I) {
+    unsigned LineNo = I + LineStart;
+
+    // Gather the child subviews that are visible on this line.
+    auto LineSubViews = gatherLineSubViews(CurrentChild, Children, LineNo);
+
+    renderOffset(OS, Offset);
+    if (Options.ShowLineStats)
+      renderLineCoverageColumn(OS, LineStats[I]);
+    if (Options.ShowLineNumbers)
+      renderLineNumberColumn(OS, LineNo);
+
+    // Gather highlighting ranges.
+    auto LineHighlightRanges =
+        gatherLineItems(CurrentHighlightRange, HighlightRanges, LineNo);
+    auto LineRanges = LineHighlightRanges;
+    // Highlight the expansion range if there is an expansion subview on this
+    // line.
+    if (!LineSubViews.empty() && LineSubViews.front()->isExpansionSubView() &&
+        Options.Colors) {
+      insertHighlightRange(LineHighlightRanges,
+                           LineSubViews.front()->getExpansionHighlightRange(),
+                           AdjustedLineHighlightRanges);
+      LineRanges = AdjustedLineHighlightRanges;
+    }
+
+    // Display the source code for the current line.
+    StringRef Line = *Lines;
+    // Check if the line is empty, as line_iterator skips blank lines.
+    if (LineNo < Lines.line_number())
+      Line = "";
+    else if (!Lines.is_at_eof())
+      ++Lines;
+    renderLine(OS, Line, LineRanges);
+
+    // Show the region markers.
+    bool ShowMarkers = !Options.ShowLineStatsOrRegionMarkers ||
+                       LineStats[I].hasMultipleRegions();
+    auto LineMarkers = gatherLineItems(CurrentRegionMarker, Markers, LineNo);
+    if (ShowMarkers && !LineMarkers.empty()) {
+      renderOffset(OS, Offset);
+      OS.indent(CombinedColumnWidth);
+      renderRegionMarkers(OS, LineMarkers);
+    }
+
+    // Show the line's expanded child subviews.
+    bool FirstChildExpansion = true;
+    if (LineSubViews.empty())
+      continue;
+    unsigned NewOffset = Offset + 1;
+    renderViewDivider(NewOffset, DividerWidth, OS);
+    OS << "\n";
+    for (const auto &Child : LineSubViews) {
+      // If this subview shows a function instantiation, render the function's
+      // name.
+      if (Child->isInstantiationSubView()) {
+        renderOffset(OS, NewOffset);
+        OS << ' ';
+        Options.colored_ostream(OS, raw_ostream::CYAN) << Child->FunctionName
+                                                       << ":";
+        OS << "\n";
+      } else {
+        if (!FirstChildExpansion) {
+          // Re-render the current line and highlight the expansion range for
+          // this
+          // subview.
+          insertHighlightRange(LineHighlightRanges,
+                               Child->getExpansionHighlightRange(),
+                               AdjustedLineHighlightRanges);
+          renderOffset(OS, Offset);
+          OS.indent(CombinedColumnWidth + (Offset == 0 ? 0 : 1));
+          renderLine(OS, Line, AdjustedLineHighlightRanges);
+          renderViewDivider(NewOffset, DividerWidth, OS);
+          OS << "\n";
+        } else
+          FirstChildExpansion = false;
+      }
+      // Render the child subview
+      Child->render(OS, NewOffset);
+      renderViewDivider(NewOffset, DividerWidth, OS);
+      OS << "\n";
+    }
+  }
+}
+
+void
+SourceCoverageView::createLineCoverageInfo(SourceCoverageDataManager &Data) {
+  LineStats.resize(LineCount);
+  for (const auto &Region : Data.getSourceRegions()) {
+    auto Value = Region.second;
+    LineStats[Region.first.LineStart - LineStart].addRegionStartCount(Value);
+    for (unsigned Line = Region.first.LineStart + 1;
+         Line <= Region.first.LineEnd; ++Line)
+      LineStats[Line - LineStart].addRegionCount(Value);
+  }
+
+  // Reset the line stats for skipped regions.
+  for (const auto &Region : Data.getSkippedRegions()) {
+    for (unsigned Line = Region.LineStart; Line <= Region.LineEnd; ++Line)
+      LineStats[Line - LineStart] = LineCoverageInfo();
+  }
+}
+
+void
+SourceCoverageView::createHighlightRanges(SourceCoverageDataManager &Data) {
+  auto Regions = Data.getSourceRegions();
+  std::vector<bool> AlreadyHighlighted;
+  AlreadyHighlighted.resize(Regions.size(), false);
+
+  for (size_t I = 0, S = Regions.size(); I < S; ++I) {
+    const auto &Region = Regions[I];
+    auto Value = Region.second;
+    auto SrcRange = Region.first;
+    if (Value != 0)
+      continue;
+    if (AlreadyHighlighted[I])
+      continue;
+    for (size_t J = 0; J < S; ++J) {
+      if (SrcRange.contains(Regions[J].first)) {
+        AlreadyHighlighted[J] = true;
+      }
+    }
+    if (SrcRange.LineStart == SrcRange.LineEnd) {
+      HighlightRanges.push_back(HighlightRange(
+          SrcRange.LineStart, SrcRange.ColumnStart, SrcRange.ColumnEnd));
+      continue;
+    }
+    HighlightRanges.push_back(
+        HighlightRange(SrcRange.LineStart, SrcRange.ColumnStart,
+                       std::numeric_limits<unsigned>::max()));
+    HighlightRanges.push_back(
+        HighlightRange(SrcRange.LineEnd, 1, SrcRange.ColumnEnd));
+    for (unsigned Line = SrcRange.LineStart + 1; Line < SrcRange.LineEnd;
+         ++Line) {
+      HighlightRanges.push_back(
+          HighlightRange(Line, 1, std::numeric_limits<unsigned>::max()));
+    }
+  }
+
+  std::sort(HighlightRanges.begin(), HighlightRanges.end());
+
+  if (Options.Debug) {
+    for (const auto &Range : HighlightRanges) {
+      outs() << "Highlighted line " << Range.Line << ", " << Range.ColumnStart
+             << " -> ";
+      if (Range.ColumnEnd == std::numeric_limits<unsigned>::max()) {
+        outs() << "?\n";
+      } else {
+        outs() << Range.ColumnEnd << "\n";
+      }
+    }
+  }
+}
+
+void SourceCoverageView::createRegionMarkers(SourceCoverageDataManager &Data) {
+  for (const auto &Region : Data.getSourceRegions()) {
+    if (Region.first.LineStart >= LineStart)
+      Markers.push_back(RegionMarker(Region.first.LineStart,
+                                     Region.first.ColumnStart, Region.second));
+  }
+
+  if (Options.Debug) {
+    for (const auto &Marker : Markers) {
+      outs() << "Marker at " << Marker.Line << ":" << Marker.Column << " = "
+             << Marker.ExecutionCount << "\n";
+    }
+  }
+}
+
+void SourceCoverageView::load(SourceCoverageDataManager &Data) {
+  if (Options.ShowLineStats)
+    createLineCoverageInfo(Data);
+  if (Options.Colors)
+    createHighlightRanges(Data);
+  if (Options.ShowRegionMarkers)
+    createRegionMarkers(Data);
+}

Added: llvm/trunk/tools/llvm-cov/SourceCoverageView.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageView.h?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageView.h (added)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageView.h Fri Aug 22 17:56:03 2014
@@ -0,0 +1,213 @@
+//===- SourceCoverageView.h - Code coverage view for source code ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements rendering for code coverage of source code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_SOURCECOVERAGEVIEW_H
+#define LLVM_COV_SOURCECOVERAGEVIEW_H
+
+#include "CoverageViewOptions.h"
+#include "SourceCoverageDataManager.h"
+#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <vector>
+
+namespace llvm {
+
+/// \brief A code coverage view of a specific source file.
+/// It can have embedded coverage views.
+class SourceCoverageView {
+public:
+  enum SubViewKind { View, ExpansionView, InstantiationView };
+
+  /// \brief Coverage information for a single line.
+  struct LineCoverageInfo {
+    uint64_t ExecutionCount;
+    unsigned RegionCount;
+    bool Mapped;
+
+    LineCoverageInfo() : ExecutionCount(0), RegionCount(0), Mapped(false) {}
+
+    bool isMapped() const { return Mapped; }
+
+    bool hasMultipleRegions() const { return RegionCount > 1; }
+
+    void addRegionStartCount(uint64_t Count) {
+      Mapped = true;
+      ExecutionCount = Count;
+      ++RegionCount;
+    }
+
+    void addRegionCount(uint64_t Count) {
+      Mapped = true;
+      ExecutionCount = Count;
+    }
+  };
+
+  /// \brief A marker that points at the start
+  /// of a specific mapping region.
+  struct RegionMarker {
+    unsigned Line, Column;
+    uint64_t ExecutionCount;
+
+    RegionMarker(unsigned Line, unsigned Column, uint64_t Value)
+        : Line(Line), Column(Column), ExecutionCount(Value) {}
+  };
+
+  /// \brief A single line source range used to
+  /// render highlighted text.
+  struct HighlightRange {
+    enum HighlightKind {
+      /// The code that wasn't executed.
+      NotCovered,
+
+      /// The region of code that was expanded.
+      Expanded
+    };
+    HighlightKind Kind;
+    unsigned Line;
+    unsigned ColumnStart;
+    unsigned ColumnEnd;
+
+    HighlightRange(unsigned Line, unsigned ColumnStart, unsigned ColumnEnd,
+                   HighlightKind Kind = NotCovered)
+        : Kind(Kind), Line(Line), ColumnStart(ColumnStart),
+          ColumnEnd(ColumnEnd) {}
+
+    bool operator<(const HighlightRange &Other) const {
+      if (Line == Other.Line)
+        return ColumnStart < Other.ColumnStart;
+      return Line < Other.Line;
+    }
+
+    bool columnStartOverlaps(const HighlightRange &Other) const {
+      return ColumnStart <= Other.ColumnStart && ColumnEnd > Other.ColumnStart;
+    }
+    bool columnEndOverlaps(const HighlightRange &Other) const {
+      return ColumnEnd >= Other.ColumnEnd && ColumnStart < Other.ColumnEnd;
+    }
+    bool contains(const HighlightRange &Other) const {
+      if (Line != Other.Line)
+        return false;
+      return ColumnStart <= Other.ColumnStart && ColumnEnd >= Other.ColumnEnd;
+    }
+
+    bool overlaps(const HighlightRange &Other) const {
+      if (Line != Other.Line)
+        return false;
+      return columnStartOverlaps(Other) || columnEndOverlaps(Other);
+    }
+  };
+
+private:
+  const MemoryBuffer &File;
+  const CoverageViewOptions &Options;
+  unsigned LineStart, LineCount;
+  SubViewKind Kind;
+  coverage::CounterMappingRegion ExpansionRegion;
+  std::vector<std::unique_ptr<SourceCoverageView>> Children;
+  std::vector<LineCoverageInfo> LineStats;
+  std::vector<HighlightRange> HighlightRanges;
+  std::vector<RegionMarker> Markers;
+  StringRef FunctionName;
+
+  /// \brief Create the line coverage information using the coverage data.
+  void createLineCoverageInfo(SourceCoverageDataManager &Data);
+
+  /// \brief Create the line highlighting ranges using the coverage data.
+  void createHighlightRanges(SourceCoverageDataManager &Data);
+
+  /// \brief Create the region markers using the coverage data.
+  void createRegionMarkers(SourceCoverageDataManager &Data);
+
+  /// \brief Sort children by the starting location.
+  void sortChildren();
+
+  /// \brief Return a highlight range for the expansion region of this view.
+  HighlightRange getExpansionHighlightRange() const;
+
+  /// \brief Render a source line with highlighting.
+  void renderLine(raw_ostream &OS, StringRef Line,
+                  ArrayRef<HighlightRange> Ranges);
+
+  void renderOffset(raw_ostream &OS, unsigned I);
+
+  void renderViewDivider(unsigned Offset, unsigned Length, raw_ostream &OS);
+
+  /// \brief Render the line's execution count column.
+  void renderLineCoverageColumn(raw_ostream &OS, const LineCoverageInfo &Line);
+
+  /// \brief Render the line number column.
+  void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo);
+
+  /// \brief Render all the region's execution counts on a line.
+  void renderRegionMarkers(raw_ostream &OS, ArrayRef<RegionMarker> Regions);
+
+  static const unsigned LineCoverageColumnWidth = 7;
+  static const unsigned LineNumberColumnWidth = 5;
+
+public:
+  SourceCoverageView(const MemoryBuffer &File,
+                     const CoverageViewOptions &Options)
+      : File(File), Options(Options), LineStart(1), Kind(View),
+        ExpansionRegion(coverage::Counter(), 0, 0, 0, 0, 0) {
+    LineCount = File.getBuffer().count('\n') + 1;
+  }
+
+  SourceCoverageView(const MemoryBuffer &File,
+                     const CoverageViewOptions &Options, unsigned LineStart,
+                     unsigned LineEnd)
+      : File(File), Options(Options), LineStart(LineStart),
+        LineCount(LineEnd - LineStart + 1), Kind(View),
+        ExpansionRegion(coverage::Counter(), 0, 0, 0, 0, 0) {}
+
+  SourceCoverageView(SourceCoverageView &Parent, unsigned LineStart,
+                     unsigned LineEnd, StringRef FunctionName)
+      : File(Parent.File), Options(Parent.Options), LineStart(LineStart),
+        LineCount(LineEnd - LineStart + 1), Kind(InstantiationView),
+        ExpansionRegion(coverage::Counter(), 0, LineEnd, 0, LineEnd, 0),
+        FunctionName(FunctionName) {}
+
+  SourceCoverageView(const MemoryBuffer &File,
+                     const CoverageViewOptions &Options, unsigned LineStart,
+                     unsigned LineEnd,
+                     const coverage::CounterMappingRegion &ExpansionRegion)
+      : File(File), Options(Options), LineStart(LineStart),
+        LineCount(LineEnd - LineStart + 1), Kind(ExpansionView),
+        ExpansionRegion(ExpansionRegion) {}
+
+  const CoverageViewOptions &getOptions() const { return Options; }
+
+  bool isExpansionSubView() const { return Kind == ExpansionView; }
+
+  bool isInstantiationSubView() const { return Kind == InstantiationView; }
+
+  /// \brief Return the line number after which the subview expansion is shown.
+  unsigned getSubViewsExpansionLine() const {
+    return ExpansionRegion.LineStart;
+  }
+
+  void addChild(std::unique_ptr<SourceCoverageView> View) {
+    Children.push_back(std::move(View));
+  }
+
+  /// \brief Print the code coverage information for a specific
+  /// portion of a source file to the output stream.
+  void render(raw_ostream &OS, unsigned Offset = 0);
+
+  /// \brief Load the coverage information required for rendering
+  /// from the mapping regions in the data manager.
+  void load(SourceCoverageDataManager &Data);
+};
+
+} // namespace llvm
+
+#endif // LLVM_COV_SOURCECOVERAGEVIEW_H

Added: llvm/trunk/tools/llvm-cov/TestingSupport.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/TestingSupport.cpp?rev=216300&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-cov/TestingSupport.cpp (added)
+++ llvm/trunk/tools/llvm-cov/TestingSupport.cpp Fri Aug 22 17:56:03 2014
@@ -0,0 +1,92 @@
+//===- TestingSupport.cpp - Convert objects files into test files --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryObject.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include <system_error>
+#include <functional>
+
+using namespace llvm;
+using namespace object;
+
+int convert_for_testing_main(int argc, const char **argv) {
+  sys::PrintStackTraceOnErrorSignal();
+  PrettyStackTraceProgram X(argc, argv);
+  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+  cl::opt<std::string> InputSourceFile(cl::Positional, cl::Required,
+                                       cl::desc("<Source file>"));
+
+  cl::opt<std::string> OutputFilename(
+      "o", cl::Required,
+      cl::desc(
+          "File with the profile data obtained after an instrumented run"));
+
+  cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
+
+  auto ObjErr = llvm::object::ObjectFile::createObjectFile(InputSourceFile);
+  if (auto Err = ObjErr.getError()) {
+    errs() << "error: " << Err.message() << "\n";
+    return 1;
+  }
+  ObjectFile *OF = ObjErr.get().getBinary().get();
+  auto BytesInAddress = OF->getBytesInAddress();
+  if (BytesInAddress != 8) {
+    errs() << "error: 64 bit binary expected\n";
+    return 1;
+  }
+
+  // Look for the sections that we are interested in.
+  int FoundSectionCount = 0;
+  SectionRef ProfileNames, CoverageMapping;
+  for (const auto &Section : OF->sections()) {
+    StringRef Name;
+    if (Section.getName(Name))
+      return 1;
+    if (Name == "__llvm_prf_names") {
+      ProfileNames = Section;
+    } else if (Name == "__llvm_covmap") {
+      CoverageMapping = Section;
+    } else
+      continue;
+    ++FoundSectionCount;
+  }
+  if (FoundSectionCount != 2)
+    return 1;
+
+  // Get the contents of the given sections.
+  StringRef CoverageMappingData;
+  uint64_t ProfileNamesAddress;
+  StringRef ProfileNamesData;
+  if (CoverageMapping.getContents(CoverageMappingData) ||
+      ProfileNames.getAddress(ProfileNamesAddress) ||
+      ProfileNames.getContents(ProfileNamesData))
+    return 1;
+
+  int FD;
+  if (auto Err =
+          sys::fs::openFileForWrite(OutputFilename, FD, sys::fs::F_None)) {
+    errs() << "error: " << Err.message() << "\n";
+    return 1;
+  }
+
+  raw_fd_ostream OS(FD, true);
+  OS << "llvmcovmtestdata";
+  encodeULEB128(ProfileNamesData.size(), OS);
+  encodeULEB128(ProfileNamesAddress, OS);
+  OS << ProfileNamesData << CoverageMappingData;
+
+  return 0;
+}

Modified: llvm/trunk/tools/llvm-cov/llvm-cov.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/llvm-cov.cpp?rev=216300&r1=216299&r2=216300&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/llvm-cov.cpp (original)
+++ llvm/trunk/tools/llvm-cov/llvm-cov.cpp Fri Aug 22 17:56:03 2014
@@ -11,9 +11,63 @@
 //
 //===----------------------------------------------------------------------===//
 
-/// \brief The main function for the gcov compatible coverage tool
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Path.h"
+#include <string>
+
+using namespace llvm;
+
+/// \brief The main entry point for the 'show' subcommand.
+int show_main(int argc, const char **argv);
+
+/// \brief The main entry point for the 'report' subcommand.
+int report_main(int argc, const char **argv);
+
+/// \brief The main entry point for the 'convert-for-testing' subcommand.
+int convert_for_testing_main(int argc, const char **argv);
+
+/// \brief The main entry point for the gcov compatible coverage tool.
 int gcov_main(int argc, const char **argv);
 
 int main(int argc, const char **argv) {
+  // If argv[0] is or ends with 'gcov', always be gcov compatible
+  if (sys::path::stem(argv[0]).endswith_lower("gcov"))
+    return gcov_main(argc, argv);
+
+  // Check if we are invoking a specific tool command.
+  if (argc > 1) {
+    int (*func)(int, const char **) = nullptr;
+
+    StringRef command = argv[1];
+    if (command.equals_lower("show"))
+      func = show_main;
+    else if (command.equals_lower("report"))
+      func = report_main;
+    else if (command.equals_lower("convert-for-testing"))
+      func = convert_for_testing_main;
+    else if (command.equals_lower("gcov"))
+      func = gcov_main;
+
+    if (func) {
+      std::string Invocation(std::string(argv[0]) + " " + argv[1]);
+      argv[1] = Invocation.c_str();
+      return func(argc - 1, argv + 1);
+    }
+  }
+
+  // Give a warning and fall back to gcov
+  errs().changeColor(raw_ostream::RED);
+  errs() << "warning:";
+  // Assume that argv[1] wasn't a command when it stats with a '-' or is a
+  // filename (i.e. contains a '.')
+  if (argc > 1 && !StringRef(argv[1]).startswith("-") &&
+      StringRef(argv[1]).find(".") == StringRef::npos)
+    errs() << " Unrecognized command '" << argv[1] << "'.";
+  errs() << " Using the gcov compatible mode "
+            "(this behaviour may be dropped in the future).";
+  errs().resetColor();
+  errs() << "\n";
+
   return gcov_main(argc, argv);
 }





More information about the llvm-commits mailing list