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

Eric Fiselier via llvm-commits llvm-commits at lists.llvm.org
Sat Nov 18 14:42:53 PST 2017


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> 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> 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
>> 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
>>
>> 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.tx
>> t?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
>> ============================================================
>> ==================
>> --- 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_G
>> ISEL_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/InstructionSelect
>> or.h
>> URL: 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/InstructionSelect
>> orImpl.h
>> URL: 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
>> ============================================================
>> ==================
>> --- 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
>> ============================================================
>> ==================
>> --- 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
>> ============================================================
>> ==================
>> --- 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().getInstructi
>> onSelector();
>> +  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
>> ============================================================
>> ==================
>> --- 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
>> ============================================================
>> ==================
>> --- 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/AA
>> rch64/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/AM
>> DGPU/AMDGPUInstructionSelector.cpp?rev=318356&r1=318355&r2=3
>> 18356&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/AM
>> DGPU/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/AR
>> M/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/X8
>> 6/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
>> ============================================================
>> ==================
>> --- 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/TableGe
>> n/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-gi
>> sel-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
>> 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/20171118/b49f4e5e/attachment-0001.html>


More information about the llvm-commits mailing list