Revert r253253 and r253126: "Don't recompute LCSSA after loop-unrolling when possible."
[oota-llvm.git] / tools / llvm-cov / CodeCoverage.cpp
index 3945b17bc3dbaebe72ddb10dddfb89b7e4c580cf..8dc4d665f23ca62784c959895e7c3f93cbc63d94 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "RenderingSupport.h"
-#include "CoverageViewOptions.h"
 #include "CoverageFilters.h"
-#include "SourceCoverageDataManager.h"
-#include "SourceCoverageView.h"
-#include "CoverageSummary.h"
 #include "CoverageReport.h"
-#include "llvm/ADT/StringRef.h"
+#include "CoverageViewOptions.h"
+#include "SourceCoverageView.h"
 #include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
 #include "llvm/ProfileData/CoverageMapping.h"
-#include "llvm/ProfileData/CoverageMappingReader.h"
+#include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FileSystem.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/MemoryObject.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Support/Signals.h"
 #include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
 #include <functional>
 #include <system_error>
-#include <unordered_map>
 
 using namespace llvm;
 using namespace coverage;
 
 namespace {
-/// \brief Distribute the functions into instantiation sets.
-/// An instantiation set is a collection of functions
-/// that have the same source code, e.g.
-/// template functions specializations.
-class FunctionInstantiationSetCollector {
-  ArrayRef<FunctionCoverageMapping> FunctionMappings;
-  typedef uint64_t KeyType;
-  typedef std::vector<const FunctionCoverageMapping *> SetType;
-  std::unordered_map<uint64_t, SetType> InstantiatedFunctions;
-
-  static KeyType getKey(const CountedRegion &R) {
-    return uint64_t(R.LineStart) | uint64_t(R.ColumnStart) << 32;
-  }
-
-public:
-  void insert(const FunctionCoverageMapping &Function, unsigned FileID) {
-    KeyType Key = 0;
-    for (const auto &R : Function.CountedRegions) {
-      if (R.FileID == FileID) {
-        Key = getKey(R);
-        break;
-      }
-    }
-    auto I = InstantiatedFunctions.find(Key);
-    if (I == InstantiatedFunctions.end()) {
-      SetType Set;
-      Set.push_back(&Function);
-      InstantiatedFunctions.insert(std::make_pair(Key, Set));
-    } else
-      I->second.push_back(&Function);
-  }
-
-  std::unordered_map<KeyType, SetType>::iterator begin() {
-    return InstantiatedFunctions.begin();
-  }
-
-  std::unordered_map<KeyType, SetType>::iterator end() {
-    return InstantiatedFunctions.end();
-  }
-};
-
 /// \brief The implementation of the coverage tool.
 class CodeCoverageTool {
 public:
@@ -100,47 +54,21 @@ public:
   /// \brief Return a memory buffer for the given source file.
   ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
 
-  /// \brief Return true if two filepaths refer to the same file.
-  bool equivalentFiles(StringRef A, StringRef B);
-
-  /// \brief Collect a set of function's file ids which correspond to the
-  /// given source file. Return false if the set is empty.
-  bool gatherInterestingFileIDs(StringRef SourceFile,
-                                const FunctionCoverageMapping &Function,
-                                SmallSet<unsigned, 8> &InterestingFileIDs);
-
-  /// \brief Find the file id which is not an expanded file id.
-  bool findMainViewFileID(StringRef SourceFile,
-                          const FunctionCoverageMapping &Function,
-                          unsigned &MainViewFileID);
-
-  bool findMainViewFileID(const FunctionCoverageMapping &Function,
-                          unsigned &MainViewFileID);
-
-  /// \brief Create a source view which shows coverage for an expansion
-  /// of a file.
-  void createExpansionSubView(const CountedRegion &ExpandedRegion,
-                              const FunctionCoverageMapping &Function,
-                              SourceCoverageView &Parent);
+  /// \brief Create source views for the expansions of the view.
+  void attachExpansionSubViews(SourceCoverageView &View,
+                               ArrayRef<ExpansionRecord> Expansions,
+                               CoverageMapping &Coverage);
 
-  void createExpansionSubViews(SourceCoverageView &View, unsigned ViewFileID,
-                               const FunctionCoverageMapping &Function);
-
-  /// \brief Create a source view which shows coverage for an instantiation
-  /// of a funciton.
-  void createInstantiationSubView(StringRef SourceFile,
-                                  const FunctionCoverageMapping &Function,
-                                  SourceCoverageView &View);
+  /// \brief Create the source view of a particular function.
+  std::unique_ptr<SourceCoverageView>
+  createFunctionView(const FunctionRecord &Function, CoverageMapping &Coverage);
 
   /// \brief Create the main source view of a particular source file.
-  /// Return true if this particular source file is not covered.
-  bool
-  createSourceFileView(StringRef SourceFile, SourceCoverageView &View,
-                       ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
-                       bool UseOnlyRegionsInMainFile = false);
+  std::unique_ptr<SourceCoverageView>
+  createSourceFileView(StringRef SourceFile, CoverageMapping &Coverage);
 
   /// \brief Load the coverage mapping data. Return true if an error occured.
-  bool load();
+  std::unique_ptr<CoverageMapping> load();
 
   int run(Command Cmd, int argc, const char **argv);
 
@@ -152,15 +80,16 @@ public:
   int report(int argc, const char **argv,
              CommandLineParserType commandLineParser);
 
-  StringRef ObjectFilename;
+  std::string ObjectFilename;
   CoverageViewOptions ViewOpts;
-  std::unique_ptr<IndexedInstrProfReader> PGOReader;
+  std::string PGOFilename;
   CoverageFiltersMatchAll Filters;
   std::vector<std::string> SourceFiles;
   std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
       LoadedSourceFiles;
-  std::vector<FunctionCoverageMapping> FunctionMappingRecords;
   bool CompareFilenamesOnly;
+  StringMap<std::string> RemappedFilenames;
+  std::string CoverageArch;
 };
 }
 
