Index: llvm/trunk/docs/TableGen/LangRef.rst =================================================================== --- llvm/trunk/docs/TableGen/LangRef.rst +++ llvm/trunk/docs/TableGen/LangRef.rst @@ -116,7 +116,8 @@ .. productionlist:: TableGenFile: `Object`* - Object: `Class` | `Def` | `Defm` | `Let` | `MultiClass` | `Foreach` + Object: `Class` | `Def` | `Defm` | `Defset` | `Let` | `MultiClass` | + `Foreach` ``class``\es ------------ @@ -356,6 +357,21 @@ Note that in the :token:`BaseClassList`, all of the ``multiclass``'s must precede any ``class``'s that appear. +``defset`` +---------- +.. productionlist:: + Defset: "defset" `Type` `TokIdentifier` "=" "{" `Object`* "}" + +All records defined inside the braces via ``def`` and ``defm`` are collected +in a globally accessible list of the given name (in addition to being added +to the global collection of records as usual). Anonymous records created inside +initializier expressions using the ``Class`` syntax are never collected +in a defset. + +The given type must be ``list``, where ``A`` is some class. It is an error +to define a record (via ``def`` or ``defm``) inside the braces which doesn't +derive from ``A``. + ``foreach`` ----------- Index: llvm/trunk/include/llvm/TableGen/Record.h =================================================================== --- llvm/trunk/include/llvm/TableGen/Record.h +++ llvm/trunk/include/llvm/TableGen/Record.h @@ -1612,6 +1612,7 @@ using RecordMap = std::map>; RecordMap Classes, Defs; FoldingSet RecordTypePool; + std::map ExtraGlobals; unsigned AnonCounter = 0; public: @@ -1628,6 +1629,13 @@ return I == Defs.end() ? nullptr : I->second.get(); } + Init *getGlobal(StringRef Name) const { + if (Record *R = getDef(Name)) + return R->getDefInit(); + auto It = ExtraGlobals.find(Name); + return It == ExtraGlobals.end() ? nullptr : It->second; + } + void addClass(std::unique_ptr R) { bool Ins = Classes.insert(std::make_pair(R->getName(), std::move(R))).second; @@ -1642,6 +1650,13 @@ assert(Ins && "Record already exists"); } + void addExtraGlobal(StringRef Name, Init *I) { + bool Ins = ExtraGlobals.insert(std::make_pair(Name, I)).second; + (void)Ins; + assert(!getDef(Name)); + assert(Ins && "Global already exists"); + } + Init *getNewAnonymousName(); //===--------------------------------------------------------------------===// Index: llvm/trunk/lib/TableGen/TGLexer.h =================================================================== --- llvm/trunk/lib/TableGen/TGLexer.h +++ llvm/trunk/lib/TableGen/TGLexer.h @@ -44,7 +44,7 @@ // Keywords. Bit, Bits, Class, Code, Dag, Def, Foreach, Defm, Field, In, Int, Let, List, - MultiClass, String, + MultiClass, String, Defset, // !keywords. XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast, Index: llvm/trunk/lib/TableGen/TGLexer.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGLexer.cpp +++ llvm/trunk/lib/TableGen/TGLexer.cpp @@ -276,6 +276,7 @@ .Case("def", tgtok::Def) .Case("foreach", tgtok::Foreach) .Case("defm", tgtok::Defm) + .Case("defset", tgtok::Defset) .Case("multiclass", tgtok::MultiClass) .Case("field", tgtok::Field) .Case("let", tgtok::Let) Index: llvm/trunk/lib/TableGen/TGParser.h =================================================================== --- llvm/trunk/lib/TableGen/TGParser.h +++ llvm/trunk/lib/TableGen/TGParser.h @@ -51,6 +51,12 @@ : IterVar(IVar), ListValue(LValue) {} }; + struct DefsetRecord { + SMLoc Loc; + RecTy *EltTy; + SmallVector Elements; + }; + class TGParser { TGLexer Lex; std::vector> LetStack; @@ -61,6 +67,8 @@ typedef std::vector LoopVector; LoopVector Loops; + SmallVector Defsets; + /// CurMultiClass - If we are parsing a 'multiclass' definition, this is the /// current value. MultiClass *CurMultiClass; @@ -121,6 +129,8 @@ bool ProcessForeachDefs(Record *CurRec, SMLoc Loc); bool ProcessForeachDefs(Record *CurRec, SMLoc Loc, IterSet &IterVals); + bool addToDefsets(Record &R); + private: // Parser methods. bool ParseObjectList(MultiClass *MC = nullptr); bool ParseObject(MultiClass *MC); @@ -140,6 +150,7 @@ SMLoc DefmPrefixLoc); bool ParseDefm(MultiClass *CurMultiClass); bool ParseDef(MultiClass *CurMultiClass); + bool ParseDefset(); bool ParseForeach(MultiClass *CurMultiClass); bool ParseTopLevelLet(MultiClass *CurMultiClass); void ParseLetList(SmallVectorImpl &Result); Index: llvm/trunk/lib/TableGen/TGParser.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGParser.cpp +++ llvm/trunk/lib/TableGen/TGParser.cpp @@ -413,6 +413,8 @@ Records.addDef(std::move(IterRec)); IterRecSave->resolveReferences(); checkConcrete(*IterRecSave); + if (addToDefsets(*IterRecSave)) + return true; return false; } @@ -422,9 +424,9 @@ /// isObjectStart - Return true if this is a valid first token for an Object. static bool isObjectStart(tgtok::TokKind K) { - return K == tgtok::Class || K == tgtok::Def || - K == tgtok::Defm || K == tgtok::Let || - K == tgtok::MultiClass || K == tgtok::Foreach; + return K == tgtok::Class || K == tgtok::Def || K == tgtok::Defm || + K == tgtok::Let || K == tgtok::MultiClass || K == tgtok::Foreach || + K == tgtok::Defset; } /// ParseObjectName - If an object name is specified, return it. Otherwise, @@ -724,6 +726,7 @@ case tgtok::Dag: Lex.Lex(); return DagRecTy::get(); case tgtok::Id: if (Record *R = ParseClassID()) return RecordRecTy::get(R); + TokError("unknown class name"); return nullptr; case tgtok::Bits: { if (Lex.Lex() != tgtok::less) { // Eat 'bits' @@ -805,8 +808,8 @@ if (Mode == ParseNameMode) return Name; - if (Record *D = Records.getDef(Name->getValue())) - return DefInit::get(D); + if (Init *I = Records.getGlobal(Name->getValue())) + return I; if (Mode == ParseValueMode) { Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'"); @@ -2323,8 +2326,11 @@ // for the def that might have been created when resolving // inheritance, values and arguments above. CurRec->resolveReferences(); - if (Loops.empty()) + if (Loops.empty()) { checkConcrete(*CurRec); + if (addToDefsets(*CurRec)) + return true; + } } // If ObjectBody has template arguments, it's an error. @@ -2346,6 +2352,68 @@ return false; } +bool TGParser::addToDefsets(Record &R) { + for (DefsetRecord *Defset : Defsets) { + DefInit *I = R.getDefInit(); + if (!I->getType()->typeIsA(Defset->EltTy)) { + PrintError(R.getLoc(), + Twine("adding record of incompatible type '") + + I->getType()->getAsString() + "' to defset"); + PrintNote(Defset->Loc, "to this defset"); + return true; + } + Defset->Elements.push_back(I); + } + return false; +} + +/// ParseDefset - Parse a defset statement. +/// +/// Defset ::= DEFSET Type Id '=' '{' ObjectList '}' +/// +bool TGParser::ParseDefset() { + assert(Lex.getCode() == tgtok::Defset); + Lex.Lex(); // Eat the 'defset' token + + DefsetRecord Defset; + Defset.Loc = Lex.getLoc(); + RecTy *Type = ParseType(); + if (!Type) + return true; + if (!isa(Type)) + return Error(Defset.Loc, "expected list type"); + Defset.EltTy = cast(Type)->getElementType(); + + if (Lex.getCode() != tgtok::Id) + return TokError("expected identifier"); + StringInit *DeclName = StringInit::get(Lex.getCurStrVal()); + if (Records.getGlobal(DeclName->getValue())) + return TokError("def or global variable of this name already exists"); + + if (Lex.Lex() != tgtok::equal) // Eat the identifier + return TokError("expected '='"); + if (Lex.Lex() != tgtok::l_brace) // Eat the '=' + return TokError("expected '{'"); + SMLoc BraceLoc = Lex.getLoc(); + Lex.Lex(); // Eat the '{' + + Defsets.push_back(&Defset); + bool Err = ParseObjectList(nullptr); + Defsets.pop_back(); + if (Err) + return true; + + if (Lex.getCode() != tgtok::r_brace) { + TokError("expected '}' at end of defset"); + return Error(BraceLoc, "to match this '{'"); + } + Lex.Lex(); // Eat the '}' + + Records.addExtraGlobal(DeclName->getValue(), + ListInit::get(Defset.Elements, Defset.EltTy)); + return false; +} + /// ParseForeach - Parse a for statement. Return the record corresponding /// to it. This returns true on error. /// @@ -2598,7 +2666,8 @@ while (Lex.getCode() != tgtok::r_brace) { switch (Lex.getCode()) { default: - return TokError("expected 'let', 'def' or 'defm' in multiclass body"); + return TokError("expected 'let', 'def', 'defm' or 'foreach' in " + "multiclass body"); case tgtok::Let: case tgtok::Def: case tgtok::Defm: @@ -2919,6 +2988,8 @@ // inheritance, values and arguments above. CurRec->resolveReferences(); checkConcrete(*CurRec); + if (addToDefsets(*CurRec)) + return true; } } @@ -2939,11 +3010,16 @@ bool TGParser::ParseObject(MultiClass *MC) { switch (Lex.getCode()) { default: - return TokError("Expected class, def, defm, multiclass or let definition"); + return TokError("Expected class, def, defm, defset, multiclass, let or " + "foreach"); case tgtok::Let: return ParseTopLevelLet(MC); case tgtok::Def: return ParseDef(MC); case tgtok::Foreach: return ParseForeach(MC); case tgtok::Defm: return ParseDefm(MC); + case tgtok::Defset: + if (MC) + return TokError("defset is not allowed inside multiclass"); + return ParseDefset(); case tgtok::Class: return ParseClass(); case tgtok::MultiClass: return ParseMultiClass(); } Index: llvm/trunk/test/TableGen/defset-typeerror.td =================================================================== --- llvm/trunk/test/TableGen/defset-typeerror.td +++ llvm/trunk/test/TableGen/defset-typeerror.td @@ -0,0 +1,14 @@ +// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s +// XFAIL: vg_leak + +// CHECK: error: adding record of incompatible type 'A' to defset + +class A { + int Num = a; +} + +class B : A; + +defset list Bs = { + def A0 : A<1>; +} Index: llvm/trunk/test/TableGen/defset.td =================================================================== --- llvm/trunk/test/TableGen/defset.td +++ llvm/trunk/test/TableGen/defset.td @@ -0,0 +1,62 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// XFAIL: vg_leak + +// CHECK: --- Defs --- + +// CHECK: def Sum { +// CHECK: int x = 712; +// CHECK: } + +// CHECK: def yyy_A0 +// CHECK: def yyy_A1 +// CHECK: def yyy_A2 +// CHECK: def yyy_B0A0 +// CHECK: def yyy_B0A1 +// CHECK: def yyy_C0B0A0 +// CHECK: def yyy_C0B0A1 +// CHECK: def yyy_C0B1A0 +// CHECK: def yyy_C0B1A1 +// CHECK-NOT: def zzz_A0 +// CHECK: def zzz_B0A0 +// CHECK: def zzz_B0A1 +// CHECK: def zzz_C0B0A0 +// CHECK: def zzz_C0B0A1 +// CHECK: def zzz_C0B1A0 +// CHECK: def zzz_C0B1A1 + +class A { + int Num = a; +} + +multiclass B { + def A0 : A; + def A1 : A; +} + +multiclass C { + defm B0 : B; + defm B1 : B; +} + +defset list As = { + def A0 : A<1>; + foreach i = 1-2 in { + def A#i : A; + } + defset list SubAs = { + defm B0 : B<2>; + defm C0 : C<3>; + } +} + +def Sum { + int x = !foldl(0, As, a, b, !add(a, b.Num)); +} + +foreach a = As in { + def yyy_ # !cast(a); +} + +foreach a = SubAs in { + def zzz_ # !cast(a); +}