1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

TableGen: Allow foreach in multiclass to depend on template args

Summary:
This also allows inner foreach loops to have a list that depends on
the iteration variable of an outer foreach loop. The test cases show
some very simple examples of how this can be used.

This was perhaps the last remaining major non-orthogonality in the
TableGen frontend.

Change-Id: I79b92d41a5c0e7c03cc8af4000c5e1bda5ef464d

Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm

Subscribers: wdng, llvm-commits

Differential Revision: https://reviews.llvm.org/D47431

llvm-svn: 335221
This commit is contained in:
Nicolai Haehnle 2018-06-21 13:35:44 +00:00
parent 371b1bd7b2
commit 96e034ed15
6 changed files with 363 additions and 175 deletions

View File

@ -1596,17 +1596,6 @@ public:
raw_ostream &operator<<(raw_ostream &OS, const Record &R); 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 { class RecordKeeper {
friend class RecordRecTy; friend class RecordRecTy;
using RecordMap = std::map<std::string, std::unique_ptr<Record>>; 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); 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 // Resolvers
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -2131,15 +2131,6 @@ DagInit *Record::getValueAsDag(StringRef FieldName) const {
} }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) #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; } LLVM_DUMP_METHOD void RecordKeeper::dump() const { errs() << *this; }
#endif #endif
@ -2174,22 +2165,6 @@ RecordKeeper::getAllDerivedDefinitions(StringRef ClassName) const {
return Defs; 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) { Init *MapResolver::resolve(Init *VarName) {
auto It = Map.find(VarName); auto It = Map.find(VarName);
if (It == Map.end()) if (It == Map.end())

View File

@ -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. /// Return the qualified version of the implicit 'NAME' template argument.
static Init *QualifiedNameOfImplicitName(Record &Rec, static Init *QualifiedNameOfImplicitName(Record &Rec,
MultiClass *MC = nullptr) { MultiClass *MC = nullptr) {
@ -271,6 +289,18 @@ bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) {
return false; 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 /// AddSubMultiClass - Add SubMultiClass as a subclass to
/// CurMC, resolving its template args as SubMultiClass's /// CurMC, resolving its template args as SubMultiClass's
/// template arguments. /// template arguments.
@ -285,7 +315,7 @@ bool TGParser::AddSubMultiClass(MultiClass *CurMC,
// Prepare the mapping of template argument name to value, filling in default // Prepare the mapping of template argument name to value, filling in default
// values if necessary. // values if necessary.
SmallVector<std::pair<Init *, Init *>, 8> TemplateArgs; SubstStack TemplateArgs;
for (unsigned i = 0, e = SMCTArgs.size(); i != e; ++i) { for (unsigned i = 0, e = SMCTArgs.size(); i != e; ++i) {
if (i < SubMultiClass.TemplateArgs.size()) { if (i < SubMultiClass.TemplateArgs.size()) {
TemplateArgs.emplace_back(SMCTArgs[i], SubMultiClass.TemplateArgs[i]); TemplateArgs.emplace_back(SMCTArgs[i], SubMultiClass.TemplateArgs[i]);
@ -307,85 +337,105 @@ bool TGParser::AddSubMultiClass(MultiClass *CurMC,
VarInit::get(QualifiedNameOfImplicitName(CurMC), StringRecTy::get())); VarInit::get(QualifiedNameOfImplicitName(CurMC), StringRecTy::get()));
// Add all of the defs in the subclass into the current multiclass. // Add all of the defs in the subclass into the current multiclass.
for (const std::unique_ptr<Record> &Rec : SMC->DefPrototypes) { return resolve(SMC->Entries, TemplateArgs, false, &CurMC->Entries);
auto NewDef = make_unique<Record>(*Rec);
MapResolver R(NewDef.get());
for (const auto &TArg : TemplateArgs)
R.set(TArg.first, TArg.second);
NewDef->resolveReferences(R);
CurMC->DefPrototypes.push_back(std::move(NewDef));
}
return false;
} }
/// Add a record that results from 'def' or 'defm', after template arguments /// Add a record or foreach loop to the current context (global record keeper,
/// and the external let stack have been resolved. /// current inner-most foreach loop, or multiclass).
/// bool TGParser::addEntry(RecordsEntry E) {
/// Apply foreach loops, resolve internal variable references, and add to the assert(!E.Rec || !E.Loop);
/// current multi class or the global record keeper as appropriate.
bool TGParser::addDef(std::unique_ptr<Record> Rec) {
IterSet IterVals;
if (Loops.empty()) if (!Loops.empty()) {
return addDefOne(std::move(Rec), IterVals); Loops.back()->Entries.push_back(std::move(E));
return addDefForeach(Rec.get(), IterVals);
}
/// 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; return false;
} }
// This is the bottom of the recursion. We have all of the iterator values if (E.Loop) {
// for this point in the iteration space. Instantiate a new record to SubstStack Stack;
// reflect this combination of values. return resolve(*E.Loop, Stack, CurMultiClass == nullptr,
auto IterRec = make_unique<Record>(*Rec); CurMultiClass ? &CurMultiClass->Entries : nullptr);
return addDefOne(std::move(IterRec), IterVals); }
}
/// 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);
Rec->resolveReferences(R);
if (CurMultiClass) { if (CurMultiClass) {
if (!Rec->isAnonymous()) { CurMultiClass->Entries.push_back(std::move(E));
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;
}
}
}
CurMultiClass->DefPrototypes.emplace_back(std::move(Rec));
return false; return false;
} }
return addDefOne(std::move(E.Rec));
}
/// 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;
}
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;
}
/// 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);
MapResolver R(Rec.get());
for (const auto &S : Substs)
R.set(S.first, S.second);
Rec->resolveReferences(R);
if (Dest)
Dest->push_back(std::move(Rec));
else
Error = addDefOne(std::move(Rec));
}
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 (Record *Prev = Records.getDef(Rec->getNameInitAsString())) {
if (!Rec->isAnonymous()) { if (!Rec->isAnonymous()) {
PrintError(Rec->getLoc(), 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 // If this is in a foreach loop, make sure it's not a loop iterator
for (const auto &L : Loops) { for (const auto &L : Loops) {
VarInit *IterVar = dyn_cast<VarInit>(L.IterVar); VarInit *IterVar = dyn_cast<VarInit>(L->IterVar);
if (IterVar && IterVar->getNameInit() == Name) if (IterVar && IterVar->getNameInit() == Name)
return IterVar; return IterVar;
} }
@ -1158,7 +1208,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
Init *LHS = StringInit::get(Lex.getCurStrVal()); Init *LHS = StringInit::get(Lex.getCurStrVal());
if (CurRec->getValue(LHS)) { if (CurRec && CurRec->getValue(LHS)) {
TokError((Twine("iteration variable '") + LHS->getAsString() + TokError((Twine("iteration variable '") + LHS->getAsString() +
"' already defined") "' already defined")
.str()); .str());
@ -1217,9 +1267,18 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
return nullptr; return nullptr;
} }
CurRec->addValue(RecordVal(LHS, InEltType, false)); // We need to create a temporary record to provide a scope for the iteration
Init *RHS = ParseValue(CurRec, OutEltType); // variable while parsing top-level foreach's.
CurRec->removeValue(LHS); 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) if (!RHS)
return nullptr; return nullptr;
@ -1441,7 +1500,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
} }
Init *A = StringInit::get(Lex.getCurStrVal()); Init *A = StringInit::get(Lex.getCurStrVal());
if (CurRec->getValue(A)) { if (CurRec && CurRec->getValue(A)) {
TokError((Twine("left !foldl variable '") + A->getAsString() + TokError((Twine("left !foldl variable '") + A->getAsString() +
"' already defined") "' already defined")
.str()); .str());
@ -1459,7 +1518,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
} }
Init *B = StringInit::get(Lex.getCurStrVal()); Init *B = StringInit::get(Lex.getCurStrVal());
if (CurRec->getValue(B)) { if (CurRec && CurRec->getValue(B)) {
TokError((Twine("right !foldl variable '") + B->getAsString() + TokError((Twine("right !foldl variable '") + B->getAsString() +
"' already defined") "' already defined")
.str()); .str());
@ -1472,11 +1531,20 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
} }
Lex.Lex(); // eat the ',' Lex.Lex(); // eat the ','
CurRec->addValue(RecordVal(A, Start->getType(), false)); // We need to create a temporary record to provide a scope for the iteration
CurRec->addValue(RecordVal(B, ListType->getElementType(), false)); // variable while parsing top-level foreach's.
Init *ExprUntyped = ParseValue(CurRec); std::unique_ptr<Record> ParseRecTmp;
CurRec->removeValue(A); Record *ParseRec = CurRec;
CurRec->removeValue(B); 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) if (!ExprUntyped)
return nullptr; return nullptr;
@ -2191,7 +2259,7 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
/// ForeachDeclaration ::= ID '=' RangePiece /// ForeachDeclaration ::= ID '=' RangePiece
/// ForeachDeclaration ::= ID '=' Value /// ForeachDeclaration ::= ID '=' Value
/// ///
VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) { VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) {
if (Lex.getCode() != tgtok::Id) { if (Lex.getCode() != tgtok::Id) {
TokError("Expected identifier in foreach declaration"); TokError("Expected identifier in foreach declaration");
return nullptr; return nullptr;
@ -2231,9 +2299,10 @@ VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) {
default: { default: {
SMLoc ValueLoc = Lex.getLoc(); SMLoc ValueLoc = Lex.getLoc();
Init *I = ParseValue(nullptr); Init *I = ParseValue(nullptr);
if (!isa<ListInit>(I)) { TypedInit *TI = dyn_cast<TypedInit>(I);
if (!TI || !isa<ListRecTy>(TI->getType())) {
std::string Type; std::string Type;
if (TypedInit *TI = dyn_cast<TypedInit>(I)) if (TI)
Type = (Twine("' of type '") + TI->getType()->getAsString()).str(); Type = (Twine("' of type '") + TI->getType()->getAsString()).str();
Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'"); Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'");
if (CurMultiClass) if (CurMultiClass)
@ -2241,8 +2310,8 @@ VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) {
"resolved at this time"); "resolved at this time");
return nullptr; return nullptr;
} }
ForeachListValue = dyn_cast<ListInit>(I); ForeachListValue = I;
IterType = ForeachListValue->getElementType(); IterType = cast<ListRecTy>(TI->getType())->getElementType();
break; break;
} }
} }
@ -2390,6 +2459,18 @@ bool TGParser::ApplyLetStack(Record *CurRec) {
return false; 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 /// 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 /// optional ClassList followed by a Body. CurRec is the current def or class
/// that is being parsed. /// that is being parsed.
@ -2451,7 +2532,7 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) {
if (ParseObjectBody(CurRec.get())) if (ParseObjectBody(CurRec.get()))
return true; return true;
return addDef(std::move(CurRec)); return addEntry(std::move(CurRec));
} }
/// ParseDefset - Parse a defset statement. /// ParseDefset - Parse a defset statement.
@ -2508,12 +2589,13 @@ bool TGParser::ParseDefset() {
/// Foreach ::= FOREACH Declaration IN Object /// Foreach ::= FOREACH Declaration IN Object
/// ///
bool TGParser::ParseForeach(MultiClass *CurMultiClass) { bool TGParser::ParseForeach(MultiClass *CurMultiClass) {
SMLoc Loc = Lex.getLoc();
assert(Lex.getCode() == tgtok::Foreach && "Unknown tok"); assert(Lex.getCode() == tgtok::Foreach && "Unknown tok");
Lex.Lex(); // Eat the 'for' token. Lex.Lex(); // Eat the 'for' token.
// Make a temporary object to record items associated with the for // Make a temporary object to record items associated with the for
// loop. // loop.
ListInit *ListValue = nullptr; Init *ListValue = nullptr;
VarInit *IterName = ParseForeachDeclaration(ListValue); VarInit *IterName = ParseForeachDeclaration(ListValue);
if (!IterName) if (!IterName)
return TokError("expected declaration in for"); return TokError("expected declaration in for");
@ -2523,7 +2605,7 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) {
Lex.Lex(); // Eat the in Lex.Lex(); // Eat the in
// Create a loop object and remember it. // 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) { if (Lex.getCode() != tgtok::l_brace) {
// FOREACH Declaration IN Object // FOREACH Declaration IN Object
@ -2545,10 +2627,11 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) {
Lex.Lex(); // Eat the } 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(); Loops.pop_back();
return false; return addEntry(std::move(Loop));
} }
/// ParseClass - Parse a tblgen class definition. /// ParseClass - Parse a tblgen class definition.
@ -2795,7 +2878,7 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
return TokError("expected ':' after defm identifier"); return TokError("expected ':' after defm identifier");
// Keep track of the new generated record definitions. // 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)? // This record also inherits from a regular class (non-multiclass)?
bool InheritFromClass = false; bool InheritFromClass = false;
@ -2822,10 +2905,10 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
return Error(SubClassLoc, return Error(SubClassLoc,
"more template args specified than multiclass expects"); "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) { for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
if (i < TemplateVals.size()) { if (i < TemplateVals.size()) {
TemplateArgs.emplace_back(TArgs[i], TemplateVals[i]); Substs.emplace_back(TArgs[i], TemplateVals[i]);
} else { } else {
Init *Default = MC->Rec.getValue(TArgs[i])->getValue(); Init *Default = MC->Rec.getValue(TArgs[i])->getValue();
if (!Default->isComplete()) { if (!Default->isComplete()) {
@ -2835,24 +2918,15 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
") of multiclass '" + MC->Rec.getNameInitAsString() + ") of multiclass '" + MC->Rec.getNameInitAsString() +
"'"); "'");
} }
TemplateArgs.emplace_back(TArgs[i], Default); Substs.emplace_back(TArgs[i], Default);
} }
} }
TemplateArgs.emplace_back(QualifiedNameOfImplicitName(MC), DefmName); Substs.emplace_back(QualifiedNameOfImplicitName(MC), DefmName);
// Loop over all the def's in the multiclass, instantiating each one. if (resolve(MC->Entries, Substs, CurMultiClass == nullptr, &NewEntries,
for (const std::unique_ptr<Record> &DefProto : MC->DefPrototypes) { &SubClassLoc))
auto CurRec = make_unique<Record>(*DefProto); return true;
CurRec->appendLoc(SubClassLoc);
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 (Lex.getCode() != tgtok::comma) break; if (Lex.getCode() != tgtok::comma) break;
Lex.Lex(); // eat ','. Lex.Lex(); // eat ','.
@ -2882,9 +2956,9 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
// Get the expanded definition prototypes and teach them about // Get the expanded definition prototypes and teach them about
// the record values the current class to inherit has // the record values the current class to inherit has
for (const auto &CurRec : NewRecDefs) { for (auto &E : NewEntries) {
// Add it. // Add it.
if (AddSubClass(CurRec.get(), SubClass)) if (AddSubClass(E, SubClass))
return true; return true;
} }
@ -2894,11 +2968,11 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
} }
} }
for (auto &CurRec : NewRecDefs) { for (auto &E : NewEntries) {
if (ApplyLetStack(CurRec.get())) if (ApplyLetStack(E))
return true; return true;
addDef(std::move(CurRec)); addEntry(std::move(E));
} }
if (Lex.getCode() != tgtok::semi) if (Lex.getCode() != tgtok::semi)
@ -2961,3 +3035,31 @@ bool TGParser::ParseFile() {
return TokError("Unexpected input at top level"); 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

View File

@ -27,6 +27,7 @@ namespace llvm {
class RecordKeeper; class RecordKeeper;
class RecTy; class RecTy;
class Init; class Init;
struct ForeachLoop;
struct MultiClass; struct MultiClass;
struct SubClassReference; struct SubClassReference;
struct SubMultiClassReference; 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. /// ForeachLoop - Record the iteration state associated with a for loop.
/// This is used to instantiate items in the loop body. /// This is used to instantiate items in the loop body.
struct ForeachLoop { struct ForeachLoop {
SMLoc Loc;
VarInit *IterVar; VarInit *IterVar;
ListInit *ListValue; Init *ListValue;
std::vector<RecordsEntry> Entries;
ForeachLoop(VarInit *IVar, ListInit *LValue) void dump() const;
: IterVar(IVar), ListValue(LValue) {}
ForeachLoop(SMLoc Loc, VarInit *IVar, Init *LValue)
: Loc(Loc), IterVar(IVar), ListValue(LValue) {}
}; };
struct DefsetRecord { struct DefsetRecord {
@ -57,6 +75,16 @@ namespace llvm {
SmallVector<Init *, 16> Elements; 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 { class TGParser {
TGLexer Lex; TGLexer Lex;
std::vector<SmallVector<LetRecord, 4>> LetStack; std::vector<SmallVector<LetRecord, 4>> LetStack;
@ -64,8 +92,7 @@ class TGParser {
/// Loops - Keep track of any foreach loops we are within. /// Loops - Keep track of any foreach loops we are within.
/// ///
typedef std::vector<ForeachLoop> LoopVector; std::vector<std::unique_ptr<ForeachLoop>> Loops;
LoopVector Loops;
SmallVector<DefsetRecord *, 2> Defsets; SmallVector<DefsetRecord *, 2> Defsets;
@ -112,23 +139,19 @@ private: // Semantic analysis methods.
ArrayRef<unsigned> BitList, Init *V, ArrayRef<unsigned> BitList, Init *V,
bool AllowSelfAssignment = false); bool AllowSelfAssignment = false);
bool AddSubClass(Record *Rec, SubClassReference &SubClass); bool AddSubClass(Record *Rec, SubClassReference &SubClass);
bool AddSubClass(RecordsEntry &Entry, SubClassReference &SubClass);
bool AddSubMultiClass(MultiClass *CurMC, bool AddSubMultiClass(MultiClass *CurMC,
SubMultiClassReference &SubMultiClass); SubMultiClassReference &SubMultiClass);
// IterRecord: Map an iterator name to a value. using SubstStack = SmallVector<std::pair<Init *, Init *>, 8>;
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 bool addEntry(RecordsEntry E);
// iteration space. bool resolve(const ForeachLoop &Loop, SubstStack &Stack, bool Final,
typedef std::vector<IterRecord> IterSet; std::vector<RecordsEntry> *Dest, SMLoc *Loc = nullptr);
bool resolve(const std::vector<RecordsEntry> &Source, SubstStack &Substs,
bool addDefOne(std::unique_ptr<Record> Rec, IterSet &IterVals); bool Final, std::vector<RecordsEntry> *Dest,
bool addDefForeach(Record *Rec, IterSet &IterVals); SMLoc *Loc = nullptr);
bool addDef(std::unique_ptr<Record> Rec); bool addDefOne(std::unique_ptr<Record> Rec);
private: // Parser methods. private: // Parser methods.
bool ParseObjectList(MultiClass *MC = nullptr); bool ParseObjectList(MultiClass *MC = nullptr);
@ -148,7 +171,7 @@ private: // Parser methods.
bool ParseTemplateArgList(Record *CurRec); bool ParseTemplateArgList(Record *CurRec);
Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs); Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs);
VarInit *ParseForeachDeclaration(ListInit *&ForeachListValue); VarInit *ParseForeachDeclaration(Init *&ForeachListValue);
SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm); SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm);
SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMC); SubMultiClassReference ParseSubMultiClassReference(MultiClass *CurMC);
@ -175,6 +198,7 @@ private: // Parser methods.
Record *ParseClassID(); Record *ParseClassID();
MultiClass *ParseMultiClassID(); MultiClass *ParseMultiClassID();
bool ApplyLetStack(Record *CurRec); bool ApplyLetStack(Record *CurRec);
bool ApplyLetStack(RecordsEntry &Entry);
}; };
} // end namespace llvm } // end namespace llvm

View File

@ -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 C2D0
// CHECK: def C2D2 // CHECK: def C2D2
// CHECK: def C2D4 // CHECK: def C2D4
@ -71,3 +75,8 @@ foreach S = ["R", "C"] in {
// CHECK: def R4Q0 // CHECK: def R4Q0
// CHECK: def R4Q2 // CHECK: def R4Q2
// CHECK: def R4Q4 // CHECK: def R4Q4
// CHECK: def Z0_0
// CHECK: def Z0_2
// CHECK: def Z1_1
// CHECK: def Z1_3

View File

@ -11,9 +11,53 @@
// CHECK: int sum = 8; // CHECK: int sum = 8;
// CHECK: } // 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> { multiclass A<int x> {
// Allow foreach in multiclass as long as the list does not depend on
// template args.
foreach i = [0, 1] in { foreach i = [0, 1] in {
def NAME#i { def NAME#i {
int sum = !add(x, i); int sum = !add(x, i);
@ -22,3 +66,53 @@ multiclass A<int x> {
} }
defm A0 : A<7>; 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]>;