diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -301,6 +301,7 @@ IK_CondOpInit, IK_FoldOpInit, IK_IsAOpInit, + IK_AnonymousNameInit, IK_StringInit, IK_VarInit, IK_VarListElementInit, @@ -576,6 +577,36 @@ } }; +/// "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 @@ /// /// 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 RecordResolver final : public Resolver { DenseMap Cache; SmallVector 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 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -503,6 +503,28 @@ 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(static_cast(this)); + auto *New = R.resolve(Old); + New = New ? New : Old; + if (R.isFinal()) + if (auto *Anonymous = dyn_cast(New)) + return Anonymous->getNameInit(); + return New; +} + StringInit *StringInit::get(StringRef V, StringFormat Fmt) { static StringMap StringPool(Allocator); static StringMap CodePool(Allocator); @@ -702,7 +724,9 @@ // 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(CurRec->getNameInit()); + if (Name == CurRec->getNameInit() || + (Anonymous && Name == Anonymous->getNameInit())) { if (!IsFinal) break; D = CurRec; @@ -2305,6 +2329,12 @@ } 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; @@ -2325,16 +2355,11 @@ } } } - 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); } @@ -2589,7 +2614,7 @@ /// 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 @@ -2703,6 +2728,10 @@ 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 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -439,6 +439,7 @@ /// Resolve the record fully and add it to the record keeper. bool TGParser::addDefOne(std::unique_ptr Rec) { + Init *NewName = nullptr; if (Record *Prev = Records.getDef(Rec->getNameInitAsString())) { if (!Rec->isAnonymous()) { PrintError(Rec->getLoc(), @@ -446,10 +447,10 @@ 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 --- 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 { @@ -96,3 +109,18 @@ def F0x { Fc as_c = F0; } + +// anonymous record self-reference in foreach and multiclass +class G { + G g = !cast(NAME); +} + +foreach _ = [1, 2] in + def : G; + +multiclass H { + def : G; +} + +defm : H; +defm : H;