diff --git a/llvm/include/llvm/CodeGen/DAGISelHeader.h b/llvm/include/llvm/CodeGen/DAGISelHeader.h index 7a6c1962f74b..88c1a66d4f19 100644 --- a/llvm/include/llvm/CodeGen/DAGISelHeader.h +++ b/llvm/include/llvm/CodeGen/DAGISelHeader.h @@ -221,6 +221,8 @@ GetVBR(unsigned Val, const unsigned char *MatcherTable, unsigned &Idx) { enum BuiltinOpcodes { OPC_Push, OPC_Push2, OPC_RecordNode, + OPC_RecordChild0, OPC_RecordChild1, OPC_RecordChild2, OPC_RecordChild3, + OPC_RecordChild4, OPC_RecordChild5, OPC_RecordChild6, OPC_RecordChild7, OPC_RecordMemRef, OPC_CaptureFlagInput, OPC_MoveChild, @@ -365,7 +367,8 @@ SDNode *SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, unsigned MatcherIndex = 0; while (1) { assert(MatcherIndex < TableSize && "Invalid index"); - switch ((BuiltinOpcodes)MatcherTable[MatcherIndex++]) { + BuiltinOpcodes Opcode = (BuiltinOpcodes)MatcherTable[MatcherIndex++]; + switch (Opcode) { case OPC_Push: { unsigned NumToSkip = MatcherTable[MatcherIndex++]; MatchScope NewEntry; @@ -398,6 +401,18 @@ SDNode *SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, // Remember this node, it may end up being an operand in the pattern. RecordedNodes.push_back(N); continue; + + case OPC_RecordChild0: case OPC_RecordChild1: + case OPC_RecordChild2: case OPC_RecordChild3: + case OPC_RecordChild4: case OPC_RecordChild5: + case OPC_RecordChild6: case OPC_RecordChild7: { + unsigned ChildNo = Opcode-OPC_RecordChild0; + if (ChildNo >= N.getNumOperands()) + break; // Match fails if out of range child #. + + RecordedNodes.push_back(N->getOperand(ChildNo)); + continue; + } case OPC_RecordMemRef: MatchedMemRefs.push_back(cast(N)->getMemOperand()); continue; @@ -410,10 +425,10 @@ SDNode *SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, continue; case OPC_MoveChild: { - unsigned Child = MatcherTable[MatcherIndex++]; - if (Child >= N.getNumOperands()) + unsigned ChildNo = MatcherTable[MatcherIndex++]; + if (ChildNo >= N.getNumOperands()) break; // Match fails if out of range child #. - N = N.getOperand(Child); + N = N.getOperand(ChildNo); NodeStack.push_back(N); continue; } diff --git a/llvm/utils/TableGen/DAGISelEmitter.cpp b/llvm/utils/TableGen/DAGISelEmitter.cpp index 2d2ab3e707ef..7a01caab85da 100644 --- a/llvm/utils/TableGen/DAGISelEmitter.cpp +++ b/llvm/utils/TableGen/DAGISelEmitter.cpp @@ -1983,7 +1983,7 @@ void DAGISelEmitter::run(raw_ostream &OS) { Matcher = new PushMatcherNode(N, Matcher); } - OptimizeMatcher(Matcher); + Matcher = OptimizeMatcher(Matcher); //Matcher->dump(); EmitMatcherTable(Matcher, OS); delete Matcher; diff --git a/llvm/utils/TableGen/DAGISelMatcher.cpp b/llvm/utils/TableGen/DAGISelMatcher.cpp index 6fb417cf9657..9bb8fd51502e 100644 --- a/llvm/utils/TableGen/DAGISelMatcher.cpp +++ b/llvm/utils/TableGen/DAGISelMatcher.cpp @@ -35,6 +35,11 @@ void RecordMatcherNode::print(raw_ostream &OS, unsigned indent) const { printNext(OS, indent); } +void RecordChildMatcherNode::print(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "RecordChild: " << ChildNo << '\n'; + printNext(OS, indent); +} + void RecordMemRefMatcherNode::print(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "RecordMemRef\n"; printNext(OS, indent); diff --git a/llvm/utils/TableGen/DAGISelMatcher.h b/llvm/utils/TableGen/DAGISelMatcher.h index 4dcbc8f55fc2..ab84168bd8b9 100644 --- a/llvm/utils/TableGen/DAGISelMatcher.h +++ b/llvm/utils/TableGen/DAGISelMatcher.h @@ -26,7 +26,7 @@ namespace llvm { MatcherNode *ConvertPatternToMatcher(const PatternToMatch &Pattern, const CodeGenDAGPatterns &CGP); -void OptimizeMatcher(const MatcherNode *Matcher); +MatcherNode *OptimizeMatcher(MatcherNode *Matcher); void EmitMatcherTable(const MatcherNode *Matcher, raw_ostream &OS); @@ -41,6 +41,7 @@ public: // Matcher state manipulation. Push, // Push a checking scope. RecordNode, // Record the current node. + RecordChild, // Record a child of the current node. RecordMemRef, // Record the memref in the current node. CaptureFlagInput, // If the current node has an input flag, save it. MoveChild, // Move current node to specified child. @@ -86,6 +87,9 @@ public: MatcherNode *getNext() { return Next.get(); } const MatcherNode *getNext() const { return Next.get(); } void setNext(MatcherNode *C) { Next.reset(C); } + MatcherNode *takeNext() { return Next.take(); } + + OwningPtr &getNextPtr() { return Next; } static inline bool classof(const MatcherNode *) { return true; } @@ -109,6 +113,7 @@ public: MatcherNode *getFailure() { return Failure.get(); } const MatcherNode *getFailure() const { return Failure.get(); } void setFailure(MatcherNode *N) { Failure.reset(N); } + OwningPtr &getFailurePtr() { return Failure; } static inline bool classof(const MatcherNode *N) { return N->getKind() == Push; @@ -135,6 +140,29 @@ public: virtual void print(raw_ostream &OS, unsigned indent = 0) const; }; +/// RecordChildMatcherNode - Save a numbered child of the current node, or fail +/// the match if it doesn't exist. This is logically equivalent to: +/// MoveChild N + RecordNode + MoveParent. +class RecordChildMatcherNode : public MatcherNode { + unsigned ChildNo; + + /// WhatFor - This is a string indicating why we're recording this. This + /// should only be used for comment generation not anything semantic. + std::string WhatFor; +public: + RecordChildMatcherNode(unsigned childno, const std::string &whatfor) + : MatcherNode(RecordChild), ChildNo(childno), WhatFor(whatfor) {} + + unsigned getChildNo() const { return ChildNo; } + const std::string &getWhatFor() const { return WhatFor; } + + static inline bool classof(const MatcherNode *N) { + return N->getKind() == RecordChild; + } + + virtual void print(raw_ostream &OS, unsigned indent = 0) const; +}; + /// RecordMemRefMatcherNode - Save the current node's memref. class RecordMemRefMatcherNode : public MatcherNode { public: diff --git a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp index ecc75c8c4c6c..e78be79119d6 100644 --- a/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -159,6 +159,13 @@ EmitMatcher(const MatcherNode *N, unsigned Indent, formatted_raw_ostream &OS) { OS.PadToColumn(CommentIndent) << "// " << cast(N)->getWhatFor() << '\n'; return 1; + + case MatcherNode::RecordChild: + OS << "OPC_RecordChild" << cast(N)->getChildNo() + << ','; + OS.PadToColumn(CommentIndent) << "// " + << cast(N)->getWhatFor() << '\n'; + return 1; case MatcherNode::RecordMemRef: OS << "OPC_RecordMemRef,\n"; diff --git a/llvm/utils/TableGen/DAGISelMatcherOpt.cpp b/llvm/utils/TableGen/DAGISelMatcherOpt.cpp index 7859f36eef6e..d3658202a660 100644 --- a/llvm/utils/TableGen/DAGISelMatcherOpt.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherOpt.cpp @@ -14,6 +14,35 @@ #include "DAGISelMatcher.h" using namespace llvm; -void llvm::OptimizeMatcher(const MatcherNode *Matcher) { - // Nothing yet. + +static void FormRecordChildNodes(OwningPtr &Matcher) { + // If we reached the end of the chain, we're done. + MatcherNode *N = Matcher.get(); + if (N == 0) return; + + // If we have a push node, walk down both edges. + if (PushMatcherNode *Push = dyn_cast(N)) + FormRecordChildNodes(Push->getFailurePtr()); + + // If we found a movechild node, check to see if our pattern matches. + if (MoveChildMatcherNode *MC = dyn_cast(N)) { + if (RecordMatcherNode *RM = dyn_cast(MC->getNext())) + if (MoveParentMatcherNode *MP = + dyn_cast(RM->getNext())) { + MatcherNode *New + = new RecordChildMatcherNode(MC->getChildNo(), RM->getWhatFor()); + New->setNext(MP->takeNext()); + Matcher.reset(New); + return FormRecordChildNodes(Matcher); + } + } + + FormRecordChildNodes(N->getNextPtr()); +} + + +MatcherNode *llvm::OptimizeMatcher(MatcherNode *Matcher) { + OwningPtr MatcherPtr(Matcher); + FormRecordChildNodes(MatcherPtr); + return MatcherPtr.take(); }