Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -171,6 +171,11 @@ add_definitions(-DLLVM_BUILD_GLOBAL_ISEL) endif() +option(DAG_PRINT_USED_ISEL_PATTERNS "Debug: Prints tablegen patterns that were used for selecting" OFF) +if(DAG_PRINT_USED_ISEL_PATTERNS) + set(LLVM_TBLGEN_DAG_FLAGS "-instrument-coverage") +endif() + # Add path for custom modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} Index: include/llvm/CodeGen/SelectionDAGISel.h =================================================================== --- include/llvm/CodeGen/SelectionDAGISel.h +++ include/llvm/CodeGen/SelectionDAGISel.h @@ -151,7 +151,9 @@ OPC_MorphNodeTo, // Space-optimized forms that implicitly encode number of result VTs. OPC_MorphNodeTo0, OPC_MorphNodeTo1, OPC_MorphNodeTo2, - OPC_CompleteMatch + OPC_CompleteMatch, + // Contains offset in table for pattern being selected + OPC_Coverage }; enum { @@ -213,6 +215,15 @@ void SelectInlineAsmMemoryOperands(std::vector &Ops, const SDLoc &DL); + /// getPatternForIndex - Patterns selected by tablegen during ISEL + virtual StringRef getPatternForIndex(unsigned index) { + llvm_unreachable("Tblgen should generate the implementation of this!"); + } + + /// getIncludePathForIndex - get the td source location of pattern instantiation + virtual StringRef getIncludePathForIndex(unsigned index) { + llvm_unreachable("Tblgen should generate the implementation of this!"); + } public: // Calls to these predicates are generated by tblgen. bool CheckAndMask(SDValue LHS, ConstantSDNode *RHS, Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -3481,6 +3481,15 @@ RecordedNodes.push_back(std::pair(Res, nullptr)); continue; } + case OPC_Coverage: { + // This is emitted right before MorphNode/EmitNode. + // So it should be safe to assume that this node has been selected + unsigned index = MatcherTable[MatcherIndex++]; + index |= (MatcherTable[MatcherIndex++] << 8); + dbgs() << "MORPHTO: " << getPatternForIndex(index) << "\n"; + dbgs() << "INCLUDED: " << getIncludePathForIndex(index) << "\n"; + continue; + } case OPC_EmitNode: case OPC_MorphNodeTo: case OPC_EmitNode0: case OPC_EmitNode1: case OPC_EmitNode2: Index: lib/Target/AArch64/CMakeLists.txt =================================================================== --- lib/Target/AArch64/CMakeLists.txt +++ lib/Target/AArch64/CMakeLists.txt @@ -7,7 +7,7 @@ tablegen(LLVM AArch64GenAsmWriter.inc -gen-asm-writer) tablegen(LLVM AArch64GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1) tablegen(LLVM AArch64GenAsmMatcher.inc -gen-asm-matcher) -tablegen(LLVM AArch64GenDAGISel.inc -gen-dag-isel) +tablegen(LLVM AArch64GenDAGISel.inc -gen-dag-isel ${LLVM_TBLGEN_DAG_FLAGS}) tablegen(LLVM AArch64GenFastISel.inc -gen-fast-isel) tablegen(LLVM AArch64GenCallingConv.inc -gen-callingconv) tablegen(LLVM AArch64GenSubtargetInfo.inc -gen-subtarget) Index: utils/TableGen/DAGISelMatcherEmitter.cpp =================================================================== --- utils/TableGen/DAGISelMatcherEmitter.cpp +++ utils/TableGen/DAGISelMatcherEmitter.cpp @@ -11,14 +11,16 @@ // //===----------------------------------------------------------------------===// -#include "DAGISelMatcher.h" #include "CodeGenDAGPatterns.h" +#include "DAGISelMatcher.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" using namespace llvm; @@ -31,6 +33,11 @@ OmitComments("omit-comments", cl::desc("Do not generate comments"), cl::init(false)); +static cl::opt InstrumentCoverage( + "instrument-coverage", + cl::desc("Generates tables to help identify patterns matched"), + cl::init(false)); + namespace { class MatcherTableEmitter { const CodeGenDAGPatterns &CGP; @@ -52,6 +59,21 @@ DenseMap NodeXFormMap; std::vector NodeXForms; + typedef std::pair PatternPair; + std::vector VecPatternsCovered; + std::vector VecIncludeStrings; + + unsigned getPatternIdxFromTable(PatternPair P, std::string include_loc) { + auto It = + std::find(VecPatternsCovered.begin(), VecPatternsCovered.end(), P); + if (It == VecPatternsCovered.end()) { + VecPatternsCovered.push_back(P); + VecIncludeStrings.push_back(include_loc); + return VecPatternsCovered.size() - 1; + } + return std::distance(VecPatternsCovered.begin(), It); + } + public: MatcherTableEmitter(const CodeGenDAGPatterns &cgp) : CGP(cgp) {} @@ -114,9 +136,51 @@ return Entry-1; } +public: + void PrintPatternMatchTable(raw_ostream &OS, StringRef Prefix) { + + assert(VecPatternsCovered.size() < 65536 && + "Using only 16 bits to encode offset into Pattern Table"); + assert(VecPatternsCovered.size() == VecIncludeStrings.size() && + "The sizes of Pattern and include vectors should be the same"); + OS << "StringRef getPatternForIndex(unsigned index) override{\n"; + OS << "static const char* " << Prefix << "_PATTERN_MATCH_TABLE[] = {\n"; + + for (size_t i = 0, e = VecPatternsCovered.size(); i != e; ++i) { + OS << "\"" << VecPatternsCovered[i].first << " -> " + << VecPatternsCovered[i].second << "\""; + if (i < e - 1) + OS << ",\n"; + } + + OS << "\n};"; + OS << "\nreturn StringRef(" << Prefix << "_PATTERN_MATCH_TABLE[index]);"; + OS << "\n}"; + + OS << "\nStringRef getIncludePathForIndex(unsigned index) override{\n"; + OS << "static const char* " << Prefix << "_INCLUDE_PATH_TABLE[] = {\n"; + + for (size_t i = 0, e = VecIncludeStrings.size(); i != e; ++i) { + OS << "\"" << VecIncludeStrings[i] << "\""; + if (i < e - 1) + OS << ",\n"; + } + + OS << "\n};"; + OS << "\nreturn StringRef(" << Prefix << "_INCLUDE_PATH_TABLE[index]);"; + OS << "\n}"; + } }; } // end anonymous namespace. +static std::string GetPatFromTreePatternNode(const TreePatternNode *N) { + std::string str; + raw_string_ostream Stream(str); + Stream << *N; + Stream.str(); + return str; +} + static unsigned GetVBRSize(unsigned Val) { if (Val <= 127) return 1; @@ -150,6 +214,27 @@ return NumBytes+1; } +// This is expensive and slow. +static std::string getIncludePath(const Record *R) { + std::string str; + raw_string_ostream Stream(str); + auto Locs = R->getLoc(); + SMLoc L; + if (Locs.size() > 1) { + // Get where the pattern prototype was instantiated + L = Locs[1]; + } else if (Locs.size() == 1) { + L = Locs[0]; + } + unsigned CurBuf = SrcMgr.FindBufferContainingLoc(L); + assert(CurBuf && "Invalid or unspecified location!"); + + Stream << SrcMgr.getBufferInfo(CurBuf).Buffer->getBufferIdentifier() << ":" + << SrcMgr.FindLineNumber(L, CurBuf); + Stream.str(); + return str; +} + /// EmitMatcher - Emit bytes for the specified matcher and return /// the number of bytes emitted. unsigned MatcherTableEmitter:: @@ -537,6 +622,23 @@ case Matcher::EmitNode: case Matcher::MorphNodeTo: { + bool Coverage_emitted = false; + if (InstrumentCoverage) { + if (const MorphNodeToMatcher *SNT = dyn_cast(N)) { + Coverage_emitted = true; + OS << "OPC_Coverage, "; + std::string src = + GetPatFromTreePatternNode(SNT->getPattern().getSrcPattern()); + std::string dst = + GetPatFromTreePatternNode(SNT->getPattern().getDstPattern()); + Record *PatRecord = SNT->getPattern().getSrcRecord(); + std::string include_src = getIncludePath(PatRecord); + unsigned Offset = + getPatternIdxFromTable(make_pair(src, dst), include_src); + OS << "TARGET_VAL(" << Offset << "),\n"; + OS.PadToColumn(Indent * 2); + } + } const EmitNodeMatcherCommon *EN = cast(N); OS << (isa(EN) ? "OPC_EmitNode" : "OPC_MorphNodeTo"); bool CompressVTs = EN->getNumVTs() < 3; @@ -593,10 +695,26 @@ } else OS << '\n'; - return 5 + !CompressVTs + EN->getNumVTs() + NumOperandBytes; + return 5 + !CompressVTs + EN->getNumVTs() + NumOperandBytes + + Coverage_emitted * 3; } case Matcher::CompleteMatch: { const CompleteMatchMatcher *CM = cast(N); + bool Coverage_emitted = false; + if (InstrumentCoverage) { + Coverage_emitted = true; + OS << "OPC_Coverage, "; + std::string src = + GetPatFromTreePatternNode(CM->getPattern().getSrcPattern()); + std::string dst = + GetPatFromTreePatternNode(CM->getPattern().getDstPattern()); + Record *PatRecord = CM->getPattern().getSrcRecord(); + std::string include_src = getIncludePath(PatRecord); + unsigned Offset = + getPatternIdxFromTable(make_pair(src, dst), include_src); + OS << "TARGET_VAL(" << Offset << "),\n"; + OS.PadToColumn(Indent * 2); + } OS << "OPC_CompleteMatch, " << CM->getNumResults() << ", "; unsigned NumResultBytes = 0; for (unsigned i = 0, e = CM->getNumResults(); i != e; ++i) @@ -610,7 +728,7 @@ << *CM->getPattern().getDstPattern(); } OS << '\n'; - return 2 + NumResultBytes; + return 2 + NumResultBytes + Coverage_emitted * 3; } } llvm_unreachable("Unreachable"); @@ -686,8 +804,13 @@ ++NumOps; // Get the chained node too. OS << " case " << i << ":\n"; + if (InstrumentCoverage) + OS << " {\n"; OS << " Result.resize(NextRes+" << NumOps << ");\n"; - OS << " return " << P.getSelectFunc(); + if (InstrumentCoverage) + OS << " bool returnValue = " << P.getSelectFunc(); + else + OS << " return " << P.getSelectFunc(); OS << "("; // If the complex pattern wants the root of the match, pass it in as the @@ -704,6 +827,13 @@ for (unsigned i = 0; i != NumOps; ++i) OS << ", Result[NextRes+" << i << "].first"; OS << ");\n"; + if (InstrumentCoverage) { + OS << " if (returnValue) \n"; + OS << " dbgs() << \"\\nCOMPLEX_PATTERN: " << P.getSelectFunc() + << "\\n\" ;\n"; + OS << " return returnValue;\n"; + OS << " \n}\n"; + } } OS << " }\n"; OS << "}\n\n"; @@ -847,4 +977,8 @@ // Next up, emit the function for node and pattern predicates: MatcherEmitter.EmitPredicateFunctions(OS); + + if (InstrumentCoverage) + MatcherEmitter.PrintPatternMatchTable(OS, + CGP.getTargetInfo().getName().str()); }