[llvm] 45ea4d6 - [TableGen] Unify the priority of variables
via llvm-commits
llvm-commits at lists.llvm.org
Tue May 23 21:44:39 PDT 2023
Author: wangpc
Date: 2023-05-24T12:44:14+08:00
New Revision: 45ea4d6256186b7869cd46907e88d8d2b1ea3df0
URL: https://github.com/llvm/llvm-project/commit/45ea4d6256186b7869cd46907e88d8d2b1ea3df0
DIFF: https://github.com/llvm/llvm-project/commit/45ea4d6256186b7869cd46907e88d8d2b1ea3df0.diff
LOG: [TableGen] Unify the priority of variables
In D148197, we have made `defvar` statement able to refer to class
template arguments. However, the priority of class/multiclass
template argument is higher than variables defined by `defvar`, which
is a little counterintuitive.
In this patch, we unify the priority of variables. Each pair of
braces introduces a new scope, which may contain some additional
variables like template arguments, loop iterators, etc. We can
define local variables inside this scope via `defvar` and these
variables are of higher priority than additional variables. This
means that `defvar` will shadow additional variables with the same
name. The scope can be nested, and we use the innermost variable.
This make variables defined by `defvar` prior to class/multiclass
template arguments, loop iterators, etc. The shadow rules now are:
* `V` in a record body shadows a global `V`.
* `V` in a record body shadows template argument `V`.
* `V` in template arguments shadows a global `V`.
* `V` in a `foreach` statement list shadows any `V` in surrounding record or global scopes.
Reviewed By: tra
Differential Revision: https://reviews.llvm.org/D149016
Added:
Modified:
llvm/docs/TableGen/ProgRef.rst
llvm/lib/TableGen/TGParser.cpp
llvm/lib/TableGen/TGParser.h
llvm/test/TableGen/defvar.td
Removed:
################################################################################
diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index d145750cfbfac..d49eddff8cd9d 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -1375,15 +1375,23 @@ Defvar in a record body
In addition to defining global variables, the ``defvar`` statement can
be used inside the :token:`Body` of a class or record definition to define
-local variables. The scope of the variable extends from the ``defvar``
-statement to the end of the body. It cannot be set to a
diff erent value
-within its scope. The ``defvar`` statement can also be used in the statement
+local variables. Template arguments of ``class`` or ``multiclass`` can be
+used in the value expression. The scope of the variable extends from the
+``defvar`` statement to the end of the body. It cannot be set to a
diff erent
+value within its scope. The ``defvar`` statement can also be used in the statement
list of a ``foreach``, which establishes a scope.
A variable named ``V`` in an inner scope shadows (hides) any variables ``V``
-in outer scopes. In particular, ``V`` in a record body shadows a global
-``V``, and ``V`` in a ``foreach`` statement list shadows any ``V`` in
-surrounding record or global scopes.
+in outer scopes. In particular, there are several cases:
+
+* ``V`` in a record body shadows a global ``V``.
+
+* ``V`` in a record body shadows template argument ``V``.
+
+* ``V`` in template arguments shadows a global ``V``.
+
+* ``V`` in a ``foreach`` statement list shadows any ``V`` in surrounding record or
+ global scopes.
Variables defined in a ``foreach`` go out of scope at the end of
each loop iteration, so their value in one iteration is not available in
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index ecd19b98e1b27..1580c4d57a6be 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -139,6 +139,79 @@ static Init *QualifiedNameOfImplicitName(MultiClass *MC) {
return QualifiedNameOfImplicitName(MC->Rec, MC);
}
+Init *TGVarScope::getVar(RecordKeeper &Records, MultiClass* ParsingMultiClass,
+ StringInit *Name, SMRange NameLoc,
+ bool TrackReferenceLocs) const {
+ // First, we search in local variables.
+ auto It = Vars.find(Name->getValue());
+ if (It != Vars.end())
+ return It->second;
+
+ std::function<Init *(Record *, StringInit *, StringRef)> FindValueInArgs =
+ [&](Record *Rec, StringInit *Name, StringRef Scoper) -> Init * {
+ if (!Rec)
+ return nullptr;
+ Init *ArgName = QualifyName(*Rec, ParsingMultiClass, Name, Scoper);
+ if (Rec->isTemplateArg(ArgName)) {
+ RecordVal *RV = Rec->getValue(ArgName);
+ assert(RV && "Template arg doesn't exist??");
+ RV->setUsed(true);
+ if (TrackReferenceLocs)
+ RV->addReferenceLoc(NameLoc);
+ return VarInit::get(ArgName, RV->getType());
+ }
+ return Name->getValue() == "NAME"
+ ? VarInit::get(ArgName, StringRecTy::get(Records))
+ : nullptr;
+ };
+
+ // If not found, we try to find the variable in additional variables like
+ // arguments, loop iterator, etc.
+ switch (Kind) {
+ case SK_Local:
+ break; /* do nothing. */
+ case SK_Record: {
+ if (CurRec) {
+ // The variable is a record field?
+ if (RecordVal *RV = CurRec->getValue(Name)) {
+ if (TrackReferenceLocs)
+ RV->addReferenceLoc(NameLoc);
+ return VarInit::get(Name, RV->getType());
+ }
+
+ // The variable is a class template argument?
+ if (CurRec->isClass())
+ if (auto *V = FindValueInArgs(CurRec, Name, ":"))
+ return V;
+ }
+ break;
+ }
+ case SK_ForeachLoop: {
+ // The variable is a loop iterator?
+ if (CurLoop->IterVar) {
+ VarInit *IterVar = dyn_cast<VarInit>(CurLoop->IterVar);
+ if (IterVar && IterVar->getNameInit() == Name)
+ return IterVar;
+ }
+ break;
+ }
+ case SK_MultiClass: {
+ // The variable is a multiclass template argument?
+ if (CurMultiClass)
+ if (auto *V = FindValueInArgs(&CurMultiClass->Rec, Name, "::"))
+ return V;
+ break;
+ }
+ }
+
+ // Then, we try to find the name in parent scope.
+ if (Parent)
+ return Parent->getVar(Records, ParsingMultiClass, Name, NameLoc,
+ TrackReferenceLocs);
+
+ return nullptr;
+}
+
bool TGParser::AddValue(Record *CurRec, SMLoc Loc, const RecordVal &RV) {
if (!CurRec)
CurRec = &CurMultiClass->Rec;
@@ -1037,47 +1110,9 @@ RecTy *TGParser::ParseType() {
/// ParseIDValue
Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMRange NameLoc,
IDParseMode Mode) {
- if (CurRec) {
- if (RecordVal *RV = CurRec->getValue(Name)) {
- if (TrackReferenceLocs)
- RV->addReferenceLoc(NameLoc);
- return VarInit::get(Name, RV->getType());
- }
- }
-
- if ((CurRec && CurRec->isClass()) || CurMultiClass) {
- Init *TemplateArgName;
- if (CurMultiClass) {
- TemplateArgName =
- QualifyName(CurMultiClass->Rec, CurMultiClass, Name, "::");
- } else
- TemplateArgName = QualifyName(*CurRec, CurMultiClass, Name, ":");
-
- Record *TemplateRec = CurMultiClass ? &CurMultiClass->Rec : CurRec;
- if (TemplateRec->isTemplateArg(TemplateArgName)) {
- RecordVal *RV = TemplateRec->getValue(TemplateArgName);
- assert(RV && "Template arg doesn't exist??");
- RV->setUsed(true);
- if (TrackReferenceLocs)
- RV->addReferenceLoc(NameLoc);
- return VarInit::get(TemplateArgName, RV->getType());
- } else if (Name->getValue() == "NAME") {
- return VarInit::get(TemplateArgName, StringRecTy::get(Records));
- }
- }
-
- if (CurLocalScope)
- if (Init *I = CurLocalScope->getVar(Name->getValue()))
- return I;
-
- // If this is in a foreach loop, make sure it's not a loop iterator
- for (const auto &L : Loops) {
- if (L->IterVar) {
- VarInit *IterVar = dyn_cast<VarInit>(L->IterVar);
- if (IterVar && IterVar->getNameInit() == Name)
- return IterVar;
- }
- }
+ if (Init *I = CurScope->getVar(Records, CurMultiClass, Name, NameLoc,
+ TrackReferenceLocs))
+ return I;
if (Mode == ParseNameMode)
return Name;
@@ -1942,12 +1977,14 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
ParseRec = ParseRecTmp.get();
}
+ TGVarScope *FoldScope = PushScope(ParseRec);
ParseRec->addValue(RecordVal(A, Start->getType(), RecordVal::FK_Normal));
- ParseRec->addValue(RecordVal(B, ListType->getElementType(),
- RecordVal::FK_Normal));
+ ParseRec->addValue(
+ RecordVal(B, ListType->getElementType(), RecordVal::FK_Normal));
Init *ExprUntyped = ParseValue(ParseRec);
ParseRec->removeValue(A);
ParseRec->removeValue(B);
+ PopScope(FoldScope);
if (!ExprUntyped)
return nullptr;
@@ -2279,10 +2316,11 @@ Init *TGParser::ParseOperationForEachFilter(Record *CurRec, RecTy *ItemType) {
std::make_unique<Record>(".parse", ArrayRef<SMLoc>{}, Records);
ParseRec = ParseRecTmp.get();
}
-
+ TGVarScope *TempScope = PushScope(ParseRec);
ParseRec->addValue(RecordVal(LHS, InEltType, RecordVal::FK_Normal));
Init *RHS = ParseValue(ParseRec, ExprEltType);
ParseRec->removeValue(LHS);
+ PopScope(TempScope);
if (!RHS)
return nullptr;
@@ -3070,6 +3108,11 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
return nullptr;
}
+ if (!ParsingTemplateArgs && CurScope->varAlreadyDefined(Str)) {
+ TokError("local variable of this name already exists");
+ return nullptr;
+ }
+
SMLoc IdLoc = Lex.getLoc();
Init *DeclName = StringInit::get(Records, Str);
Lex.Lex();
@@ -3306,15 +3349,10 @@ bool TGParser::ParseBody(Record *CurRec) {
if (!consume(tgtok::l_brace))
return TokError("Expected '{' to start body or ';' for declaration only");
- // An object body introduces a new scope for local variables.
- TGLocalVarScope *BodyScope = PushLocalScope();
-
while (Lex.getCode() != tgtok::r_brace)
if (ParseBodyItem(CurRec))
return true;
- PopLocalScope(BodyScope);
-
// Eat the '}'.
Lex.Lex();
@@ -3365,6 +3403,8 @@ bool TGParser::ApplyLetStack(RecordsEntry &Entry) {
/// BaseClassListNE ::= SubClassRef (',' SubClassRef)*
///
bool TGParser::ParseObjectBody(Record *CurRec) {
+ // An object body introduces a new scope for local variables.
+ TGVarScope *ObjectScope = PushScope(CurRec);
// If there is a baseclass list, read it.
if (consume(tgtok::colon)) {
@@ -3387,7 +3427,9 @@ bool TGParser::ParseObjectBody(Record *CurRec) {
if (ApplyLetStack(CurRec))
return true;
- return ParseBody(CurRec);
+ bool Result = ParseBody(CurRec);
+ PopScope(ObjectScope);
+ return Result;
}
/// ParseDef - Parse and return a top level or multiclass record definition.
@@ -3482,14 +3524,21 @@ bool TGParser::ParseDefvar(Record *CurRec) {
if (Lex.getCode() != tgtok::Id)
return TokError("expected identifier");
StringInit *DeclName = StringInit::get(Records, Lex.getCurStrVal());
- if (CurLocalScope) {
- if (CurLocalScope->varAlreadyDefined(DeclName->getValue()))
- return TokError("local variable of this name already exists");
- } else {
- if (Records.getGlobal(DeclName->getValue()))
- return TokError("def or global variable of this name already exists");
+ if (CurScope->varAlreadyDefined(DeclName->getValue()))
+ return TokError("local variable of this name already exists");
+
+ // The name should not be conflicted with existed field names.
+ if (CurRec) {
+ auto *V = CurRec->getValue(DeclName->getValue());
+ if (V && !V->isTemplateArg())
+ return TokError("field of this name already exists");
}
+ // If this defvar is in the top level, the name should not be conflicted
+ // with existed global names.
+ if (CurScope->isOutermost() && Records.getGlobal(DeclName->getValue()))
+ return TokError("def or global variable of this name already exists");
+
Lex.Lex();
if (!consume(tgtok::equal))
return TokError("expected '='");
@@ -3501,8 +3550,8 @@ bool TGParser::ParseDefvar(Record *CurRec) {
if (!consume(tgtok::semi))
return TokError("expected ';'");
- if (CurLocalScope)
- CurLocalScope->addVar(DeclName->getValue(), Value);
+ if (!CurScope->isOutermost())
+ CurScope->addVar(DeclName->getValue(), Value);
else
Records.addExtraGlobal(DeclName->getValue(), Value);
@@ -3531,10 +3580,10 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) {
return TokError("Unknown tok");
// Create a loop object and remember it.
- Loops.push_back(std::make_unique<ForeachLoop>(Loc, IterName, ListValue));
-
+ auto TheLoop = std::make_unique<ForeachLoop>(Loc, IterName, ListValue);
// A foreach loop introduces a new scope for local variables.
- TGLocalVarScope *ForeachScope = PushLocalScope();
+ TGVarScope *ForeachScope = PushScope(TheLoop.get());
+ Loops.push_back(std::move(TheLoop));
if (Lex.getCode() != tgtok::l_brace) {
// FOREACH Declaration IN Object
@@ -3555,7 +3604,7 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) {
}
}
- PopLocalScope(ForeachScope);
+ PopScope(ForeachScope);
// Resolve the loop or store it for later resolution.
std::unique_ptr<ForeachLoop> Loop = std::move(Loops.back());
@@ -3644,7 +3693,8 @@ bool TGParser::ParseIf(MultiClass *CurMultiClass) {
/// IfBody ::= '{' ObjectList '}'
///
bool TGParser::ParseIfBody(MultiClass *CurMultiClass, StringRef Kind) {
- TGLocalVarScope *BodyScope = PushLocalScope();
+ // An if-statement introduces a new scope for local variables.
+ TGVarScope *BodyScope = PushScope();
if (Lex.getCode() != tgtok::l_brace) {
// A single object.
@@ -3665,7 +3715,7 @@ bool TGParser::ParseIfBody(MultiClass *CurMultiClass, StringRef Kind) {
}
}
- PopLocalScope(BodyScope);
+ PopScope(BodyScope);
return false;
}
@@ -3732,6 +3782,8 @@ bool TGParser::ParseClass() {
}
Lex.Lex(); // eat the name.
+ // A class definition introduces a new scope.
+ TGVarScope *ClassScope = PushScope(CurRec);
// If there are template args, parse them.
if (Lex.getCode() == tgtok::less)
if (ParseTemplateArgList(CurRec))
@@ -3742,6 +3794,8 @@ bool TGParser::ParseClass() {
if (!NoWarnOnUnusedTemplateArgs)
CurRec->checkUnusedTemplateArgs();
+
+ PopScope(ClassScope);
return false;
}
@@ -3807,8 +3861,6 @@ bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) {
if (!consume(tgtok::In))
return TokError("expected 'in' at end of top-level 'let'");
- TGLocalVarScope *LetScope = PushLocalScope();
-
// If this is a scalar let, just handle it now
if (Lex.getCode() != tgtok::l_brace) {
// LET LetList IN Object
@@ -3819,6 +3871,9 @@ bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) {
// Otherwise, this is a group let.
Lex.Lex(); // eat the '{'.
+ // A group let introduces a new scope for local variables.
+ TGVarScope *LetScope = PushScope();
+
// Parse the object list.
if (ParseObjectList(CurMultiClass))
return true;
@@ -3827,9 +3882,9 @@ bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) {
TokError("expected '}' at end of top level let command");
return Error(BraceLoc, "to match this '{'");
}
- }
- PopLocalScope(LetScope);
+ PopScope(LetScope);
+ }
// Outside this let scope, this let block is not active.
LetStack.pop_back();
@@ -3867,6 +3922,9 @@ bool TGParser::ParseMultiClass() {
CurMultiClass = Result.first->second.get();
Lex.Lex(); // Eat the identifier.
+ // A multiclass body introduces a new scope for local variables.
+ TGVarScope *MulticlassScope = PushScope(CurMultiClass);
+
// If there are template args, parse them.
if (Lex.getCode() == tgtok::less)
if (ParseTemplateArgList(nullptr))
@@ -3904,9 +3962,6 @@ bool TGParser::ParseMultiClass() {
if (Lex.Lex() == tgtok::r_brace) // eat the '{'.
return TokError("multiclass must contain at least one def");
- // A multiclass body introduces a new scope for local variables.
- TGLocalVarScope *MulticlassScope = PushLocalScope();
-
while (Lex.getCode() != tgtok::r_brace) {
switch (Lex.getCode()) {
default:
@@ -3933,13 +3988,12 @@ bool TGParser::ParseMultiClass() {
PrintError(SemiLoc, "A multiclass body should not end with a semicolon");
PrintNote("Semicolon ignored; remove to eliminate this error");
}
-
- PopLocalScope(MulticlassScope);
}
if (!NoWarnOnUnusedTemplateArgs)
CurMultiClass->Rec.checkUnusedTemplateArgs();
+ PopScope(MulticlassScope);
CurMultiClass = nullptr;
return false;
}
@@ -4118,7 +4172,10 @@ bool TGParser::ParseObjectList(MultiClass *MC) {
bool TGParser::ParseFile() {
Lex.Lex(); // Prime the lexer.
- if (ParseObjectList()) return true;
+ TGVarScope *GlobalScope = PushScope();
+ if (ParseObjectList())
+ return true;
+ PopScope(GlobalScope);
// If we have unread input at the end of the file, report it.
if (Lex.getCode() == tgtok::Eof)
diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h
index 4569b22151fdc..91c68fb5a9446 100644
--- a/llvm/lib/TableGen/TGParser.h
+++ b/llvm/lib/TableGen/TGParser.h
@@ -77,55 +77,66 @@ namespace llvm {
SmallVector<Init *, 16> Elements;
};
-class TGLocalVarScope {
- // A scope to hold local variable definitions from defvar.
- std::map<std::string, Init *, std::less<>> vars;
- std::unique_ptr<TGLocalVarScope> parent;
+ struct MultiClass {
+ Record Rec; // Placeholder for template args and Name.
+ std::vector<RecordsEntry> Entries;
-public:
- TGLocalVarScope() = default;
- TGLocalVarScope(std::unique_ptr<TGLocalVarScope> parent)
- : parent(std::move(parent)) {}
-
- std::unique_ptr<TGLocalVarScope> extractParent() {
- // This is expected to be called just before we are destructed, so
- // it doesn't much matter what state we leave 'parent' in.
- return std::move(parent);
- }
+ void dump() const;
- Init *getVar(StringRef Name) const {
- auto It = vars.find(Name);
- if (It != vars.end())
- return It->second;
- if (parent)
- return parent->getVar(Name);
- return nullptr;
- }
+ MultiClass(StringRef Name, SMLoc Loc, RecordKeeper &Records)
+ : Rec(Name, Loc, Records) {}
+ };
- bool varAlreadyDefined(StringRef Name) const {
- // When we check whether a variable is already defined, for the purpose of
- // reporting an error on redefinition, we don't look up to the parent
- // scope, because it's all right to shadow an outer definition with an
- // inner one.
- return vars.find(Name) != vars.end();
- }
+ class TGVarScope {
+ public:
+ enum ScopeKind { SK_Local, SK_Record, SK_ForeachLoop, SK_MultiClass };
+
+ private:
+ ScopeKind Kind;
+ std::unique_ptr<TGVarScope> Parent;
+ // A scope to hold variable definitions from defvar.
+ std::map<std::string, Init *, std::less<>> Vars;
+ Record *CurRec = nullptr;
+ ForeachLoop *CurLoop = nullptr;
+ MultiClass *CurMultiClass = nullptr;
+
+ public:
+ TGVarScope(std::unique_ptr<TGVarScope> Parent)
+ : Kind(SK_Local), Parent(std::move(Parent)) {}
+ TGVarScope(std::unique_ptr<TGVarScope> Parent, Record *Rec)
+ : Kind(SK_Record), Parent(std::move(Parent)), CurRec(Rec) {}
+ TGVarScope(std::unique_ptr<TGVarScope> Parent, ForeachLoop *Loop)
+ : Kind(SK_ForeachLoop), Parent(std::move(Parent)), CurLoop(Loop) {}
+ TGVarScope(std::unique_ptr<TGVarScope> Parent, MultiClass *Multiclass)
+ : Kind(SK_MultiClass), Parent(std::move(Parent)),
+ CurMultiClass(Multiclass) {}
+
+ std::unique_ptr<TGVarScope> extractParent() {
+ // This is expected to be called just before we are destructed, so
+ // it doesn't much matter what state we leave 'parent' in.
+ return std::move(Parent);
+ }
- void addVar(StringRef Name, Init *I) {
- bool Ins = vars.insert(std::make_pair(std::string(Name), I)).second;
- (void)Ins;
- assert(Ins && "Local variable already exists");
- }
-};
+ Init *getVar(RecordKeeper &Records, MultiClass *ParsingMultiClass,
+ StringInit *Name, SMRange NameLoc,
+ bool TrackReferenceLocs) const;
-struct MultiClass {
- Record Rec; // Placeholder for template args and Name.
- std::vector<RecordsEntry> Entries;
+ bool varAlreadyDefined(StringRef Name) const {
+ // When we check whether a variable is already defined, for the purpose of
+ // reporting an error on redefinition, we don't look up to the parent
+ // scope, because it's all right to shadow an outer definition with an
+ // inner one.
+ return Vars.find(Name) != Vars.end();
+ }
- void dump() const;
+ void addVar(StringRef Name, Init *I) {
+ bool Ins = Vars.insert(std::make_pair(std::string(Name), I)).second;
+ (void)Ins;
+ assert(Ins && "Local variable already exists");
+ }
- MultiClass(StringRef Name, SMLoc Loc, RecordKeeper &Records) :
- Rec(Name, Loc, Records) {}
-};
+ bool isOutermost() const { return Parent == nullptr; }
+ };
class TGParser {
TGLexer Lex;
@@ -142,9 +153,8 @@ class TGParser {
/// current value.
MultiClass *CurMultiClass;
- /// CurLocalScope - Innermost of the current nested scopes for 'defvar' local
- /// variables.
- std::unique_ptr<TGLocalVarScope> CurLocalScope;
+ /// CurScope - Innermost of the current nested scopes for 'defvar' variables.
+ std::unique_ptr<TGVarScope> CurScope;
// Record tracker
RecordKeeper &Records;
@@ -186,17 +196,29 @@ class TGParser {
return Lex.getDependencies();
}
- TGLocalVarScope *PushLocalScope() {
- CurLocalScope = std::make_unique<TGLocalVarScope>(std::move(CurLocalScope));
+ TGVarScope *PushScope() {
+ CurScope = std::make_unique<TGVarScope>(std::move(CurScope));
// Returns a pointer to the new scope, so that the caller can pass it back
- // to PopLocalScope which will check by assertion that the pushes and pops
+ // to PopScope which will check by assertion that the pushes and pops
// match up properly.
- return CurLocalScope.get();
+ return CurScope.get();
+ }
+ TGVarScope *PushScope(Record *Rec) {
+ CurScope = std::make_unique<TGVarScope>(std::move(CurScope), Rec);
+ return CurScope.get();
+ }
+ TGVarScope *PushScope(ForeachLoop *Loop) {
+ CurScope = std::make_unique<TGVarScope>(std::move(CurScope), Loop);
+ return CurScope.get();
+ }
+ TGVarScope *PushScope(MultiClass *Multiclass) {
+ CurScope = std::make_unique<TGVarScope>(std::move(CurScope), Multiclass);
+ return CurScope.get();
}
- void PopLocalScope(TGLocalVarScope *ExpectedStackTop) {
- assert(ExpectedStackTop == CurLocalScope.get() &&
+ void PopScope(TGVarScope *ExpectedStackTop) {
+ assert(ExpectedStackTop == CurScope.get() &&
"Mismatched pushes and pops of local variable scopes");
- CurLocalScope = CurLocalScope->extractParent();
+ CurScope = CurScope->extractParent();
}
private: // Semantic analysis methods.
diff --git a/llvm/test/TableGen/defvar.td b/llvm/test/TableGen/defvar.td
index 2bf9fabf9eca5..d6f2d084dc58f 100644
--- a/llvm/test/TableGen/defvar.td
+++ b/llvm/test/TableGen/defvar.td
@@ -2,6 +2,8 @@
// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
// RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s
// RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s
+// RUN: not llvm-tblgen -DERROR4 %s 2>&1 | FileCheck --check-prefix=ERROR4 %s
+// RUN: not llvm-tblgen -DERROR5 %s 2>&1 | FileCheck --check-prefix=ERROR5 %s
#ifdef ERROR1
// Refer to a variable we haven't defined *yet*, expecting an error.
@@ -18,18 +20,6 @@ defvar myvar = "foo";
defvar myvar = "another value";
#endif
-// These variables should be overrided by template arguments.
-defvar a = 2333;
-defvar b = 2333;
-class VarScopeTest<int a, int b> {
- defvar c = !add(a, b);
- int value = !add(c, c);
-}
-
-// CHECK: def aaa_scope_test {
-// CHECK-NEXT: int value = 10;
-def aaa_scope_test: VarScopeTest<2, 3>;
-
multiclass Test<int x> {
// Refer to a global variable, while inside a local scope like a multiclass.
def _with_global_string { string s = myvar; }
@@ -146,6 +136,62 @@ foreach first = [ 1, 2 ] in {
def shadowOuterBelowIf # first { int var = shadowedVariable; }
}
+class RedefinitionTest<int a, int b> {
+ #ifdef ERROR4
+ defvar value = !add(a, b);
+ #endif
+ // ERROR4: [[@LINE+1]]:7: error: local variable of this name already exists
+ int value = !add(a, b);
+ #ifdef ERROR5
+ // ERROR5: [[@LINE+1]]:10: error: field of this name already exists
+ defvar value = !add(a, b);
+ #endif
+}
+
+// These variables should be shadowed by class/multiclass template arguments.
+defvar a = 2333;
+defvar b = 2333;
+defvar c = 2333;
+class ShadowGlobalsTest<int a, int b, int c> {
+ // Template arguments have higher priorities than global variables.
+ int value = !add(a, b, c);
+}
+
+class ShadowClassArgumentTest<int a, int b, int c> {
+ // Local variable 'c' has higher priority than class template argument 'c'.
+ defvar c = !add(c, c);
+ int value = !add(a, b, c);
+}
+
+multiclass ShadowMulticlassArgumentTest<int a, int b, int c> {
+ // Local variable 'c' has higher priority than multiclass template argument 'c'.
+ defvar c = !add(c, c);
+ def "" {
+ int value = !add(a, b, c);
+ }
+}
+
+// CHECK: def shadowTestOfClassArgument {
+// CHECK-NEXT: int value = 11;
+// CHECK: def shadowTestOfGlobals {
+// CHECK-NEXT: int value = 8;
+// CHECK: def shadowTestOfLoopIterator0 {
+// CHECK-NEXT: int value = 10;
+// CHECK: def shadowTestOfLoopIterator1 {
+// CHECK-NEXT: int value = 11;
+// CHECK: def shadowTestOfMulticlassArgument {
+// CHECK-NEXT: int value = 11;
+def shadowTestOfClassArgument: ShadowClassArgumentTest<2, 3, 3>;
+def shadowTestOfGlobals: ShadowGlobalsTest<2, 3, 3>;
+foreach i = 0...1 in {
+ // Local variable 'i' has higher priority than loop iterator 'i'.
+ def shadowTestOfLoopIterator # i {
+ defvar i = !add(10, i);
+ int value = i;
+ }
+}
+defm shadowTestOfMulticlassArgument: ShadowMulticlassArgumentTest<2, 3, 3>;
+
// Test that a top-level let statement also makes a variable scope (on the
// general principle of consistency, because it defines a braced sub-block).
More information about the llvm-commits
mailing list