llvm.org GIT mirror llvm / 64b7700
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@318356 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Sanders 2 years ago
17 changed file(s) with 372 addition(s) and 40 deletion(s). Raw diff Collapse all Expand all
166166 endif()
167167
168168 option(LLVM_ENABLE_DAGISEL_COV "Debug: Prints tablegen patterns that were used for selecting" OFF)
169 option(LLVM_ENABLE_GISEL_COV "Enable collection of GlobalISel rule coverage" OFF)
170 if(LLVM_ENABLE_GISEL_COV)
171 set(LLVM_GISEL_COV_PREFIX "${CMAKE_BINARY_DIR}/gisel-coverage-" CACHE STRING "Provide a filename prefix to collect the GlobalISel rule coverage")
172 endif()
169173
170174 # Add path for custom modules
171175 set(CMAKE_MODULE_PATH
4949 list(FIND ARGN "-gen-dag-isel" idx)
5050 if( NOT idx EQUAL -1 )
5151 list(APPEND LLVM_TABLEGEN_FLAGS "-instrument-coverage")
52 endif()
53 endif()
54 if (LLVM_ENABLE_GISEL_COV)
55 list(FIND ARGN "-gen-global-isel" idx)
56 if( NOT idx EQUAL -1 )
57 list(APPEND LLVM_TABLEGEN_FLAGS "-instrument-gisel-coverage")
58 list(APPEND LLVM_TABLEGEN_FLAGS "-gisel-coverage-file=${LLVM_GISEL_COV_PREFIX}all")
5259 endif()
5360 endif()
5461
1616 #define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
1717
1818 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/Optional.h"
1920 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/Optional.h"
21 #include "llvm/Support/CodeGenCoverage.h"
2122 #include
2223 #include
2324 #include
3233 class LLT;
3334 class MachineInstr;
3435 class MachineInstrBuilder;
36 class MachineFunction;
3537 class MachineOperand;
3638 class MachineRegisterInfo;
3739 class RegisterBankInfo;
261263
262264 /// A successful emission
263265 GIR_Done,
266
267 /// Increment the rule coverage counter.
268 /// - RuleID - The ID of the rule that was covered.
269 GIR_Coverage,
264270 };
265271
266272 enum {
288294 /// if returns true:
289295 /// for I in all mutated/inserted instructions:
290296 /// !isPreISelGenericOpcode(I.getOpcode())
291 virtual bool select(MachineInstr &I) const = 0;
297 virtual bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const = 0;
292298
293299 protected:
294300 using ComplexRendererFns =
327333 const MatcherInfoTy &MatcherInfo,
328334 const int64_t *MatchTable, const TargetInstrInfo &TII,
329335 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
330 const RegisterBankInfo &RBI,
331 const PredicateBitset &AvailableFeatures) const;
336 const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
337 CodeGenCoverage &CoverageInfo) const;
332338
333339 /// Constrain a register operand of an instruction \p I to a specified
334340 /// register class. This could involve inserting COPYs before (for uses) or
4848 const MatcherInfoTy &MatcherInfo,
4949 const int64_t *MatchTable, const TargetInstrInfo &TII,
5050 MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
51 const RegisterBankInfo &RBI,
52 const PredicateBitset &AvailableFeatures) const {
51 const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
52 CodeGenCoverage &CoverageInfo) const {
5353 uint64_t CurrentIdx = 0;
5454 SmallVector OnFailResumeAt;
5555
676676 break;
677677 }
678678
679 case GIR_Coverage: {
680 int64_t RuleID = MatchTable[CurrentIdx++];
681 CoverageInfo.setCovered(RuleID);
682
683 DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
684 dbgs()
685 << CurrentIdx << ": GIR_Coverage(" << RuleID << ")");
686 break;
687 }
688
679689 case GIR_Done:
680690 DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
681691 dbgs() << CurrentIdx << ": GIR_Done");
436436 /* Define to a function implementing strdup */
437437 #cmakedefine strdup ${strdup}
438438
439 /* Whether GlobalISel rule coverage is being collected */
440 #cmakedefine01 LLVM_GISEL_COV_ENABLED
441
442 /* Define to the default GlobalISel coverage file prefix */
443 #cmakedefine LLVM_GISEL_COV_PREFIX "${LLVM_GISEL_COV_PREFIX}"
444
439445 #endif
0 //== llvm/Support/CodeGenCoverage.h ------------------------------*- C++ -*-==//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file This file provides rule coverage tracking for tablegen-erated CodeGen.
9 //===----------------------------------------------------------------------===//
10
11 #ifndef LLVM_SUPPORT_CODEGENCOVERAGE_H
12 #define LLVM_SUPPORT_CODEGENCOVERAGE_H
13
14 #include "llvm/ADT/BitVector.h"
15 #include "llvm/Config/config.h"
16
17 namespace llvm {
18 class LLVMContext;
19
20 class CodeGenCoverage {
21 protected:
22 BitVector RuleCoverage;
23
24 public:
25 CodeGenCoverage();
26
27 void setCovered(uint64_t RuleID);
28 bool isCovered(uint64_t RuleID);
29
30 bool parse(MemoryBuffer &Buffer, StringRef BackendName);
31 bool emit(StringRef FilePrefix, StringRef BackendName) const;
32 void reset();
33 };
34 } // end namespace llvm
35
36 #endif // ifndef LLVM_SUPPORT_CODEGENCOVERAGE_H
1919 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
2020 #include "llvm/CodeGen/MachineRegisterInfo.h"
2121 #include "llvm/CodeGen/TargetPassConfig.h"
22 #include "llvm/Config/config.h"
2223 #include "llvm/IR/Constants.h"
2324 #include "llvm/IR/Function.h"
2425 #include "llvm/Support/CommandLine.h"
2526 #include "llvm/Support/Debug.h"
27 #include "llvm/Support/TargetRegistry.h"
2628 #include "llvm/Target/TargetLowering.h"
2729 #include "llvm/Target/TargetSubtargetInfo.h"
2830
2931 #define DEBUG_TYPE "instruction-select"
3032
3133 using namespace llvm;
34
35 #ifdef LLVM_GISEL_COV_PREFIX
36 static cl::opt
37 CoveragePrefix("gisel-coverage-prefix", cl::init(LLVM_GISEL_COV_PREFIX),
38 cl::desc("Record GlobalISel rule coverage files of this "
39 "prefix if instrumentation was generated"));
40 #else
41 static const std::string CoveragePrefix = "";
42 #endif
3243
3344 char InstructionSelect::ID = 0;
3445 INITIALIZE_PASS_BEGIN(InstructionSelect, DEBUG_TYPE,
6576
6677 const TargetPassConfig &TPC = getAnalysis();
6778 const InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector();
79 CodeGenCoverage CoverageInfo;
6880 assert(ISel && "Cannot work without InstructionSelector");
6981
7082 // An optimization remark emitter. Used to report failures.
126138 continue;
127139 }
128140
129 if (!ISel->select(MI)) {
141 if (!ISel->select(MI, CoverageInfo)) {
130142 // FIXME: It would be nice to dump all inserted instructions. It's
131143 // not obvious how, esp. considering select() can insert after MI.
132144 reportGISelFailure(MF, TPC, MORE, "gisel-select", "cannot select", MI);
186198 auto &TLI = *MF.getSubtarget().getTargetLowering();
187199 TLI.finalizeLowering(MF);
188200
201 CoverageInfo.emit(CoveragePrefix,
202 MF.getSubtarget()
203 .getTargetLowering()
204 ->getTargetMachine()
205 .getTarget()
206 .getBackendName());
207
189208 // FIXME: Should we accurately track changes?
190209 return true;
191210 }
4747 circular_raw_ostream.cpp
4848 Chrono.cpp
4949 COM.cpp
50 CodeGenCoverage.cpp
5051 CommandLine.cpp
5152 Compression.cpp
5253 ConvertUTF.cpp
0 //===- lib/Support/CodeGenCoverage.cpp -------------------------------------==//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file
9 /// This file implements the CodeGenCoverage class.
10 //===----------------------------------------------------------------------===//
11
12 #include "llvm/Support/CodeGenCoverage.h"
13
14 #include "llvm/Support/Endian.h"
15 #include "llvm/Support/FileSystem.h"
16 #include "llvm/Support/Mutex.h"
17 #include "llvm/Support/ScopedPrinter.h"
18 #include "llvm/Support/ToolOutputFile.h"
19
20 #if LLVM_ON_UNIX
21 #include
22 #elif LLVM_ON_WIN32
23 #include
24 #endif
25
26 using namespace llvm;
27
28 static sys::SmartMutex OutputMutex;
29
30 CodeGenCoverage::CodeGenCoverage() {}
31
32 void CodeGenCoverage::setCovered(uint64_t RuleID) {
33 if (RuleCoverage.size() <= RuleID)
34 RuleCoverage.resize(RuleID + 1, 0);
35 RuleCoverage[RuleID] = true;
36 }
37
38 bool CodeGenCoverage::isCovered(uint64_t RuleID) {
39 if (RuleCoverage.size() <= RuleID)
40 return false;
41 return RuleCoverage[RuleID];
42 }
43
44 bool CodeGenCoverage::parse(MemoryBuffer &Buffer, StringRef BackendName) {
45 const char *CurPtr = Buffer.getBufferStart();
46
47 while (CurPtr != Buffer.getBufferEnd()) {
48 // Read the backend name from the input.
49 const char *LexedBackendName = CurPtr;
50 while (*CurPtr++ != 0)
51 ;
52 if (CurPtr == Buffer.getBufferEnd())
53 return false; // Data is invalid, expected rule id's to follow.
54
55 bool IsForThisBackend = BackendName.equals(LexedBackendName);
56 while (CurPtr != Buffer.getBufferEnd()) {
57 if (std::distance(CurPtr, Buffer.getBufferEnd()) < 8)
58 return false; // Data is invalid. Not enough bytes for another rule id.
59
60 uint64_t RuleID = support::endian::read64(CurPtr, support::native);
61 CurPtr += 8;
62
63 // ~0ull terminates the rule id list.
64 if (RuleID == ~0ull)
65 break;
66
67 // Anything else, is recorded or ignored depending on whether it's
68 // intended for the backend we're interested in.
69 if (IsForThisBackend)
70 setCovered(RuleID);
71 }
72 }
73
74 return true;
75 }
76
77 bool CodeGenCoverage::emit(StringRef CoveragePrefix,
78 StringRef BackendName) const {
79 if (!CoveragePrefix.empty() && !RuleCoverage.empty()) {
80 sys::SmartScopedLock Lock(OutputMutex);
81
82 // We can handle locking within a process easily enough but we don't want to
83 // manage it between multiple processes. Use the process ID to ensure no
84 // more than one process is ever writing to the same file at the same time.
85 std::string Pid =
86 #if LLVM_ON_UNIX
87 llvm::to_string(::getpid());
88 #elif LLVM_ON_WIN32
89 llvm::to_string(::GetCurrentProcessId());
90 #else
91 "";
92 #endif
93
94 std::string CoverageFilename = (CoveragePrefix + Pid).str();
95
96 std::error_code EC;
97 sys::fs::OpenFlags OpenFlags = sys::fs::F_Append;
98 std::unique_ptr CoverageFile =
99 llvm::make_unique(CoverageFilename, EC, OpenFlags);
100 if (EC)
101 return false;
102
103 uint64_t Zero = 0;
104 uint64_t InvZero = ~0ull;
105 CoverageFile->os() << BackendName;
106 CoverageFile->os().write((const char *)&Zero, sizeof(unsigned char));
107 for (uint64_t I : RuleCoverage.set_bits())
108 CoverageFile->os().write((const char *)&I, sizeof(uint64_t));
109 CoverageFile->os().write((const char *)&InvZero, sizeof(uint64_t));
110
111 CoverageFile->keep();
112 }
113
114 return true;
115 }
116
117 void CodeGenCoverage::reset() { RuleCoverage.resize(0); }
4747 const AArch64Subtarget &STI,
4848 const AArch64RegisterBankInfo &RBI);
4949
50 bool select(MachineInstr &I) const override;
50 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
5151 static const char *getName() { return DEBUG_TYPE; }
5252
5353 private:
5454 /// tblgen-erated 'select' implementation, used as the initial selector for
5555 /// the patterns that don't require complex C++.
56 bool selectImpl(MachineInstr &I) const;
56 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
5757
5858 bool selectVaStartAAPCS(MachineInstr &I, MachineFunction &MF,
5959 MachineRegisterInfo &MRI) const;
608608 return true;
609609 }
610610
611 bool AArch64InstructionSelector::select(MachineInstr &I) const {
611 bool AArch64InstructionSelector::select(MachineInstr &I,
612 CodeGenCoverage &CoverageInfo) const {
612613 assert(I.getParent() && "Instruction should be in a basic block!");
613614 assert(I.getParent()->getParent() && "Instruction should be in a function!");
614615
666667 return false;
667668 }
668669
669 if (selectImpl(I))
670 if (selectImpl(I, CoverageInfo))
670671 return true;
671672
672673 LLT Ty =
401401 return Ret;
402402 }
403403
404 bool AMDGPUInstructionSelector::select(MachineInstr &I) const {
404 bool AMDGPUInstructionSelector::select(MachineInstr &I,
405 CodeGenCoverage &CoverageInfo) const {
405406
406407 if (!isPreISelGenericOpcode(I.getOpcode()))
407408 return true;
3434 AMDGPUInstructionSelector(const SISubtarget &STI,
3535 const AMDGPURegisterBankInfo &RBI);
3636
37 bool select(MachineInstr &I) const override;
37 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
38
3839 private:
3940 struct GEPInfo {
4041 const MachineInstr &GEP;
3434 ARMInstructionSelector(const ARMBaseTargetMachine &TM, const ARMSubtarget &STI,
3535 const ARMRegisterBankInfo &RBI);
3636
37 bool select(MachineInstr &I) const override;
37 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
3838 static const char *getName() { return DEBUG_TYPE; }
3939
4040 private:
41 bool selectImpl(MachineInstr &I) const;
41 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
4242
4343 struct CmpConstants;
4444 struct InsertInfo;
652652 return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
653653 }
654654
655 bool ARMInstructionSelector::select(MachineInstr &I) const {
655 bool ARMInstructionSelector::select(MachineInstr &I,
656 CodeGenCoverage &CoverageInfo) const {
656657 assert(I.getParent() && "Instruction should be in a basic block!");
657658 assert(I.getParent()->getParent() && "Instruction should be in a function!");
658659
667668 return true;
668669 }
669670
670 if (selectImpl(I))
671 if (selectImpl(I, CoverageInfo))
671672 return true;
672673
673674 MachineInstrBuilder MIB{MF, I};
6060 X86InstructionSelector(const X86TargetMachine &TM, const X86Subtarget &STI,
6161 const X86RegisterBankInfo &RBI);
6262
63 bool select(MachineInstr &I) const override;
63 bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
6464 static const char *getName() { return DEBUG_TYPE; }
6565
6666 private:
6767 /// tblgen-erated 'select' implementation, used as the initial selector for
6868 /// the patterns that don't require complex C++.
69 bool selectImpl(MachineInstr &I) const;
69 bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
7070
7171 // TODO: remove after supported by Tablegen-erated instruction selection.
7272 unsigned getLoadStoreOp(const LLT &Ty, const RegisterBank &RB, unsigned Opc,
9292 MachineFunction &MF) const;
9393 bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const;
9494 bool selectUnmergeValues(MachineInstr &I, MachineRegisterInfo &MRI,
95 MachineFunction &MF) const;
95 MachineFunction &MF,
96 CodeGenCoverage &CoverageInfo) const;
9697 bool selectMergeValues(MachineInstr &I, MachineRegisterInfo &MRI,
97 MachineFunction &MF) const;
98 MachineFunction &MF,
99 CodeGenCoverage &CoverageInfo) const;
98100 bool selectInsert(MachineInstr &I, MachineRegisterInfo &MRI,
99101 MachineFunction &MF) const;
100102 bool selectExtract(MachineInstr &I, MachineRegisterInfo &MRI,
293295 return true;
294296 }
295297
296 bool X86InstructionSelector::select(MachineInstr &I) const {
298 bool X86InstructionSelector::select(MachineInstr &I,
299 CodeGenCoverage &CoverageInfo) const {
297300 assert(I.getParent() && "Instruction should be in a basic block!");
298301 assert(I.getParent()->getParent() && "Instruction should be in a function!");
299302
317320 assert(I.getNumOperands() == I.getNumExplicitOperands() &&
318321 "Generic instruction has unexpected implicit operands\n");
319322
320 if (selectImpl(I))
323 if (selectImpl(I, CoverageInfo))
321324 return true;
322325
323326 DEBUG(dbgs() << " C++ instruction selection: "; I.print(dbgs()));
349352 case TargetOpcode::G_UADDE:
350353 return selectUadde(I, MRI, MF);
351354 case TargetOpcode::G_UNMERGE_VALUES:
352 return selectUnmergeValues(I, MRI, MF);
355 return selectUnmergeValues(I, MRI, MF, CoverageInfo);
353356 case TargetOpcode::G_MERGE_VALUES:
354 return selectMergeValues(I, MRI, MF);
357 return selectMergeValues(I, MRI, MF, CoverageInfo);
355358 case TargetOpcode::G_EXTRACT:
356359 return selectExtract(I, MRI, MF);
357360 case TargetOpcode::G_INSERT:
10921095 return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
10931096 }
10941097
1095 bool X86InstructionSelector::selectUnmergeValues(MachineInstr &I,
1096 MachineRegisterInfo &MRI,
1097 MachineFunction &MF) const {
1098 bool X86InstructionSelector::selectUnmergeValues(
1099 MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF,
1100 CodeGenCoverage &CoverageInfo) const {
10981101 assert((I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES) &&
10991102 "unexpected instruction");
11001103
11101113 .addReg(SrcReg)
11111114 .addImm(Idx * DefSize);
11121115
1113 if (!select(ExtrInst))
1116 if (!select(ExtrInst, CoverageInfo))
11141117 return false;
11151118 }
11161119
11181121 return true;
11191122 }
11201123
1121 bool X86InstructionSelector::selectMergeValues(MachineInstr &I,
1122 MachineRegisterInfo &MRI,
1123 MachineFunction &MF) const {
1124 bool X86InstructionSelector::selectMergeValues(
1125 MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF,
1126 CodeGenCoverage &CoverageInfo) const {
11241127 assert((I.getOpcode() == TargetOpcode::G_MERGE_VALUES) &&
11251128 "unexpected instruction");
11261129
11521155
11531156 DefReg = Tmp;
11541157
1155 if (!select(InsertInst))
1158 if (!select(InsertInst, CoverageInfo))
11561159 return false;
11571160 }
11581161
11601163 TII.get(TargetOpcode::COPY), DstReg)
11611164 .addReg(DefReg);
11621165
1163 if (!select(CopyInst))
1166 if (!select(CopyInst, CoverageInfo))
11641167 return false;
11651168
11661169 I.eraseFromParent();
152152 // CHECK-NEXT: &MyTargetInstructionSelector::selectComplexPatternRR, // gi_complex_rr
153153 // CHECK-NEXT: }
154154
155 // CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const {
155 // CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const {
156156 // CHECK-NEXT: MachineFunction &MF = *I.getParent()->getParent();
157157 // CHECK-NEXT: MachineRegisterInfo &MRI = MF.getRegInfo();
158158 // CHECK: AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, &MF);
898898
899899 // CHECK-NEXT: GIM_Reject,
900900 // CHECK-NEXT: };
901 // CHECK-NEXT: if (executeMatchTable(*this, OutMIs, State, MatcherInfo, MatchTable0, TII, MRI, TRI, RBI, AvailableFeatures)) {
901 // CHECK-NEXT: if (executeMatchTable(*this, OutMIs, State, MatcherInfo, MatchTable0, TII, MRI, TRI, RBI, AvailableFeatures, CoverageInfo)) {
902902 // CHECK-NEXT: return true;
903903 // CHECK-NEXT: }
3535 #include "llvm/ADT/SmallSet.h"
3636 #include "llvm/ADT/Statistic.h"
3737 #include "llvm/CodeGen/MachineValueType.h"
38 #include "llvm/Support/CodeGenCoverage.h"
3839 #include "llvm/Support/CommandLine.h"
3940 #include "llvm/Support/Error.h"
4041 #include "llvm/Support/LowLevelTypeImpl.h"
4243 #include "llvm/TableGen/Error.h"
4344 #include "llvm/TableGen/Record.h"
4445 #include "llvm/TableGen/TableGenBackend.h"
46 #include
4547 #include
46 #include
4748 using namespace llvm;
4849
4950 #define DEBUG_TYPE "gisel-emitter"
5152 STATISTIC(NumPatternTotal, "Total number of patterns");
5253 STATISTIC(NumPatternImported, "Number of patterns imported from SelectionDAG");
5354 STATISTIC(NumPatternImportsSkipped, "Number of SelectionDAG imports skipped");
55 STATISTIC(NumPatternsTested, "Number of patterns executed according to coverage information");
5456 STATISTIC(NumPatternEmitted, "Number of patterns emitted");
5557
5658 cl::OptionCategory GlobalISelEmitterCat("Options for -gen-global-isel");
6062 cl::desc("Explain why a pattern was skipped for inclusion "
6163 "in the GlobalISel selector"),
6264 cl::init(false), cl::cat(GlobalISelEmitterCat));
65
66 static cl::opt GenerateCoverage(
67 "instrument-gisel-coverage",
68 cl::desc("Generate coverage instrumentation for GlobalISel"),
69 cl::init(false), cl::cat(GlobalISelEmitterCat));
70
71 static cl::opt UseCoverageFile(
72 "gisel-coverage-file", cl::init(""),
73 cl::desc("Specify file to retrieve coverage information from"),
74 cl::cat(GlobalISelEmitterCat));
6375
6476 namespace {
6577 //===- Helper functions ---------------------------------------------------===//
568580 /// A map of Symbolic Names to ComplexPattern sub-operands.
569581 DefinedComplexPatternSubOperandMap ComplexSubOperands;
570582
583 uint64_t RuleID;
584 static uint64_t NextRuleID;
585
571586 public:
572587 RuleMatcher(ArrayRef SrcLoc)
573588 : Matchers(), Actions(), InsnVariableIDs(), MutatableInsns(),
574589 DefinedOperands(), NextInsnVarID(0), NextOutputInsnID(0),
575 NextTempRegID(0), SrcLoc(SrcLoc), ComplexSubOperands() {}
590 NextTempRegID(0), SrcLoc(SrcLoc), ComplexSubOperands(),
591 RuleID(NextRuleID++) {}
576592 RuleMatcher(RuleMatcher &&Other) = default;
577593 RuleMatcher &operator=(RuleMatcher &&Other) = default;
594
595 uint64_t getRuleID() const { return RuleID; }
578596
579597 InstructionMatcher &addInstructionMatcher(StringRef SymbolicName);
580598 void addRequiredFeature(Record *Feature);
662680 unsigned allocateOutputInsnID() { return NextOutputInsnID++; }
663681 unsigned allocateTempRegID() { return NextTempRegID++; }
664682 };
683
684 uint64_t RuleMatcher::NextRuleID = 0;
665685
666686 using action_iterator = RuleMatcher::action_iterator;
667687
22032223
22042224 for (const auto &MA : Actions)
22052225 MA->emitActionOpcodes(Table, *this);
2226
2227 if (GenerateCoverage)
2228 Table << MatchTable::Opcode("GIR_Coverage") << MatchTable::IntValue(RuleID)
2229 << MatchTable::LineBreak;
2230
22062231 Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak
22072232 << MatchTable::Label(LabelID);
22082233 }
23072332
23082333 // Map of predicates to their subtarget features.
23092334 SubtargetFeatureInfoMap SubtargetFeatures;
2335
2336 // Rule coverage information.
2337 Optional RuleCoverage;
23102338
23112339 void gatherNodeEquivs();
23122340 Record *findNodeEquiv(Record *N) const;
32263254 }
32273255
32283256 void GlobalISelEmitter::run(raw_ostream &OS) {
3257 if (!UseCoverageFile.empty()) {
3258 RuleCoverage = CodeGenCoverage();
3259 auto RuleCoverageBufOrErr = MemoryBuffer::getFile(UseCoverageFile);
3260 if (!RuleCoverageBufOrErr) {
3261 PrintWarning(SMLoc(), "Missing rule coverage data");
3262 RuleCoverage = None;
3263 } else {
3264 if (!RuleCoverage->parse(*RuleCoverageBufOrErr.get(), Target.getName())) {
3265 PrintWarning(SMLoc(), "Ignoring invalid or missing rule coverage data");
3266 RuleCoverage = None;
3267 }
3268 }
3269 }
3270
32293271 // Track the GINodeEquiv definitions.
32303272 gatherNodeEquivs();
32313273
32513293 continue;
32523294 }
32533295
3296 if (RuleCoverage) {
3297 if (RuleCoverage->isCovered(MatcherOrErr->getRuleID()))
3298 ++NumPatternsTested;
3299 else
3300 PrintWarning(Pat.getSrcRecord()->getLoc(),
3301 "Pattern is not covered by a test");
3302 }
32543303 Rules.push_back(std::move(MatcherOrErr.get()));
32553304 }
32563305
34303479 OS << "};\n\n";
34313480
34323481 OS << "bool " << Target.getName()
3433 << "InstructionSelector::selectImpl(MachineInstr &I) const {\n"
3482 << "InstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage "
3483 "&CoverageInfo) const {\n"
34343484 << " MachineFunction &MF = *I.getParent()->getParent();\n"
34353485 << " MachineRegisterInfo &MRI = MF.getRegInfo();\n"
34363486 << " // FIXME: This should be computed on a per-function basis rather "
34513501 Table.emitDeclaration(OS);
34523502 OS << " if (executeMatchTable(*this, OutMIs, State, MatcherInfo, ";
34533503 Table.emitUse(OS);
3454 OS << ", TII, MRI, TRI, RBI, AvailableFeatures)) {\n"
3504 OS << ", TII, MRI, TRI, RBI, AvailableFeatures, CoverageInfo)) {\n"
34553505 << " return true;\n"
34563506 << " }\n\n";
34573507
0 #!/usr/bin/env python
1 """
2 Summarize the information in the given coverage files.
3
4 Emits the number of rules covered or the percentage of rules covered depending
5 on whether --num-rules has been used to specify the total number of rules.
6 """
7
8 import argparse
9 import struct
10
11 class FileFormatError(Exception):
12 pass
13
14 def backend_int_pair(s):
15 backend, sep, value = s.partition('=')
16 if (sep is None):
17 raise argparse.ArgumentTypeError("'=' missing, expected name=value")
18 if (not backend):
19 raise argparse.ArgumentTypeError("Expected name=value")
20 if (not value):
21 raise argparse.ArgumentTypeError("Expected name=value")
22 return backend, int(value)
23
24 def main():
25 parser = argparse.ArgumentParser(description=__doc__)
26 parser.add_argument('input', nargs='+')
27 parser.add_argument('--num-rules', type=backend_int_pair, action='append',
28 metavar='BACKEND=NUM',
29 help='Specify the number of rules for a backend')
30 args = parser.parse_args()
31
32 covered_rules = {}
33
34 for input_filename in args.input:
35 with open(input_filename, 'rb') as input_fh:
36 data = input_fh.read()
37 pos = 0
38 while data:
39 backend, _, data = data.partition('\0')
40 pos += len(backend)
41 pos += 1
42
43 if len(backend) == 0:
44 raise FileFormatError()
45 backend, = struct.unpack("%ds" % len(backend), backend)
46
47 while data:
48 if len(data) < 8:
49 raise FileFormatError()
50 rule_id, = struct.unpack("Q", data[:8])
51 pos += 8
52 data = data[8:]
53 if rule_id == (2 ** 64) - 1:
54 break
55 covered_rules[backend] = covered_rules.get(backend, {})
56 covered_rules[backend][rule_id] = covered_rules[backend].get(rule_id, 0) + 1
57
58 num_rules = dict(args.num_rules)
59 for backend, rules_for_backend in covered_rules.items():
60 if backend in num_rules:
61 print "%s: %3.2f%% of rules covered" % (backend, (float(len(rules_for_backend.keys())) / num_rules[backend]) * 100)
62 else:
63 print "%s: %d rules covered" % (backend, len(rules_for_backend.keys()))
64
65 if __name__ == '__main__':
66 main()