diff --git a/include/llvm/CodeGen/SelectionDAGISel.h b/include/llvm/CodeGen/SelectionDAGISel.h index f88654caa19..b4a08056963 100644 --- a/include/llvm/CodeGen/SelectionDAGISel.h +++ b/include/llvm/CodeGen/SelectionDAGISel.h @@ -121,6 +121,7 @@ public: OPC_CheckOpcode, OPC_SwitchOpcode, OPC_CheckType, + OPC_SwitchType, OPC_CheckChild0Type, OPC_CheckChild1Type, OPC_CheckChild2Type, OPC_CheckChild3Type, OPC_CheckChild4Type, OPC_CheckChild5Type, OPC_CheckChild6Type, OPC_CheckChild7Type, diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 8e88f16d699..bdf4cb6bc51 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -2065,9 +2065,7 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, case OPC_SwitchOpcode: { unsigned CurNodeOpcode = N.getOpcode(); - unsigned SwitchStart = MatcherIndex-1; (void)SwitchStart; - unsigned CaseSize; while (1) { // Get the size of this case. @@ -2084,7 +2082,7 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, MatcherIndex += CaseSize; } - // If we failed to match, bail out. + // If no cases matched, bail out. if (CaseSize == 0) break; // Otherwise, execute the case we found. @@ -2103,6 +2101,39 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, } continue; } + + case OPC_SwitchType: { + MVT::SimpleValueType CurNodeVT = N.getValueType().getSimpleVT().SimpleTy; + unsigned SwitchStart = MatcherIndex-1; (void)SwitchStart; + unsigned CaseSize; + while (1) { + // Get the size of this case. + CaseSize = MatcherTable[MatcherIndex++]; + if (CaseSize & 128) + CaseSize = GetVBR(CaseSize, MatcherTable, MatcherIndex); + if (CaseSize == 0) break; + + MVT::SimpleValueType CaseVT = + (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; + if (CaseVT == MVT::iPTR) + CaseVT = TLI.getPointerTy().SimpleTy; + + // If the VT matches, then we will execute this case. + if (CurNodeVT == CaseVT) + break; + + // Otherwise, skip over this case. + MatcherIndex += CaseSize; + } + + // If no cases matched, bail out. + if (CaseSize == 0) break; + + // Otherwise, execute the case we found. + DEBUG(errs() << " TypeSwitch[" << EVT(CurNodeVT).getEVTString() + << "] from " << SwitchStart << " to " << MatcherIndex<<'\n'); + continue; + } case OPC_CheckChild0Type: case OPC_CheckChild1Type: case OPC_CheckChild2Type: case OPC_CheckChild3Type: case OPC_CheckChild4Type: case OPC_CheckChild5Type: diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp index a2603e9683a..c4f1cbfcf05 100644 --- a/utils/TableGen/DAGISelMatcher.cpp +++ b/utils/TableGen/DAGISelMatcher.cpp @@ -102,6 +102,15 @@ void CheckTypeMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CheckType " << getEnumName(Type) << '\n'; } +void SwitchTypeMatcher::printImpl(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "SwitchType: {\n"; + for (unsigned i = 0, e = Cases.size(); i != e; ++i) { + OS.indent(indent) << "case " << getEnumName(Cases[i].first) << ":\n"; + Cases[i].second->print(OS, indent+2); + } + OS.indent(indent) << "}\n"; +} + void CheckChildTypeMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "CheckChildType " << ChildNo << " " << getEnumName(Type) << '\n'; diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h index 3eb6755674a..c2e81711e08 100644 --- a/utils/TableGen/DAGISelMatcher.h +++ b/utils/TableGen/DAGISelMatcher.h @@ -56,6 +56,7 @@ public: CheckOpcode, // Fail if not opcode. SwitchOpcode, // Dispatch based on opcode. CheckType, // Fail if not correct type. + SwitchType, // Dispatch based on type. CheckChildType, // Fail if child has wrong type. CheckInteger, // Fail if wrong val. CheckCondCode, // Fail if not condcode. @@ -472,6 +473,34 @@ private: virtual bool isContradictoryImpl(const Matcher *M) const; }; +/// SwitchTypeMatcher - Switch based on the current node's type, dispatching +/// to one matcher per case. If the type doesn't match any of the cases, +/// then the match fails. This is semantically equivalent to a Scope node where +/// every child does a CheckType, but is much faster. +class SwitchTypeMatcher : public Matcher { + SmallVector, 8> Cases; +public: + SwitchTypeMatcher(const std::pair *cases, + unsigned numcases) + : Matcher(SwitchType), Cases(cases, cases+numcases) {} + + static inline bool classof(const Matcher *N) { + return N->getKind() == SwitchType; + } + + unsigned getNumCases() const { return Cases.size(); } + + MVT::SimpleValueType getCaseType(unsigned i) const { return Cases[i].first; } + Matcher *getCaseMatcher(unsigned i) { return Cases[i].second; } + const Matcher *getCaseMatcher(unsigned i) const { return Cases[i].second; } + +private: + virtual void printImpl(raw_ostream &OS, unsigned indent) const; + virtual bool isEqualImpl(const Matcher *M) const { return false; } + virtual unsigned getHashImpl() const { return 4123; } +}; + + /// CheckChildTypeMatcher - This checks to see if a child node has the /// specified type, if not it fails to match. class CheckChildTypeMatcher : public Matcher { diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp index 2e3e58d1735..1f0405038c6 100644 --- a/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -261,17 +261,32 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, << cast(N)->getOpcode().getEnumName() << ",\n"; return 2; - case Matcher::SwitchOpcode: { + case Matcher::SwitchOpcode: + case Matcher::SwitchType: { unsigned StartIdx = CurrentIdx; - const SwitchOpcodeMatcher *SOM = cast(N); - OS << "OPC_SwitchOpcode "; + + unsigned NumCases; + if (const SwitchOpcodeMatcher *SOM = dyn_cast(N)) { + OS << "OPC_SwitchOpcode "; + NumCases = SOM->getNumCases(); + } else { + OS << "OPC_SwitchType "; + NumCases = cast(N)->getNumCases(); + } + if (!OmitComments) - OS << "/*" << SOM->getNumCases() << " cases */"; + OS << "/*" << NumCases << " cases */"; OS << ", "; ++CurrentIdx; // For each case we emit the size, then the opcode, then the matcher. - for (unsigned i = 0, e = SOM->getNumCases(); i != e; ++i) { + for (unsigned i = 0, e = NumCases; i != e; ++i) { + const Matcher *Child; + if (const SwitchOpcodeMatcher *SOM = dyn_cast(N)) + Child = SOM->getCaseMatcher(i); + else + Child = cast(N)->getCaseMatcher(i); + // We need to encode the opcode and the offset of the case code before // emitting the case code. Handle this by buffering the output into a // string while we get the size. Unfortunately, the offset of the @@ -286,8 +301,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, TmpBuf.clear(); raw_svector_ostream OS(TmpBuf); formatted_raw_ostream FOS(OS); - ChildSize = EmitMatcherList(SOM->getCaseMatcher(i), - Indent+1, CurrentIdx+VBRSize+1, FOS); + ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx+VBRSize+1, FOS); } while (GetVBRSize(ChildSize) != VBRSize); assert(ChildSize != 0 && "Should not have a zero-sized child!"); @@ -295,13 +309,20 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, if (i != 0) { OS.PadToColumn(Indent*2); if (!OmitComments) - OS << "/*SwitchOpcode*/ "; + OS << (isa(N) ? + "/*SwitchOpcode*/ " : "/*SwitchType*/ "); } // Emit the VBR. CurrentIdx += EmitVBRValue(ChildSize, OS); - OS << " " << SOM->getCaseOpcode(i).getEnumName() << ","; + OS << ' '; + if (const SwitchOpcodeMatcher *SOM = dyn_cast(N)) + OS << SOM->getCaseOpcode(i).getEnumName(); + else + OS << getEnumName(cast(N)->getCaseType(i)); + OS << ','; + if (!OmitComments) OS << "// ->" << CurrentIdx+ChildSize+1; OS << '\n'; @@ -313,7 +334,9 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, // Emit the final zero to terminate the switch. OS.PadToColumn(Indent*2) << "0, "; if (!OmitComments) - OS << "// EndSwitchOpcode"; + OS << (isa(N) ? + "// EndSwitchOpcode" : "// EndSwitchType"); + OS << '\n'; ++CurrentIdx; return CurrentIdx-StartIdx; @@ -323,6 +346,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, OS << "OPC_CheckType, " << getEnumName(cast(N)->getType()) << ",\n"; return 2; + case Matcher::CheckChildType: OS << "OPC_CheckChild" << cast(N)->getChildNo() << "Type, " @@ -673,6 +697,7 @@ void MatcherTableEmitter::EmitHistogram(formatted_raw_ostream &OS) { case Matcher::CheckOpcode: OS << "OPC_CheckOpcode"; break; case Matcher::SwitchOpcode: OS << "OPC_SwitchOpcode"; break; case Matcher::CheckType: OS << "OPC_CheckType"; break; + case Matcher::SwitchType: OS << "OPC_SwitchType"; break; case Matcher::CheckChildType: OS << "OPC_CheckChildType"; break; case Matcher::CheckInteger: OS << "OPC_CheckInteger"; break; case Matcher::CheckCondCode: OS << "OPC_CheckCondCode"; break; diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp index a625fa85d40..dc077a99091 100644 --- a/utils/TableGen/DAGISelMatcherOpt.cpp +++ b/utils/TableGen/DAGISelMatcherOpt.cpp @@ -14,7 +14,7 @@ #define DEBUG_TYPE "isel-opt" #include "DAGISelMatcher.h" #include "CodeGenDAGPatterns.h" -#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -361,27 +361,39 @@ static void FactorNodes(OwningPtr &MatcherPtr) { // Check to see if all of the leading entries are now opcode checks. If so, // we can convert this Scope to be a OpcodeSwitch instead. - bool AllOpcodeChecks = true; + bool AllOpcodeChecks = true, AllTypeChecks = true; for (unsigned i = 0, e = NewOptionsToMatch.size(); i != e; ++i) { - if (isa(NewOptionsToMatch[i])) continue; - + if (!isa(NewOptionsToMatch[i])) { #if 0 - if (i > 3) { - errs() << "FAILING OPC #" << i << "\n"; - NewOptionsToMatch[i]->dump(); - } + if (i > 3 && AllOpcodeChecks) { + errs() << "FAILING OPC #" << i << "\n"; + NewOptionsToMatch[i]->dump(); + } #endif - - AllOpcodeChecks = false; - break; + AllOpcodeChecks = false; + } + + if (!isa(NewOptionsToMatch[i]) || + // iPTR checks could alias any other case without us knowing, don't + // bother with them. + cast(NewOptionsToMatch[i])->getType() == MVT::iPTR) { +#if 0 + if (i > 3 && AllTypeChecks) { + errs() << "FAILING TYPE #" << i << "\n"; + NewOptionsToMatch[i]->dump(); + } +#endif + AllTypeChecks = false; + } } + // TODO: Can also do CheckChildNType. // If all the options are CheckOpcode's, we can form the SwitchOpcode, woot. if (AllOpcodeChecks) { StringSet<> Opcodes; SmallVector, 8> Cases; for (unsigned i = 0, e = NewOptionsToMatch.size(); i != e; ++i) { - CheckOpcodeMatcher *COM =cast(NewOptionsToMatch[i]); + CheckOpcodeMatcher *COM = cast(NewOptionsToMatch[i]); assert(Opcodes.insert(COM->getOpcode().getEnumName()) && "Duplicate opcodes not factored?"); Cases.push_back(std::make_pair(&COM->getOpcode(), COM->getNext())); @@ -391,6 +403,21 @@ static void FactorNodes(OwningPtr &MatcherPtr) { return; } + // If all the options are CheckType's, we can form the SwitchType, woot. + if (AllTypeChecks) { + DenseSet Types; + SmallVector, 8> Cases; + for (unsigned i = 0, e = NewOptionsToMatch.size(); i != e; ++i) { + CheckTypeMatcher *CTM = cast(NewOptionsToMatch[i]); + assert(Types.insert(CTM->getType()).second && + "Duplicate types not factored?"); + Cases.push_back(std::make_pair(CTM->getType(), CTM->getNext())); + } + + MatcherPtr.reset(new SwitchTypeMatcher(&Cases[0], Cases.size())); + return; + } + // Reassemble the Scope node with the adjusted children. Scope->setNumChildren(NewOptionsToMatch.size());