Index: llvm/trunk/include/llvm/TableGen/Record.h =================================================================== --- llvm/trunk/include/llvm/TableGen/Record.h +++ llvm/trunk/include/llvm/TableGen/Record.h @@ -320,6 +320,7 @@ IK_VarInit, IK_VarListElementInit, IK_VarBitInit, + IK_VarDefInit, IK_LastTypedInit, IK_UnsetInit }; @@ -1052,6 +1053,58 @@ } }; +/// classname - Represent an uninstantiated anonymous class +/// instantiation. +class VarDefInit final : public TypedInit, public FoldingSetNode, + public TrailingObjects { + Record *Class; + DefInit *Def = nullptr; // after instantiation + unsigned NumArgs; + + explicit VarDefInit(Record *Class, unsigned N) + : TypedInit(IK_VarDefInit, RecordRecTy::get(Class)), Class(Class), NumArgs(N) {} + + DefInit *instantiate(); + +public: + VarDefInit(const VarDefInit &) = delete; + VarDefInit &operator=(const VarDefInit &) = delete; + + // Do not use sized deallocation due to trailing objects. + void operator delete(void *p) { ::operator delete(p); } + + static bool classof(const Init *I) { + return I->getKind() == IK_VarDefInit; + } + static VarDefInit *get(Record *Class, ArrayRef Args); + + void Profile(FoldingSetNodeID &ID) const; + + Init *resolveReferences(Resolver &R) const override; + Init *Fold() const; + + std::string getAsString() const override; + + Init *getArg(unsigned i) const { + assert(i < NumArgs && "Argument index out of range!"); + return getTrailingObjects()[i]; + } + + using const_iterator = Init *const *; + + const_iterator args_begin() const { return getTrailingObjects(); } + const_iterator args_end () const { return args_begin() + NumArgs; } + + size_t args_size () const { return NumArgs; } + bool args_empty() const { return NumArgs == 0; } + + ArrayRef args() const { return makeArrayRef(args_begin(), NumArgs); } + + Init *getBit(unsigned Bit) const override { + llvm_unreachable("Illegal bit reference off anonymous def"); + } +}; + /// X.Y - Represent a reference to a subfield of a variable class FieldInit : public TypedInit { Init *Rec; // Record we are referring to @@ -1754,6 +1807,21 @@ } }; +/// (Optionally) delegate resolving to a sub-resolver, and keep track whether +/// there were unresolved references. +class TrackUnresolvedResolver final : public Resolver { + Resolver *R; + bool FoundUnresolved = false; + +public: + explicit TrackUnresolvedResolver(Resolver *R = nullptr) + : Resolver(R ? R->getCurrentRecord() : nullptr), R(R) {} + + bool foundUnresolved() const { return FoundUnresolved; } + + Init *resolve(Init *VarName) override; +}; + } // end namespace llvm #endif // LLVM_TABLEGEN_RECORD_H Index: llvm/trunk/lib/TableGen/Record.cpp =================================================================== --- llvm/trunk/lib/TableGen/Record.cpp +++ llvm/trunk/lib/TableGen/Record.cpp @@ -1355,6 +1355,132 @@ return Def->getName(); } +static void ProfileVarDefInit(FoldingSetNodeID &ID, + Record *Class, + ArrayRef Args) { + ID.AddInteger(Args.size()); + ID.AddPointer(Class); + + for (Init *I : Args) + ID.AddPointer(I); +} + +VarDefInit *VarDefInit::get(Record *Class, ArrayRef Args) { + static FoldingSet ThePool; + + FoldingSetNodeID ID; + ProfileVarDefInit(ID, Class, Args); + + void *IP = nullptr; + if (VarDefInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) + return I; + + void *Mem = Allocator.Allocate(totalSizeToAlloc(Args.size()), + alignof(VarDefInit)); + VarDefInit *I = new(Mem) VarDefInit(Class, Args.size()); + std::uninitialized_copy(Args.begin(), Args.end(), + I->getTrailingObjects()); + ThePool.InsertNode(I, IP); + return I; +} + +void VarDefInit::Profile(FoldingSetNodeID &ID) const { + ProfileVarDefInit(ID, Class, args()); +} + +DefInit *VarDefInit::instantiate() { + if (!Def) { + RecordKeeper &Records = Class->getRecords(); + auto NewRecOwner = make_unique(Records.getNewAnonymousName(), + Class->getLoc(), Records, + /*IsAnonymous=*/true); + Record *NewRec = NewRecOwner.get(); + + // Copy values from class to instance + for (const RecordVal &Val : Class->getValues()) { + if (Val.getName() != "NAME") + NewRec->addValue(Val); + } + + // Substitute and resolve template arguments + ArrayRef TArgs = Class->getTemplateArgs(); + MapResolver R(NewRec); + + for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { + if (i < args_size()) + R.set(TArgs[i], getArg(i)); + else + R.set(TArgs[i], NewRec->getValue(TArgs[i])->getValue()); + + NewRec->removeValue(TArgs[i]); + } + + NewRec->resolveReferences(R); + + // Add superclasses. + ArrayRef> SCs = Class->getSuperClasses(); + for (const auto &SCPair : SCs) + NewRec->addSuperClass(SCPair.first, SCPair.second); + + NewRec->addSuperClass(Class, + SMRange(Class->getLoc().back(), + Class->getLoc().back())); + + // Resolve internal references and store in record keeper + NewRec->resolveReferences(); + Records.addDef(std::move(NewRecOwner)); + + Def = DefInit::get(NewRec); + } + + return Def; +} + +Init *VarDefInit::resolveReferences(Resolver &R) const { + TrackUnresolvedResolver UR(&R); + bool Changed = false; + SmallVector NewArgs; + NewArgs.reserve(args_size()); + + for (Init *Arg : args()) { + Init *NewArg = Arg->resolveReferences(UR); + NewArgs.push_back(NewArg); + Changed |= NewArg != Arg; + } + + if (Changed) { + auto New = VarDefInit::get(Class, NewArgs); + if (!UR.foundUnresolved()) + return New->instantiate(); + return New; + } + return const_cast(this); +} + +Init *VarDefInit::Fold() const { + if (Def) + return Def; + + TrackUnresolvedResolver R; + for (Init *Arg : args()) + Arg->resolveReferences(R); + + if (!R.foundUnresolved()) + return const_cast(this)->instantiate(); + return const_cast(this); +} + +std::string VarDefInit::getAsString() const { + std::string Result = Class->getNameInitAsString() + "<"; + const char *sep = ""; + for (Init *Arg : args()) { + Result += sep; + sep = ", "; + Result += Arg->getAsString(); + } + return Result + ">"; +} + FieldInit *FieldInit::get(Init *R, StringInit *FN) { using Key = std::pair; static DenseMap ThePool; @@ -1917,3 +2043,23 @@ Cache[VarName] = Val; return Val; } + +Init *TrackUnresolvedResolver::resolve(Init *VarName) { + Init *I = nullptr; + + if (R) { + I = R->resolve(VarName); + if (I && !FoundUnresolved) { + // Do not recurse into the resolved initializer, as that would change + // the behavior of the resolver we're delegating, but do check to see + // if there are unresolved variables remaining. + TrackUnresolvedResolver Sub; + I->resolveReferences(Sub); + FoundUnresolved |= Sub.FoundUnresolved; + } + } + + if (!I) + FoundUnresolved = true; + return I; +} Index: llvm/trunk/lib/TableGen/TGParser.cpp =================================================================== --- llvm/trunk/lib/TableGen/TGParser.cpp +++ llvm/trunk/lib/TableGen/TGParser.cpp @@ -1346,61 +1346,49 @@ return nullptr; } - SubClassReference SCRef; - ParseValueList(SCRef.TemplateArgs, CurRec, Class); - if (SCRef.TemplateArgs.empty()) return nullptr; + SmallVector Args; + ParseValueList(Args, CurRec, Class); + if (Args.empty()) return nullptr; if (Lex.getCode() != tgtok::greater) { TokError("expected '>' at end of value list"); return nullptr; } Lex.Lex(); // eat the '>' - SMLoc EndLoc = Lex.getLoc(); - // Create the new record, set it as CurRec temporarily. - auto NewRecOwner = - make_unique(Records.getNewAnonymousName(), NameLoc, Records, - /*IsAnonymous=*/true); - Record *NewRec = NewRecOwner.get(); // Keep a copy since we may release. - SCRef.RefRange = SMRange(NameLoc, EndLoc); - SCRef.Rec = Class; - // Add info about the subclass to NewRec. - if (AddSubClass(NewRec, SCRef)) - return nullptr; - - if (!CurMultiClass) { - NewRec->resolveReferences(); - Records.addDef(std::move(NewRecOwner)); - } else { - // This needs to get resolved once the multiclass template arguments are - // known before any use. - NewRec->setResolveFirst(true); - // Otherwise, we're inside a multiclass, add it to the multiclass. - CurMultiClass->DefPrototypes.push_back(std::move(NewRecOwner)); - - // Copy the template arguments for the multiclass into the def. - for (Init *TArg : CurMultiClass->Rec.getTemplateArgs()) { - const RecordVal *RV = CurMultiClass->Rec.getValue(TArg); - assert(RV && "Template arg doesn't exist?"); - NewRec->addValue(*RV); - } - - // We can't return the prototype def here, instead return: - // !cast(!strconcat(NAME, AnonName)). - const RecordVal *MCNameRV = CurMultiClass->Rec.getValue("NAME"); - assert(MCNameRV && "multiclass record must have a NAME"); - - return UnOpInit::get(UnOpInit::CAST, - BinOpInit::get(BinOpInit::STRCONCAT, - VarInit::get(MCNameRV->getName(), - MCNameRV->getType()), - NewRec->getNameInit(), - StringRecTy::get()), - NewRec->getDefInit()->getType()); + // Typecheck the template arguments list + ArrayRef ExpectedArgs = Class->getTemplateArgs(); + if (ExpectedArgs.size() < Args.size()) { + Error(NameLoc, + "More template args specified than expected"); + return nullptr; + } + + for (unsigned i = 0, e = ExpectedArgs.size(); i != e; ++i) { + RecordVal *ExpectedArg = Class->getValue(ExpectedArgs[i]); + if (i < Args.size()) { + if (TypedInit *TI = dyn_cast(Args[i])) { + RecTy *ExpectedType = ExpectedArg->getType(); + if (!TI->getType()->typeIsConvertibleTo(ExpectedType)) { + Error(NameLoc, + "Value specified for template argument #" + Twine(i) + " (" + + ExpectedArg->getNameInitAsString() + ") is of type '" + + TI->getType()->getAsString() + "', expected '" + + ExpectedType->getAsString() + "': " + TI->getAsString()); + return nullptr; + } + continue; + } + } else if (ExpectedArg->getValue()->isComplete()) + continue; + + Error(NameLoc, + "Value not specified for template argument #" + Twine(i) + " (" + + ExpectedArgs[i]->getAsUnquotedString() + ")"); + return nullptr; } - // The result of the expression is a reference to the new record. - return DefInit::get(NewRec); + return VarDefInit::get(Class, Args)->Fold(); } case tgtok::l_brace: { // Value ::= '{' ValueList '}' SMLoc BraceLoc = Lex.getLoc(); Index: llvm/trunk/test/TableGen/AnonDefinitionOnDemand.td =================================================================== --- llvm/trunk/test/TableGen/AnonDefinitionOnDemand.td +++ llvm/trunk/test/TableGen/AnonDefinitionOnDemand.td @@ -1,6 +1,24 @@ -// RUN: llvm-tblgen < %s +// RUN: llvm-tblgen %s | FileCheck %s // XFAIL: vg_leak +// CHECK: --- Defs --- + +// CHECK: def X { +// CHECK: foo Y = anonymous_0; +// CHECK: } + +// CHECK: def ZD { +// CHECK: foo Z = anonymous_1; +// CHECK: } + +// CHECK: def anonymous_0 { +// CHECK: int THEVAL = 1; +// CHECK: } + +// CHECK: def anonymous_1 { +// CHECK: int THEVAL = 42; +// CHECK: } + class foo { int THEVAL = X; } def foo_imp : foo<1>; @@ -11,3 +29,9 @@ def X { foo Y = foo<1>; // This should work too, synthesizing a new foo<1>. } + +class Z { + foo Z = foo; +} + +def ZD : Z<42>;