TableGen: Allow arbitrary list values as ranges of foreach

The changes to FieldInit are required to make field references (Def.field)
work inside a ForeachDeclaration: previously, Def.field wasn't resolved
immediately when Def was already a fully resolved DefInit.

Change-Id: I9875baec2fc5aac8c2b249e45b9cf18c65ae699b
llvm-svn: 327120
This commit is contained in:
Nicolai Haehnle 2018-03-09 12:24:30 +00:00
parent c8e80dc722
commit 1ebb6681e2
5 changed files with 53 additions and 31 deletions

View File

@ -360,13 +360,17 @@ precede any ``class``'s that appear.
-----------
.. productionlist::
Foreach: "foreach" `Declaration` "in" "{" `Object`* "}"
:| "foreach" `Declaration` "in" `Object`
Foreach: "foreach" `ForeachDeclaration` "in" "{" `Object`* "}"
:| "foreach" `ForeachDeclaration` "in" `Object`
ForeachDeclaration: ID "=" ( "{" `RangeList` "}" | `RangePiece` | `Value` )
The value assigned to the variable in the declaration is iterated over and
the object or object list is reevaluated with the variable set at each
iterated value.
Note that the productions involving RangeList and RangePiece have precedence
over the more generic value parsing based on the first token.
Top-Level ``let``
-----------------

View File

@ -1203,6 +1203,7 @@ public:
Init *getBit(unsigned Bit) const override;
Init *resolveReferences(Resolver &R) const override;
Init *Fold() const;
std::string getAsString() const override {
return Rec->getAsString() + "." + FieldName->getValue().str();

View File

@ -1633,16 +1633,17 @@ Init *FieldInit::getBit(unsigned Bit) const {
Init *FieldInit::resolveReferences(Resolver &R) const {
Init *NewRec = Rec->resolveReferences(R);
if (DefInit *DI = dyn_cast<DefInit>(NewRec)) {
Init *FieldVal = DI->getDef()->getValue(FieldName)->getValue();
Init *BVR = FieldVal->resolveReferences(R);
if (BVR->isComplete())
return BVR;
}
if (NewRec != Rec)
return FieldInit::get(NewRec, FieldName);
return FieldInit::get(NewRec, FieldName)->Fold();
return const_cast<FieldInit *>(this);
}
Init *FieldInit::Fold() const {
if (DefInit *DI = dyn_cast<DefInit>(Rec)) {
Init *FieldVal = DI->getDef()->getValue(FieldName)->getValue();
if (FieldVal->isComplete())
return FieldVal;
}
return const_cast<FieldInit *>(this);
}

View File

@ -1819,7 +1819,7 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
Result->getAsString() + "'");
return nullptr;
}
Result = FieldInit::get(Result, FieldName);
Result = FieldInit::get(Result, FieldName)->Fold();
Lex.Lex(); // eat field name
break;
}
@ -2038,9 +2038,9 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
/// the name of the declared object or a NULL Init on error. Return
/// the name of the parsed initializer list through ForeachListName.
///
/// ForeachDeclaration ::= ID '=' '[' ValueList ']'
/// ForeachDeclaration ::= ID '=' '{' RangeList '}'
/// ForeachDeclaration ::= ID '=' RangePiece
/// ForeachDeclaration ::= ID '=' Value
///
VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) {
if (Lex.getCode() != tgtok::Id) {
@ -2062,24 +2062,6 @@ VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) {
SmallVector<unsigned, 16> Ranges;
switch (Lex.getCode()) {
default: TokError("Unknown token when expecting a range list"); return nullptr;
case tgtok::l_square: { // '[' ValueList ']'
Init *List = ParseSimpleValue(nullptr);
ForeachListValue = dyn_cast<ListInit>(List);
if (!ForeachListValue) {
TokError("Expected a Value list");
return nullptr;
}
RecTy *ValueType = ForeachListValue->getType();
ListRecTy *ListType = dyn_cast<ListRecTy>(ValueType);
if (!ListType) {
TokError("Value list is not of list type");
return nullptr;
}
IterType = ListType->getElementType();
break;
}
case tgtok::IntVal: { // RangePiece.
if (ParseRangePiece(Ranges))
return nullptr;
@ -2096,6 +2078,21 @@ VarInit *TGParser::ParseForeachDeclaration(ListInit *&ForeachListValue) {
Lex.Lex();
break;
}
default: {
SMLoc ValueLoc = Lex.getLoc();
Init *I = ParseValue(nullptr);
if (!isa<ListInit>(I)) {
std::string Type;
if (TypedInit *TI = dyn_cast<TypedInit>(I))
Type = (Twine("' of type '") + TI->getType()->getAsString()).str();
Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'");
return nullptr;
}
ForeachListValue = dyn_cast<ListInit>(I);
IterType = ForeachListValue->getElementType();
break;
}
}
if (!Ranges.empty()) {

View File

@ -10,6 +10,18 @@ foreach i = [0, 1, 2, 3, 4, 5, 6, 7] in {
def F#i : Register<"F"#i, i>;
}
def Defs {
list<int> a = [0, 1];
list<int> b = [2, 3];
}
foreach i = Defs.a in {
def X#i;
}
foreach i = !listconcat(Defs.a, Defs.b) in
def Y#i;
// CHECK: def F0
// CHECK: string Name = "F0";
// CHECK: int Index = 0;
@ -73,3 +85,10 @@ foreach i = [0, 1, 2, 3, 4, 5, 6, 7] in {
// CHECK: def R7
// CHECK: string Name = "R7";
// CHECK: int Index = 7;
// CHECK: def X0
// CHECK: def X1
// CHECK: def Y0
// CHECK: def Y1
// CHECK: def Y2
// CHECK: def Y3