[llvm] 267b573 - [TableGen] Fix anonymous record self-reference in foreach and multiclass

Paul C. Anagnostopoulos via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 1 08:01:25 PST 2021


Author: J-Y You
Date: 2021-02-01T10:59:07-05:00
New Revision: 267b573b55f7f43aaeaf4860e31101cd6a3dbba0

URL: https://github.com/llvm/llvm-project/commit/267b573b55f7f43aaeaf4860e31101cd6a3dbba0
DIFF: https://github.com/llvm/llvm-project/commit/267b573b55f7f43aaeaf4860e31101cd6a3dbba0.diff

LOG: [TableGen] Fix anonymous record self-reference in foreach and multiclass

If we instantiate self-referenced anonymous records in foreach and
multiclass, the NAME value will point to incorrect record. It's because
anonymous name is resolved too early.

This patch adds AnonymousNameInit to represent an anonymous record name.
When instantiating an anonymous record, it will update the referred name.

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

Added: 
    

Modified: 
    llvm/include/llvm/TableGen/Record.h
    llvm/lib/TableGen/Record.cpp
    llvm/lib/TableGen/TGParser.cpp
    llvm/test/TableGen/self-reference.td

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index b71aa0a89056..b79de83ac698 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -301,6 +301,7 @@ class Init {
     IK_CondOpInit,
     IK_FoldOpInit,
     IK_IsAOpInit,
+    IK_AnonymousNameInit,
     IK_StringInit,
     IK_VarInit,
     IK_VarListElementInit,
@@ -576,6 +577,36 @@ class IntInit : public TypedInit {
   }
 };
 
