<div dir="ltr">The big-endian buildbots are failing, I will commit an XFAIL for big-endian for now.</div><div class="gmail_extra"><br><br><div class="gmail_quote">2014-08-22 15:56 GMT-07:00 Alex Lorenz <span dir="ltr"><<a href="mailto:arphaman@gmail.com" target="_blank">arphaman@gmail.com</a>></span>:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: arphaman<br>
Date: Fri Aug 22 17:56:03 2014<br>
New Revision: 216300<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=216300&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=216300&view=rev</a><br>
Log:<br>
llvm-cov: add code coverage tool that's based on coverage mapping format and clang's pgo.<br>
<br>
This commit expands llvm-cov's functionality by adding support for a new code coverage<br>
tool that uses LLVM's coverage mapping format and clang's instrumentation based profiling.<br>
The gcov compatible tool can be invoked by supplying the 'gcov' command as the first argument,<br>
or by modifying the tool's name to end with 'gcov'.<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D4445" target="_blank">http://reviews.llvm.org/D4445</a><br>
<br>
Added:<br>
    llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.covmapping   (with props)<br>
    llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata   (with props)<br>
    llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping   (with props)<br>
    llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata   (with props)<br>
    llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping   (with props)<br>
    llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata   (with props)<br>
    llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp<br>
    llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp<br>
    llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp<br>
    llvm/trunk/tools/llvm-cov/CodeCoverage.cpp<br>
    llvm/trunk/tools/llvm-cov/CoverageFilters.cpp<br>
    llvm/trunk/tools/llvm-cov/CoverageFilters.h<br>
    llvm/trunk/tools/llvm-cov/CoverageReport.cpp<br>
    llvm/trunk/tools/llvm-cov/CoverageReport.h<br>
    llvm/trunk/tools/llvm-cov/CoverageSummary.cpp<br>
    llvm/trunk/tools/llvm-cov/CoverageSummary.h<br>
    llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp<br>
    llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h<br>
    llvm/trunk/tools/llvm-cov/CoverageViewOptions.h<br>
    llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h<br>
    llvm/trunk/tools/llvm-cov/RenderingSupport.h<br>
    llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp<br>
    llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h<br>
    llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp<br>
    llvm/trunk/tools/llvm-cov/SourceCoverageView.h<br>
    llvm/trunk/tools/llvm-cov/TestingSupport.cpp<br>
Modified:<br>
    llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp<br>
    llvm/trunk/test/tools/llvm-cov/Inputs/README<br>
    llvm/trunk/tools/llvm-cov/CMakeLists.txt<br>
    llvm/trunk/tools/llvm-cov/LLVMBuild.txt<br>
    llvm/trunk/tools/llvm-cov/Makefile<br>
    llvm/trunk/tools/llvm-cov/llvm-cov.cpp<br>
<br>
Modified: llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp?rev=216300&r1=216299&r2=216300&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp?rev=216300&r1=216299&r2=216300&view=diff</a><br>

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

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

==============================================================================<br>
Binary file - no diff available.<br>
<br>
Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.covmapping<br>
------------------------------------------------------------------------------<br>
    svn:mime-type = application/octet-stream<br>
<br>
Added: llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata?rev=216300&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata?rev=216300&view=auto</a><br>

==============================================================================<br>
Binary file - no diff available.<br>
<br>
Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata<br>
------------------------------------------------------------------------------<br>
    svn:mime-type = application/octet-stream<br>
<br>
Added: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping?rev=216300&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping?rev=216300&view=auto</a><br>

==============================================================================<br>
Binary file - no diff available.<br>
<br>
Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping<br>
------------------------------------------------------------------------------<br>
    svn:mime-type = application/octet-stream<br>
<br>
Added: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata?rev=216300&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata?rev=216300&view=auto</a><br>

==============================================================================<br>
Binary file - no diff available.<br>
<br>
Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata<br>
------------------------------------------------------------------------------<br>
    svn:mime-type = application/octet-stream<br>
<br>
Added: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping?rev=216300&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping?rev=216300&view=auto</a><br>

==============================================================================<br>
Binary file - no diff available.<br>
<br>
Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping<br>
------------------------------------------------------------------------------<br>
    svn:mime-type = application/octet-stream<br>
<br>
Added: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata?rev=216300&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata?rev=216300&view=auto</a><br>

==============================================================================<br>
Binary file - no diff available.<br>
<br>
Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata<br>
------------------------------------------------------------------------------<br>
    svn:mime-type = application/octet-stream<br>
<br>
Added: llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp?rev=216300&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp?rev=216300&view=auto</a><br>

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

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

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

==============================================================================<br>
--- llvm/trunk/tools/llvm-cov/CMakeLists.txt (original)<br>
+++ llvm/trunk/tools/llvm-cov/CMakeLists.txt Fri Aug 22 17:56:03 2014<br>
@@ -1,6 +1,14 @@<br>
-set(LLVM_LINK_COMPONENTS core support )<br>
+set(LLVM_LINK_COMPONENTS core support object profiledata)<br>
<br>
 add_llvm_tool(llvm-cov<br>
   llvm-cov.cpp<br>
   gcov.cpp<br>
+  CodeCoverage.cpp<br>
+  CoverageFilters.cpp<br>
+  CoverageReport.cpp<br>
+  CoverageSummary.cpp<br>
+  CoverageSummaryInfo.cpp<br>
+  SourceCoverageDataManager.cpp<br>
+  SourceCoverageView.cpp<br>
+  TestingSupport.cpp<br>
   )<br>
<br>
Added: llvm/trunk/tools/llvm-cov/CodeCoverage.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=216300&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=216300&view=auto</a><br>

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

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

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

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

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

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

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

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

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

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

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

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

==============================================================================<br>
--- llvm/trunk/tools/llvm-cov/Makefile (original)<br>
+++ llvm/trunk/tools/llvm-cov/Makefile Fri Aug 22 17:56:03 2014<br>
@@ -9,7 +9,7 @@<br>
<br>
 LEVEL := ../..<br>
 TOOLNAME := llvm-cov<br>
-LINK_COMPONENTS := core support<br>
+LINK_COMPONENTS := core support profiledata object<br>
<br>
 # This tool has no plugins, optimize startup time.<br>
 TOOL_NO_EXPORTS := 1<br>
<br>
Added: llvm/trunk/tools/llvm-cov/RenderingSupport.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/RenderingSupport.h?rev=216300&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/RenderingSupport.h?rev=216300&view=auto</a><br>

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

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

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

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

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

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

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