[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