From da272d1a704bd564272e88cbdbcf14712e3abbdc Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Mon, 15 Feb 2010 08:04:42 +0000 Subject: [PATCH] Check in the first big step of rewriting DAGISelEmitter to produce a table based matcher instead of gobs of C++ Code. Though it's not done yet, the shrinkage seems promising, the table for the X86 ISel is 75K and still has a lot of optimization to come (compare to the ~1.5M of .o generated the old way, much of which will go away). The code is currently disabled by default (the #if 0 in DAGISelEmitter.cpp). When enabled it generates a dead SelectCode2 function in the DAGISel Header which will eventually replace SelectCode. There is still a lot of stuff left to do, which are documented with a trail of FIXMEs. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@96215 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/DAGISelHeader.h | 264 +++++++++++++++++ utils/TableGen/CMakeLists.txt | 3 + utils/TableGen/DAGISelEmitter.cpp | 26 +- utils/TableGen/DAGISelMatcher.cpp | 108 +++++++ utils/TableGen/DAGISelMatcher.h | 362 +++++++++++++++++++++++ utils/TableGen/DAGISelMatcherEmitter.cpp | 217 ++++++++++++++ utils/TableGen/DAGISelMatcherGen.cpp | 287 ++++++++++++++++++ 7 files changed, 1265 insertions(+), 2 deletions(-) create mode 100644 utils/TableGen/DAGISelMatcher.cpp create mode 100644 utils/TableGen/DAGISelMatcher.h create mode 100644 utils/TableGen/DAGISelMatcherEmitter.cpp create mode 100644 utils/TableGen/DAGISelMatcherGen.cpp diff --git a/include/llvm/CodeGen/DAGISelHeader.h b/include/llvm/CodeGen/DAGISelHeader.h index 4d50879a152..f9490a77caa 100644 --- a/include/llvm/CodeGen/DAGISelHeader.h +++ b/include/llvm/CodeGen/DAGISelHeader.h @@ -132,4 +132,268 @@ void SelectRoot(SelectionDAG &DAG) { CurDAG->setRoot(Dummy.getValue()); } + +/// CheckInteger - Return true if the specified node is not a ConstantSDNode or +/// if it doesn't have the specified value. +static bool CheckInteger(SDValue V, int64_t Val) { + ConstantSDNode *C = dyn_cast(V); + return C == 0 || C->getSExtValue() != Val; +} + +/// CheckAndImmediate - Check to see if the specified node is an and with an +/// immediate returning true on failure. +/// +/// FIXME: Inline this gunk into CheckAndMask. +bool CheckAndImmediate(SDValue V, int64_t Val) { + if (V->getOpcode() == ISD::AND) + if (ConstantSDNode *C = dyn_cast(V->getOperand(1))) + if (CheckAndMask(V.getOperand(0), C, Val)) + return false; + return true; +} + +/// CheckOrImmediate - Check to see if the specified node is an or with an +/// immediate returning true on failure. +/// +/// FIXME: Inline this gunk into CheckOrMask. +bool CheckOrImmediate(SDValue V, int64_t Val) { + if (V->getOpcode() == ISD::OR) + if (ConstantSDNode *C = dyn_cast(V->getOperand(1))) + if (CheckOrMask(V.getOperand(0), C, Val)) + return false; + return true; +} + +static int8_t GetInt1(const unsigned char *MatcherTable, unsigned &Idx) { + return MatcherTable[Idx++]; +} + +static int16_t GetInt2(const unsigned char *MatcherTable, unsigned &Idx) { + int16_t Val = GetInt1(MatcherTable, Idx); + Val |= int16_t(GetInt1(MatcherTable, Idx)) << 8; + return Val; +} + +static int32_t GetInt4(const unsigned char *MatcherTable, unsigned &Idx) { + int32_t Val = GetInt2(MatcherTable, Idx); + Val |= int32_t(GetInt2(MatcherTable, Idx)) << 16; + return Val; +} + +static int64_t GetInt8(const unsigned char *MatcherTable, unsigned &Idx) { + int64_t Val = GetInt4(MatcherTable, Idx); + Val |= int64_t(GetInt4(MatcherTable, Idx)) << 32; + return Val; +} + +enum BuiltinOpcodes { + OPC_Emit, + OPC_Push, + OPC_Record, + OPC_MoveChild, + OPC_MoveParent, + OPC_CheckSame, + OPC_CheckPatternPredicate, + OPC_CheckPredicate, + OPC_CheckOpcode, + OPC_CheckType, + OPC_CheckInteger1, OPC_CheckInteger2, OPC_CheckInteger4, OPC_CheckInteger8, + OPC_CheckCondCode, + OPC_CheckValueType, + OPC_CheckComplexPat, + OPC_CheckAndImm1, OPC_CheckAndImm2, OPC_CheckAndImm4, OPC_CheckAndImm8, + OPC_CheckOrImm1, OPC_CheckOrImm2, OPC_CheckOrImm4, OPC_CheckOrImm8 +}; + +struct MatchScope { + /// FailIndex - If this match fails, this is the index to continue with. + unsigned FailIndex; + + /// NodeStackSize - The size of the node stack when the scope was formed. + unsigned NodeStackSize; + + /// NumRecordedNodes - The number of recorded nodes when the scope was formed. + unsigned NumRecordedNodes; +}; + +SDNode *SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, + unsigned TableSize) { + switch (NodeToMatch->getOpcode()) { + default: + break; + case ISD::EntryToken: // These nodes remain the same. + case ISD::BasicBlock: + case ISD::Register: + case ISD::HANDLENODE: + case ISD::TargetConstant: + case ISD::TargetConstantFP: + case ISD::TargetConstantPool: + case ISD::TargetFrameIndex: + case ISD::TargetExternalSymbol: + case ISD::TargetBlockAddress: + case ISD::TargetJumpTable: + case ISD::TargetGlobalTLSAddress: + case ISD::TargetGlobalAddress: + case ISD::TokenFactor: + case ISD::CopyFromReg: + case ISD::CopyToReg: + return 0; + case ISD::AssertSext: + case ISD::AssertZext: + ReplaceUses(SDValue(NodeToMatch, 0), NodeToMatch->getOperand(0)); + return 0; + case ISD::INLINEASM: return Select_INLINEASM(NodeToMatch); + case ISD::EH_LABEL: return Select_EH_LABEL(NodeToMatch); + case ISD::UNDEF: return Select_UNDEF(NodeToMatch); + } + + assert(!NodeToMatch->isMachineOpcode() && "Node already selected!"); + + SmallVector MatchScopes; + + // RecordedNodes - This is the set of nodes that have been recorded by the + // state machine. + SmallVector RecordedNodes; + + // Set up the node stack with NodeToMatch as the only node on the stack. + SmallVector NodeStack; + SDValue N = SDValue(NodeToMatch, 0); + NodeStack.push_back(N); + + // Interpreter starts at opcode #0. + unsigned MatcherIndex = 0; + while (1) { + assert(MatcherIndex < TableSize && "Invalid index"); + switch ((BuiltinOpcodes)MatcherTable[MatcherIndex++]) { + case OPC_Emit: { + errs() << "EMIT NODE\n"; + return 0; + } + case OPC_Push: { + unsigned NumToSkip = MatcherTable[MatcherIndex++]; + MatchScope NewEntry; + NewEntry.FailIndex = MatcherIndex+NumToSkip; + NewEntry.NodeStackSize = NodeStack.size(); + NewEntry.NumRecordedNodes = RecordedNodes.size(); + MatchScopes.push_back(NewEntry); + continue; + } + case OPC_Record: + // Remember this node, it may end up being an operand in the pattern. + RecordedNodes.push_back(N); + continue; + + case OPC_MoveChild: { + unsigned Child = MatcherTable[MatcherIndex++]; + if (Child >= N.getNumOperands()) + break; // Match fails if out of range child #. + N = N.getOperand(Child); + NodeStack.push_back(N); + continue; + } + + case OPC_MoveParent: + // Pop the current node off the NodeStack. + NodeStack.pop_back(); + assert(!NodeStack.empty() && "Node stack imbalance!"); + N = NodeStack.back(); + continue; + + case OPC_CheckSame: { + // Accept if it is exactly the same as a previously recorded node. + unsigned RecNo = MatcherTable[MatcherIndex++]; + assert(RecNo < RecordedNodes.size() && "Invalid CheckSame"); + if (N != RecordedNodes[RecNo]) break; + continue; + } + case OPC_CheckPatternPredicate: { + unsigned PredNo = MatcherTable[MatcherIndex++]; + (void)PredNo; + // FIXME: CHECK IT. + continue; + } + case OPC_CheckPredicate: { + unsigned PredNo = MatcherTable[MatcherIndex++]; + (void)PredNo; + // FIXME: CHECK IT. + continue; + } + case OPC_CheckComplexPat: { + unsigned PatNo = MatcherTable[MatcherIndex++]; + (void)PatNo; + // FIXME: CHECK IT. + continue; + } + + case OPC_CheckOpcode: + if (N->getOpcode() != MatcherTable[MatcherIndex++]) break; + continue; + case OPC_CheckType: + if (N.getValueType() != + (MVT::SimpleValueType)MatcherTable[MatcherIndex++]) break; + continue; + case OPC_CheckCondCode: + if (cast(N)->get() != + (ISD::CondCode)MatcherTable[MatcherIndex++]) break; + continue; + case OPC_CheckValueType: + if (cast(N)->getVT() != + (MVT::SimpleValueType)MatcherTable[MatcherIndex++]) break; + continue; + + case OPC_CheckInteger1: + if (CheckInteger(N, GetInt1(MatcherTable, MatcherIndex))) break; + continue; + case OPC_CheckInteger2: + if (CheckInteger(N, GetInt2(MatcherTable, MatcherIndex))) break; + continue; + case OPC_CheckInteger4: + if (CheckInteger(N, GetInt4(MatcherTable, MatcherIndex))) break; + continue; + case OPC_CheckInteger8: + if (CheckInteger(N, GetInt8(MatcherTable, MatcherIndex))) break; + continue; + + case OPC_CheckAndImm1: + if (CheckAndImmediate(N, GetInt1(MatcherTable, MatcherIndex))) break; + continue; + case OPC_CheckAndImm2: + if (CheckAndImmediate(N, GetInt2(MatcherTable, MatcherIndex))) break; + continue; + case OPC_CheckAndImm4: + if (CheckAndImmediate(N, GetInt4(MatcherTable, MatcherIndex))) break; + continue; + case OPC_CheckAndImm8: + if (CheckAndImmediate(N, GetInt8(MatcherTable, MatcherIndex))) break; + continue; + + case OPC_CheckOrImm1: + if (CheckOrImmediate(N, GetInt1(MatcherTable, MatcherIndex))) break; + continue; + case OPC_CheckOrImm2: + if (CheckOrImmediate(N, GetInt2(MatcherTable, MatcherIndex))) break; + continue; + case OPC_CheckOrImm4: + if (CheckOrImmediate(N, GetInt4(MatcherTable, MatcherIndex))) break; + continue; + case OPC_CheckOrImm8: + if (CheckOrImmediate(N, GetInt8(MatcherTable, MatcherIndex))) break; + continue; + } + + // If the code reached this point, then the match failed pop out to the next + // match scope. + if (MatchScopes.empty()) { + CannotYetSelect(NodeToMatch); + return 0; + } + + RecordedNodes.resize(MatchScopes.back().NumRecordedNodes); + NodeStack.resize(MatchScopes.back().NodeStackSize); + MatcherIndex = MatchScopes.back().FailIndex; + MatchScopes.pop_back(); + } +} + + #endif /* LLVM_CODEGEN_DAGISEL_HEADER_H */ diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index f344b288426..a2678a29f70 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -9,6 +9,9 @@ add_executable(tblgen CodeGenInstruction.cpp CodeGenTarget.cpp DAGISelEmitter.cpp + DAGISelMatcherEmitter.cpp + DAGISelMatcherGen.cpp + DAGISelMatcher.cpp DisassemblerEmitter.cpp EDEmitter.cpp FastISelEmitter.cpp diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp index e8aa1643025..0eb06bb5412 100644 --- a/utils/TableGen/DAGISelEmitter.cpp +++ b/utils/TableGen/DAGISelEmitter.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "DAGISelEmitter.h" +#include "DAGISelMatcher.h" #include "Record.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" @@ -1609,7 +1610,7 @@ static std::string getLegalCName(std::string OpName) { void DAGISelEmitter::EmitInstructionSelector(raw_ostream &OS) { const CodeGenTarget &Target = CGP.getTargetInfo(); - + // Get the namespace to insert instructions into. std::string InstNS = Target.getInstNamespace(); if (!InstNS.empty()) InstNS += "::"; @@ -1621,7 +1622,6 @@ void DAGISelEmitter::EmitInstructionSelector(raw_ostream &OS) { for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), E = CGP.ptm_end(); I != E; ++I) { const PatternToMatch &Pattern = *I; - TreePatternNode *Node = Pattern.getSrcPattern(); if (!Node->isLeaf()) { PatternsByOpcode[getOpcodeName(Node->getOperator(), CGP)]. @@ -2011,4 +2011,26 @@ void DAGISelEmitter::run(raw_ostream &OS) { // definitions. Emit the resultant instruction selector. EmitInstructionSelector(OS); +#if 0 + MatcherNode *Matcher = 0; + // Walk the patterns backwards, building a matcher for each and adding it to + // the matcher for the whole target. + for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), + E = CGP.ptm_end(); I != E;) { + const PatternToMatch &Pattern = *--E; + MatcherNode *N = ConvertPatternToMatcher(Pattern, CGP); + + if (Matcher == 0) + Matcher = N; + else + Matcher = new PushMatcherNode(N, Matcher); + } + + + EmitMatcherTable(Matcher, OS); + + + //Matcher->dump(); + delete Matcher; +#endif } diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp new file mode 100644 index 00000000000..1363aa3e812 --- /dev/null +++ b/utils/TableGen/DAGISelMatcher.cpp @@ -0,0 +1,108 @@ +//===- DAGISelMatcher.cpp - Representation of DAG pattern matcher ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DAGISelMatcher.h" +#include "CodeGenDAGPatterns.h" +#include "CodeGenTarget.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +void MatcherNode::dump() const { + print(errs()); +} + +void EmitNodeMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "EmitNode: Src = " << *Pattern.getSrcPattern() << "\n"; + OS.indent(indent) << "EmitNode: Dst = " << *Pattern.getDstPattern() << "\n"; +} + +void MatcherNodeWithChild::printChild(raw_ostream &OS, unsigned indent) const { + if (Child) + return Child->print(OS, indent); + OS.indent(indent) << "\n"; +} + + +void PushMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "Push\n"; + printChild(OS, indent+2); + Failure->print(OS, indent); +} + +void RecordMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "Record\n"; + printChild(OS, indent); +} + +void MoveChildMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "MoveChild " << ChildNo << '\n'; + printChild(OS, indent); +} + +void MoveParentMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "MoveParent\n"; + printChild(OS, indent); +} + +void CheckSameMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckSame " << MatchNumber << '\n'; + printChild(OS, indent); +} + +void CheckPatternPredicateMatcherNode:: +print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckPatternPredicate " << Predicate << '\n'; + printChild(OS, indent); +} + +void CheckPredicateMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckPredicate " << PredName << '\n'; + printChild(OS, indent); +} + +void CheckOpcodeMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckOpcode " << OpcodeName << '\n'; + printChild(OS, indent); +} + +void CheckTypeMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckType " << getEnumName(Type) << '\n'; + printChild(OS, indent); +} + +void CheckIntegerMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckInteger " << Value << '\n'; + printChild(OS, indent); +} + +void CheckCondCodeMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckCondCode ISD::" << CondCodeName << '\n'; + printChild(OS, indent); +} + +void CheckValueTypeMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckValueType MVT::" << TypeName << '\n'; + printChild(OS, indent); +} + +void CheckComplexPatMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckComplexPat " << Pattern.getSelectFunc() << '\n'; + printChild(OS, indent); +} + +void CheckAndImmMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckAndImm " << Value << '\n'; + printChild(OS, indent); +} + +void CheckOrImmMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "CheckOrImm " << Value << '\n'; + printChild(OS, indent); +} + diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h new file mode 100644 index 00000000000..72bdb7bf277 --- /dev/null +++ b/utils/TableGen/DAGISelMatcher.h @@ -0,0 +1,362 @@ +//===- DAGISelMatcher.h - Representation of DAG pattern matcher -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef TBLGEN_DAGISELMATCHER_H +#define TBLGEN_DAGISELMATCHER_H + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/ValueTypes.h" + +namespace llvm { + class CodeGenDAGPatterns; + class MatcherNode; + class PatternToMatch; + class raw_ostream; + class ComplexPattern; + +MatcherNode *ConvertPatternToMatcher(const PatternToMatch &Pattern, + const CodeGenDAGPatterns &CGP); + +void EmitMatcherTable(const MatcherNode *Matcher, raw_ostream &OS); + + +/// MatcherNode - Base class for all the the DAG ISel Matcher representation +/// nodes. +class MatcherNode { +public: + enum KindTy { + EmitNode, + Push, // [Push, Dest0, Dest1, Dest2, Dest3] + Record, // [Record] + MoveChild, // [MoveChild, Child#] + MoveParent, // [MoveParent] + + CheckSame, // [CheckSame, N] Fail if not same as prev match. + CheckPatternPredicate, + CheckPredicate, // [CheckPredicate, P] Fail if predicate fails. + CheckOpcode, // [CheckOpcode, Opcode] Fail if not opcode. + CheckType, // [CheckType, MVT] Fail if not correct type. + CheckInteger, // [CheckInteger, int0,int1,int2,...int7] Fail if wrong val. + CheckCondCode, // [CheckCondCode, CondCode] Fail if not condcode. + CheckValueType, + CheckComplexPat, + CheckAndImm, + CheckOrImm + }; + const KindTy Kind; + +protected: + MatcherNode(KindTy K) : Kind(K) {} +public: + virtual ~MatcherNode() {} + + KindTy getKind() const { return Kind; } + + + static inline bool classof(const MatcherNode *) { return true; } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const = 0; + void dump() const; +}; + +/// EmitNodeMatcherNode - This signals a successful match and generates a node. +class EmitNodeMatcherNode : public MatcherNode { + const PatternToMatch &Pattern; +public: + EmitNodeMatcherNode(const PatternToMatch &pattern) + : MatcherNode(EmitNode), Pattern(pattern) {} + + const PatternToMatch &getPattern() const { return Pattern; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == EmitNode; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// MatcherNodeWithChild - Every node accept the final accept state has a child +/// that is executed after the node runs. This class captures this commonality. +class MatcherNodeWithChild : public MatcherNode { + OwningPtr Child; +public: + MatcherNodeWithChild(KindTy K) : MatcherNode(K) {} + + MatcherNode *getChild() { return Child.get(); } + const MatcherNode *getChild() const { return Child.get(); } + void setChild(MatcherNode *C) { Child.reset(C); } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() != EmitNode; + } + +protected: + void printChild(raw_ostream &OS, unsigned indent) const; +}; + +/// PushMatcherNode - This pushes a failure scope on the stack and evaluates +/// 'child'. If 'child' fails to match, it pops its scope and attempts to +/// match 'Failure'. +class PushMatcherNode : public MatcherNodeWithChild { + OwningPtr Failure; +public: + PushMatcherNode(MatcherNode *child = 0, MatcherNode *failure = 0) + : MatcherNodeWithChild(Push), Failure(failure) { + setChild(child); + } + + MatcherNode *getFailure() { return Failure.get(); } + const MatcherNode *getFailure() const { return Failure.get(); } + void setFailure(MatcherNode *N) { Failure.reset(N); } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == Push; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// RecordMatcherNode - Save the current node in the operand list. +class RecordMatcherNode : public MatcherNodeWithChild { +public: + RecordMatcherNode() : MatcherNodeWithChild(Record) {} + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == Record; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// MoveChildMatcherNode - This tells the interpreter to move into the +/// specified child node. +class MoveChildMatcherNode : public MatcherNodeWithChild { + unsigned ChildNo; +public: + MoveChildMatcherNode(unsigned childNo) + : MatcherNodeWithChild(MoveChild), ChildNo(childNo) {} + + unsigned getChildNo() const { return ChildNo; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == MoveChild; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// MoveParentMatcherNode - This tells the interpreter to move to the parent +/// of the current node. +class MoveParentMatcherNode : public MatcherNodeWithChild { +public: + MoveParentMatcherNode() + : MatcherNodeWithChild(MoveParent) {} + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == MoveParent; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// CheckSameMatcherNode - This checks to see if this node is exactly the same +/// node as the specified match that was recorded with 'Record'. This is used +/// when patterns have the same name in them, like '(mul GPR:$in, GPR:$in)'. +class CheckSameMatcherNode : public MatcherNodeWithChild { + unsigned MatchNumber; +public: + CheckSameMatcherNode(unsigned matchnumber) + : MatcherNodeWithChild(CheckSame), MatchNumber(matchnumber) {} + + unsigned getMatchNumber() const { return MatchNumber; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckSame; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// CheckPatternPredicateMatcherNode - This checks the target-specific predicate +/// to see if the entire pattern is capable of matching. This predicate does +/// not take a node as input. This is used for subtarget feature checks etc. +class CheckPatternPredicateMatcherNode : public MatcherNodeWithChild { + std::string Predicate; +public: + CheckPatternPredicateMatcherNode(StringRef predicate) + : MatcherNodeWithChild(CheckPatternPredicate), Predicate(predicate) {} + + StringRef getPredicate() const { return Predicate; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckPatternPredicate; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// CheckPredicateMatcherNode - This checks the target-specific predicate to +/// see if the node is acceptable. +class CheckPredicateMatcherNode : public MatcherNodeWithChild { + StringRef PredName; +public: + CheckPredicateMatcherNode(StringRef predname) + : MatcherNodeWithChild(CheckPredicate), PredName(predname) {} + + StringRef getPredicateName() const { return PredName; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckPredicate; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + + +/// CheckOpcodeMatcherNode - This checks to see if the current node has the +/// specified opcode, if not it fails to match. +class CheckOpcodeMatcherNode : public MatcherNodeWithChild { + StringRef OpcodeName; +public: + CheckOpcodeMatcherNode(StringRef opcodename) + : MatcherNodeWithChild(CheckOpcode), OpcodeName(opcodename) {} + + StringRef getOpcodeName() const { return OpcodeName; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckOpcode; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// CheckTypeMatcherNode - This checks to see if the current node has the +/// specified type, if not it fails to match. +class CheckTypeMatcherNode : public MatcherNodeWithChild { + MVT::SimpleValueType Type; +public: + CheckTypeMatcherNode(MVT::SimpleValueType type) + : MatcherNodeWithChild(CheckType), Type(type) {} + + MVT::SimpleValueType getType() const { return Type; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckType; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// CheckIntegerMatcherNode - This checks to see if the current node is a +/// ConstantSDNode with the specified integer value, if not it fails to match. +class CheckIntegerMatcherNode : public MatcherNodeWithChild { + int64_t Value; +public: + CheckIntegerMatcherNode(int64_t value) + : MatcherNodeWithChild(CheckInteger), Value(value) {} + + int64_t getValue() const { return Value; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckInteger; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// CheckCondCodeMatcherNode - This checks to see if the current node is a +/// CondCodeSDNode with the specified condition, if not it fails to match. +class CheckCondCodeMatcherNode : public MatcherNodeWithChild { + StringRef CondCodeName; +public: + CheckCondCodeMatcherNode(StringRef condcodename) + : MatcherNodeWithChild(CheckCondCode), CondCodeName(condcodename) {} + + StringRef getCondCodeName() const { return CondCodeName; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckCondCode; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// CheckValueTypeMatcherNode - This checks to see if the current node is a +/// VTSDNode with the specified type, if not it fails to match. +class CheckValueTypeMatcherNode : public MatcherNodeWithChild { + StringRef TypeName; +public: + CheckValueTypeMatcherNode(StringRef type_name) + : MatcherNodeWithChild(CheckValueType), TypeName(type_name) {} + + StringRef getTypeName() const { return TypeName; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckValueType; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + + + +/// CheckComplexPatMatcherNode - This node runs the specified ComplexPattern on +/// the current node. +class CheckComplexPatMatcherNode : public MatcherNodeWithChild { + const ComplexPattern &Pattern; +public: + CheckComplexPatMatcherNode(const ComplexPattern &pattern) + : MatcherNodeWithChild(CheckComplexPat), Pattern(pattern) {} + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckComplexPat; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// CheckAndImmMatcherNode - This checks to see if the current node is an 'and' +/// with something equivalent to the specified immediate. +class CheckAndImmMatcherNode : public MatcherNodeWithChild { + int64_t Value; +public: + CheckAndImmMatcherNode(int64_t value) + : MatcherNodeWithChild(CheckAndImm), Value(value) {} + + int64_t getValue() const { return Value; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckAndImm; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + +/// CheckOrImmMatcherNode - This checks to see if the current node is an 'and' +/// with something equivalent to the specified immediate. +class CheckOrImmMatcherNode : public MatcherNodeWithChild { + int64_t Value; +public: + CheckOrImmMatcherNode(int64_t value) + : MatcherNodeWithChild(CheckOrImm), Value(value) {} + + int64_t getValue() const { return Value; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == CheckOrImm; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + + +} // end namespace llvm + +#endif diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp new file mode 100644 index 00000000000..1a41713c220 --- /dev/null +++ b/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -0,0 +1,217 @@ +//===- DAGISelMatcherEmitter.cpp - Matcher Emitter ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to generate C++ code a matcher. +// +//===----------------------------------------------------------------------===// + +#include "DAGISelMatcher.h" +#include "CodeGenDAGPatterns.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + +namespace { +enum { + CommentIndent = 25 +}; +} + +static unsigned EmitMatcherAndChildren(const MatcherNode *N, + formatted_raw_ostream &FOS, + unsigned Indent); + +/// ClassifyInt - Classify an integer by size, return '1','2','4','8' if this +/// fits in 1, 2, 4, or 8 sign extended bytes. +static char ClassifyInt(int64_t Val) { + if (Val == int8_t(Val)) return '1'; + if (Val == int16_t(Val)) return '2'; + if (Val == int32_t(Val)) return '4'; + return '8'; +} + +/// EmitInt - Emit the specified integer, returning the number of bytes emitted. +static unsigned EmitInt(int64_t Val, formatted_raw_ostream &OS) { + unsigned BytesEmitted = 1; + OS << (int)(unsigned char)Val << ", "; + if (Val == int8_t(Val)) { + OS << "\n"; + return BytesEmitted; + } + + OS << (int)(unsigned char)(Val >> 8) << ", "; + ++BytesEmitted; + + if (Val != int16_t(Val)) { + OS << (int)(unsigned char)(Val >> 16) << ',' + << (int)(unsigned char)(Val >> 24) << ','; + BytesEmitted += 2; + + if (Val != int32_t(Val)) { + OS << (int)(unsigned char)(Val >> 32) << ',' + << (int)(unsigned char)(Val >> 40) << ',' + << (int)(unsigned char)(Val >> 48) << ',' + << (int)(unsigned char)(Val >> 56) << ','; + BytesEmitted += 4; + } + } + + OS.PadToColumn(CommentIndent) << "// " << Val << '\n'; + return BytesEmitted; +} + +/// EmitMatcherOpcodes - Emit bytes for the specified matcher and return +/// the number of bytes emitted. +static unsigned EmitMatcher(const MatcherNode *N, formatted_raw_ostream &OS, + unsigned Indent) { + OS.PadToColumn(Indent*2); + + switch (N->getKind()) { + case MatcherNode::Push: assert(0 && "Should be handled by caller"); + case MatcherNode::EmitNode: + OS << "OPC_Emit, /*XXX*/"; + OS.PadToColumn(CommentIndent) << "// Src: " + << *cast(N)->getPattern().getSrcPattern() << '\n'; + OS.PadToColumn(CommentIndent) << "// Dst: " + << *cast(N)->getPattern().getDstPattern() << '\n'; + return 1; + case MatcherNode::Record: + OS << "OPC_Record,\n"; + return 1; + case MatcherNode::MoveChild: + OS << "OPC_MoveChild, " + << cast(N)->getChildNo() << ",\n"; + return 2; + + case MatcherNode::MoveParent: + OS << "OPC_MoveParent,\n"; + return 1; + + case MatcherNode::CheckSame: + OS << "OPC_CheckSame, " + << cast(N)->getMatchNumber() << ",\n"; + return 2; + + case MatcherNode::CheckPatternPredicate: + OS << "OPC_CheckPatternPredicate, /*XXX*/0,"; + OS.PadToColumn(CommentIndent) << "// " + << cast(N)->getPredicate() << '\n'; + return 2; + + case MatcherNode::CheckPredicate: + OS << "OPC_CheckPredicate, /*XXX*/0,"; + OS.PadToColumn(CommentIndent) << "// " + << cast(N)->getPredicateName() << '\n'; + return 2; + + case MatcherNode::CheckOpcode: + OS << "OPC_CheckOpcode, " + << cast(N)->getOpcodeName() << ",\n"; + return 2; + + case MatcherNode::CheckType: + OS << "OPC_CheckType, " + << getEnumName(cast(N)->getType()) << ",\n"; + return 2; + + case MatcherNode::CheckInteger: { + int64_t Val = cast(N)->getValue(); + OS << "OPC_CheckInteger" << ClassifyInt(Val) << ", "; + return EmitInt(Val, OS)+1; + } + case MatcherNode::CheckCondCode: + OS << "OPC_CheckCondCode, ISD::" + << cast(N)->getCondCodeName() << ",\n"; + return 2; + + case MatcherNode::CheckValueType: + OS << "OPC_CheckValueType, MVT::" + << cast(N)->getTypeName() << ",\n"; + return 2; + + case MatcherNode::CheckComplexPat: + OS << "OPC_CheckComplexPat, 0/*XXX*/,\n"; + return 2; + + case MatcherNode::CheckAndImm: { + int64_t Val = cast(N)->getValue(); + OS << "OPC_CheckAndImm" << ClassifyInt(Val) << ", "; + return EmitInt(Val, OS)+1; + } + + case MatcherNode::CheckOrImm: { + int64_t Val = cast(N)->getValue(); + OS << "OPC_CheckOrImm" << ClassifyInt(Val) << ", "; + return EmitInt(Val, OS)+1; + } + } + assert(0 && "Unreachable"); + return 0; +} + +/// EmitMatcherAndChildren - Emit the bytes for the specified matcher subtree. +static unsigned EmitMatcherAndChildren(const MatcherNode *N, + formatted_raw_ostream &OS, + unsigned Indent) { + unsigned Size = 0; + while (1) { + // Push is a special case since it is binary. + if (const PushMatcherNode *PMN = dyn_cast(N)) { + // We need to encode the child and the offset of the failure code before + // emitting either of them. Handle this by buffering the output into a + // string while we get the size. + SmallString<128> TmpBuf; + unsigned ChildSize; + { + raw_svector_ostream OS(TmpBuf); + formatted_raw_ostream FOS(OS); + ChildSize = + EmitMatcherAndChildren(cast(N)->getChild(), FOS, + Indent+1); + } + + if (ChildSize > 255) { + errs() << + "Tblgen internal error: can't handle predicate this complex yet\n"; + exit(1); + } + + OS.PadToColumn(Indent*2); + OS << "OPC_Push, " << ChildSize << ",\n"; + OS << TmpBuf.str(); + + Size += 2 + ChildSize; + + N = PMN->getFailure(); + continue; + } + + Size += EmitMatcher(N, OS, Indent); + + // If there are children of this node, iterate to them, otherwise we're + // done. + if (const MatcherNodeWithChild *MNWC = dyn_cast(N)) + N = MNWC->getChild(); + else + return Size; + } +} + +void llvm::EmitMatcherTable(const MatcherNode *Matcher, raw_ostream &O) { + formatted_raw_ostream OS(O); + + OS << "// The main instruction selector code.\n"; + OS << "SDNode *SelectCode2(SDNode *N) {\n"; + + OS << " static const unsigned char MatcherTable[] = {\n"; + unsigned TotalSize = EmitMatcherAndChildren(Matcher, OS, 2); + OS << " 0\n }; // Total Array size is " << (TotalSize+1) << " bytes\n\n"; + OS << " return SelectCodeCommon(N, MatcherTable, sizeof(MatcherTable));\n}\n"; +} diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp new file mode 100644 index 00000000000..afa258718f1 --- /dev/null +++ b/utils/TableGen/DAGISelMatcherGen.cpp @@ -0,0 +1,287 @@ +//===- DAGISelMatcherGen.cpp - Matcher generator --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DAGISelMatcher.h" +#include "CodeGenDAGPatterns.h" +#include "Record.h" +#include "llvm/ADT/StringMap.h" +using namespace llvm; + +namespace { + class MatcherGen { + const PatternToMatch &Pattern; + const CodeGenDAGPatterns &CGP; + + /// PatWithNoTypes - This is a clone of Pattern.getSrcPattern() that starts + /// out with all of the types removed. This allows us to insert type checks + /// as we scan the tree. + TreePatternNode *PatWithNoTypes; + + /// VariableMap - A map from variable names ('$dst') to the recorded operand + /// number that they were captured as. These are biased by 1 to make + /// insertion easier. + StringMap VariableMap; + unsigned NextRecordedOperandNo; + + MatcherNodeWithChild *Matcher; + MatcherNodeWithChild *CurPredicate; + public: + MatcherGen(const PatternToMatch &pattern, const CodeGenDAGPatterns &cgp); + + ~MatcherGen() { + delete PatWithNoTypes; + } + + void EmitMatcherCode(); + + MatcherNodeWithChild *GetMatcher() const { return Matcher; } + MatcherNodeWithChild *GetCurPredicate() const { return CurPredicate; } + private: + void AddMatcherNode(MatcherNodeWithChild *NewNode); + void InferPossibleTypes(); + void EmitMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes); + void EmitLeafMatchCode(const TreePatternNode *N); + void EmitOperatorMatchCode(const TreePatternNode *N, + TreePatternNode *NodeNoTypes); + }; + +} // end anon namespace. + +MatcherGen::MatcherGen(const PatternToMatch &pattern, + const CodeGenDAGPatterns &cgp) +: Pattern(pattern), CGP(cgp), NextRecordedOperandNo(0), + Matcher(0), CurPredicate(0) { + // We need to produce the matcher tree for the patterns source pattern. To do + // this we need to match the structure as well as the types. To do the type + // matching, we want to figure out the fewest number of type checks we need to + // emit. For example, if there is only one integer type supported by a + // target, there should be no type comparisons at all for integer patterns! + // + // To figure out the fewest number of type checks needed, clone the pattern, + // remove the types, then perform type inference on the pattern as a whole. + // If there are unresolved types, emit an explicit check for those types, + // apply the type to the tree, then rerun type inference. Iterate until all + // types are resolved. + // + PatWithNoTypes = Pattern.getSrcPattern()->clone(); + PatWithNoTypes->RemoveAllTypes(); + + // If there are types that are manifestly known, infer them. + InferPossibleTypes(); +} + +/// InferPossibleTypes - As we emit the pattern, we end up generating type +/// checks and applying them to the 'PatWithNoTypes' tree. As we do this, we +/// want to propagate implied types as far throughout the tree as possible so +/// that we avoid doing redundant type checks. This does the type propagation. +void MatcherGen::InferPossibleTypes() { + // TP - Get *SOME* tree pattern, we don't care which. It is only used for + // diagnostics, which we know are impossible at this point. + TreePattern &TP = *CGP.pf_begin()->second; + + try { + bool MadeChange = true; + while (MadeChange) + MadeChange = PatWithNoTypes->ApplyTypeConstraints(TP, + true/*Ignore reg constraints*/); + } catch (...) { + errs() << "Type constraint application shouldn't fail!"; + abort(); + } +} + + +/// AddMatcherNode - Add a matcher node to the current graph we're building. +void MatcherGen::AddMatcherNode(MatcherNodeWithChild *NewNode) { + if (CurPredicate != 0) + CurPredicate->setChild(NewNode); + else + Matcher = NewNode; + CurPredicate = NewNode; +} + + + +/// EmitLeafMatchCode - Generate matching code for leaf nodes. +void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { + assert(N->isLeaf() && "Not a leaf?"); + // Direct match against an integer constant. + if (IntInit *II = dynamic_cast(N->getLeafValue())) + return AddMatcherNode(new CheckIntegerMatcherNode(II->getValue())); + + DefInit *DI = dynamic_cast(N->getLeafValue()); + if (DI == 0) { + errs() << "Unknown leaf kind: " << *DI << "\n"; + abort(); + } + + Record *LeafRec = DI->getDef(); + if (// Handle register references. Nothing to do here, they always match. + LeafRec->isSubClassOf("RegisterClass") || + LeafRec->isSubClassOf("PointerLikeRegClass") || + LeafRec->isSubClassOf("Register") || + // Place holder for SRCVALUE nodes. Nothing to do here. + LeafRec->getName() == "srcvalue") + return; + + if (LeafRec->isSubClassOf("ValueType")) + return AddMatcherNode(new CheckValueTypeMatcherNode(LeafRec->getName())); + + if (LeafRec->isSubClassOf("CondCode")) + return AddMatcherNode(new CheckCondCodeMatcherNode(LeafRec->getName())); + + if (LeafRec->isSubClassOf("ComplexPattern")) { + // Handle complex pattern. + const ComplexPattern &CP = CGP.getComplexPattern(LeafRec); + return AddMatcherNode(new CheckComplexPatMatcherNode(CP)); + } + + errs() << "Unknown leaf kind: " << *N << "\n"; + abort(); +} + +void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, + TreePatternNode *NodeNoTypes) { + assert(!N->isLeaf() && "Not an operator?"); + const SDNodeInfo &CInfo = CGP.getSDNodeInfo(N->getOperator()); + + // If this is an 'and R, 1234' where the operation is AND/OR and the RHS is + // a constant without a predicate fn that has more that one bit set, handle + // this as a special case. This is usually for targets that have special + // handling of certain large constants (e.g. alpha with it's 8/16/32-bit + // handling stuff). Using these instructions is often far more efficient + // than materializing the constant. Unfortunately, both the instcombiner + // and the dag combiner can often infer that bits are dead, and thus drop + // them from the mask in the dag. For example, it might turn 'AND X, 255' + // into 'AND X, 254' if it knows the low bit is set. Emit code that checks + // to handle this. + if ((N->getOperator()->getName() == "and" || + N->getOperator()->getName() == "or") && + N->getChild(1)->isLeaf() && N->getChild(1)->getPredicateFns().empty()) { + if (IntInit *II = dynamic_cast(N->getChild(1)->getLeafValue())) { + if (!isPowerOf2_32(II->getValue())) { // Don't bother with single bits. + if (N->getOperator()->getName() == "and") + AddMatcherNode(new CheckAndImmMatcherNode(II->getValue())); + else + AddMatcherNode(new CheckOrImmMatcherNode(II->getValue())); + + // Match the LHS of the AND as appropriate. + AddMatcherNode(new MoveChildMatcherNode(0)); + EmitMatchCode(N->getChild(0), NodeNoTypes->getChild(0)); + AddMatcherNode(new MoveParentMatcherNode()); + return; + } + } + } + + // Check that the current opcode lines up. + AddMatcherNode(new CheckOpcodeMatcherNode(CInfo.getEnumName())); + + // If this node has a chain, then the chain is operand #0 is the SDNode, and + // the child numbers of the node are all offset by one. + unsigned OpNo = 0; + if (N->NodeHasProperty(SDNPHasChain, CGP)) + OpNo = 1; + + if (N->TreeHasProperty(SDNPHasChain, CGP)) { + // FIXME: Handle Chains with multiple uses etc. + // [ld] + // ^ ^ + // | | + // / \--- + // / [YY] + // | ^ + // [XX]-------| + } + + // FIXME: Handle Flags & .hasOneUse() + + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i, ++OpNo) { + // Get the code suitable for matching this child. Move to the child, check + // it then move back to the parent. + AddMatcherNode(new MoveChildMatcherNode(i)); + EmitMatchCode(N->getChild(i), NodeNoTypes->getChild(i)); + AddMatcherNode(new MoveParentMatcherNode()); + } +} + + +void MatcherGen::EmitMatchCode(const TreePatternNode *N, + TreePatternNode *NodeNoTypes) { + // If N and NodeNoTypes don't agree on a type, then this is a case where we + // need to do a type check. Emit the check, apply the tyep to NodeNoTypes and + // reinfer any correlated types. + if (NodeNoTypes->getExtTypes() != N->getExtTypes()) { + AddMatcherNode(new CheckTypeMatcherNode(N->getTypeNum(0))); + NodeNoTypes->setTypes(N->getExtTypes()); + InferPossibleTypes(); + } + + + // If this node has a name associated with it, capture it in VariableMap. If + // we already saw this in the pattern, emit code to verify dagness. + if (!N->getName().empty()) { + unsigned &VarMapEntry = VariableMap[N->getName()]; + if (VarMapEntry == 0) { + VarMapEntry = ++NextRecordedOperandNo; + AddMatcherNode(new RecordMatcherNode()); + } else { + // If we get here, this is a second reference to a specific name. Since + // we already have checked that the first reference is valid, we don't + // have to recursively match it, just check that it's the same as the + // previously named thing. + AddMatcherNode(new CheckSameMatcherNode(VarMapEntry-1)); + return; + } + } + + // If there are node predicates for this node, generate their checks. + for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i) + AddMatcherNode(new CheckPredicateMatcherNode(N->getPredicateFns()[i])); + + if (N->isLeaf()) + EmitLeafMatchCode(N); + else + EmitOperatorMatchCode(N, NodeNoTypes); +} + +void MatcherGen::EmitMatcherCode() { + // If the pattern has a predicate on it (e.g. only enabled when a subtarget + // feature is around, do the check). + if (!Pattern.getPredicateCheck().empty()) + AddMatcherNode(new + CheckPatternPredicateMatcherNode(Pattern.getPredicateCheck())); + + // Emit the matcher for the pattern structure and types. + EmitMatchCode(Pattern.getSrcPattern(), PatWithNoTypes); +} + + +MatcherNode *llvm::ConvertPatternToMatcher(const PatternToMatch &Pattern, + const CodeGenDAGPatterns &CGP) { + MatcherGen Gen(Pattern, CGP); + + // Generate the code for the matcher. + Gen.EmitMatcherCode(); + + // If the match succeeds, then we generate Pattern. + EmitNodeMatcherNode *Result = new EmitNodeMatcherNode(Pattern); + + // Link it into the pattern. + if (MatcherNodeWithChild *Pred = Gen.GetCurPredicate()) { + Pred->setChild(Result); + return Gen.GetMatcher(); + } + + // Unconditional match. + return Result; +} + + + -- 2.34.1