@@ -173,262 +102,142 @@ void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
 
 ErrorOr<const MemoryBuffer &>
 CodeCoverageTool::getSourceFile(StringRef SourceFile) {
-  SmallString<256> Path(SourceFile);
-  sys::fs::make_absolute(Path);
-  for (const auto &Files : LoadedSourceFiles) {
-    if (equivalentFiles(Path.str(), Files.first)) {
-      return *Files.second;
-    }
+  // If we've remapped filenames, look up the real location for this file.
+  if (!RemappedFilenames.empty()) {
+    auto Loc = RemappedFilenames.find(SourceFile);
+    if (Loc != RemappedFilenames.end())
+      SourceFile = Loc->second;
   }
+  for (const auto &Files : LoadedSourceFiles)
+    if (sys::fs::equivalent(SourceFile, Files.first))
+      return *Files.second;
   auto Buffer = MemoryBuffer::getFile(SourceFile);
   if (auto EC = Buffer.getError()) {
     error(EC.message(), SourceFile);
     return EC;
   }
-  LoadedSourceFiles.push_back(std::make_pair(
-      std::string(Path.begin(), Path.end()), std::move(Buffer.get())));
+  LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get()));
   return *LoadedSourceFiles.back().second;
 }
 
-/// \brief Return a line start - line end range which contains
-/// all the mapping regions of a given function with a particular file id.
-std::pair<unsigned, unsigned>
-findExpandedFileInterestingLineRange(unsigned FileID,
-                                     const FunctionCoverageMapping &Function) {
-  unsigned LineStart = std::numeric_limits<unsigned>::max();
-  unsigned LineEnd = 0;
-  for (const auto &CR : Function.CountedRegions) {
-    if (CR.FileID != FileID)
+void
+CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View,
+                                          ArrayRef<ExpansionRecord> Expansions,
+                                          CoverageMapping &Coverage) {
+  if (!ViewOpts.ShowExpandedRegions)
+    return;
+  for (const auto &Expansion : Expansions) {
+    auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
+    if (ExpansionCoverage.empty())
       continue;
-    LineStart = std::min(CR.LineStart, LineStart);
-    LineEnd = std::max(CR.LineEnd, LineEnd);
-  }
-  return std::make_pair(LineStart, LineEnd);
-}
-
-bool CodeCoverageTool::equivalentFiles(StringRef A, StringRef B) {
-  if (CompareFilenamesOnly)
-    return sys::path::filename(A).equals_lower(sys::path::filename(B));
-  return sys::fs::equivalent(A, B);
-}
-
-bool CodeCoverageTool::gatherInterestingFileIDs(
-    StringRef SourceFile, const FunctionCoverageMapping &Function,
-    SmallSet<unsigned, 8> &InterestingFileIDs) {
-  bool Interesting = false;
-  for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
-    if (equivalentFiles(SourceFile, Function.Filenames[I])) {
-      InterestingFileIDs.insert(I);
-      Interesting = true;
-    }
-  }
-  return Interesting;
-}
-
-bool
-CodeCoverageTool::findMainViewFileID(StringRef SourceFile,
-                                     const FunctionCoverageMapping &Function,
-                                     unsigned &MainViewFileID) {
-  llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
-  llvm::SmallVector<bool, 8> FilenameEquivalence(Function.Filenames.size(),
-                                                 false);
-  for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
-    if (equivalentFiles(SourceFile, Function.Filenames[I]))
-      FilenameEquivalence[I] = true;
-  }
-  for (const auto &CR : Function.CountedRegions) {
-    if (CR.Kind == CounterMappingRegion::ExpansionRegion &&
-        FilenameEquivalence[CR.FileID])
-      IsExpandedFile[CR.ExpandedFileID] = true;
-  }
-  for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
-    if (!FilenameEquivalence[I] || IsExpandedFile[I])
+    auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
+    if (!SourceBuffer)
       continue;
