diff --git a/docs/TableGenFundamentals.html b/docs/TableGenFundamentals.html index ad7263dc008..e9915cb0294 100644 --- a/docs/TableGenFundamentals.html +++ b/docs/TableGenFundamentals.html @@ -104,8 +104,10 @@ definition, so the backend can find all definitions of a particular class, such as "Instruction".

TableGen multiclasses are groups of abstract records that are -instantiated all at once. Each instantiation can result in multiple TableGen -definitions.

+instantiated all at once. Each instantiation can result in multiple +TableGen definitions. If a multiclass inherits from another multiclass, +the definitions in the sub-multiclass become part of the current +multiclass, as if they were declared in the current multiclass.

diff --git a/test/TableGen/MultiClassInherit.td b/test/TableGen/MultiClassInherit.td new file mode 100644 index 00000000000..5a1fc7ee405 --- /dev/null +++ b/test/TableGen/MultiClassInherit.td @@ -0,0 +1,32 @@ +// RUN: tblgen %s | grep {zing = 4} | count 4 + +class C1 { + int bar = A; + string thestr = B; + int zing; +} + +def T : C1<4, "blah">; + +multiclass t { + def S1 : C1 { + int foo = 4; + let bar = 1; + } + def S2 : C1; +} + +multiclass s : t { + def S3 : C1 { + int moo = 3; + let bar = 1; + } + def S4 : C1; +} + +defm FOO : s<42, 24>; + +def T4 : C1<6, "foo">; + +let zing = 4 in + defm BAZ : s<3, 4>; diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp index 32ac719966c..ddaf55803fd 100644 --- a/utils/TableGen/TGParser.cpp +++ b/utils/TableGen/TGParser.cpp @@ -25,7 +25,8 @@ using namespace llvm; namespace llvm { struct MultiClass { Record Rec; // Placeholder for template args and Name. - std::vector DefPrototypes; + typedef std::vector RecordVector; + RecordVector DefPrototypes; MultiClass(const std::string &Name, TGLoc Loc) : Rec(Name, Loc) {} }; @@ -38,6 +39,15 @@ struct SubClassReference { bool isInvalid() const { return Rec == 0; } }; + +struct SubMultiClassReference { + TGLoc RefLoc; + MultiClass *MC; + std::vector TemplateArgs; + SubMultiClassReference() : MC(0) {} + + bool isInvalid() const { return MC == 0; } +}; } // end namespace llvm @@ -177,6 +187,85 @@ bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) { return false; } +/// AddSubMultiClass - Add SubMultiClass as a subclass to +/// CurMultiClass, resolving its template args as SubMultiClass's +/// template arguments. +bool TGParser::AddSubMultiClass(MultiClass *CurMultiClass, class SubMultiClassReference &SubMultiClass) { + MultiClass *SMC = SubMultiClass.MC; + Record *CurRec = &CurMultiClass->Rec; + + const std::vector &MCVals = CurMultiClass->Rec.getValues(); + + // Add all of the values in the subclass into the current class. + const std::vector &SMCVals = SMC->Rec.getValues(); + for (unsigned i = 0, e = SMCVals.size(); i != e; ++i) + if (AddValue(CurRec, SubMultiClass.RefLoc, SMCVals[i])) + return true; + + // Add all of the defs in the subclass into the current multiclass. + for (MultiClass::RecordVector::const_iterator i = SMC->DefPrototypes.begin(), + iend = SMC->DefPrototypes.end(); + i != iend; + ++i) { + // Clone the def and add it to the current multiclass + Record *NewDef = new Record(**i); + + // Add all of the values in the superclass into the current def. + for (unsigned i = 0, e = MCVals.size(); i != e; ++i) + if (AddValue(NewDef, SubMultiClass.RefLoc, MCVals[i])) + return true; + + CurMultiClass->DefPrototypes.push_back(NewDef); + } + + const std::vector &SMCTArgs = SMC->Rec.getTemplateArgs(); + + // Ensure that an appropriate number of template arguments are specified. + if (SMCTArgs.size() < SubMultiClass.TemplateArgs.size()) + return Error(SubMultiClass.RefLoc, "More template args specified than expected"); + + // Loop over all of the template arguments, setting them to the specified + // value or leaving them as the default if necessary. + for (unsigned i = 0, e = SMCTArgs.size(); i != e; ++i) { + if (i < SubMultiClass.TemplateArgs.size()) { + // If a value is specified for this template arg, set it in the superclass now. + if (SetValue(CurRec, SubMultiClass.RefLoc, SMCTArgs[i], std::vector(), + SubMultiClass.TemplateArgs[i])) + return true; + + // Resolve it next. + CurRec->resolveReferencesTo(CurRec->getValue(SMCTArgs[i])); + + // Now remove it. + CurRec->removeValue(SMCTArgs[i]); + + // If a value is specified for this template arg, set it in the defs now. + for (MultiClass::RecordVector::iterator j = CurMultiClass->DefPrototypes.begin(), + jend = CurMultiClass->DefPrototypes.end(); + j != jend; + ++j) { + Record *Def = *j; + + if (SetValue(Def, SubMultiClass.RefLoc, SMCTArgs[i], std::vector(), + SubMultiClass.TemplateArgs[i])) + return true; + + // Resolve it next. + Def->resolveReferencesTo(Def->getValue(SMCTArgs[i])); + + // Now remove it + Def->removeValue(SMCTArgs[i]); + } + } else if (!CurRec->getValue(SMCTArgs[i])->getValue()->isComplete()) { + return Error(SubMultiClass.RefLoc,"Value not specified for template argument #" + + utostr(i) + " (" + SMCTArgs[i] + ") of subclass '" + + SMC->Rec.getName() + "'!"); + } + } + + return false; +} + //===----------------------------------------------------------------------===// // Parser Code //===----------------------------------------------------------------------===// @@ -223,6 +312,25 @@ Record *TGParser::ParseClassID() { return Result; } +/// ParseMultiClassID - Parse and resolve a reference to a multiclass name. This returns +/// null on error. +/// +/// MultiClassID ::= ID +/// +MultiClass *TGParser::ParseMultiClassID() { + if (Lex.getCode() != tgtok::Id) { + TokError("expected name for ClassID"); + return 0; + } + + MultiClass *Result = MultiClasses[Lex.getCurStrVal()]; + if (Result == 0) + TokError("Couldn't find class '" + Lex.getCurStrVal() + "'"); + + Lex.Lex(); + return Result; +} + Record *TGParser::ParseDefmID() { if (Lex.getCode() != tgtok::Id) { TokError("expected multiclass name"); @@ -285,6 +393,47 @@ ParseSubClassReference(Record *CurRec, bool isDefm) { return Result; } +/// ParseSubMultiClassReference - Parse a reference to a subclass or to a templated +/// submulticlass. This returns a SubMultiClassRefTy with a null Record* on error. +/// +/// SubMultiClassRef ::= MultiClassID +/// SubMultiClassRef ::= MultiClassID '<' ValueList '>' +/// +SubMultiClassReference TGParser:: +ParseSubMultiClassReference(MultiClass *CurMC) { + SubMultiClassReference Result; + Result.RefLoc = Lex.getLoc(); + + Result.MC = ParseMultiClassID(); + if (Result.MC == 0) return Result; + + // If there is no template arg list, we're done. + if (Lex.getCode() != tgtok::less) + return Result; + Lex.Lex(); // Eat the '<' + + if (Lex.getCode() == tgtok::greater) { + TokError("subclass reference requires a non-empty list of template values"); + Result.MC = 0; + return Result; + } + + Result.TemplateArgs = ParseValueList(&CurMC->Rec); + if (Result.TemplateArgs.empty()) { + Result.MC = 0; // Error parsing value list. + return Result; + } + + if (Lex.getCode() != tgtok::greater) { + TokError("expected '>' in template value list"); + Result.MC = 0; + return Result; + } + Lex.Lex(); + + return Result; +} + /// ParseRangePiece - Parse a bit/value range. /// RangePiece ::= INTVAL /// RangePiece ::= INTVAL '-' INTVAL @@ -1231,7 +1380,7 @@ bool TGParser::ParseMultiClassDef(MultiClass *CurMC) { /// ParseMultiClass - Parse a multiclass definition. /// -/// MultiClassInst ::= MULTICLASS ID TemplateArgList? '{' MultiClassDef+ '}' +/// MultiClassInst ::= MULTICLASS ID TemplateArgList? ':' BaseMultiClassList '{' MultiClassDef+ '}' /// bool TGParser::ParseMultiClass() { assert(Lex.getCode() == tgtok::MultiClass && "Unexpected token"); @@ -1252,6 +1401,26 @@ bool TGParser::ParseMultiClass() { if (ParseTemplateArgList(0)) return true; + // If there are submulticlasses, parse them. + if (Lex.getCode() == tgtok::colon) { + Lex.Lex(); + + // Read all of the submulticlasses. + SubMultiClassReference SubMultiClass = ParseSubMultiClassReference(CurMultiClass); + while (1) { + // Check for error. + if (SubMultiClass.MC == 0) return true; + + // Add it. + if (AddSubMultiClass(CurMultiClass, SubMultiClass)) + return true; + + if (Lex.getCode() != tgtok::comma) break; + Lex.Lex(); // eat ','. + SubMultiClass = ParseSubMultiClassReference(CurMultiClass); + } + } + if (Lex.getCode() != tgtok::l_brace) return TokError("expected '{' in multiclass definition"); diff --git a/utils/TableGen/TGParser.h b/utils/TableGen/TGParser.h index b04139f80a5..2979d0e189f 100644 --- a/utils/TableGen/TGParser.h +++ b/utils/TableGen/TGParser.h @@ -25,6 +25,7 @@ namespace llvm { struct Init; struct MultiClass; struct SubClassReference; + struct SubMultiClassReference; struct LetRecord { std::string Name; @@ -46,7 +47,6 @@ class TGParser { /// current value. MultiClass *CurMultiClass; public: - TGParser(TGSourceMgr &SrcMgr) : Lex(SrcMgr), CurMultiClass(0) {} void setIncludeDirs(const std::vector &D){Lex.setIncludeDirs(D);} @@ -67,6 +67,7 @@ private: // Semantic analysis methods. bool SetValue(Record *TheRec, TGLoc Loc, const std::string &ValName, const std::vector &BitList, Init *V); bool AddSubClass(Record *Rec, SubClassReference &SubClass); + bool AddSubMultiClass(MultiClass *MV, class SubMultiClassReference &SubMultiClass); private: // Parser methods. bool ParseObjectList(); @@ -87,6 +88,7 @@ private: // Parser methods. std::string ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs); SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm); + SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMultiClass); Init *ParseIDValue(Record *CurRec); Init *ParseIDValue(Record *CurRec, const std::string &Name, TGLoc NameLoc); @@ -101,6 +103,7 @@ private: // Parser methods. RecTy *ParseType(); std::string ParseObjectName(); Record *ParseClassID(); + MultiClass *ParseMultiClassID(); Record *ParseDefmID(); };