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
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
#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>
class LLT;
class MachineInstr;
class MachineInstrBuilder;
+class MachineFunction;
class MachineOperand;
class MachineRegisterInfo;
class RegisterBankInfo;
/// A successful emission
GIR_Done,
+
+ /// Increment the rule coverage counter.
+ /// - RuleID - The ID of the rule that was covered.
+ GIR_Coverage,
};
enum {
/// 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 =
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
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;
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");
/* 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
--- /dev/null
+//== 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
#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"
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",
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.
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);
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;
}
circular_raw_ostream.cpp
Chrono.cpp
COM.cpp
+ CodeGenCoverage.cpp
CommandLine.cpp
Compression.cpp
ConvertUTF.cpp
--- /dev/null
+//===- 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); }
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;
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!");
return false;
}
- if (selectImpl(I))
+ if (selectImpl(I, CoverageInfo))
return true;
LLT Ty =
return Ret;
}
-bool AMDGPUInstructionSelector::select(MachineInstr &I) const {
+bool AMDGPUInstructionSelector::select(MachineInstr &I,
+ CodeGenCoverage &CoverageInfo) const {
if (!isPreISelGenericOpcode(I.getOpcode()))
return true;
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;
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;
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!");
return true;
}
- if (selectImpl(I))
+ if (selectImpl(I, CoverageInfo))
return true;
MachineInstrBuilder MIB{MF, I};
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,
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,
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!");
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()));
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:
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");
.addReg(SrcReg)
.addImm(Idx * DefSize);
- if (!select(ExtrInst))
+ if (!select(ExtrInst, CoverageInfo))
return false;
}
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");
DefReg = Tmp;
- if (!select(InsertInst))
+ if (!select(InsertInst, CoverageInfo))
return false;
}
TII.get(TargetOpcode::COPY), DstReg)
.addReg(DefReg);
- if (!select(CopyInst))
+ if (!select(CopyInst, CoverageInfo))
return false;
I.eraseFromParent();
// 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);
// 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: }
#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"
#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"
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");
"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 ---------------------------------------------------===//
/// 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;
unsigned allocateTempRegID() { return NextTempRegID++; }
};
+uint64_t RuleMatcher::NextRuleID = 0;
+
using action_iterator = RuleMatcher::action_iterator;
template <class PredicateTy> class PredicateListMatcher {
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);
}
// Map of predicates to their subtarget features.
SubtargetFeatureInfoMap SubtargetFeatures;
+ // Rule coverage information.
+ Optional<CodeGenCoverage> RuleCoverage;
+
void gatherNodeEquivs();
Record *findNodeEquiv(Record *N) const;
}
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();
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()));
}
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 "
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";
--- /dev/null
+#!/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()