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 @@ -317,7 +317,8 @@ IK_VarBitInit, IK_VarDefInit, IK_LastTypedInit, - IK_UnsetInit + IK_UnsetInit, + IK_PositionalArgumentInit }; private: @@ -480,6 +481,64 @@ std::string getAsString() const override { return "?"; } }; +// Represent an argument. +class ArgumentInit : public Init { + Init *Value; + +protected: + explicit ArgumentInit(InitKind K, Init *Value) : Init(K), Value(Value) {} + +public: + ArgumentInit(const ArgumentInit &) = delete; + ArgumentInit &operator=(const ArgumentInit &) = delete; + + static bool classof(const Init *I) { + return I->getKind() == IK_PositionalArgumentInit; + } + + RecordKeeper &getRecordKeeper() const { return Value->getRecordKeeper(); } + + Init *getValue() const { return Value; } + virtual ArgumentInit *changeValue(Init *Value) = 0; + + bool isComplete() const override { return false; } + bool isConcrete() const override { return false; } + Init *getBit(unsigned Bit) const override { return Value->getBit(Bit); } + Init *getCastTo(RecTy *Ty) const override { return Value->getCastTo(Ty); } + Init *convertInitializerTo(RecTy *Ty) const override { + return Value->convertInitializerTo(Ty); + } +}; + +// Represent a positional argument. +class PositionalArgumentInit : public ArgumentInit, public FoldingSetNode { + unsigned Index; + + PositionalArgumentInit(unsigned Index, Init *Value) + : ArgumentInit(IK_PositionalArgumentInit, Value), Index(Index) {} + +public: + PositionalArgumentInit(const PositionalArgumentInit &) = delete; + PositionalArgumentInit &operator=(const PositionalArgumentInit &) = delete; + + static bool classof(const Init *I) { + return I->getKind() == IK_PositionalArgumentInit; + } + + static PositionalArgumentInit *get(unsigned Index, Init *Value); + + ArgumentInit *changeValue(Init *Value) override { return get(Index, Value); } + + unsigned getIndex() const { return Index; } + + void Profile(FoldingSetNodeID &ID) const; + + Init *resolveReferences(Resolver &R) const override; + std::string getAsString() const override { + return utostr(Index) + ": " + getValue()->getAsString(); + } +}; + /// 'true'/'false' - Represent a concrete initializer for a bit. class BitInit final : public TypedInit { friend detail::RecordKeeperImpl; @@ -1278,8 +1337,9 @@ /// classname - Represent an uninstantiated anonymous class /// instantiation. -class VarDefInit final : public TypedInit, public FoldingSetNode, - public TrailingObjects { +class VarDefInit final : public TypedInit, + public FoldingSetNode, + public TrailingObjects { Record *Class; DefInit *Def = nullptr; // after instantiation unsigned NumArgs; @@ -1295,10 +1355,8 @@ // 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); + static bool classof(const Init *I) { return I->getKind() == IK_VarDefInit; } + static VarDefInit *get(Record *Class, ArrayRef Args); void Profile(FoldingSetNodeID &ID) const; @@ -1307,20 +1365,24 @@ std::string getAsString() const override; - Init *getArg(unsigned i) const { + ArgumentInit *getArg(unsigned i) const { assert(i < NumArgs && "Argument index out of range!"); - return getTrailingObjects()[i]; + return getTrailingObjects()[i]; } - using const_iterator = Init *const *; + using const_iterator = ArgumentInit *const *; - const_iterator args_begin() const { return getTrailingObjects(); } - const_iterator args_end () const { return args_begin() + NumArgs; } + 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; } + size_t args_size() const { return NumArgs; } + bool args_empty() const { return NumArgs == 0; } - ArrayRef args() const { return ArrayRef(args_begin(), NumArgs); } + ArrayRef args() const { + return ArrayRef(args_begin(), NumArgs); + } Init *getBit(unsigned Bit) const override { llvm_unreachable("Illegal bit reference off anonymous def"); 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 @@ -70,6 +70,7 @@ BitInit TrueBitInit; BitInit FalseBitInit; + FoldingSet ThePositionalArgumentInitPool; FoldingSet TheBitsInitPool; std::map TheIntInitPool; StringMap StringInitStringPool; @@ -349,6 +350,8 @@ RecordKeeper &Init::getRecordKeeper() const { if (auto *TyInit = dyn_cast(this)) return TyInit->getType()->getRecordKeeper(); + if (auto *ArgInit = dyn_cast(this)) + return ArgInit->getRecordKeeper(); return cast(this)->getRecordKeeper(); } @@ -364,6 +367,43 @@ return const_cast(this); } +static void ProfilePositionalArgumentInit(FoldingSetNodeID &ID, unsigned Index, + Init *Value) { + ID.AddInteger(Index); + ID.AddPointer(Value); +} + +void PositionalArgumentInit::Profile(FoldingSetNodeID &ID) const { + ProfilePositionalArgumentInit(ID, Index, getValue()); +} + +PositionalArgumentInit *PositionalArgumentInit::get(unsigned Index, + Init *Value) { + FoldingSetNodeID ID; + ProfilePositionalArgumentInit(ID, Index, Value); + + RecordKeeper &RK = Value->getRecordKeeper(); + detail::RecordKeeperImpl &RKImpl = RK.getImpl(); + void *IP = nullptr; + if (PositionalArgumentInit *I = + RKImpl.ThePositionalArgumentInitPool.FindNodeOrInsertPos(ID, IP)) + return I; + + PositionalArgumentInit *I = + new (RKImpl.Allocator) PositionalArgumentInit(Index, Value); + RKImpl.ThePositionalArgumentInitPool.InsertNode(I, IP); + return I; +} + +Init *PositionalArgumentInit::resolveReferences(Resolver &R) const { + Init *OldValue = getValue(); + Init *NewValue = OldValue->resolveReferences(R); + if (NewValue != OldValue) + return PositionalArgumentInit::get(Index, NewValue); + + return const_cast(this); +} + BitInit *BitInit::get(RecordKeeper &RK, bool V) { return V ? &RK.getImpl().TrueBitInit : &RK.getImpl().FalseBitInit; } @@ -2131,9 +2171,8 @@ std::string DefInit::getAsString() const { return std::string(Def->getName()); } -static void ProfileVarDefInit(FoldingSetNodeID &ID, - Record *Class, - ArrayRef Args) { +static void ProfileVarDefInit(FoldingSetNodeID &ID, Record *Class, + ArrayRef Args) { ID.AddInteger(Args.size()); ID.AddPointer(Class); @@ -2145,7 +2184,7 @@ : TypedInit(IK_VarDefInit, RecordRecTy::get(Class)), Class(Class), NumArgs(N) {} -VarDefInit *VarDefInit::get(Record *Class, ArrayRef Args) { +VarDefInit *VarDefInit::get(Record *Class, ArrayRef Args) { FoldingSetNodeID ID; ProfileVarDefInit(ID, Class, Args); @@ -2154,11 +2193,11 @@ if (VarDefInit *I = RK.TheVarDefInitPool.FindNodeOrInsertPos(ID, IP)) return I; - void *Mem = RK.Allocator.Allocate(totalSizeToAlloc(Args.size()), - alignof(VarDefInit)); + void *Mem = RK.Allocator.Allocate( + totalSizeToAlloc(Args.size()), alignof(VarDefInit)); VarDefInit *I = new (Mem) VarDefInit(Class, Args.size()); std::uninitialized_copy(Args.begin(), Args.end(), - I->getTrailingObjects()); + I->getTrailingObjects()); RK.TheVarDefInitPool.InsertNode(I, IP); return I; } @@ -2171,8 +2210,8 @@ if (!Def) { RecordKeeper &Records = Class->getRecords(); auto NewRecOwner = std::make_unique(Records.getNewAnonymousName(), - Class->getLoc(), Records, - /*IsAnonymous=*/true); + Class->getLoc(), Records, + /*IsAnonymous=*/true); Record *NewRec = NewRecOwner.get(); // Copy values from class to instance @@ -2186,13 +2225,16 @@ 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()); + for (unsigned I = 0, E = TArgs.size(); I != E; ++I) { + R.set(TArgs[I], NewRec->getValue(TArgs[I])->getValue()); + NewRec->removeValue(TArgs[I]); + } - NewRec->removeValue(TArgs[i]); + for (auto *Arg : args()) { + if (auto *PosArg = dyn_cast(Arg)) + R.set(TArgs[PosArg->getIndex()], PosArg->getValue()); + else + llvm_unreachable("Unsupported subtype of ArgumentInit!"); } NewRec->resolveReferences(R); @@ -2222,12 +2264,13 @@ Init *VarDefInit::resolveReferences(Resolver &R) const { TrackUnresolvedResolver UR(&R); bool Changed = false; - SmallVector NewArgs; + SmallVector NewArgs; NewArgs.reserve(args_size()); - for (Init *Arg : args()) { + for (ArgumentInit *Arg : args()) { Init *NewArg = Arg->resolveReferences(UR); - NewArgs.push_back(NewArg); + assert(isa(NewArg) && "Should be an ArgumentInit"); + NewArgs.push_back(cast(NewArg)); Changed |= NewArg != Arg; } diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -244,13 +244,13 @@ using ArgValueHandler = std::function; bool resolveArguments( - Record *Rec, ArrayRef ArgValues, SMLoc Loc, + Record *Rec, ArrayRef ArgValues, SMLoc Loc, ArgValueHandler ArgValueHandler = [](Init *, Init *) {}); bool resolveArgumentsOfClass(MapResolver &R, Record *Rec, - ArrayRef ArgValues, SMLoc Loc); + ArrayRef ArgValues, SMLoc Loc); bool resolveArgumentsOfMultiClass(SubstStack &Substs, MultiClass *MC, - ArrayRef ArgValues, Init *DefmName, - SMLoc Loc); + ArrayRef ArgValues, + Init *DefmName, SMLoc Loc); private: // Parser methods. bool consume(tgtok::TokKind K); @@ -288,7 +288,7 @@ IDParseMode Mode = ParseValueMode); void ParseValueList(SmallVectorImpl &Result, Record *CurRec, RecTy *ItemType = nullptr); - bool ParseTemplateArgValueList(SmallVectorImpl &Result, + bool ParseTemplateArgValueList(SmallVectorImpl &Result, Record *CurRec, Record *ArgsRec); void ParseDagArgList( SmallVectorImpl> &Result, @@ -312,7 +312,7 @@ MultiClass *ParseMultiClassID(); bool ApplyLetStack(Record *CurRec); bool ApplyLetStack(RecordsEntry &Entry); - bool CheckTemplateArgValues(SmallVectorImpl &Values, + bool CheckTemplateArgValues(SmallVectorImpl &Values, SMLoc Loc, Record *ArgsRec); }; 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 @@ -20,6 +20,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Record.h" #include #include #include @@ -36,7 +37,7 @@ struct SubClassReference { SMRange RefRange; Record *Rec; - SmallVector TemplateArgs; + SmallVector TemplateArgs; SubClassReference() : Rec(nullptr) {} @@ -46,7 +47,7 @@ struct SubMultiClassReference { SMRange RefRange; MultiClass *MC; - SmallVector TemplateArgs; + SmallVector TemplateArgs; SubMultiClassReference() : MC(nullptr) {} @@ -569,26 +570,41 @@ return false; } -bool TGParser::resolveArguments(Record *Rec, ArrayRef ArgValues, +bool TGParser::resolveArguments(Record *Rec, ArrayRef ArgValues, SMLoc Loc, ArgValueHandler ArgValueHandler) { ArrayRef ArgNames = Rec->getTemplateArgs(); assert(ArgValues.size() <= ArgNames.size() && "Too many template arguments allowed"); - // Loop over the template argument names. If a value was specified, - // reset the map value. If not and there was no default, complain. - for (unsigned I = 0, E = ArgNames.size(); I != E; ++I) { - if (I < ArgValues.size()) - ArgValueHandler(ArgNames[I], ArgValues[I]); - else { - Init *Default = Rec->getValue(ArgNames[I])->getValue(); - if (!Default->isComplete()) - return Error(Loc, "Value not specified for template argument '" + - ArgNames[I]->getAsUnquotedString() + "' (#" + - Twine(I) + ") of parent class '" + - Rec->getNameInitAsString() + "'"); - ArgValueHandler(ArgNames[I], Default); + // Loop over the template arguments and handle the (name, value) pair. + SmallVector UnsolvedArgNames(ArgNames); + for (auto *Arg : ArgValues) { + Init *ArgName = nullptr; + Init *ArgValue = Arg->getValue(); + if (auto *PosArg = dyn_cast(Arg)) + ArgName = ArgNames[PosArg->getIndex()]; + else + llvm_unreachable("Unsupported subtype of ArgumentInit!"); + + // We can only specify the template argument once. + if (!is_contained(UnsolvedArgNames, ArgName)) + return Error(Loc, "We can only specify the template argument '" + + ArgName->getAsUnquotedString() + "' once"); + + ArgValueHandler(ArgName, ArgValue); + llvm::erase_value(UnsolvedArgNames, ArgName); + } + + // For unsolved arguments, if there is no default value, complain. + for (auto *UnsolvedArgName : UnsolvedArgNames) { + Init *Default = Rec->getValue(UnsolvedArgName)->getValue(); + if (!Default->isComplete()) { + return Error(Loc, "value not specified for template argument (" + + UnsolvedArgName->getAsUnquotedString() + + ") of multiclass '" + Rec->getNameInitAsString() + + "'"); } + ArgValueHandler(UnsolvedArgName, Default); } return false; @@ -597,7 +613,8 @@ /// Resolve the arguments of class and set them to MapResolver. /// Returns true if failed. bool TGParser::resolveArgumentsOfClass(MapResolver &R, Record *Rec, - ArrayRef ArgValues, SMLoc Loc) { + ArrayRef ArgValues, + SMLoc Loc) { return resolveArguments(Rec, ArgValues, Loc, [&](Init *Name, Init *Value) { R.set(Name, Value); }); } @@ -605,7 +622,7 @@ /// Resolve the arguments of multiclass and store them into SubstStack. /// Returns true if failed. bool TGParser::resolveArgumentsOfMultiClass(SubstStack &Substs, MultiClass *MC, - ArrayRef ArgValues, + ArrayRef ArgValues, Init *DefmName, SMLoc Loc) { // Add an implicit argument NAME. Substs.emplace_back(QualifiedNameOfImplicitName(MC), DefmName); @@ -2596,7 +2613,7 @@ return nullptr; } - SmallVector Args; + SmallVector Args; Lex.Lex(); // consume the < if (ParseTemplateArgValueList(Args, CurRec, Class)) return nullptr; // Error parsing value list. @@ -3117,12 +3134,12 @@ // ParseTemplateArgValueList - Parse a template argument list with the syntax // shown, filling in the Result vector. The open angle has been consumed. -// An empty argument list is allowed. Return false if okay, true if an +// An empty argument list is allowed. Return false if okay, true if an // error was detected. // // TemplateArgList ::= '<' [Value {',' Value}*] '>' -bool TGParser::ParseTemplateArgValueList(SmallVectorImpl &Result, - Record *CurRec, Record *ArgsRec) { +bool TGParser::ParseTemplateArgValueList( + SmallVectorImpl &Result, Record *CurRec, Record *ArgsRec) { assert(Result.empty() && "Result vector is not empty"); ArrayRef TArgs = ArgsRec->getTemplateArgs(); @@ -3144,7 +3161,7 @@ Init *Value = ParseValue(CurRec, ItemType); if (!Value) return true; - Result.push_back(Value); + Result.push_back(PositionalArgumentInit::get(ArgIndex, Value)); if (consume(tgtok::greater)) // end of argument list? return false; @@ -4247,30 +4264,34 @@ // inheritance, multiclass invocation, or anonymous class invocation. // If necessary, replace an argument with a cast to the required type. // The argument count has already been checked. -bool TGParser::CheckTemplateArgValues(SmallVectorImpl &Values, - SMLoc Loc, Record *ArgsRec) { - +bool TGParser::CheckTemplateArgValues( + SmallVectorImpl &Values, SMLoc Loc, Record *ArgsRec) { ArrayRef TArgs = ArgsRec->getTemplateArgs(); for (unsigned I = 0, E = Values.size(); I < E; ++I) { - RecordVal *Arg = ArgsRec->getValue(TArgs[I]); + Init *ArgName; + ArgumentInit *Value = Values[I]; + if (auto *PosArg = dyn_cast(Value)) + ArgName = TArgs[PosArg->getIndex()]; + else + llvm_unreachable("Unsupported subtype of ArgumentInit!"); + + RecordVal *Arg = ArgsRec->getValue(ArgName); RecTy *ArgType = Arg->getType(); - auto *Value = Values[I]; - if (TypedInit *ArgValue = dyn_cast(Value)) { + if (TypedInit *ArgValue = dyn_cast(Value->getValue())) { auto *CastValue = ArgValue->getCastTo(ArgType); if (CastValue) { assert((!isa(CastValue) || cast(CastValue)->getType()->typeIsA(ArgType)) && "result of template arg value cast has wrong type"); - Values[I] = CastValue; + Values[I] = Value->changeValue(CastValue); } else { - PrintFatalError(Loc, - "Value specified for template argument '" + - Arg->getNameInitAsString() + "' (#" + Twine(I) + - ") is of type " + ArgValue->getType()->getAsString() + - "; expected type " + ArgType->getAsString() + ": " + - ArgValue->getAsString()); + PrintFatalError(Loc, "Value specified for template argument '" + + Arg->getNameInitAsString() + "' is of type " + + ArgValue->getType()->getAsString() + + "; expected type " + ArgType->getAsString() + + ": " + ArgValue->getAsString()); } } } diff --git a/llvm/test/TableGen/template-args.td b/llvm/test/TableGen/template-args.td --- a/llvm/test/TableGen/template-args.td +++ b/llvm/test/TableGen/template-args.td @@ -25,7 +25,7 @@ } #ifdef ERROR1 -// ERROR1: Value specified for template argument 'Class1:nm' (#0) is of type int +// ERROR1: Value specified for template argument 'Class1:nm' is of type int def Rec2 : Class1<42> { } @@ -52,7 +52,7 @@ } #ifdef ERROR2 -// ERROR2: Value specified for template argument 'Class2:cd' (#0) is of type string +// ERROR2: Value specified for template argument 'Class2:cd' is of type string def Rec5 : Class2<"oops"> { list CodeList = [Code]; @@ -69,7 +69,7 @@ } #ifdef ERROR3 -// ERROR3: Value specified for template argument 'Class1:nm' (#0) is of type int +// ERROR3: Value specified for template argument 'Class1:nm' is of type int def Rec7 { string Name = Class1<42>.Name; @@ -84,7 +84,7 @@ } #ifdef ERROR4 -// ERROR4: Value specified for template argument 'Class2:cd' (#0) is of type string +// ERROR4: Value specified for template argument 'Class2:cd' is of type string def Rec9 { list CodeList = [Class2<"huh?">.Code]; @@ -110,7 +110,7 @@ defm RecMC1 : MC1<"Carol">; #ifdef ERROR5 -// ERROR5: Value specified for template argument 'MC1::nm' (#0) is of type int +// ERROR5: Value specified for template argument 'MC1::nm' is of type int defm RecMC2 : MC1<42>; #endif @@ -137,7 +137,7 @@ defm RecMC3 : MC2<42>; #ifdef ERROR6 -// ERROR6: Value specified for template argument 'MC2::cd' (#0) is of type string +// ERROR6: Value specified for template argument 'MC2::cd' is of type string defm RecMC4 : MC2<"Bob">; #endif