[llvm] r318356 - [globalisel][tablegen] Generate rule coverage and use it to identify untested rules

Daniel Sanders via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 20 07:44:37 PST 2017


Hi Eric,

Sorry for the breakage and thanks for fixing it.

> On 18 Nov 2017, at 14:42, Eric Fiselier <eric at efcs.ca> wrote:
> 
> I took the liberty of fixing the build error in r318602.
> 
> /Eric
> 
> On Sat, Nov 18, 2017 at 2:05 PM, Eric Fiselier <eric at efcs.ca <mailto:eric at efcs.ca>> wrote:
> Hi Daniel,
> 
> This broke the use of installed LLVM headers, since one of the changes adds a `config.h` include, but `config.h` isn't an installed header.
> 
> /Eric
> 
> On Wed, Nov 15, 2017 at 5:46 PM, Daniel Sanders via llvm-commits <llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>> wrote:
> Author: dsanders
> Date: Wed Nov 15 16:46:35 2017
> New Revision: 318356
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=318356&view=rev <http://llvm.org/viewvc/llvm-project?rev=318356&view=rev>
> Log:
> [globalisel][tablegen] Generate rule coverage and use it to identify untested rules
> 
> Summary:
> This patch adds a LLVM_ENABLE_GISEL_COV which, like LLVM_ENABLE_DAGISEL_COV,
> causes TableGen to instrument the generated table to collect rule coverage
> information. However, LLVM_ENABLE_GISEL_COV goes a bit further than
> LLVM_ENABLE_DAGISEL_COV. The information is written to files
> (${CMAKE_BINARY_DIR}/gisel-coverage-* by default). These files can then be
> concatenated into ${LLVM_GISEL_COV_PREFIX}-all after which TableGen will
> read this information and use it to emit warnings about untested rules.
> 
> This technique could also be used by SelectionDAG and can be further
> extended to detect hot rules and give them priority over colder rules.
> 
> Usage:
> * Enable LLVM_ENABLE_GISEL_COV in CMake
> * Build the compiler and run some tests
> * cat gisel-coverage-[0-9]* > gisel-coverage-all
> * Delete lib/Target/*/*GenGlobalISel.inc*
> * Build the compiler
> 
> Known issues:
> * ${LLVM_GISEL_COV_PREFIX}-all must be generated as a manual
>   step due to a lack of a portable 'cat' command. It should be the
>   concatenation of all ${LLVM_GISEL_COV_PREFIX}-[0-9]* files.
> * There's no mechanism to discard coverage information when the ruleset
>   changes
> 
> Depends on D39742
> 
> Reviewers: ab, qcolombet, t.p.northover, aditya_nandakumar, rovka
> 
> Reviewed By: rovka
> 
> Subscribers: vsk, arsenm, nhaehnle, mgorny, kristof.beyls, javed.absar, igorb, llvm-commits
> 
> Differential Revision: https://reviews.llvm.org/D39747 <https://reviews.llvm.org/D39747>
> 
> Added:
>     llvm/trunk/include/llvm/Support/CodeGenCoverage.h
>     llvm/trunk/lib/Support/CodeGenCoverage.cpp
>     llvm/trunk/utils/llvm-gisel-cov.py
> Modified:
>     llvm/trunk/CMakeLists.txt
>     llvm/trunk/cmake/modules/TableGen.cmake
>     llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
>     llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
>     llvm/trunk/include/llvm/Config/config.h.cmake
>     llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp
>     llvm/trunk/lib/Support/CMakeLists.txt
>     llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp
>     llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
>     llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.h
>     llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp
>     llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp
>     llvm/trunk/test/TableGen/GlobalISelEmitter.td
>     llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
> 
> Modified: llvm/trunk/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/CMakeLists.txt?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/CMakeLists.txt?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/CMakeLists.txt (original)
> +++ llvm/trunk/CMakeLists.txt Wed Nov 15 16:46:35 2017
> @@ -167,6 +167,10 @@ if(LLVM_DEPENDENCY_DEBUGGING)
>  endif()
> 
>  option(LLVM_ENABLE_DAGISEL_COV "Debug: Prints tablegen patterns that were used for selecting" OFF)
> +option(LLVM_ENABLE_GISEL_COV "Enable collection of GlobalISel rule coverage" OFF)
> +if(LLVM_ENABLE_GISEL_COV)
> +  set(LLVM_GISEL_COV_PREFIX "${CMAKE_BINARY_DIR}/gisel-coverage-" CACHE STRING "Provide a filename prefix to collect the GlobalISel rule coverage")
> +endif()
> 
>  # Add path for custom modules
>  set(CMAKE_MODULE_PATH
> 
> Modified: llvm/trunk/cmake/modules/TableGen.cmake
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/cmake/modules/TableGen.cmake?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/cmake/modules/TableGen.cmake?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/cmake/modules/TableGen.cmake (original)
> +++ llvm/trunk/cmake/modules/TableGen.cmake Wed Nov 15 16:46:35 2017
> @@ -52,6 +52,13 @@ function(tablegen project ofn)
>        list(APPEND LLVM_TABLEGEN_FLAGS "-instrument-coverage")
>      endif()
>    endif()
> +  if (LLVM_ENABLE_GISEL_COV)
> +    list(FIND ARGN "-gen-global-isel" idx)
> +    if( NOT idx EQUAL -1 )
> +      list(APPEND LLVM_TABLEGEN_FLAGS "-instrument-gisel-coverage")
> +      list(APPEND LLVM_TABLEGEN_FLAGS "-gisel-coverage-file=${LLVM_GISEL_COV_PREFIX}all")
> +    endif()
> +  endif()
> 
>    # We need both _TABLEGEN_TARGET and _TABLEGEN_EXE in the  DEPENDS list
>    # (both the target and the file) to have .inc files rebuilt on
> 
> Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h (original)
> +++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h Wed Nov 15 16:46:35 2017
> @@ -17,8 +17,9 @@
>  #define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
> 
>  #include "llvm/ADT/DenseMap.h"
> -#include "llvm/ADT/SmallVector.h"
>  #include "llvm/ADT/Optional.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/Support/CodeGenCoverage.h"
>  #include <bitset>
>  #include <cstddef>
>  #include <cstdint>
> @@ -33,6 +34,7 @@ class APFloat;
>  class LLT;
>  class MachineInstr;
>  class MachineInstrBuilder;
> +class MachineFunction;
>  class MachineOperand;
>  class MachineRegisterInfo;
>  class RegisterBankInfo;
> @@ -262,6 +264,10 @@ enum {
> 
>    /// A successful emission
>    GIR_Done,
> +
> +  /// Increment the rule coverage counter.
> +  /// - RuleID - The ID of the rule that was covered.
> +  GIR_Coverage,
>  };
> 
>  enum {
> @@ -289,7 +295,7 @@ public:
>    ///   if returns true:
>    ///     for I in all mutated/inserted instructions:
>    ///       !isPreISelGenericOpcode(I.getOpcode())
> -  virtual bool select(MachineInstr &I) const = 0;
> +  virtual bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const = 0;
> 
>  protected:
>    using ComplexRendererFns =
> @@ -328,8 +334,8 @@ protected:
>        const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> &MatcherInfo,
>        const int64_t *MatchTable, const TargetInstrInfo &TII,
>        MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
> -      const RegisterBankInfo &RBI,
> -      const PredicateBitset &AvailableFeatures) const;
> +      const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
> +      CodeGenCoverage &CoverageInfo) const;
> 
>    /// Constrain a register operand of an instruction \p I to a specified
>    /// register class. This could involve inserting COPYs before (for uses) or
> 
> Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h (original)
> +++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h Wed Nov 15 16:46:35 2017
> @@ -49,8 +49,8 @@ bool InstructionSelector::executeMatchTa
>      const MatcherInfoTy<PredicateBitset, ComplexMatcherMemFn> &MatcherInfo,
>      const int64_t *MatchTable, const TargetInstrInfo &TII,
>      MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
> -    const RegisterBankInfo &RBI,
> -    const PredicateBitset &AvailableFeatures) const {
> +    const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
> +    CodeGenCoverage &CoverageInfo) const {
>    uint64_t CurrentIdx = 0;
>    SmallVector<uint64_t, 8> OnFailResumeAt;
> 
> @@ -677,6 +677,16 @@ bool InstructionSelector::executeMatchTa
>        break;
>      }
> 
> +    case GIR_Coverage: {
> +      int64_t RuleID = MatchTable[CurrentIdx++];
> +      CoverageInfo.setCovered(RuleID);
> +
> +      DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
> +                      dbgs()
> +                          << CurrentIdx << ": GIR_Coverage(" << RuleID << ")");
> +      break;
> +    }
> +
>      case GIR_Done:
>        DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
>                        dbgs() << CurrentIdx << ": GIR_Done");
> 
> Modified: llvm/trunk/include/llvm/Config/config.h.cmake
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Config/config.h.cmake?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Config/config.h.cmake?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/include/llvm/Config/config.h.cmake (original)
> +++ llvm/trunk/include/llvm/Config/config.h.cmake Wed Nov 15 16:46:35 2017
> @@ -437,4 +437,10 @@
>  /* Define to a function implementing strdup */
>  #cmakedefine strdup ${strdup}
> 
> +/* Whether GlobalISel rule coverage is being collected */
> +#cmakedefine01 LLVM_GISEL_COV_ENABLED
> +
> +/* Define to the default GlobalISel coverage file prefix */
> +#cmakedefine LLVM_GISEL_COV_PREFIX "${LLVM_GISEL_COV_PREFIX}"
> +
>  #endif
> 
> Added: llvm/trunk/include/llvm/Support/CodeGenCoverage.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/CodeGenCoverage.h?rev=318356&view=auto <http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/CodeGenCoverage.h?rev=318356&view=auto>
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/CodeGenCoverage.h (added)
> +++ llvm/trunk/include/llvm/Support/CodeGenCoverage.h Wed Nov 15 16:46:35 2017
> @@ -0,0 +1,37 @@
> +//== llvm/Support/CodeGenCoverage.h ------------------------------*- C++ -*-==//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +/// \file This file provides rule coverage tracking for tablegen-erated CodeGen.
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_SUPPORT_CODEGENCOVERAGE_H
> +#define LLVM_SUPPORT_CODEGENCOVERAGE_H
> +
> +#include "llvm/ADT/BitVector.h"
> +#include "llvm/Config/config.h"
> +
> +namespace llvm {
> +class LLVMContext;
> +
> +class CodeGenCoverage {
> +protected:
> +  BitVector RuleCoverage;
> +
> +public:
> +  CodeGenCoverage();
> +
> +  void setCovered(uint64_t RuleID);
> +  bool isCovered(uint64_t RuleID);
> +
> +  bool parse(MemoryBuffer &Buffer, StringRef BackendName);
> +  bool emit(StringRef FilePrefix, StringRef BackendName) const;
> +  void reset();
> +};
> +} // end namespace llvm
> +
> +#endif // ifndef LLVM_SUPPORT_CODEGENCOVERAGE_H
> 
> Modified: llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp (original)
> +++ llvm/trunk/lib/CodeGen/GlobalISel/InstructionSelect.cpp Wed Nov 15 16:46:35 2017
> @@ -20,10 +20,12 @@
>  #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
>  #include "llvm/CodeGen/MachineRegisterInfo.h"
>  #include "llvm/CodeGen/TargetPassConfig.h"
> +#include "llvm/Config/config.h"
>  #include "llvm/IR/Constants.h"
>  #include "llvm/IR/Function.h"
>  #include "llvm/Support/CommandLine.h"
>  #include "llvm/Support/Debug.h"
> +#include "llvm/Support/TargetRegistry.h"
>  #include "llvm/Target/TargetLowering.h"
>  #include "llvm/Target/TargetSubtargetInfo.h"
> 
> @@ -31,6 +33,15 @@
> 
>  using namespace llvm;
> 
> +#ifdef LLVM_GISEL_COV_PREFIX
> +static cl::opt<std::string>
> +    CoveragePrefix("gisel-coverage-prefix", cl::init(LLVM_GISEL_COV_PREFIX),
> +                   cl::desc("Record GlobalISel rule coverage files of this "
> +                            "prefix if instrumentation was generated"));
> +#else
> +static const std::string CoveragePrefix = "";
> +#endif
> +
>  char InstructionSelect::ID = 0;
>  INITIALIZE_PASS_BEGIN(InstructionSelect, DEBUG_TYPE,
>                        "Select target instructions out of generic instructions",
> @@ -66,6 +77,7 @@ bool InstructionSelect::runOnMachineFunc
> 
>    const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
>    const InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector();
> +  CodeGenCoverage CoverageInfo;
>    assert(ISel && "Cannot work without InstructionSelector");
> 
>    // An optimization remark emitter. Used to report failures.
> @@ -127,7 +139,7 @@ bool InstructionSelect::runOnMachineFunc
>          continue;
>        }
> 
> -      if (!ISel->select(MI)) {
> +      if (!ISel->select(MI, CoverageInfo)) {
>          // FIXME: It would be nice to dump all inserted instructions.  It's
>          // not obvious how, esp. considering select() can insert after MI.
>          reportGISelFailure(MF, TPC, MORE, "gisel-select", "cannot select", MI);
> @@ -187,6 +199,13 @@ bool InstructionSelect::runOnMachineFunc
>    auto &TLI = *MF.getSubtarget().getTargetLowering();
>    TLI.finalizeLowering(MF);
> 
> +  CoverageInfo.emit(CoveragePrefix,
> +                    MF.getSubtarget()
> +                        .getTargetLowering()
> +                        ->getTargetMachine()
> +                        .getTarget()
> +                        .getBackendName());
> +
>    // FIXME: Should we accurately track changes?
>    return true;
>  }
> 
> Modified: llvm/trunk/lib/Support/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CMakeLists.txt?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CMakeLists.txt?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/lib/Support/CMakeLists.txt (original)
> +++ llvm/trunk/lib/Support/CMakeLists.txt Wed Nov 15 16:46:35 2017
> @@ -48,6 +48,7 @@ add_llvm_library(LLVMSupport
>    circular_raw_ostream.cpp
>    Chrono.cpp
>    COM.cpp
> +  CodeGenCoverage.cpp
>    CommandLine.cpp
>    Compression.cpp
>    ConvertUTF.cpp
> 
> Added: llvm/trunk/lib/Support/CodeGenCoverage.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CodeGenCoverage.cpp?rev=318356&view=auto <http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CodeGenCoverage.cpp?rev=318356&view=auto>
> ==============================================================================
> --- llvm/trunk/lib/Support/CodeGenCoverage.cpp (added)
> +++ llvm/trunk/lib/Support/CodeGenCoverage.cpp Wed Nov 15 16:46:35 2017
> @@ -0,0 +1,118 @@
> +//===- lib/Support/CodeGenCoverage.cpp -------------------------------------==//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +/// \file
> +/// This file implements the CodeGenCoverage class.
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/Support/CodeGenCoverage.h"
> +
> +#include "llvm/Support/Endian.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/Mutex.h"
> +#include "llvm/Support/ScopedPrinter.h"
> +#include "llvm/Support/ToolOutputFile.h"
> +
> +#if LLVM_ON_UNIX
> +#include <unistd.h>
> +#elif LLVM_ON_WIN32
> +#include <windows.h>
> +#endif
> +
> +using namespace llvm;
> +
> +static sys::SmartMutex<true> OutputMutex;
> +
> +CodeGenCoverage::CodeGenCoverage() {}
> +
> +void CodeGenCoverage::setCovered(uint64_t RuleID) {
> +  if (RuleCoverage.size() <= RuleID)
> +    RuleCoverage.resize(RuleID + 1, 0);
> +  RuleCoverage[RuleID] = true;
> +}
> +
> +bool CodeGenCoverage::isCovered(uint64_t RuleID) {
> +  if (RuleCoverage.size() <= RuleID)
> +    return false;
> +  return RuleCoverage[RuleID];
> +}
> +
> +bool CodeGenCoverage::parse(MemoryBuffer &Buffer, StringRef BackendName) {
> +  const char *CurPtr = Buffer.getBufferStart();
> +
> +  while (CurPtr != Buffer.getBufferEnd()) {
> +    // Read the backend name from the input.
> +    const char *LexedBackendName = CurPtr;
> +    while (*CurPtr++ != 0)
> +      ;
> +    if (CurPtr == Buffer.getBufferEnd())
> +      return false; // Data is invalid, expected rule id's to follow.
> +
> +    bool IsForThisBackend = BackendName.equals(LexedBackendName);
> +    while (CurPtr != Buffer.getBufferEnd()) {
> +      if (std::distance(CurPtr, Buffer.getBufferEnd()) < 8)
> +        return false; // Data is invalid. Not enough bytes for another rule id.
> +
> +      uint64_t RuleID = support::endian::read64(CurPtr, support::native);
> +      CurPtr += 8;
> +
> +      // ~0ull terminates the rule id list.
> +      if (RuleID == ~0ull)
> +        break;
> +
> +      // Anything else, is recorded or ignored depending on whether it's
> +      // intended for the backend we're interested in.
> +      if (IsForThisBackend)
> +        setCovered(RuleID);
> +    }
> +  }
> +
> +  return true;
> +}
> +
> +bool CodeGenCoverage::emit(StringRef CoveragePrefix,
> +                           StringRef BackendName) const {
> +  if (!CoveragePrefix.empty() && !RuleCoverage.empty()) {
> +    sys::SmartScopedLock<true> Lock(OutputMutex);
> +
> +    // We can handle locking within a process easily enough but we don't want to
> +    // manage it between multiple processes. Use the process ID to ensure no
> +    // more than one process is ever writing to the same file at the same time.
> +    std::string Pid =
> +#if LLVM_ON_UNIX
> +        llvm::to_string(::getpid());
> +#elif LLVM_ON_WIN32
> +        llvm::to_string(::GetCurrentProcessId());
> +#else
> +        "";
> +#endif
> +
> +    std::string CoverageFilename = (CoveragePrefix + Pid).str();
> +
> +    std::error_code EC;
> +    sys::fs::OpenFlags OpenFlags = sys::fs::F_Append;
> +    std::unique_ptr<ToolOutputFile> CoverageFile =
> +        llvm::make_unique<ToolOutputFile>(CoverageFilename, EC, OpenFlags);
> +    if (EC)
> +      return false;
> +
> +    uint64_t Zero = 0;
> +    uint64_t InvZero = ~0ull;
> +    CoverageFile->os() << BackendName;
> +    CoverageFile->os().write((const char *)&Zero, sizeof(unsigned char));
> +    for (uint64_t I : RuleCoverage.set_bits())
> +      CoverageFile->os().write((const char *)&I, sizeof(uint64_t));
> +    CoverageFile->os().write((const char *)&InvZero, sizeof(uint64_t));
> +
> +    CoverageFile->keep();
> +  }
> +
> +  return true;
> +}
> +
> +void CodeGenCoverage::reset() { RuleCoverage.resize(0); }
> 
> Modified: llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp (original)
> +++ llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp Wed Nov 15 16:46:35 2017
> @@ -48,13 +48,13 @@ public:
>                               const AArch64Subtarget &STI,
>                               const AArch64RegisterBankInfo &RBI);
> 
> -  bool select(MachineInstr &I) const override;
> +  bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
>    static const char *getName() { return DEBUG_TYPE; }
> 
>  private:
>    /// tblgen-erated 'select' implementation, used as the initial selector for
>    /// the patterns that don't require complex C++.
> -  bool selectImpl(MachineInstr &I) const;
> +  bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
> 
>    bool selectVaStartAAPCS(MachineInstr &I, MachineFunction &MF,
>                            MachineRegisterInfo &MRI) const;
> @@ -609,7 +609,8 @@ bool AArch64InstructionSelector::selectV
>    return true;
>  }
> 
> -bool AArch64InstructionSelector::select(MachineInstr &I) const {
> +bool AArch64InstructionSelector::select(MachineInstr &I,
> +                                        CodeGenCoverage &CoverageInfo) const {
>    assert(I.getParent() && "Instruction should be in a basic block!");
>    assert(I.getParent()->getParent() && "Instruction should be in a function!");
> 
> @@ -667,7 +668,7 @@ bool AArch64InstructionSelector::select(
>      return false;
>    }
> 
> -  if (selectImpl(I))
> +  if (selectImpl(I, CoverageInfo))
>      return true;
> 
>    LLT Ty =
> 
> Modified: llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp (original)
> +++ llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp Wed Nov 15 16:46:35 2017
> @@ -402,7 +402,8 @@ bool AMDGPUInstructionSelector::selectG_
>    return Ret;
>  }
> 
> -bool AMDGPUInstructionSelector::select(MachineInstr &I) const {
> +bool AMDGPUInstructionSelector::select(MachineInstr &I,
> +                                       CodeGenCoverage &CoverageInfo) const {
> 
>    if (!isPreISelGenericOpcode(I.getOpcode()))
>      return true;
> 
> Modified: llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.h?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.h?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.h (original)
> +++ llvm/trunk/lib/Target/AMDGPU/AMDGPUInstructionSelector.h Wed Nov 15 16:46:35 2017
> @@ -35,7 +35,8 @@ public:
>    AMDGPUInstructionSelector(const SISubtarget &STI,
>                              const AMDGPURegisterBankInfo &RBI);
> 
> -  bool select(MachineInstr &I) const override;
> +  bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
> +
>  private:
>    struct GEPInfo {
>      const MachineInstr &GEP;
> 
> Modified: llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/ARMInstructionSelector.cpp Wed Nov 15 16:46:35 2017
> @@ -35,11 +35,11 @@ public:
>    ARMInstructionSelector(const ARMBaseTargetMachine &TM, const ARMSubtarget &STI,
>                           const ARMRegisterBankInfo &RBI);
> 
> -  bool select(MachineInstr &I) const override;
> +  bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
>    static const char *getName() { return DEBUG_TYPE; }
> 
>  private:
> -  bool selectImpl(MachineInstr &I) const;
> +  bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
> 
>    struct CmpConstants;
>    struct InsertInfo;
> @@ -653,7 +653,8 @@ bool ARMInstructionSelector::selectShift
>    return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
>  }
> 
> -bool ARMInstructionSelector::select(MachineInstr &I) const {
> +bool ARMInstructionSelector::select(MachineInstr &I,
> +                                    CodeGenCoverage &CoverageInfo) const {
>    assert(I.getParent() && "Instruction should be in a basic block!");
>    assert(I.getParent()->getParent() && "Instruction should be in a function!");
> 
> @@ -668,7 +669,7 @@ bool ARMInstructionSelector::select(Mach
>      return true;
>    }
> 
> -  if (selectImpl(I))
> +  if (selectImpl(I, CoverageInfo))
>      return true;
> 
>    MachineInstrBuilder MIB{MF, I};
> 
> Modified: llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp (original)
> +++ llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp Wed Nov 15 16:46:35 2017
> @@ -61,13 +61,13 @@ public:
>    X86InstructionSelector(const X86TargetMachine &TM, const X86Subtarget &STI,
>                           const X86RegisterBankInfo &RBI);
> 
> -  bool select(MachineInstr &I) const override;
> +  bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
>    static const char *getName() { return DEBUG_TYPE; }
> 
>  private:
>    /// tblgen-erated 'select' implementation, used as the initial selector for
>    /// the patterns that don't require complex C++.
> -  bool selectImpl(MachineInstr &I) const;
> +  bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
> 
>    // TODO: remove after supported by Tablegen-erated instruction selection.
>    unsigned getLoadStoreOp(const LLT &Ty, const RegisterBank &RB, unsigned Opc,
> @@ -93,9 +93,11 @@ private:
>                     MachineFunction &MF) const;
>    bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
>    bool selectUnmergeValues(MachineInstr &I, MachineRegisterInfo &MRI,
> -                           MachineFunction &MF) const;
> +                           MachineFunction &MF,
> +                           CodeGenCoverage &CoverageInfo) const;
>    bool selectMergeValues(MachineInstr &I, MachineRegisterInfo &MRI,
> -                         MachineFunction &MF) const;
> +                         MachineFunction &MF,
> +                         CodeGenCoverage &CoverageInfo) const;
>    bool selectInsert(MachineInstr &I, MachineRegisterInfo &MRI,
>                      MachineFunction &MF) const;
>    bool selectExtract(MachineInstr &I, MachineRegisterInfo &MRI,
> @@ -294,7 +296,8 @@ bool X86InstructionSelector::selectCopy(
>    return true;
>  }
> 
> -bool X86InstructionSelector::select(MachineInstr &I) const {
> +bool X86InstructionSelector::select(MachineInstr &I,
> +                                    CodeGenCoverage &CoverageInfo) const {
>    assert(I.getParent() && "Instruction should be in a basic block!");
>    assert(I.getParent()->getParent() && "Instruction should be in a function!");
> 
> @@ -318,7 +321,7 @@ bool X86InstructionSelector::select(Mach
>    assert(I.getNumOperands() == I.getNumExplicitOperands() &&
>           "Generic instruction has unexpected implicit operands\n");
> 
> -  if (selectImpl(I))
> +  if (selectImpl(I, CoverageInfo))
>      return true;
> 
>    DEBUG(dbgs() << " C++ instruction selection: "; I.print(dbgs()));
> @@ -350,9 +353,9 @@ bool X86InstructionSelector::select(Mach
>    case TargetOpcode::G_UADDE:
>      return selectUadde(I, MRI, MF);
>    case TargetOpcode::G_UNMERGE_VALUES:
> -    return selectUnmergeValues(I, MRI, MF);
> +    return selectUnmergeValues(I, MRI, MF, CoverageInfo);
>    case TargetOpcode::G_MERGE_VALUES:
> -    return selectMergeValues(I, MRI, MF);
> +    return selectMergeValues(I, MRI, MF, CoverageInfo);
>    case TargetOpcode::G_EXTRACT:
>      return selectExtract(I, MRI, MF);
>    case TargetOpcode::G_INSERT:
> @@ -1093,9 +1096,9 @@ bool X86InstructionSelector::selectInser
>    return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
>  }
> 
> -bool X86InstructionSelector::selectUnmergeValues(MachineInstr &I,
> -                                                 MachineRegisterInfo &MRI,
> -                                                 MachineFunction &MF) const {
> +bool X86InstructionSelector::selectUnmergeValues(
> +    MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF,
> +    CodeGenCoverage &CoverageInfo) const {
>    assert((I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES) &&
>           "unexpected instruction");
> 
> @@ -1111,7 +1114,7 @@ bool X86InstructionSelector::selectUnmer
>               .addReg(SrcReg)
>               .addImm(Idx * DefSize);
> 
> -    if (!select(ExtrInst))
> +    if (!select(ExtrInst, CoverageInfo))
>        return false;
>    }
> 
> @@ -1119,9 +1122,9 @@ bool X86InstructionSelector::selectUnmer
>    return true;
>  }
> 
> -bool X86InstructionSelector::selectMergeValues(MachineInstr &I,
> -                                               MachineRegisterInfo &MRI,
> -                                               MachineFunction &MF) const {
> +bool X86InstructionSelector::selectMergeValues(
> +    MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF,
> +    CodeGenCoverage &CoverageInfo) const {
>    assert((I.getOpcode() == TargetOpcode::G_MERGE_VALUES) &&
>           "unexpected instruction");
> 
> @@ -1153,7 +1156,7 @@ bool X86InstructionSelector::selectMerge
> 
>      DefReg = Tmp;
> 
> -    if (!select(InsertInst))
> +    if (!select(InsertInst, CoverageInfo))
>        return false;
>    }
> 
> @@ -1161,7 +1164,7 @@ bool X86InstructionSelector::selectMerge
>                                      TII.get(TargetOpcode::COPY), DstReg)
>                                  .addReg(DefReg);
> 
> -  if (!select(CopyInst))
> +  if (!select(CopyInst, CoverageInfo))
>      return false;
> 
>    I.eraseFromParent();
> 
> Modified: llvm/trunk/test/TableGen/GlobalISelEmitter.td
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/GlobalISelEmitter.td?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/GlobalISelEmitter.td?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/test/TableGen/GlobalISelEmitter.td (original)
> +++ llvm/trunk/test/TableGen/GlobalISelEmitter.td Wed Nov 15 16:46:35 2017
> @@ -153,7 +153,7 @@ def HasC : Predicate<"Subtarget->hasC()"
>  // CHECK-NEXT:    &MyTargetInstructionSelector::selectComplexPatternRR, // gi_complex_rr
>  // CHECK-NEXT:  }
> 
> -// CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const {
> +// CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const {
>  // CHECK-NEXT: MachineFunction &MF = *I.getParent()->getParent();
>  // CHECK-NEXT: MachineRegisterInfo &MRI = MF.getRegInfo();
>  // CHECK:      AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, &MF);
> @@ -899,6 +899,6 @@ def BR : I<(outs), (ins unknown:$target)
> 
>  // CHECK-NEXT:    GIM_Reject,
>  // CHECK-NEXT:  };
> -// CHECK-NEXT:  if (executeMatchTable(*this, OutMIs, State, MatcherInfo, MatchTable0, TII, MRI, TRI, RBI, AvailableFeatures)) {
> +// CHECK-NEXT:  if (executeMatchTable(*this, OutMIs, State, MatcherInfo, MatchTable0, TII, MRI, TRI, RBI, AvailableFeatures, CoverageInfo)) {
>  // CHECK-NEXT:    return true;
>  // CHECK-NEXT:  }
> 
> Modified: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp?rev=318356&r1=318355&r2=318356&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp?rev=318356&r1=318355&r2=318356&view=diff>
> ==============================================================================
> --- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp (original)
> +++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp Wed Nov 15 16:46:35 2017
> @@ -36,6 +36,7 @@
>  #include "llvm/ADT/SmallSet.h"
>  #include "llvm/ADT/Statistic.h"
>  #include "llvm/CodeGen/MachineValueType.h"
> +#include "llvm/Support/CodeGenCoverage.h"
>  #include "llvm/Support/CommandLine.h"
>  #include "llvm/Support/Error.h"
>  #include "llvm/Support/LowLevelTypeImpl.h"
> @@ -43,8 +44,8 @@
>  #include "llvm/TableGen/Error.h"
>  #include "llvm/TableGen/Record.h"
>  #include "llvm/TableGen/TableGenBackend.h"
> -#include <string>
>  #include <numeric>
> +#include <string>
>  using namespace llvm;
> 
>  #define DEBUG_TYPE "gisel-emitter"
> @@ -52,6 +53,7 @@ using namespace llvm;
>  STATISTIC(NumPatternTotal, "Total number of patterns");
>  STATISTIC(NumPatternImported, "Number of patterns imported from SelectionDAG");
>  STATISTIC(NumPatternImportsSkipped, "Number of SelectionDAG imports skipped");
> +STATISTIC(NumPatternsTested, "Number of patterns executed according to coverage information");
>  STATISTIC(NumPatternEmitted, "Number of patterns emitted");
> 
>  cl::OptionCategory GlobalISelEmitterCat("Options for -gen-global-isel");
> @@ -62,6 +64,16 @@ static cl::opt<bool> WarnOnSkippedPatter
>               "in the GlobalISel selector"),
>      cl::init(false), cl::cat(GlobalISelEmitterCat));
> 
> +static cl::opt<bool> GenerateCoverage(
> +    "instrument-gisel-coverage",
> +    cl::desc("Generate coverage instrumentation for GlobalISel"),
> +    cl::init(false), cl::cat(GlobalISelEmitterCat));
> +
> +static cl::opt<std::string> UseCoverageFile(
> +    "gisel-coverage-file", cl::init(""),
> +    cl::desc("Specify file to retrieve coverage information from"),
> +    cl::cat(GlobalISelEmitterCat));
> +
>  namespace {
>  //===- Helper functions ---------------------------------------------------===//
> 
> @@ -569,14 +581,20 @@ protected:
>    /// A map of Symbolic Names to ComplexPattern sub-operands.
>    DefinedComplexPatternSubOperandMap ComplexSubOperands;
> 
> +  uint64_t RuleID;
> +  static uint64_t NextRuleID;
> +
>  public:
>    RuleMatcher(ArrayRef<SMLoc> SrcLoc)
>        : Matchers(), Actions(), InsnVariableIDs(), MutatableInsns(),
>          DefinedOperands(), NextInsnVarID(0), NextOutputInsnID(0),
> -        NextTempRegID(0), SrcLoc(SrcLoc), ComplexSubOperands() {}
> +        NextTempRegID(0), SrcLoc(SrcLoc), ComplexSubOperands(),
> +        RuleID(NextRuleID++) {}
>    RuleMatcher(RuleMatcher &&Other) = default;
>    RuleMatcher &operator=(RuleMatcher &&Other) = default;
> 
> +  uint64_t getRuleID() const { return RuleID; }
> +
>    InstructionMatcher &addInstructionMatcher(StringRef SymbolicName);
>    void addRequiredFeature(Record *Feature);
>    const std::vector<Record *> &getRequiredFeatures() const;
> @@ -664,6 +682,8 @@ public:
>    unsigned allocateTempRegID() { return NextTempRegID++; }
>  };
> 
> +uint64_t RuleMatcher::NextRuleID = 0;
> +
>  using action_iterator = RuleMatcher::action_iterator;
> 
>  template <class PredicateTy> class PredicateListMatcher {
> @@ -2204,6 +2224,11 @@ void RuleMatcher::emit(MatchTable &Table
> 
>    for (const auto &MA : Actions)
>      MA->emitActionOpcodes(Table, *this);
> +
> +  if (GenerateCoverage)
> +    Table << MatchTable::Opcode("GIR_Coverage") << MatchTable::IntValue(RuleID)
> +          << MatchTable::LineBreak;
> +
>    Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak
>          << MatchTable::Label(LabelID);
>  }
> @@ -2309,6 +2334,9 @@ private:
>    // Map of predicates to their subtarget features.
>    SubtargetFeatureInfoMap SubtargetFeatures;
> 
> +  // Rule coverage information.
> +  Optional<CodeGenCoverage> RuleCoverage;
> +
>    void gatherNodeEquivs();
>    Record *findNodeEquiv(Record *N) const;
> 
> @@ -3227,6 +3255,20 @@ void GlobalISelEmitter::emitImmPredicate
>  }
> 
>  void GlobalISelEmitter::run(raw_ostream &OS) {
> +  if (!UseCoverageFile.empty()) {
> +    RuleCoverage = CodeGenCoverage();
> +    auto RuleCoverageBufOrErr = MemoryBuffer::getFile(UseCoverageFile);
> +    if (!RuleCoverageBufOrErr) {
> +      PrintWarning(SMLoc(), "Missing rule coverage data");
> +      RuleCoverage = None;
> +    } else {
> +      if (!RuleCoverage->parse(*RuleCoverageBufOrErr.get(), Target.getName())) {
> +        PrintWarning(SMLoc(), "Ignoring invalid or missing rule coverage data");
> +        RuleCoverage = None;
> +      }
> +    }
> +  }
> +
>    // Track the GINodeEquiv definitions.
>    gatherNodeEquivs();
> 
> @@ -3252,6 +3294,13 @@ void GlobalISelEmitter::run(raw_ostream
>        continue;
>      }
> 
> +    if (RuleCoverage) {
> +      if (RuleCoverage->isCovered(MatcherOrErr->getRuleID()))
> +        ++NumPatternsTested;
> +      else
> +        PrintWarning(Pat.getSrcRecord()->getLoc(),
> +                     "Pattern is not covered by a test");
> +    }
>      Rules.push_back(std::move(MatcherOrErr.get()));
>    }
> 
> @@ -3431,7 +3480,8 @@ void GlobalISelEmitter::run(raw_ostream
>    OS << "};\n\n";
> 
>    OS << "bool " << Target.getName()
> -     << "InstructionSelector::selectImpl(MachineInstr &I) const {\n"
> +     << "InstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage "
> +        "&CoverageInfo) const {\n"
>       << "  MachineFunction &MF = *I.getParent()->getParent();\n"
>       << "  MachineRegisterInfo &MRI = MF.getRegInfo();\n"
>       << "  // FIXME: This should be computed on a per-function basis rather "
> @@ -3452,7 +3502,7 @@ void GlobalISelEmitter::run(raw_ostream
>    Table.emitDeclaration(OS);
>    OS << "  if (executeMatchTable(*this, OutMIs, State, MatcherInfo, ";
>    Table.emitUse(OS);
> -  OS << ", TII, MRI, TRI, RBI, AvailableFeatures)) {\n"
> +  OS << ", TII, MRI, TRI, RBI, AvailableFeatures, CoverageInfo)) {\n"
>       << "    return true;\n"
>       << "  }\n\n";
> 
> 
> Added: llvm/trunk/utils/llvm-gisel-cov.py
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/llvm-gisel-cov.py?rev=318356&view=auto <http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/llvm-gisel-cov.py?rev=318356&view=auto>
> ==============================================================================
> --- llvm/trunk/utils/llvm-gisel-cov.py (added)
> +++ llvm/trunk/utils/llvm-gisel-cov.py Wed Nov 15 16:46:35 2017
> @@ -0,0 +1,67 @@
> +#!/usr/bin/env python
> +"""
> +Summarize the information in the given coverage files.
> +
> +Emits the number of rules covered or the percentage of rules covered depending
> +on whether --num-rules has been used to specify the total number of rules.
> +"""
> +
> +import argparse
> +import struct
> +
> +class FileFormatError(Exception):
> +  pass
> +
> +def backend_int_pair(s):
> +  backend, sep, value = s.partition('=')
> +  if (sep is None):
> +    raise argparse.ArgumentTypeError("'=' missing, expected name=value")
> +  if (not backend):
> +    raise argparse.ArgumentTypeError("Expected name=value")
> +  if (not value):
> +    raise argparse.ArgumentTypeError("Expected name=value")
> +  return backend, int(value)
> +
> +def main():
> +  parser = argparse.ArgumentParser(description=__doc__)
> +  parser.add_argument('input', nargs='+')
> +  parser.add_argument('--num-rules', type=backend_int_pair, action='append',
> +                      metavar='BACKEND=NUM',
> +                      help='Specify the number of rules for a backend')
> +  args = parser.parse_args()
> +
> +  covered_rules = {}
> +
> +  for input_filename in args.input:
> +    with open(input_filename, 'rb') as input_fh:
> +      data = input_fh.read()
> +      pos = 0
> +      while data:
> +        backend, _, data = data.partition('\0')
> +        pos += len(backend)
> +        pos += 1
> +
> +        if len(backend) == 0:
> +          raise FileFormatError()
> +        backend, = struct.unpack("%ds" % len(backend), backend)
> +
> +        while data:
> +          if len(data) < 8:
> +            raise FileFormatError()
> +          rule_id, = struct.unpack("Q", data[:8])
> +          pos += 8
> +          data = data[8:]
> +          if rule_id == (2 ** 64) - 1:
> +            break
> +          covered_rules[backend] = covered_rules.get(backend, {})
> +          covered_rules[backend][rule_id] = covered_rules[backend].get(rule_id, 0) + 1
> +
> +  num_rules = dict(args.num_rules)
> +  for backend, rules_for_backend in covered_rules.items():
> +    if backend in num_rules:
> +      print "%s: %3.2f%% of rules covered" % (backend, (float(len(rules_for_backend.keys())) / num_rules[backend]) * 100)
> +    else:
> +      print "%s: %d rules covered" % (backend, len(rules_for_backend.keys()))
> +
> +if __name__ == '__main__':
> +  main()
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits <http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits>
> 
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20171120/72eeea1d/attachment-0001.html>


More information about the llvm-commits mailing list