-    MainViewFileID = I;
-    return false;
-  }
-  return true;
-}
 
-bool
-CodeCoverageTool::findMainViewFileID(const FunctionCoverageMapping &Function,
-                                     unsigned &MainViewFileID) {
-  llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
-  for (const auto &CR : Function.CountedRegions) {
-    if (CR.Kind == CounterMappingRegion::ExpansionRegion)
-      IsExpandedFile[CR.ExpandedFileID] = true;
+    auto SubViewExpansions = ExpansionCoverage.getExpansions();
+    auto SubView = llvm::make_unique<SourceCoverageView>(
+        SourceBuffer.get(), ViewOpts, std::move(ExpansionCoverage));
+    attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
+    View.addExpansion(Expansion.Region, std::move(SubView));
   }
-  for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
-    if (IsExpandedFile[I])
-      continue;
-    MainViewFileID = I;
-    return false;
-  }
-  return true;
 }
 
-void CodeCoverageTool::createExpansionSubView(
-    const CountedRegion &ExpandedRegion,
-    const FunctionCoverageMapping &Function, SourceCoverageView &Parent) {
-  auto ExpandedLines = findExpandedFileInterestingLineRange(
-      ExpandedRegion.ExpandedFileID, Function);
-  if (ViewOpts.Debug)
-    llvm::outs() << "Expansion of " << ExpandedRegion.ExpandedFileID << ":"
-                 << ExpandedLines.first << " -> " << ExpandedLines.second
-                 << " @ " << ExpandedRegion.FileID << ", "
-                 << ExpandedRegion.LineStart << ":"
-                 << ExpandedRegion.ColumnStart << "\n";
-  auto SourceBuffer =
-      getSourceFile(Function.Filenames[ExpandedRegion.ExpandedFileID]);
+std::unique_ptr<SourceCoverageView>
+CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
+                                     CoverageMapping &Coverage) {
+  auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
+  if (FunctionCoverage.empty())
+    return nullptr;
+  auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
   if (!SourceBuffer)
-    return;
-  auto SubView = llvm::make_unique<SourceCoverageView>(
-      SourceBuffer.get(), Parent.getOptions(), ExpandedLines.first,
-      ExpandedLines.second, ExpandedRegion);
-  SourceCoverageDataManager RegionManager;
-  for (const auto &CR : Function.CountedRegions) {
-    if (CR.FileID == ExpandedRegion.ExpandedFileID)
-      RegionManager.insert(CR);
-  }
-  SubView->load(RegionManager);
-  createExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function);
-  Parent.addChild(std::move(SubView));
-}
+    return nullptr;
 
-void CodeCoverageTool::createExpansionSubViews(
-    SourceCoverageView &View, unsigned ViewFileID,
-    const FunctionCoverageMapping &Function) {
-  if (!ViewOpts.ShowExpandedRegions)
-    return;
-  for (const auto &CR : Function.CountedRegions) {
-    if (CR.Kind != CounterMappingRegion::ExpansionRegion)
-      continue;
-    if (CR.FileID != ViewFileID)
-      continue;
-    createExpansionSubView(CR, Function, View);
-  }
-}
+  auto Expansions = FunctionCoverage.getExpansions();
+  auto View = llvm::make_unique<SourceCoverageView>(
+      SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage));
+  attachExpansionSubViews(*View, Expansions, Coverage);
 
