summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/TableGen/Record.h16
-rw-r--r--llvm/lib/TableGen/Record.cpp25
-rw-r--r--llvm/lib/TableGen/TGParser.cpp316
-rw-r--r--llvm/lib/TableGen/TGParser.h62
-rw-r--r--llvm/test/TableGen/NestedForeach.td9
-rw-r--r--llvm/test/TableGen/foreach-multiclass.td98
6 files changed, 357 insertions, 169 deletions
diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index cfe6d7ababc..229e8dcc5c3 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -1596,17 +1596,6 @@ public:
raw_ostream &operator<<(raw_ostream &OS, const Record &R);
-struct MultiClass {
- Record Rec; // Placeholder for template args and Name.
- using RecordVector = std::vector<std::unique_ptr<Record>>;
- 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<std::string, std::unique_ptr<Record>>;
@@ -1776,11 +1765,6 @@ struct LessRecordRegister {
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
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 867dd006ed6..43d178caef3 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -2131,15 +2131,6 @@ DagInit *Record::getValueAsDag(StringRef FieldName) const {
}
#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 @@ RecordKeeper::getAllDerivedDefinitions(StringRef ClassName) const {
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<BinOpInit>(NewName))
- NewName = BinOp->Fold(&CurRec);
- return NewName;
-}
-
Init *MapResolver::resolve(Init *VarName) {
auto It = Map.find(VarName);
if (It == Map.end())
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index a0ec4dbfdc7..1d1f3603c83 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -110,6 +110,24 @@ static void checkConcrete(Record &R) {
}
}
+/// 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<BinOpInit>(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 @@ bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) {
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.
@@ -285,7 +315,7 @@ bool TGParser::AddSubMultiClass(MultiClass *CurMC,
// Prepare the mapping of template argument name to value, filling in default
// values if necessary.
- SmallVector<std::pair<Init *, Init *>, 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]);
@@ -307,85 +337,105 @@ bool TGParser::AddSubMultiClass(MultiClass *CurMC,
VarInit::get(QualifiedNameOfImplicitName(CurMC), StringRecTy::get()));
// Add all of the defs in the subclass into the current multiclass.
- for (const std::unique_ptr<Record> &Rec : SMC->DefPrototypes) {
- auto NewDef = make_unique<Record>(*Rec);
+ return resolve(SMC->Entries, TemplateArgs, false, &CurMC->Entries);
+}
- MapResolver R(NewDef.get());
- for (const auto &TArg : TemplateArgs)
- R.set(TArg.first, TArg.second);
- NewDef->resolveReferences(R);
+/// 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) {
+ assert(!E.Rec || !E.Loop);
- CurMC->DefPrototypes.push_back(std::move(NewDef));
+ 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<Record> 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<RecordsEntry> *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<ListInit>(List);
+ if (!LI) {
+ if (!Final) {
+ Dest->emplace_back(make_unique<ForeachLoop>(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<Record>(*Rec);
- return addDefOne(std::move(IterRec), IterVals);
+ bool Error = false;
+ for (auto Elt : *LI) {
+ Substs.emplace_back(Loop.IterVar->getNameInit(), Elt);
+ 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<Record> 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<RecordsEntry> &Source,
+ SubstStack &Substs, bool Final,
+ std::vector<RecordsEntry> *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<Record>(*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<Record> Rec) {
if (Record *Prev = Records.getDef(Rec->getNameInitAsString())) {
if (!Rec->isAnonymous()) {
PrintError(Rec->getLoc(),
@@ -804,7 +854,7 @@ Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc,
// If this is in a foreach loop, make sure it's not a loop iterator
for (const auto &L : Loops) {
- VarInit *IterVar = dyn_cast<VarInit>(L.IterVar);
+ VarInit *IterVar = dyn_cast<VarInit>(L->IterVar);
if (IterVar && IterVar->getNameInit() == Name)
return IterVar;
}
@@ -1158,7 +1208,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
Init *LHS = StringInit::get(Lex.getCurStrVal());
- if (CurRec->getValue(LHS)) {
+ if (CurRec && CurRec->getValue(LHS)) {
TokError((Twine("iteration variable '") + LHS->getAsString() +
"' already defined")
.str());
@@ -1217,9 +1267,18 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
return nullptr;
}
- CurRec->addValue(RecordVal(LHS, InEltType, false));
- Init *RHS = ParseValue(CurRec, OutEltType);
- CurRec->removeValue(LHS);
+ // We need to create a temporary record to provide a scope for the iteration
+ // variable while parsing top-level foreach's.
+ std::unique_ptr<Record> ParseRecTmp;
+ Record *ParseRec = CurRec;
+ if (!ParseRec) {
+ ParseRecTmp = make_unique<Record>(".parse", ArrayRef<SMLoc>{}, Records);
+ ParseRec = ParseRecTmp.get();
+ }
+
+ ParseRec->addValue(RecordVal(LHS, InEltType, false));
+ Init *RHS = ParseValue(ParseRec, OutEltType);
+ ParseRec->removeValue(LHS);
if (!RHS)
return nullptr;
@@ -1441,7 +1500,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
}
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());
@@ -1459,7 +1518,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
}
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());
@@ -1472,11 +1531,20 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
}
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);
+ // We need to create a temporary record to provide a scope for the iteration
+ // variable while parsing top-level foreach's.
+ std::unique_ptr<Record> ParseRecTmp;
+ Record *ParseRec = CurRec;
+ if (!ParseRec) {
+ ParseRecTmp = make_unique<Record>(".parse", ArrayRef<SMLoc>{}, 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;
@@ -2191,7 +2259,7 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
/// 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;
@@ -2231,9 +2299,10 @@ VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) {
default: {
SMLoc ValueLoc = Lex.getLoc();
Init *I = ParseValue(nullptr);
- if (!isa<ListInit>(I)) {
+ TypedInit *TI = dyn_cast<TypedInit>(I);
+ if (!TI || !isa<ListRecTy>(TI->getType())) {
std::string Type;
- if (TypedInit *TI = dyn_cast<TypedInit>(I))
+ if (TI)
Type = (Twine("' of type '") + TI->getType()->getAsString()).str();
Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'");
if (CurMultiClass)
@@ -2241,8 +2310,8 @@ VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) {
"resolved at this time");
return nullptr;
}
- ForeachListValue = dyn_cast<ListInit>(I);
- IterType = ForeachListValue->getElementType();
+ ForeachListValue = I;
+ IterType = cast<ListRecTy>(TI->getType())->getElementType();
break;
}
}
@@ -2390,6 +2459,18 @@ bool TGParser::ApplyLetStack(Record *CurRec) {
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.
@@ -2451,7 +2532,7 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) {
if (ParseObjectBody(CurRec.get()))
return true;
- return addDef(std::move(CurRec));
+ return addEntry(std::move(CurRec));
}
/// ParseDefset - Parse a defset statement.
@@ -2508,12 +2589,13 @@ bool TGParser::ParseDefset() {
/// 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");
@@ -2523,7 +2605,7 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) {
Lex.Lex(); // Eat the in
// Create a loop object and remember it.
- Loops.push_back(ForeachLoop(IterName, ListValue));
+ Loops.push_back(llvm::make_unique<ForeachLoop>(Loc, IterName, ListValue));
if (Lex.getCode() != tgtok::l_brace) {
// FOREACH Declaration IN Object
@@ -2545,10 +2627,11 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) {
Lex.Lex(); // Eat the }
}
- // We've processed everything in this loop.
+ // Resolve the loop or store it for later resolution.
+ std::unique_ptr<ForeachLoop> Loop = std::move(Loops.back());
Loops.pop_back();
- return false;
+ return addEntry(std::move(Loop));
}
/// ParseClass - Parse a tblgen class definition.
@@ -2795,7 +2878,7 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
return TokError("expected ':' after defm identifier");
// Keep track of the new generated record definitions.
- SmallVector<std::unique_ptr<Record>, 8> NewRecDefs;
+ std::vector<RecordsEntry> NewEntries;
// This record also inherits from a regular class (non-multiclass)?
bool InheritFromClass = false;
@@ -2822,10 +2905,10 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
return Error(SubClassLoc,
"more template args specified than multiclass expects");
- SmallVector<std::pair<Init *, Init *>, 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()) {
@@ -2835,24 +2918,15 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
") 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<Record> &DefProto : MC->DefPrototypes) {
- auto CurRec = make_unique<Record>(*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 ','.
@@ -2882,9 +2956,9 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
// 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;
}
@@ -2894,11 +2968,11 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
}
}
- 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)
@@ -2961,3 +3035,31 @@ bool TGParser::ParseFile() {
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
diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h
index a457aab3ff6..0a28b3a03aa 100644
--- a/llvm/lib/TableGen/TGParser.h
+++ b/llvm/lib/TableGen/TGParser.h
@@ -27,6 +27,7 @@ namespace llvm {
class RecordKeeper;
class RecTy;
class Init;
+ struct ForeachLoop;
struct MultiClass;
struct SubClassReference;
struct SubMultiClassReference;
@@ -41,14 +42,31 @@ namespace llvm {
}
};
+ /// RecordsEntry - Can be either a record or a foreach loop.
+ struct RecordsEntry {
+ std::unique_ptr<Record> Rec;
+ std::unique_ptr<ForeachLoop> Loop;
+
+ void dump() const;
+
+ RecordsEntry() {}
+ RecordsEntry(std::unique_ptr<Record> Rec) : Rec(std::move(Rec)) {}
+ RecordsEntry(std::unique_ptr<ForeachLoop> 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<RecordsEntry> 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 @@ namespace llvm {
SmallVector<Init *, 16> Elements;
};
+struct MultiClass {
+ Record Rec; // Placeholder for template args and Name.
+ std::vector<RecordsEntry> Entries;
+
+ void dump() const;
+
+ MultiClass(StringRef Name, SMLoc Loc, RecordKeeper &Records) :
+ Rec(Name, Loc, Records) {}
+};
+
class TGParser {
TGLexer Lex;
std::vector<SmallVector<LetRecord, 4>> LetStack;
@@ -64,8 +92,7 @@ class TGParser {
/// Loops - Keep track of any foreach loops we are within.
///
- typedef std::vector<ForeachLoop> LoopVector;
- LoopVector Loops;
+ std::vector<std::unique_ptr<ForeachLoop>> Loops;
SmallVector<DefsetRecord *, 2> Defsets;
@@ -112,23 +139,19 @@ private: // Semantic analysis methods.
ArrayRef<unsigned> 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<IterRecord> IterSet;
+ using SubstStack = SmallVector<std::pair<Init *, Init *>, 8>;
- bool addDefOne(std::unique_ptr<Record> Rec, IterSet &IterVals);
- bool addDefForeach(Record *Rec, IterSet &IterVals);
- bool addDef(std::unique_ptr<Record> Rec);
+ bool addEntry(RecordsEntry E);
+ bool resolve(const ForeachLoop &Loop, SubstStack &Stack, bool Final,
+ std::vector<RecordsEntry> *Dest, SMLoc *Loc = nullptr);
+ bool resolve(const std::vector<RecordsEntry> &Source, SubstStack &Substs,
+ bool Final, std::vector<RecordsEntry> *Dest,
+ SMLoc *Loc = nullptr);
+ bool addDefOne(std::unique_ptr<Record> Rec);
private: // Parser methods.
bool ParseObjectList(MultiClass *MC = nullptr);
@@ -148,7 +171,7 @@ private: // Parser methods.
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 @@ private: // Parser methods.
Record *ParseClassID();
MultiClass *ParseMultiClassID();
bool ApplyLetStack(Record *CurRec);
+ bool ApplyLetStack(RecordsEntry &Entry);
};
} // end namespace llvm
diff --git a/llvm/test/TableGen/NestedForeach.td b/llvm/test/TableGen/NestedForeach.td
index 5b63175b192..db5bdd0e0bc 100644
--- a/llvm/test/TableGen/NestedForeach.td
+++ b/llvm/test/TableGen/NestedForeach.td
@@ -17,6 +17,10 @@ foreach S = ["R", "C"] in {
}
}
+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 @@ foreach S = ["R", "C"] in {
// 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
diff --git a/llvm/test/TableGen/foreach-multiclass.td b/llvm/test/TableGen/foreach-multiclass.td
index 38be10f2112..d17d5bfa60d 100644
--- a/llvm/test/TableGen/foreach-multiclass.td
+++ b/llvm/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 B20 {
+// CHECK: int val = 7;
+// CHECK: }
+
+// CHECK: def B24 {
+// CHECK: int val = 11;
+// CHECK: }
+
+// CHECK: def B25 {
+// CHECK: int val = 12;
+// 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<int x> {
- // 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 @@ multiclass A<int x> {
}
defm A0 : A<7>;
+
+multiclass B<int x, list<int> 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, [0, 4, 5]>;
+
+multiclass C<int x> {
+ foreach i = [x, !add(x, 1)] in {
+ def NAME#i;
+ }
+}
+
+defm C0 : C<4>;
+
+multiclass D<bit b> {
+ def A;
+
+ foreach _ = !if(b, [0], []<int>) in
+ def B;
+}
+
+defm D0 : D<0>;
+defm D1 : D<1>;
+
+multiclass E<list<int> lst, int x>
+ : C<x> {
+ foreach i = lst in
+ defm C#i : C<i>;
+}
+
+defm E0 : E<[], 1>;
+defm E1 : E<[3, 5], 8>;
+
+multiclass F<list<int> lst> {
+ foreach i = lst in
+ foreach j = !foldl([]<int>, 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]>;
OpenPOWER on IntegriCloud