Index: include/llvm/TableGen/Record.h =================================================================== --- include/llvm/TableGen/Record.h +++ include/llvm/TableGen/Record.h @@ -1596,17 +1596,6 @@ raw_ostream &operator<<(raw_ostream &OS, const Record &R); -struct MultiClass { - Record Rec; // Placeholder for template args and Name. - using RecordVector = std::vector>; - RecordVector DefPrototypes; - - void dump() const; - - MultiClass(StringRef Name, SMLoc Loc, RecordKeeper &Records) : - Rec(Name, Loc, Records) {} -}; - class RecordKeeper { friend class RecordRecTy; using RecordMap = std::map>; @@ -1776,11 +1765,6 @@ raw_ostream &operator<<(raw_ostream &OS, const RecordKeeper &RK); -/// Return an Init with a qualifier prefix referring -/// to CurRec's name. -Init *QualifyName(Record &CurRec, MultiClass *CurMultiClass, - Init *Name, StringRef Scoper); - //===----------------------------------------------------------------------===// // Resolvers //===----------------------------------------------------------------------===// Index: lib/TableGen/Record.cpp =================================================================== --- lib/TableGen/Record.cpp +++ lib/TableGen/Record.cpp @@ -2131,15 +2131,6 @@ } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void MultiClass::dump() const { - errs() << "Record:\n"; - Rec.dump(); - - errs() << "Defs:\n"; - for (const auto &Proto : DefPrototypes) - Proto->dump(); -} - LLVM_DUMP_METHOD void RecordKeeper::dump() const { errs() << *this; } #endif @@ -2174,22 +2165,6 @@ return Defs; } -Init *llvm::QualifyName(Record &CurRec, MultiClass *CurMultiClass, - Init *Name, StringRef Scoper) { - Init *NewName = - BinOpInit::getStrConcat(CurRec.getNameInit(), StringInit::get(Scoper)); - NewName = BinOpInit::getStrConcat(NewName, Name); - if (CurMultiClass && Scoper != "::") { - Init *Prefix = BinOpInit::getStrConcat(CurMultiClass->Rec.getNameInit(), - StringInit::get("::")); - NewName = BinOpInit::getStrConcat(Prefix, NewName); - } - - if (BinOpInit *BinOp = dyn_cast(NewName)) - NewName = BinOp->Fold(&CurRec); - return NewName; -} - Init *MapResolver::resolve(Init *VarName) { auto It = Map.find(VarName); if (It == Map.end()) Index: lib/TableGen/TGParser.h =================================================================== --- lib/TableGen/TGParser.h +++ lib/TableGen/TGParser.h @@ -27,6 +27,7 @@ class RecordKeeper; class RecTy; class Init; + struct ForeachLoop; struct MultiClass; struct SubClassReference; struct SubMultiClassReference; @@ -41,14 +42,31 @@ } }; + /// RecordsEntry - Can be either a record or a foreach loop. + struct RecordsEntry { + std::unique_ptr Rec; + std::unique_ptr Loop; + + void dump() const; + + RecordsEntry() {} + RecordsEntry(std::unique_ptr Rec) : Rec(std::move(Rec)) {} + RecordsEntry(std::unique_ptr Loop) + : Loop(std::move(Loop)) {} + }; + /// ForeachLoop - Record the iteration state associated with a for loop. /// This is used to instantiate items in the loop body. struct ForeachLoop { + SMLoc Loc; VarInit *IterVar; - ListInit *ListValue; + Init *ListValue; + std::vector Entries; + + void dump() const; - ForeachLoop(VarInit *IVar, ListInit *LValue) - : IterVar(IVar), ListValue(LValue) {} + ForeachLoop(SMLoc Loc, VarInit *IVar, Init *LValue) + : Loc(Loc), IterVar(IVar), ListValue(LValue) {} }; struct DefsetRecord { @@ -57,6 +75,16 @@ SmallVector Elements; }; +struct MultiClass { + Record Rec; // Placeholder for template args and Name. + std::vector Entries; + + void dump() const; + + MultiClass(StringRef Name, SMLoc Loc, RecordKeeper &Records) : + Rec(Name, Loc, Records) {} +}; + class TGParser { TGLexer Lex; std::vector> LetStack; @@ -64,8 +92,7 @@ /// Loops - Keep track of any foreach loops we are within. /// - typedef std::vector LoopVector; - LoopVector Loops; + std::vector> Loops; SmallVector Defsets; @@ -112,23 +139,19 @@ ArrayRef BitList, Init *V, bool AllowSelfAssignment = false); bool AddSubClass(Record *Rec, SubClassReference &SubClass); + bool AddSubClass(RecordsEntry &Entry, SubClassReference &SubClass); bool AddSubMultiClass(MultiClass *CurMC, SubMultiClassReference &SubMultiClass); - // IterRecord: Map an iterator name to a value. - struct IterRecord { - VarInit *IterVar; - Init *IterValue; - IterRecord(VarInit *Var, Init *Val) : IterVar(Var), IterValue(Val) {} - }; - - // IterSet: The set of all iterator values at some point in the - // iteration space. - typedef std::vector IterSet; + using SubstStack = SmallVector, 8>; - bool addDefOne(std::unique_ptr Rec, IterSet &IterVals); - bool addDefForeach(Record *Rec, IterSet &IterVals); - bool addDef(std::unique_ptr Rec); + bool addEntry(RecordsEntry E); + bool resolve(const ForeachLoop &Loop, SubstStack &Stack, bool Final, + std::vector *Dest, SMLoc *Loc = nullptr); + bool resolve(const std::vector &Source, SubstStack &Substs, + bool Final, std::vector *Dest, + SMLoc *Loc = nullptr); + bool addDefOne(std::unique_ptr Rec); private: // Parser methods. bool ParseObjectList(MultiClass *MC = nullptr); @@ -148,7 +171,7 @@ bool ParseTemplateArgList(Record *CurRec); Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs); - VarInit *ParseForeachDeclaration(ListInit *&ForeachListValue); + VarInit *ParseForeachDeclaration(Init *&ForeachListValue); SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm); SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMC); @@ -175,6 +198,7 @@ Record *ParseClassID(); MultiClass *ParseMultiClassID(); bool ApplyLetStack(Record *CurRec); + bool ApplyLetStack(RecordsEntry &Entry); }; } // end namespace llvm Index: lib/TableGen/TGParser.cpp =================================================================== --- lib/TableGen/TGParser.cpp +++ lib/TableGen/TGParser.cpp @@ -110,6 +110,24 @@ } } +/// Return an Init with a qualifier prefix referring +/// to CurRec's name. +static Init *QualifyName(Record &CurRec, MultiClass *CurMultiClass, + Init *Name, StringRef Scoper) { + Init *NewName = + BinOpInit::getStrConcat(CurRec.getNameInit(), StringInit::get(Scoper)); + NewName = BinOpInit::getStrConcat(NewName, Name); + if (CurMultiClass && Scoper != "::") { + Init *Prefix = BinOpInit::getStrConcat(CurMultiClass->Rec.getNameInit(), + StringInit::get("::")); + NewName = BinOpInit::getStrConcat(Prefix, NewName); + } + + if (BinOpInit *BinOp = dyn_cast(NewName)) + NewName = BinOp->Fold(&CurRec); + return NewName; +} + /// Return the qualified version of the implicit 'NAME' template argument. static Init *QualifiedNameOfImplicitName(Record &Rec, MultiClass *MC = nullptr) { @@ -271,6 +289,18 @@ return false; } +bool TGParser::AddSubClass(RecordsEntry &Entry, SubClassReference &SubClass) { + if (Entry.Rec) + return AddSubClass(Entry.Rec.get(), SubClass); + + for (auto &E : Entry.Loop->Entries) { + if (AddSubClass(E, SubClass)) + return true; + } + + return false; +} + /// AddSubMultiClass - Add SubMultiClass as a subclass to /// CurMC, resolving its template args as SubMultiClass's /// template arguments. @@ -283,7 +313,7 @@ return Error(SubMultiClass.RefRange.Start, "More template args specified than expected"); - SmallVector, 8> TemplateArgs; + SubstStack TemplateArgs; for (unsigned i = 0, e = SMCTArgs.size(); i != e; ++i) { if (i < SubMultiClass.TemplateArgs.size()) { TemplateArgs.emplace_back(SMCTArgs[i], SubMultiClass.TemplateArgs[i]); @@ -305,85 +335,103 @@ VarInit::get(QualifiedNameOfImplicitName(CurMC), StringRecTy::get())); // Add all of the defs in the subclass into the current multiclass. - for (const std::unique_ptr &Rec : SMC->DefPrototypes) { - auto NewDef = make_unique(*Rec); - - MapResolver R(NewDef.get()); - for (const auto &TArg : TemplateArgs) - R.set(TArg.first, TArg.second); - NewDef->resolveReferences(R); + return resolve(SMC->Entries, TemplateArgs, false, &CurMC->Entries); +} - CurMC->DefPrototypes.push_back(std::move(NewDef)); +/// Add a record or foreach loop to the current context (global record keeper, +/// current inner-most foreach loop, or multiclass). +bool TGParser::addEntry(RecordsEntry E) { + if (!Loops.empty()) { + Loops.back()->Entries.push_back(std::move(E)); + return false; } - return false; -} - -/// Add a record that results from 'def' or 'defm', after template arguments -/// and the external let stack have been resolved. -/// -/// Apply foreach loops, resolve internal variable references, and add to the -/// current multi class or the global record keeper as appropriate. -bool TGParser::addDef(std::unique_ptr Rec) { - IterSet IterVals; + if (E.Loop) { + SubstStack Stack; + return resolve(*E.Loop, Stack, CurMultiClass == nullptr, + CurMultiClass ? &CurMultiClass->Entries : nullptr); + } - if (Loops.empty()) - return addDefOne(std::move(Rec), IterVals); + if (CurMultiClass) { + CurMultiClass->Entries.push_back(std::move(E)); + return false; + } - return addDefForeach(Rec.get(), IterVals); + return addDefOne(std::move(E.Rec)); } -/// Recursive helper function for addDef/addDefOne to resolve references to -/// foreach variables. -bool TGParser::addDefForeach(Record *Rec, IterSet &IterVals) { - if (IterVals.size() != Loops.size()) { - assert(IterVals.size() < Loops.size()); - ForeachLoop &CurLoop = Loops[IterVals.size()]; - ListInit *List = CurLoop.ListValue; - - // Process each value. - for (unsigned i = 0; i < List->size(); ++i) { - IterVals.push_back(IterRecord(CurLoop.IterVar, List->getElement(i))); - if (addDefForeach(Rec, IterVals)) - return true; - IterVals.pop_back(); - } - return false; +/// Resolve the entries in \p Loop, going over inner loops recursively +/// and making the given subsitutions of (name, value) pairs. +/// +/// The resulting records are stored in \p Dest if non-null. Otherwise, they +/// are added to the global record keeper. +bool TGParser::resolve(const ForeachLoop &Loop, SubstStack &Substs, + bool Final, std::vector *Dest, + SMLoc *Loc) { + MapResolver R; + for (const auto &S : Substs) + R.set(S.first, S.second); + Init *List = Loop.ListValue->resolveReferences(R); + auto LI = dyn_cast(List); + if (!LI) { + if (!Final) { + Dest->emplace_back(make_unique(Loop.Loc, Loop.IterVar, + List)); + return resolve(Loop.Entries, Substs, Final, &Dest->back().Loop->Entries, + Loc); + } + + PrintError(Loop.Loc, Twine("attempting to loop over '") + + List->getAsString() + "', expected a list"); + return true; } - // This is the bottom of the recursion. We have all of the iterator values - // for this point in the iteration space. Instantiate a new record to - // reflect this combination of values. - auto IterRec = make_unique(*Rec); - return addDefOne(std::move(IterRec), IterVals); + bool Error = false; + for (unsigned i = 0; i < LI->size(); ++i) { + Substs.emplace_back(Loop.IterVar->getNameInit(), LI->getElement(i)); + Error = resolve(Loop.Entries, Substs, Final, Dest); + Substs.pop_back(); + if (Error) + break; + } + return Error; } -/// After resolving foreach loops, add the record as a prototype to the -/// current multiclass, or resolve fully and add to the record keeper. -bool TGParser::addDefOne(std::unique_ptr Rec, IterSet &IterVals) { - MapResolver R(Rec.get()); - - for (IterRecord &IR : IterVals) - R.set(IR.IterVar->getNameInit(), IR.IterValue); +/// Resolve the entries in \p Source, going over loops recursively and +/// making the given substitutions of (name, value) pairs. +/// +/// The resulting records are stored in \p Dest if non-null. Otherwise, they +/// are added to the global record keeper. +bool TGParser::resolve(const std::vector &Source, + SubstStack &Substs, bool Final, + std::vector *Dest, SMLoc *Loc) { + bool Error = false; + for (auto &E : Source) { + if (E.Loop) { + Error = resolve(*E.Loop, Substs, Final, Dest); + } else { + auto Rec = make_unique(*E.Rec); + if (Loc) + Rec->appendLoc(*Loc); - Rec->resolveReferences(R); + MapResolver R(Rec.get()); + for (const auto &S : Substs) + R.set(S.first, S.second); + Rec->resolveReferences(R); - if (CurMultiClass) { - if (!Rec->isAnonymous()) { - for (const auto &Proto : CurMultiClass->DefPrototypes) { - if (Proto->getNameInit() == Rec->getNameInit()) { - PrintError(Rec->getLoc(), - Twine("def '") + Rec->getNameInitAsString() + - "' already defined in this multiclass!"); - PrintNote(Proto->getLoc(), "location of previous definition"); - return true; - } - } + if (Dest) + Dest->push_back(std::move(Rec)); + else + Error = addDefOne(std::move(Rec)); } - CurMultiClass->DefPrototypes.emplace_back(std::move(Rec)); - return false; + if (Error) + break; } + return Error; +} +/// Resolve the record fully and add it to the record keeper. +bool TGParser::addDefOne(std::unique_ptr Rec) { if (Record *Prev = Records.getDef(Rec->getNameInitAsString())) { if (!Rec->isAnonymous()) { PrintError(Rec->getLoc(), @@ -802,7 +850,7 @@ // If this is in a foreach loop, make sure it's not a loop iterator for (const auto &L : Loops) { - VarInit *IterVar = dyn_cast(L.IterVar); + VarInit *IterVar = dyn_cast(L->IterVar); if (IterVar && IterVar->getNameInit() == Name) return IterVar; } @@ -1156,7 +1204,7 @@ Init *LHS = StringInit::get(Lex.getCurStrVal()); - if (CurRec->getValue(LHS)) { + if (CurRec && CurRec->getValue(LHS)) { TokError((Twine("iteration variable '") + LHS->getAsString() + "' already defined") .str()); @@ -1215,9 +1263,16 @@ return nullptr; } - CurRec->addValue(RecordVal(LHS, InEltType, false)); - Init *RHS = ParseValue(CurRec, OutEltType); - CurRec->removeValue(LHS); + std::unique_ptr ParseRecTmp; + Record *ParseRec = CurRec; + if (!ParseRec) { + ParseRecTmp = make_unique(".parse", ArrayRef{}, Records); + ParseRec = ParseRecTmp.get(); + } + + ParseRec->addValue(RecordVal(LHS, InEltType, false)); + Init *RHS = ParseValue(ParseRec, OutEltType); + ParseRec->removeValue(LHS); if (!RHS) return nullptr; @@ -1439,7 +1494,7 @@ } Init *A = StringInit::get(Lex.getCurStrVal()); - if (CurRec->getValue(A)) { + if (CurRec && CurRec->getValue(A)) { TokError((Twine("left !foldl variable '") + A->getAsString() + "' already defined") .str()); @@ -1457,7 +1512,7 @@ } Init *B = StringInit::get(Lex.getCurStrVal()); - if (CurRec->getValue(B)) { + if (CurRec && CurRec->getValue(B)) { TokError((Twine("right !foldl variable '") + B->getAsString() + "' already defined") .str()); @@ -1470,11 +1525,18 @@ } Lex.Lex(); // eat the ',' - CurRec->addValue(RecordVal(A, Start->getType(), false)); - CurRec->addValue(RecordVal(B, ListType->getElementType(), false)); - Init *ExprUntyped = ParseValue(CurRec); - CurRec->removeValue(A); - CurRec->removeValue(B); + std::unique_ptr ParseRecTmp; + Record *ParseRec = CurRec; + if (!ParseRec) { + ParseRecTmp = make_unique(".parse", ArrayRef{}, Records); + ParseRec = ParseRecTmp.get(); + } + + ParseRec->addValue(RecordVal(A, Start->getType(), false)); + ParseRec->addValue(RecordVal(B, ListType->getElementType(), false)); + Init *ExprUntyped = ParseValue(ParseRec); + ParseRec->removeValue(A); + ParseRec->removeValue(B); if (!ExprUntyped) return nullptr; @@ -2189,7 +2251,7 @@ /// ForeachDeclaration ::= ID '=' RangePiece /// ForeachDeclaration ::= ID '=' Value /// -VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) { +VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) { if (Lex.getCode() != tgtok::Id) { TokError("Expected identifier in foreach declaration"); return nullptr; @@ -2229,9 +2291,10 @@ default: { SMLoc ValueLoc = Lex.getLoc(); Init *I = ParseValue(nullptr); - if (!isa(I)) { + TypedInit *TI = dyn_cast(I); + if (!TI || !isa(TI->getType())) { std::string Type; - if (TypedInit *TI = dyn_cast(I)) + if (TI) Type = (Twine("' of type '") + TI->getType()->getAsString()).str(); Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'"); if (CurMultiClass) @@ -2239,8 +2302,8 @@ "resolved at this time"); return nullptr; } - ForeachListValue = dyn_cast(I); - IterType = ForeachListValue->getElementType(); + ForeachListValue = I; + IterType = cast(TI->getType())->getElementType(); break; } } @@ -2388,6 +2451,18 @@ return false; } +bool TGParser::ApplyLetStack(RecordsEntry &Entry) { + if (Entry.Rec) + return ApplyLetStack(Entry.Rec.get()); + + for (auto &E : Entry.Loop->Entries) { + if (ApplyLetStack(E)) + return true; + } + + return false; +} + /// ParseObjectBody - Parse the body of a def or class. This consists of an /// optional ClassList followed by a Body. CurRec is the current def or class /// that is being parsed. @@ -2449,7 +2524,7 @@ if (ParseObjectBody(CurRec.get())) return true; - return addDef(std::move(CurRec)); + return addEntry(std::move(CurRec)); } /// ParseDefset - Parse a defset statement. @@ -2506,12 +2581,13 @@ /// Foreach ::= FOREACH Declaration IN Object /// bool TGParser::ParseForeach(MultiClass *CurMultiClass) { + SMLoc Loc = Lex.getLoc(); assert(Lex.getCode() == tgtok::Foreach && "Unknown tok"); Lex.Lex(); // Eat the 'for' token. // Make a temporary object to record items associated with the for // loop. - ListInit *ListValue = nullptr; + Init *ListValue = nullptr; VarInit *IterName = ParseForeachDeclaration(ListValue); if (!IterName) return TokError("expected declaration in for"); @@ -2521,7 +2597,7 @@ Lex.Lex(); // Eat the in // Create a loop object and remember it. - Loops.push_back(ForeachLoop(IterName, ListValue)); + Loops.push_back(llvm::make_unique(Loc, IterName, ListValue)); if (Lex.getCode() != tgtok::l_brace) { // FOREACH Declaration IN Object @@ -2543,10 +2619,11 @@ Lex.Lex(); // Eat the } } - // We've processed everything in this loop. + // Resolve the loop or store it for later resolution. + std::unique_ptr Loop = std::move(Loops.back()); Loops.pop_back(); - return false; + return addEntry(std::move(Loop)); } /// ParseClass - Parse a tblgen class definition. @@ -2793,7 +2870,7 @@ return TokError("expected ':' after defm identifier"); // Keep track of the new generated record definitions. - SmallVector, 8> NewRecDefs; + std::vector NewEntries; // This record also inherits from a regular class (non-multiclass)? bool InheritFromClass = false; @@ -2820,10 +2897,10 @@ return Error(SubClassLoc, "more template args specified than multiclass expects"); - SmallVector, 8> TemplateArgs; + SubstStack Substs; for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { if (i < TemplateVals.size()) { - TemplateArgs.emplace_back(TArgs[i], TemplateVals[i]); + Substs.emplace_back(TArgs[i], TemplateVals[i]); } else { Init *Default = MC->Rec.getValue(TArgs[i])->getValue(); if (!Default->isComplete()) { @@ -2833,24 +2910,15 @@ ") of multiclass '" + MC->Rec.getNameInitAsString() + "'"); } - TemplateArgs.emplace_back(TArgs[i], Default); + Substs.emplace_back(TArgs[i], Default); } } - TemplateArgs.emplace_back(QualifiedNameOfImplicitName(MC), DefmName); - - // Loop over all the def's in the multiclass, instantiating each one. - for (const std::unique_ptr &DefProto : MC->DefPrototypes) { - auto CurRec = make_unique(*DefProto); - CurRec->appendLoc(SubClassLoc); + Substs.emplace_back(QualifiedNameOfImplicitName(MC), DefmName); - MapResolver R(CurRec.get()); - for (const auto &TArg : TemplateArgs) - R.set(TArg.first, TArg.second); - CurRec->resolveReferences(R); - - NewRecDefs.emplace_back(std::move(CurRec)); - } + if (resolve(MC->Entries, Substs, CurMultiClass == nullptr, &NewEntries, + &SubClassLoc)) + return true; if (Lex.getCode() != tgtok::comma) break; Lex.Lex(); // eat ','. @@ -2880,9 +2948,9 @@ // Get the expanded definition prototypes and teach them about // the record values the current class to inherit has - for (const auto &CurRec : NewRecDefs) { + for (auto &E : NewEntries) { // Add it. - if (AddSubClass(CurRec.get(), SubClass)) + if (AddSubClass(E, SubClass)) return true; } @@ -2892,11 +2960,11 @@ } } - for (auto &CurRec : NewRecDefs) { - if (ApplyLetStack(CurRec.get())) + for (auto &E : NewEntries) { + if (ApplyLetStack(E)) return true; - addDef(std::move(CurRec)); + addEntry(std::move(E)); } if (Lex.getCode() != tgtok::semi) @@ -2959,3 +3027,31 @@ return TokError("Unexpected input at top level"); } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void RecordsEntry::dump() const { + if (Loop) + Loop->dump(); + if (Rec) + Rec->dump(); +} + +LLVM_DUMP_METHOD void ForeachLoop::dump() const { + errs() << "foreach " << IterVar->getAsString() << " = " + << ListValue->getAsString() << " in {\n"; + + for (const auto &E : Entries) + E.dump(); + + errs() << "}\n"; +} + +LLVM_DUMP_METHOD void MultiClass::dump() const { + errs() << "Record:\n"; + Rec.dump(); + + errs() << "Defs:\n"; + for (const auto &E : Entries) + E.dump(); +} +#endif Index: test/TableGen/NestedForeach.td =================================================================== --- test/TableGen/NestedForeach.td +++ test/TableGen/NestedForeach.td @@ -17,6 +17,10 @@ } } +foreach i = [0, 1] in +foreach j = !foreach(x, [0, 2], !add(i, x)) in +def Z#i#_#j; + // CHECK: def C2D0 // CHECK: def C2D2 // CHECK: def C2D4 @@ -71,3 +75,8 @@ // CHECK: def R4Q0 // CHECK: def R4Q2 // CHECK: def R4Q4 + +// CHECK: def Z0_0 +// CHECK: def Z0_2 +// CHECK: def Z1_1 +// CHECK: def Z1_3 Index: test/TableGen/foreach-multiclass.td =================================================================== --- test/TableGen/foreach-multiclass.td +++ test/TableGen/foreach-multiclass.td @@ -11,9 +11,53 @@ // CHECK: int sum = 8; // CHECK: } +// CHECK-NOT: def B0 + +// CHECK: def B12 { +// CHECK: int val = 9; +// CHECK: } + +// CHECK: def B2-1 { +// CHECK: int val = 6; +// CHECK: } + +// CHECK: def B20 { +// CHECK: int val = 7; +// CHECK: } + +// CHECK: def B24 { +// CHECK: int val = 11; +// CHECK: } + +// CHECK: def C04 +// CHECK: def C05 + +// CHECK: def D0A +// CHECK-NOT: def D0B +// CHECK: def D1A +// CHECK: def D1B + +// CHECK: def E01 +// CHECK: def E02 +// CHECK-NOT: def E0C + +// CHECK: def E18 +// CHECK: def E19 +// CHECK: def E1C33 +// CHECK: def E1C34 +// CHECK: def E1C55 +// CHECK: def E1C56 + +// CHECK-NOT: def F0 +// CHECK-NOT: def F1 +// CHECK-NOT: def F2_0_0 +// CHECK: def F2_1_0 +// CHECK-NOT: def F2_1_2 +// CHECK: def F2_2_0 +// CHECK: def F2_2_1 +// CHECK-NOT: def F2_2_2 + multiclass A { - // Allow foreach in multiclass as long as the list does not depend on - // template args. foreach i = [0, 1] in { def NAME#i { int sum = !add(x, i); @@ -22,3 +66,53 @@ } defm A0 : A<7>; + +multiclass B lst> { + foreach i = lst in { + def NAME#i { + int val = !add(x, i); + } + } +} + +defm B0 : B<7, []>; +defm B1 : B<7, [2]>; +defm B2 : B<7, [-1, 0, 4]>; + +multiclass C { + foreach i = [x, !add(x, 1)] in { + def NAME#i; + } +} + +defm C0 : C<4>; + +multiclass D { + def A; + + foreach _ = !if(b, [0], []) in + def B; +} + +defm D0 : D<0>; +defm D1 : D<1>; + +multiclass E lst, int x> + : C { + foreach i = lst in + defm C#i : C; +} + +defm E0 : E<[], 1>; +defm E1 : E<[3, 5], 8>; + +multiclass F lst> { + foreach i = lst in + foreach j = !foldl([], lst, lhs, x, + !if(!lt(x, i), !listconcat(lhs, [x]), lhs)) in + def _#i#_#j; +} + +defm F0 : F<[]>; +defm F1 : F<[0]>; +defm F2 : F<[0, 1, 2]>;