+/// "anonymous_n" - Represent an anonymous record name
+class AnonymousNameInit : public TypedInit {
+  unsigned Value;
+
+  explicit AnonymousNameInit(unsigned V)
+      : TypedInit(IK_AnonymousNameInit, StringRecTy::get()), Value(V) {}
+
+public:
+  AnonymousNameInit(const AnonymousNameInit &) = delete;
+  AnonymousNameInit &operator=(const AnonymousNameInit &) = delete;
+
+  static bool classof(const Init *I) {
+    return I->getKind() == IK_AnonymousNameInit;
+  }
+
+  static AnonymousNameInit *get(unsigned);
+
+  unsigned getValue() const { return Value; }
+
+  StringInit *getNameInit() const;
+
+  std::string getAsString() const override;
+
+  Init *resolveReferences(Resolver &R) const override;
+
+  Init *getBit(unsigned Bit) const override {
+    llvm_unreachable("Illegal bit reference off string");
+  }
+};
+
 /// "foo" - Represent an initialization by a string value.
 class StringInit : public TypedInit {
 public:
@@ -1618,7 +1649,7 @@ class Record {
   ///
   /// This is a final resolve: any error messages, e.g. due to undefined
   /// !cast references, are generated now.
-  void resolveReferences();
+  void resolveReferences(Init *NewName = nullptr);
 
   /// Apply the resolver to the name of the record as well as to the
   /// initializers of all fields of the record except SkipVal.
@@ -2002,10 +2033,13 @@ class MapResolver final : public Resolver {
 class RecordResolver final : public Resolver {
   DenseMap<Init *, Init *> Cache;
   SmallVector<Init *, 4> Stack;
+  Init *Name = nullptr;
 
 public:
   explicit RecordResolver(Record &R) : Resolver(&R) {}
 
+  void setName(Init *NewName) { Name = NewName; }
+
   Init *resolve(Init *VarName) override;
 
   bool keepUnsetBits() const override { return true; }

diff  --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index b6c6b8f031d3..18348b4c9641 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -502,6 +502,28 @@ IntInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const {
   return BitsInit::get(NewBits);
 }
 
+AnonymousNameInit *AnonymousNameInit::get(unsigned V) {
+  return new (Allocator) AnonymousNameInit(V);
+}
+
+StringInit *AnonymousNameInit::getNameInit() const {
+  return StringInit::get(getAsString());
+}
+
+std::string AnonymousNameInit::getAsString() const {
+  return "anonymous_" + utostr(Value);
+}
+
+Init *AnonymousNameInit::resolveReferences(Resolver &R) const {
+  auto *Old = const_cast<Init *>(static_cast<const Init *>(this));
+  auto *New = R.resolve(Old);
+  New = New ? New : Old;
+  if (R.isFinal())
+    if (auto *Anonymous = dyn_cast<AnonymousNameInit>(New))
+      return Anonymous->getNameInit();
+  return New;
+}
+
 StringInit *StringInit::get(StringRef V, StringFormat Fmt) {
   static StringMap<StringInit*, BumpPtrAllocator &> StringPool(Allocator);
   static StringMap<StringInit*, BumpPtrAllocator &> CodePool(Allocator);
@@ -701,7 +723,9 @@ Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const {
 
         // Self-references are allowed, but their resolution is delayed until
         // the final resolve to ensure that we get the correct type for them.
-        if (Name == CurRec->getNameInit()) {
+        auto *Anonymous = dyn_cast<AnonymousNameInit>(CurRec->getNameInit());
+        if (Name == CurRec->getNameInit() ||
+            (Anonymous && Name == Anonymous->getNameInit())) {
           if (!IsFinal)
             break;
           D = CurRec;
@@ -2304,6 +2328,12 @@ void Record::getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const {
 }
 
 void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) {
+  Init *OldName = getNameInit();
+  Init *NewName = Name->resolveReferences(R);
+  if (NewName != OldName) {
+    // Re-register with RecordKeeper.
+    setName(NewName);
+  }
   for (RecordVal &Value : Values) {
     if (SkipVal == &Value) // Skip resolve the same field as the given one
       continue;
@@ -2324,16 +2354,11 @@ void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) {
       }
     }
   }
-  Init *OldName = getNameInit();
-  Init *NewName = Name->resolveReferences(R);
-  if (NewName != OldName) {
-    // Re-register with RecordKeeper.
-    setName(NewName);
-  }
 }
 
-void Record::resolveReferences() {
+void Record::resolveReferences(Init *NewName) {
   RecordResolver R(*this);
+  R.setName(NewName);
   R.setFinal(true);
   resolveReferences(R);
 }
@@ -2588,7 +2613,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const RecordKeeper &RK) {
 /// GetNewAnonymousName - Generate a unique anonymous name that can be used as
 /// an identifier.
 Init *RecordKeeper::getNewAnonymousName() {
-  return StringInit::get("anonymous_" + utostr(AnonCounter++));
+  return AnonymousNameInit::get(AnonCounter++);
 }
 
 // These functions implement the phase timing facility. Starting a timer
@@ -2702,6 +2727,10 @@ Init *RecordResolver::resolve(Init *VarName) {
       Val = Val->resolveReferences(*this);
       Stack.pop_back();
     }
+  } else if (Name && VarName == getCurrentRecord()->getNameInit()) {
+    Stack.push_back(VarName);
+    Val = Name->resolveReferences(*this);
+    Stack.pop_back();
   }
 
   Cache[VarName] = Val;

diff  --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 1995477507c4..87faf77671c6 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -439,6 +439,7 @@ bool TGParser::resolve(const std::vector<RecordsEntry> &Source,
 
 /// Resolve the record fully and add it to the record keeper.
 bool TGParser::addDefOne(std::unique_ptr<Record> Rec) {
+  Init *NewName = nullptr;
   if (Record *Prev = Records.getDef(Rec->getNameInitAsString())) {
     if (!Rec->isAnonymous()) {
       PrintError(Rec->getLoc(),
@@ -446,10 +447,10 @@ bool TGParser::addDefOne(std::unique_ptr<Record> Rec) {
       PrintNote(Prev->getLoc(), "location of previous definition");
       return true;
     }
-    Rec->setName(Records.getNewAnonymousName());
+    NewName = Records.getNewAnonymousName();
   }
 
-  Rec->resolveReferences();
+  Rec->resolveReferences(NewName);
   checkConcrete(*Rec);
 
   CheckRecordAsserts(*Rec);

diff  --git a/llvm/test/TableGen/self-reference.td b/llvm/test/TableGen/self-reference.td
index 5789d3ba570f..0e4c67271714 100644
--- a/llvm/test/TableGen/self-reference.td
+++ b/llvm/test/TableGen/self-reference.td
@@ -32,6 +32,19 @@
 // CHECK:   Fc as_c = F0;
 // CHECK: }
 
+// CHECK: def anonymous_0 {
+// CHECK:   G g = anonymous_0;
+// CHECK: }
+// CHECK: def anonymous_1 {
+// CHECK:   G g = anonymous_1;
+// CHECK: }
+// CHECK: def anonymous_2 {
+// CHECK:   G g = anonymous_2;
+// CHECK: }
+// CHECK: def anonymous_5 {
+// CHECK:   G g = anonymous_5;
+// CHECK: }
+
 def ops;
 
 class A<dag d> {
@@ -96,3 +109,18 @@ def F0 : Fa, Fb<F0>, Fc<F0>;
 def F0x {
   Fc as_c = F0;
 }
+
+// anonymous record self-reference in foreach and multiclass
+class G {
+  G g = !cast<G>(NAME);
+}
+
+foreach _ = [1, 2] in
+  def : G;
+
+multiclass H {
+  def : G;
+}
+
+defm : H;
+defm : H;


        


More information about the llvm-commits mailing list