-void CodeCoverageTool::createInstantiationSubView(
-    StringRef SourceFile, const FunctionCoverageMapping &Function,
-    SourceCoverageView &View) {
-  SourceCoverageDataManager RegionManager;
-  SmallSet<unsigned, 8> InterestingFileIDs;
-  if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs))
-    return;
-  // Get the interesting regions
-  for (const auto &CR : Function.CountedRegions) {
-    if (InterestingFileIDs.count(CR.FileID))
-      RegionManager.insert(CR);
-  }
-  View.load(RegionManager);
-  unsigned MainFileID;
-  if (findMainViewFileID(SourceFile, Function, MainFileID))
-    return;
-  createExpansionSubViews(View, MainFileID, Function);
+  return View;
 }
 
-bool CodeCoverageTool::createSourceFileView(
-    StringRef SourceFile, SourceCoverageView &View,
-    ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
-    bool UseOnlyRegionsInMainFile) {
-  SourceCoverageDataManager RegionManager;
-  FunctionInstantiationSetCollector InstantiationSetCollector;
-
-  for (const auto &Function : FunctionMappingRecords) {
-    unsigned MainFileID;
-    if (findMainViewFileID(SourceFile, Function, MainFileID))
-      continue;
-    SmallSet<unsigned, 8> InterestingFileIDs;
-    if (UseOnlyRegionsInMainFile) {
-      InterestingFileIDs.insert(MainFileID);
-    } else if (!gatherInterestingFileIDs(SourceFile, Function,
-                                         InterestingFileIDs))
-      continue;
-    // Get the interesting regions
-    for (const auto &CR : Function.CountedRegions) {
-      if (InterestingFileIDs.count(CR.FileID))
-        RegionManager.insert(CR);
+std::unique_ptr<SourceCoverageView>
+CodeCoverageTool::createSourceFileView(StringRef SourceFile,
+                                       CoverageMapping &Coverage) {
+  auto SourceBuffer = getSourceFile(SourceFile);
+  if (!SourceBuffer)
+    return nullptr;
+  auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
+  if (FileCoverage.empty())
+    return nullptr;
+
+  auto Expansions = FileCoverage.getExpansions();
+  auto View = llvm::make_unique<SourceCoverageView>(
+      SourceBuffer.get(), ViewOpts, std::move(FileCoverage));
+  attachExpansionSubViews(*View, Expansions, Coverage);
+
+  for (auto Function : Coverage.getInstantiations(SourceFile)) {
+    auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
+    auto SubViewExpansions = SubViewCoverage.getExpansions();
+    auto SubView = llvm::make_unique<SourceCoverageView>(
+        SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
+    attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
+
+    if (SubView) {
+      unsigned FileID = Function->CountedRegions.front().FileID;
+      unsigned Line = 0;
+      for (const auto &CR : Function->CountedRegions)
+        if (CR.FileID == FileID)
+          Line = std::max(CR.LineEnd, Line);
+      View->addInstantiation(Function->Name, Line, std::move(SubView));
     }
-    InstantiationSetCollector.insert(Function, MainFileID);
-    createExpansionSubViews(View, MainFileID, Function);
   }
-  if (RegionManager.getSourceRegions().empty())
-    return true;
-  View.load(RegionManager);
-  // Show instantiations
-  if (!ViewOpts.ShowFunctionInstantiations)
+  return View;
+}
+
+static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
+  sys::fs::file_status Status;
+  if (sys::fs::status(LHS, Status))
     return false;
-  for (const auto &InstantiationSet : InstantiationSetCollector) {
-    if (InstantiationSet.second.size() < 2)
-      continue;
-    auto InterestingRange = findExpandedFileInterestingLineRange(
-        InstantiationSet.second.front()->CountedRegions.front().FileID,
-        *InstantiationSet.second.front());
-    for (auto Function : InstantiationSet.second) {
-      auto SubView = llvm::make_unique<SourceCoverageView>(
-          View, InterestingRange.first, InterestingRange.second,
-          Function->Name);
-      createInstantiationSubView(SourceFile, *Function, *SubView);
-      View.addChild(std::move(SubView));
-    }
-  }
-  return false;
+  auto LHSTime = Status.getLastModificationTime();
+  if (sys::fs::status(RHS, Status))
+    return false;
+  auto RHSTime = Status.getLastModificationTime();
+  return LHSTime > RHSTime;
 }
 
-bool CodeCoverageTool::load() {
-  auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
-  if (auto EC = CounterMappingBuff.getError()) {
-    error(EC.message(), ObjectFilename);
-    return true;
+std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
+  if (modifiedTimeGT(ObjectFilename, PGOFilename))
+    errs() << "warning: profile data may be out of date - object is newer\n";
+  auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename,
+                                             CoverageArch);
+  if (std::error_code EC = CoverageOrErr.getError()) {
+    colored_ostream(errs(), raw_ostream::RED)
+        << "error: Failed to load coverage: " << EC.message();
+    errs() << "\n";
+    return nullptr;
   }
-  ObjectFileCoverageMappingReader MappingReader(CounterMappingBuff.get());
-  if (auto EC = MappingReader.readHeader()) {
-    error(EC.message(), ObjectFilename);
-    return true;
+  auto Coverage = std::move(CoverageOrErr.get());
+  unsigned Mismatched = Coverage->getMismatchedCount();
+  if (Mismatched) {
+    colored_ostream(errs(), raw_ostream::RED)
+        << "warning: " << Mismatched << " functions have mismatched data. ";
+    errs() << "\n";
   }
 
-  std::vector<uint64_t> Counts;
-  for (const auto &I : MappingReader) {
-    FunctionCoverageMapping Function(I.FunctionName, I.Filenames);
-
-    // Create the mapping regions with evaluated execution counts
-    Counts.clear();
-    PGOReader->getFunctionCounts(Function.Name, I.FunctionHash, Counts);
-
-    // Get the biggest referenced counters
-    bool RegionError = false;
-    CounterMappingContext Ctx(I.Expressions, Counts);
-    for (const auto &R : I.MappingRegions) {
-      // Compute the values of mapped regions
-      if (ViewOpts.Debug) {
-        outs() << "File " << R.FileID << "| " << R.LineStart << ":"
-               << R.ColumnStart << " -> " << R.LineEnd << ":" << R.ColumnEnd
-               << " = ";
-        Ctx.dump(R.Count);
-        if (R.Kind == CounterMappingRegion::ExpansionRegion) {
-          outs() << " (Expanded file id = " << R.ExpandedFileID << ") ";
+  if (CompareFilenamesOnly) {
+    auto CoveredFiles = Coverage.get()->getUniqueSourceFiles();
+    for (auto &SF : SourceFiles) {
+      StringRef SFBase = sys::path::filename(SF);
+      for (const auto &CF : CoveredFiles)
+        if (SFBase == sys::path::filename(CF)) {
+          RemappedFilenames[CF] = SF;
+          SF = CF;
+          break;
         }
-        outs() << "\n";
-      }
-      ErrorOr<int64_t> ExecutionCount = Ctx.evaluate(R.Count);
-      if (ExecutionCount) {
-        Function.CountedRegions.push_back(CountedRegion(R, *ExecutionCount));
-      } else if (!RegionError) {
-        colored_ostream(errs(), raw_ostream::RED)
-            << "error: Regions and counters don't match in a function '"
-            << Function.Name << "' (re-run the instrumented binary).";
-        errs() << "\n";
-        RegionError = true;
-      }
     }
-
-    if (RegionError || !Filters.matches(Function))
-      continue;
-
-    FunctionMappingRecords.push_back(Function);
   }
-  return false;
+
+  return Coverage;
 }
 
 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
@@ -437,20 +246,28 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
   PrettyStackTraceProgram X(argc, argv);
   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
 
+  cl::opt<std::string, true> ObjectFilename(
+      cl::Positional, cl::Required, cl::location(this->ObjectFilename),
+      cl::desc("Covered executable or object file."));
+
   cl::list<std::string> InputSourceFiles(
       cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
 
-  cl::opt<std::string> PGOFilename(
-      "instr-profile", cl::Required,
+  cl::opt<std::string, true> PGOFilename(
+      "instr-profile", cl::Required, cl::location(this->PGOFilename),
       cl::desc(
           "File with the profile data obtained after an instrumented run"));
 
+  cl::opt<std::string> Arch(
+      "arch", cl::desc("architecture of the coverage mapping binary"));
+
   cl::opt<bool> DebugDump("dump", cl::Optional,
                           cl::desc("Show internal debug dump"));
 
   cl::opt<bool> FilenameEquivalence(
       "filename-equivalence", cl::Optional,
-      cl::desc("Compare the filenames instead of full filepaths"));
+      cl::desc("Treat source files as equivalent to paths in the coverage data "
+               "when the file names match, even if the full paths do not"));
 
   cl::OptionCategory FilteringCategory("Function filtering options");
 
@@ -489,15 +306,18 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
                "greater than the given threshold"),
       cl::cat(FilteringCategory));
 
+  cl::opt<cl::boolOrDefault> UseColor(
+      "use-color", cl::desc("Emit colored output (default=autodetect)"),
+      cl::init(cl::BOU_UNSET));
+
   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
     ViewOpts.Debug = DebugDump;
     CompareFilenamesOnly = FilenameEquivalence;
 
-    if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader)) {
-      error(EC.message(), PGOFilename);
-      return 1;
-    }
+    ViewOpts.Colors = UseColor == cl::BOU_UNSET
+                          ? sys::Process::StandardOutHasColors()
+                          : UseColor == cl::BOU_TRUE;
 
     // Create the function filters
     if (!NameFilters.empty() || !NameRegexFilters.empty()) {
@@ -529,27 +349,25 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
       Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
     }
 
-    SourceFiles = InputSourceFiles;
+    if (!Arch.empty() &&
+        Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
+      errs() << "error: Unknown architecture: " << Arch << "\n";
+      return 1;
+    }
+    CoverageArch = Arch;
+
+    for (const auto &File : InputSourceFiles) {
+      SmallString<128> Path(File);
+      if (!CompareFilenamesOnly)
+        if (std::error_code EC = sys::fs::make_absolute(Path)) {
+          errs() << "error: " << File << ": " << EC.message();
+          return 1;
+        }
+      SourceFiles.push_back(Path.str());
+    }
     return 0;
   };
 
-  // Parse the object filename
-  if (argc > 1) {
-    StringRef Arg(argv[1]);
-    if (Arg.equals_lower("-help") || Arg.equals_lower("-version")) {
-      cl::ParseCommandLineOptions(2, argv, "LLVM code coverage tool\n");
-      return 0;
-    }
-    ObjectFilename = Arg;
-
-    argv[1] = argv[0];
-    --argc;
-    ++argv;
-  } else {
-    errs() << sys::path::filename(argv[0]) << ": No executable file given!\n";
-    return 1;
-  }
-
   switch (Cmd) {
   case Show:
     return show(argc, argv, commandLineParser);
@@ -588,15 +406,10 @@ int CodeCoverageTool::show(int argc, const char **argv,
                                    cl::desc("Show function instantiations"),
                                    cl::cat(ViewCategory));
 
-  cl::opt<bool> NoColors("no-colors", cl::Optional,
-                         cl::desc("Don't show text colors"), cl::init(false),
-                         cl::cat(ViewCategory));
-
   auto Err = commandLineParser(argc, argv);
   if (Err)
     return Err;
 
-  ViewOpts.Colors = !NoColors;
   ViewOpts.ShowLineNumbers = true;
   ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
                            !ShowRegions || ShowBestLineRegionsCounts;
@@ -605,29 +418,28 @@ int CodeCoverageTool::show(int argc, const char **argv,
   ViewOpts.ShowExpandedRegions = ShowExpansions;
   ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
 
-  if (load())
+  auto Coverage = load();
+  if (!Coverage)
     return 1;
 
   if (!Filters.empty()) {
     // Show functions
-    for (const auto &Function : FunctionMappingRecords) {
-      unsigned MainFileID;
-      if (findMainViewFileID(Function, MainFileID))
+    for (const auto &Function : Coverage->getCoveredFunctions()) {
+      if (!Filters.matches(Function))
         continue;
-      StringRef SourceFile = Function.Filenames[MainFileID];
-      auto SourceBuffer = getSourceFile(SourceFile);
-      if (!SourceBuffer)
-        return 1;
-      auto Range = findExpandedFileInterestingLineRange(MainFileID, Function);
-      SourceCoverageView mainView(SourceBuffer.get(), ViewOpts, Range.first,
-                                  Range.second);
-      createSourceFileView(SourceFile, mainView, Function, true);
-      ViewOpts.colored_ostream(outs(), raw_ostream::CYAN)
-          << Function.Name << " from " << SourceFile << ":";
-      outs() << "\n";
-      mainView.render(outs());
-      if (FunctionMappingRecords.size() > 1)
+
+      auto mainView = createFunctionView(Function, *Coverage);
+      if (!mainView) {
+        ViewOpts.colored_ostream(outs(), raw_ostream::RED)
+            << "warning: Could not read coverage for '" << Function.Name;
         outs() << "\n";
+        continue;
+      }
+      ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << Function.Name
+                                                          << ":";
+      outs() << "\n";
+      mainView->render(outs(), /*WholeFile=*/false);
+      outs() << "\n";
     }
     return 0;
   }
@@ -635,23 +447,14 @@ int CodeCoverageTool::show(int argc, const char **argv,
   // Show files
   bool ShowFilenames = SourceFiles.size() != 1;
 
-  if (SourceFiles.empty()) {
+  if (SourceFiles.empty())
     // Get the source files from the function coverage mapping
-    std::set<StringRef> UniqueFilenames;
-    for (const auto &Function : FunctionMappingRecords) {
-      for (const auto &Filename : Function.Filenames)
-        UniqueFilenames.insert(Filename);
-    }
-    for (const auto &Filename : UniqueFilenames)
+    for (StringRef Filename : Coverage->getUniqueSourceFiles())
       SourceFiles.push_back(Filename);
-  }
 
   for (const auto &SourceFile : SourceFiles) {
-    auto SourceBuffer = getSourceFile(SourceFile);
-    if (!SourceBuffer)
-      return 1;
-    SourceCoverageView mainView(SourceBuffer.get(), ViewOpts);
-    if (createSourceFileView(SourceFile, mainView, FunctionMappingRecords)) {
+    auto mainView = createSourceFileView(SourceFile, *Coverage);
+    if (!mainView) {
       ViewOpts.colored_ostream(outs(), raw_ostream::RED)
           << "warning: The file '" << SourceFile << "' isn't covered.";
       outs() << "\n";
@@ -662,7 +465,7 @@ int CodeCoverageTool::show(int argc, const char **argv,
       ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":";
       outs() << "\n";
     }
-    mainView.render(outs());
+    mainView->render(outs(), /*Wholefile=*/true);
     if (SourceFiles.size() > 1)
       outs() << "\n";
   }
@@ -672,36 +475,28 @@ int CodeCoverageTool::show(int argc, const char **argv,
 
 int CodeCoverageTool::report(int argc, const char **argv,
                              CommandLineParserType commandLineParser) {
-  cl::opt<bool> NoColors("no-colors", cl::Optional,
-                         cl::desc("Don't show text colors"), cl::init(false));
-
   auto Err = commandLineParser(argc, argv);
   if (Err)
     return Err;
 
-  ViewOpts.Colors = !NoColors;
-
-  if (load())
+  auto Coverage = load();
+  if (!Coverage)
     return 1;
 
-  CoverageSummary Summarizer;
-  Summarizer.createSummaries(FunctionMappingRecords);
-  CoverageReport Report(ViewOpts, Summarizer);
-  if (SourceFiles.empty() && Filters.empty()) {
+  CoverageReport Report(ViewOpts, std::move(Coverage));
+  if (SourceFiles.empty())
     Report.renderFileReports(llvm::outs());
-    return 0;
-  }
-
-  Report.renderFunctionReports(llvm::outs());
+  else
+    Report.renderFunctionReports(SourceFiles, llvm::outs());
   return 0;
 }
 
-int show_main(int argc, const char **argv) {
+int showMain(int argc, const char *argv[]) {
   CodeCoverageTool Tool;
   return Tool.run(CodeCoverageTool::Show, argc, argv);
 }
 
-int report_main(int argc, const char **argv) {
+int reportMain(int argc, const char *argv[]) {
   CodeCoverageTool Tool;
   return Tool.run(CodeCoverageTool::Report, argc, argv);
 }