diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -86,6 +86,9 @@ Changes to TableGen ------------------- +* Named arguments are supported. Arguments can be specified in the form of + ``name=value``. + Changes to Interprocedural Optimizations ---------------------------------------- diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst --- a/llvm/docs/TableGen/ProgRef.rst +++ b/llvm/docs/TableGen/ProgRef.rst @@ -475,7 +475,7 @@ def Foo#i; .. productionlist:: - SimpleValue8: `ClassID` "<" `ValueListNE` ">" + SimpleValue8: `ClassID` "<" `ArgValueList` ">" This form creates a new anonymous record definition (as would be created by an unnamed ``def`` inheriting from the given class with the given template @@ -642,12 +642,30 @@ RecordBody: `ParentClassList` `Body` ParentClassList: [":" `ParentClassListNE`] ParentClassListNE: `ClassRef` ("," `ClassRef`)* - ClassRef: (`ClassID` | `MultiClassID`) ["<" [`ValueList`] ">"] + ClassRef: (`ClassID` | `MultiClassID`) ["<" [`ArgValueList`] ">"] + ArgValueList: `PostionalArgValueList` [","] `NamedArgValueList` + PostionalArgValueList: [`Value` {"," `Value`}*] + NamedArgValueList: [`NameValue` "=" `Value` {"," `NameValue` "=" `Value`}*] A :token:`ParentClassList` containing a :token:`MultiClassID` is valid only in the class list of a ``defm`` statement. In that case, the ID must be the name of a multiclass. +The argument values can be specified in two forms: + +* Positional argument (``value``). The value is assigned to the argument in the + corresponding position. For ``Foo``, ``a0`` will be assigned to first + argument and ``a1`` will be assigned to second argument. +* Named argument (``name=value``). The value is assigned to argument with + specified name. For ``Foo``, ``a0`` will be assigned to argument + with name ``a`` and ``a1`` will be assigned to argument with name ``b``. + +Positional arguments should be put before named arguments. Required arguments +can alse be specified as named argument. + +Note that the argument can only be specified once regardless of the way (named +or positional) to specify. + .. productionlist:: Body: ";" | "{" `BodyItem`* "}" BodyItem: (`Type` | "code") `TokIdentifier` ["=" `Value`] ";" 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,9 @@ IK_VarBitInit, IK_VarDefInit, IK_LastTypedInit, - IK_UnsetInit + IK_UnsetInit, + IK_PositionalArgumentInit, + IK_NamedArgumentInit }; private: @@ -480,6 +482,101 @@ std::string getAsString() const override { return "?"; } }; +// Represent an argument. +class ArgumentInit : public Init { + RecordKeeper &RK; + Init *Value; + +protected: + explicit ArgumentInit(RecordKeeper &RK, InitKind K, Init *Value) + : Init(K), RK(RK), Value(Value) {} + +public: + ArgumentInit(const ArgumentInit &) = delete; + ArgumentInit &operator=(const ArgumentInit &) = delete; + + static bool classof(const Init *I) { + return I->getKind() == IK_PositionalArgumentInit || + I->getKind() == IK_NamedArgumentInit; + } + + RecordKeeper &getRecordKeeper() const { return RK; } + + 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 const_cast(this); + } + Init *getCastTo(RecTy *Ty) const override { return nullptr; } + Init *convertInitializerTo(RecTy *Ty) const override { return nullptr; } +}; + +// Represent a positional argument. +class PositionalArgumentInit : public ArgumentInit, public FoldingSetNode { + unsigned Index; + + PositionalArgumentInit(RecordKeeper &RK, unsigned Index, Init *Value) + : ArgumentInit(RK, 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(RecordKeeper &RK, unsigned Index, + Init *Value); + + ArgumentInit *changeValue(Init *Value) override { + return get(getRecordKeeper(), 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(); + } +}; + +// Represent a named argument. +class NamedArgumentInit : public ArgumentInit, public FoldingSetNode { + Init *Name; + + NamedArgumentInit(RecordKeeper &RK, Init *Name, Init *Value) + : ArgumentInit(RK, IK_NamedArgumentInit, Value), Name(Name) {} + +public: + NamedArgumentInit(const NamedArgumentInit &) = delete; + NamedArgumentInit &operator=(const NamedArgumentInit &) = delete; + + static bool classof(const Init *I) { + return I->getKind() == IK_NamedArgumentInit; + } + + static NamedArgumentInit *get(RecordKeeper &RK, Init *Name, Init *Value); + + ArgumentInit *changeValue(Init *Value) override { + return get(getRecordKeeper(), Name, Value); + } + + Init *getName() const { return Name; } + + void Profile(FoldingSetNodeID &ID) const; + + Init *resolveReferences(Resolver &R) const override; + std::string getAsString() const override { + return Name->getAsString() + ": " + getValue()->getAsString(); + } +}; + /// 'true'/'false' - Represent a concrete initializer for a bit. class BitInit final : public TypedInit { friend detail::RecordKeeperImpl; @@ -1278,8 +1375,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 +1393,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 +1403,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,8 @@ BitInit TrueBitInit; BitInit FalseBitInit; + FoldingSet ThePositionalArgumentInitPool; + FoldingSet TheNamedArgumentInitPool; FoldingSet TheBitsInitPool; std::map TheIntInitPool; StringMap StringInitStringPool; @@ -349,6 +351,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 +368,78 @@ 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(RecordKeeper &RK, unsigned Index, Init *Value) { + FoldingSetNodeID ID; + ProfilePositionalArgumentInit(ID, Index, Value); + + detail::RecordKeeperImpl &RKImpl = RK.getImpl(); + void *IP = nullptr; + if (PositionalArgumentInit *I = + RKImpl.ThePositionalArgumentInitPool.FindNodeOrInsertPos(ID, IP)) + return I; + + PositionalArgumentInit *I = + new (RKImpl.Allocator) PositionalArgumentInit(RK, 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(getRecordKeeper(), Index, NewValue); + + return const_cast(this); +} + +static void ProfileNamedArgumentInit(FoldingSetNodeID &ID, Init *Name, + Init *Value) { + ID.AddPointer(Name); + ID.AddPointer(Value); +} + +void NamedArgumentInit::Profile(FoldingSetNodeID &ID) const { + ProfileNamedArgumentInit(ID, Name, getValue()); +} + +NamedArgumentInit *NamedArgumentInit::get(RecordKeeper &RK, Init *Name, + Init *Value) { + FoldingSetNodeID ID; + ProfileNamedArgumentInit(ID, Name, Value); + + detail::RecordKeeperImpl &RKImpl = RK.getImpl(); + void *IP = nullptr; + if (NamedArgumentInit *I = + RKImpl.TheNamedArgumentInitPool.FindNodeOrInsertPos(ID, IP)) + return I; + + NamedArgumentInit *I = + new (RKImpl.Allocator) NamedArgumentInit(RK, Name, Value); + RKImpl.TheNamedArgumentInitPool.InsertNode(I, IP); + return I; +} + +Init *NamedArgumentInit::resolveReferences(Resolver &R) const { + Init *OldValue = getValue(); + Init *NewValue = OldValue->resolveReferences(R); + if (NewValue != OldValue) + return NamedArgumentInit::get(getRecordKeeper(), Name, NewValue); + + return const_cast(this); +} + BitInit *BitInit::get(RecordKeeper &RK, bool V) { return V ? &RK.getImpl().TrueBitInit : &RK.getImpl().FalseBitInit; } @@ -2131,9 +2207,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 +2220,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 +2229,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; } @@ -2186,13 +2261,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 if (auto *NamedArg = dyn_cast(Arg)) + R.set(NamedArg->getName(), NamedArg->getValue()); } NewRec->resolveReferences(R); @@ -2222,12 +2300,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 a 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 @@ -241,6 +241,11 @@ bool Final, std::vector *Dest, SMLoc *Loc = nullptr); bool addDefOne(std::unique_ptr Rec); + bool resolveClassArguments(MapResolver &R, Record *Rec, + ArrayRef ArgValues, SMLoc Loc); + bool resolveMultiClassArguments(SubstStack &TemplateArgs, Record *Rec, + ArrayRef ArgValues, + SMLoc Loc); private: // Parser methods. bool consume(tgtok::TokKind K); @@ -278,8 +283,9 @@ IDParseMode Mode = ParseValueMode); void ParseValueList(SmallVectorImpl &Result, Record *CurRec, RecTy *ItemType = nullptr); - bool ParseTemplateArgValueList(SmallVectorImpl &Result, - Record *CurRec, Record *ArgsRec); + bool ParseTemplateArgValueList(SmallVectorImpl &Result, + Record *CurRec, Record *ArgsRec, + bool IsDefm = false); void ParseDagArgList( SmallVectorImpl> &Result, Record *CurRec); @@ -302,7 +308,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 @@ -36,7 +36,7 @@ struct SubClassReference { SMRange RefRange; Record *Rec; - SmallVector TemplateArgs; + SmallVector TemplateArgs; SubClassReference() : Rec(nullptr) {} @@ -46,7 +46,7 @@ struct SubMultiClassReference { SMRange RefRange; MultiClass *MC; - SmallVector TemplateArgs; + SmallVector TemplateArgs; SubMultiClassReference() : MC(nullptr) {} @@ -117,11 +117,6 @@ Init *NewName = BinOpInit::getStrConcat(CurRec.getNameInit(), StringInit::get(RK, Scoper)); NewName = BinOpInit::getStrConcat(NewName, Name); - if (CurMultiClass && Scoper != "::") { - Init *Prefix = BinOpInit::getStrConcat(CurMultiClass->Rec.getNameInit(), - StringInit::get(RK, "::")); - NewName = BinOpInit::getStrConcat(Prefix, NewName); - } if (BinOpInit *BinOp = dyn_cast(NewName)) NewName = BinOp->Fold(&CurRec); @@ -315,21 +310,9 @@ } } - ArrayRef TArgs = SC->getTemplateArgs(); - assert(SubClass.TemplateArgs.size() <= TArgs.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 = TArgs.size(); I != E; ++I) { - if (I < SubClass.TemplateArgs.size()) - R.set(TArgs[I], SubClass.TemplateArgs[I]); - else if (!R.isComplete(TArgs[I])) - return Error(SubClass.RefRange.Start, - "Value not specified for template argument '" + - TArgs[I]->getAsUnquotedString() + "' (#" + Twine(I) + - ") of parent class '" + SC->getNameInitAsString() + "'"); - } + if (resolveClassArguments(R, SC, SubClass.TemplateArgs, + SubClass.RefRange.Start)) + return true; // Copy the subclass record's assertions to the new record. CurRec->appendAssertions(SC); @@ -382,31 +365,13 @@ bool TGParser::AddSubMultiClass(MultiClass *CurMC, SubMultiClassReference &SubMultiClass) { MultiClass *SMC = SubMultiClass.MC; - - ArrayRef SMCTArgs = SMC->Rec.getTemplateArgs(); - if (SMCTArgs.size() < SubMultiClass.TemplateArgs.size()) - return Error(SubMultiClass.RefRange.Start, - "More template args specified than expected"); - - // Prepare the mapping of template argument name to value, filling in default - // values if necessary. SubstStack TemplateArgs; - for (unsigned i = 0, e = SMCTArgs.size(); i != e; ++i) { - if (i < SubMultiClass.TemplateArgs.size()) { - TemplateArgs.emplace_back(SMCTArgs[i], SubMultiClass.TemplateArgs[i]); - } else { - Init *Default = SMC->Rec.getValue(SMCTArgs[i])->getValue(); - if (!Default->isComplete()) { - return Error(SubMultiClass.RefRange.Start, - "value not specified for template argument #" + Twine(i) + - " (" + SMCTArgs[i]->getAsUnquotedString() + - ") of multiclass '" + SMC->Rec.getNameInitAsString() + - "'"); - } - TemplateArgs.emplace_back(SMCTArgs[i], Default); - } - } + if (resolveMultiClassArguments(TemplateArgs, &SMC->Rec, + SubMultiClass.TemplateArgs, + SubMultiClass.RefRange.Start)) + return true; + // Add an implicit argument NAME. TemplateArgs.emplace_back(QualifiedNameOfImplicitName(SMC), VarInit::get(QualifiedNameOfImplicitName(CurMC), StringRecTy::get(Records))); @@ -605,6 +570,95 @@ return false; } +/// Resolve the arguments of class and set them to MapResolver. +/// Returns true if failed. +bool TGParser::resolveClassArguments(MapResolver &R, Record *Rec, + ArrayRef ArgValues, + SMLoc Loc) { + ArrayRef ArgNames = Rec->getTemplateArgs(); + assert(ArgValues.size() <= ArgNames.size() && + "Too many template arguments allowed"); + + // Loop over the template arguments. If a value was specified, + // reset the map value. + 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 if (auto *NamedArg = dyn_cast(Arg)) + ArgName = NamedArg->getName(); + + // 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"); + + R.set(ArgName, ArgValue); + llvm::erase_value(UnsolvedArgNames, ArgName); + } + + // For unsolved arguments, if no value was specified and there was no default, + // complain. + for (auto *UnsolvedArgName : UnsolvedArgNames) { + if (!R.isComplete(UnsolvedArgName)) + return Error(Loc, "Value not specified for template argument '" + + UnsolvedArgName->getAsUnquotedString() + + "' of parent class '" + Rec->getNameInitAsString() + + "'"); + } + return false; +} + +/// Resolve the arguments of multiclass and store them into SubstStack. +/// Returns true if failed. +bool TGParser::resolveMultiClassArguments(SubstStack &TemplateArgs, Record *Rec, + ArrayRef ArgValues, + SMLoc Loc) { + ArrayRef ArgNames = Rec->getTemplateArgs(); + if (ArgNames.size() < ArgValues.size()) + return Error(Loc, "More template args specified than expected"); + + // Prepare the mapping of template argument name to value, filling in default + // values if necessary. + SmallVector UnsolvedArgNames(ArgNames); + + // Loop over the template arguments. If a value was specified, + // reset the map value. + for (auto *Arg : ArgValues) { + Init *ArgName = nullptr; + Init *ArgValue = Arg->getValue(); + if (auto *PosArg = dyn_cast(Arg)) + ArgName = ArgNames[PosArg->getIndex()]; + else if (auto *NamedArg = dyn_cast(Arg)) + ArgName = NamedArg->getName(); + + // 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"); + + TemplateArgs.emplace_back(ArgName, ArgValue); + llvm::erase_value(UnsolvedArgNames, ArgName); + } + + // For unsolved arguments, if no value was specified and there was no default, + // 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() + + "'"); + } + TemplateArgs.emplace_back(UnsolvedArgName, Default); + } + + return false; +} + //===----------------------------------------------------------------------===// // Parser Code //===----------------------------------------------------------------------===// @@ -714,7 +768,7 @@ /// multiclass. This returns a SubClassRefTy with a null Record* on error. /// /// SubClassRef ::= ClassID -/// SubClassRef ::= ClassID '<' ValueList '>' +/// SubClassRef ::= ClassID '<' ArgValueList '>' /// SubClassReference TGParser:: ParseSubClassReference(Record *CurRec, bool isDefm) { @@ -735,7 +789,8 @@ return Result; } - if (ParseTemplateArgValueList(Result.TemplateArgs, CurRec, Result.Rec)) { + if (ParseTemplateArgValueList(Result.TemplateArgs, CurRec, Result.Rec, + isDefm)) { Result.Rec = nullptr; // Error parsing value list. return Result; } @@ -755,7 +810,7 @@ /// Record* on error. /// /// SubMultiClassRef ::= MultiClassID -/// SubMultiClassRef ::= MultiClassID '<' ValueList '>' +/// SubMultiClassRef ::= MultiClassID '<' ArgValueList '>' /// SubMultiClassReference TGParser:: ParseSubMultiClassReference(MultiClass *CurMC) { @@ -772,7 +827,7 @@ } if (ParseTemplateArgValueList(Result.TemplateArgs, &CurMC->Rec, - &Result.MC->Rec)) { + &Result.MC->Rec, true)) { Result.MC = nullptr; // Error parsing value list. return Result; } @@ -2574,10 +2629,13 @@ case tgtok::Id: { SMRange NameLoc = Lex.getLocRange(); StringInit *Name = StringInit::get(Records, Lex.getCurStrVal()); - if (Lex.Lex() != tgtok::less) // consume the Id. - return ParseIDValue(CurRec, Name, NameLoc, Mode); // Value ::= IDValue + tgtok::TokKind Next = Lex.Lex(); + if (Next == tgtok::equal) // Named argument. + return Name; + if (Next != tgtok::less) // consume the Id. + return ParseIDValue(CurRec, Name, NameLoc, Mode); // Value ::= IDValue - // Value ::= CLASSID '<' ValueListNE '>' (CLASSID has been consumed) + // Value ::= CLASSID '<' ArgValueList '>' (CLASSID has been consumed) // This is supposed to synthesize a new anonymous definition, deriving // from the class with the template arguments, but no body. Record *Class = Records.getClass(Name->getValue()); @@ -2587,7 +2645,7 @@ return nullptr; } - SmallVector Args; + SmallVector Args; Lex.Lex(); // consume the < if (ParseTemplateArgValueList(Args, CurRec, Class)) return nullptr; // Error parsing value list. @@ -2598,12 +2656,30 @@ // Loop through the arguments that were not specified and make sure // they have a complete value. ArrayRef TArgs = Class->getTemplateArgs(); - for (unsigned I = Args.size(), E = TArgs.size(); I < E; ++I) { - RecordVal *Arg = Class->getValue(TArgs[I]); + SmallVector UnsolvedTArgs(TArgs); + for (auto *Arg : Args) { + Init *ArgName = nullptr; + if (auto *PosArg = dyn_cast(Arg)) + ArgName = TArgs[PosArg->getIndex()]; + else if (auto *NamedArg = dyn_cast(Arg)) + ArgName = NamedArg->getName(); + + // We can only specify the template argument once. + if (!is_contained(UnsolvedTArgs, ArgName)) { + Error(NameLoc.Start, "We can only specify the template argument '" + + ArgName->getAsUnquotedString() + "' once"); + return nullptr; // Error parsing value list. + } + + llvm::erase_value(UnsolvedTArgs, ArgName); + } + + for (auto *UnsolvedTArg : UnsolvedTArgs) { + RecordVal *Arg = Class->getValue(UnsolvedTArg); if (!Arg->getValue()->isComplete()) { Error(NameLoc.Start, "Value not specified for template argument '" + - TArgs[I]->getAsUnquotedString() + "' (#" + - Twine(I) + ") of parent class '" + + UnsolvedTArg->getAsUnquotedString() + + "' of parent class '" + Class->getNameInitAsString() + "'"); } } @@ -3118,34 +3194,73 @@ // 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) { - +// ArgValueList ::= '<' PostionalArgValueList [','] NamedArgValueList '>' +// PostionalArgValueList ::= [Value {',' Value}*] +// NamedArgValueList ::= [NameValue '=' Value {',' NameValue '=' Value}*] +bool TGParser::ParseTemplateArgValueList( + SmallVectorImpl &Result, Record *CurRec, Record *ArgsRec, + bool IsDefm) { assert(Result.empty() && "Result vector is not empty"); ArrayRef TArgs = ArgsRec->getTemplateArgs(); - unsigned ArgIndex = 0; - RecTy *ItemType; if (consume(tgtok::greater)) // empty value list return false; + bool HasNamedArg = false; + unsigned ArgIndex = 0; while (true) { if (ArgIndex >= TArgs.size()) { TokError("Too many template arguments: " + utostr(ArgIndex + 1)); return true; } - const RecordVal *Arg = ArgsRec->getValue(TArgs[ArgIndex]); - assert(Arg && "Template argument record not found"); - ItemType = Arg->getType(); - Init *Value = ParseValue(CurRec, ItemType); + SMLoc ValueLoc = Lex.getLoc(); + // If we are parsing named argument, we don't need to know the argument name + // and argument type will be resolved after we know the name. + Init *Value = ParseValue( + CurRec, + HasNamedArg ? nullptr : ArgsRec->getValue(TArgs[ArgIndex])->getType()); if (!Value) return true; - Result.push_back(Value); + + // If we meet '=', then we are parsing named arguments. + if (Lex.getCode() == tgtok::equal) { + if (auto *Name = dyn_cast(Value)) { + Init *QualifiedName = + QualifyName(*ArgsRec, CurMultiClass, Name, IsDefm ? "::" : ":"); + auto *NamedArg = ArgsRec->getValue(QualifiedName); + if (!NamedArg) { + Error(ValueLoc, "Argument " + Name->getAsString() + " doesn't exist"); + return true; + } + Lex.Lex(); // eat the '='. + ValueLoc = Lex.getLoc(); + Value = ParseValue(CurRec, NamedArg->getType()); + // Named value can't be uninitialized. + if (isa(Value)) { + Error(ValueLoc, "The value of named argument should be initialized, " + "but we got '" + + Value->getAsString() + "'"); + return true; + } + Result.push_back(NamedArgumentInit::get(Records, QualifiedName, Value)); + HasNamedArg = true; + } else { + Error(ValueLoc, + "The name of named argument should be a valid identifier"); + return true; + } + } else { + // Positional arguments should be put before named arguments. + if (HasNamedArg) { + Error(ValueLoc, + "Positional argument should be put before named argument"); + return true; + } + Result.push_back(PositionalArgumentInit::get(Records, ArgIndex, Value)); + } if (consume(tgtok::greater)) // end of argument list? return false; @@ -4119,25 +4234,12 @@ MultiClass *MC = MultiClasses[std::string(Ref.Rec->getName())].get(); assert(MC && "Didn't lookup multiclass correctly?"); - ArrayRef TemplateVals = Ref.TemplateArgs; - ArrayRef TArgs = MC->Rec.getTemplateArgs(); SubstStack Substs; + if (resolveMultiClassArguments(Substs, &MC->Rec, Ref.TemplateArgs, + SubClassLoc)) + return true; - for (unsigned i = 0, e = TArgs.size(); i != e; ++i) { - if (i < TemplateVals.size()) { - Substs.emplace_back(TArgs[i], TemplateVals[i]); - } else { - Init *Default = MC->Rec.getValue(TArgs[i])->getValue(); - if (!Default->isComplete()) - return Error(SubClassLoc, - "value not specified for template argument '" + - TArgs[i]->getAsUnquotedString() + "' (#" + - Twine(i) + ") of multiclass '" + - MC->Rec.getNameInitAsString() + "'"); - Substs.emplace_back(TArgs[i], Default); - } - } - + // Add an implicit argument NAME. Substs.emplace_back(QualifiedNameOfImplicitName(MC), DefmName); if (resolve(MC->Entries, Substs, !CurMultiClass && Loops.empty(), @@ -4264,30 +4366,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 if (auto *NamedArg = dyn_cast(Value)) + ArgName = NamedArg->getName(); + 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/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -684,7 +684,7 @@ def SRLI : Shift_ri<0b00000, 0b101, "srli">; def SRAI : Shift_ri<0b01000, 0b101, "srai">; -def ADD : ALU_rr<0b0000000, 0b000, "add", /*Commutable*/1>, +def ADD : ALU_rr<0b0000000, 0b000, "add", Commutable=1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; def SUB : ALU_rr<0b0100000, 0b000, "sub">, Sched<[WriteIALU, ReadIALU, ReadIALU]>; @@ -696,15 +696,15 @@ def SLTU : ALU_rr<0b0000000, 0b011, "sltu">, Sched<[WriteIALU, ReadIALU, ReadIALU]>; } -def XOR : ALU_rr<0b0000000, 0b100, "xor", /*Commutable*/1>, +def XOR : ALU_rr<0b0000000, 0b100, "xor", Commutable=1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; def SRL : ALU_rr<0b0000000, 0b101, "srl">, Sched<[WriteShiftReg, ReadShiftReg, ReadShiftReg]>; def SRA : ALU_rr<0b0100000, 0b101, "sra">, Sched<[WriteShiftReg, ReadShiftReg, ReadShiftReg]>; -def OR : ALU_rr<0b0000000, 0b110, "or", /*Commutable*/1>, +def OR : ALU_rr<0b0000000, 0b110, "or", Commutable=1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; -def AND : ALU_rr<0b0000000, 0b111, "and", /*Commutable*/1>, +def AND : ALU_rr<0b0000000, 0b111, "and", Commutable=1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in { @@ -798,7 +798,7 @@ def SRLIW : ShiftW_ri<0b0000000, 0b101, "srliw">; def SRAIW : ShiftW_ri<0b0100000, 0b101, "sraiw">; -def ADDW : ALUW_rr<0b0000000, 0b000, "addw", /*Commutable*/1>, +def ADDW : ALUW_rr<0b0000000, 0b000, "addw", Commutable=1>, Sched<[WriteIALU32, ReadIALU32, ReadIALU32]>; def SUBW : ALUW_rr<0b0100000, 0b000, "subw">, Sched<[WriteIALU32, ReadIALU32, ReadIALU32]>; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoD.td b/llvm/lib/Target/RISCV/RISCVInstrInfoD.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoD.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoD.td @@ -86,11 +86,11 @@ } let SchedRW = [WriteFAdd64, ReadFAdd64, ReadFAdd64] in { - defm FADD_D : FPALU_rr_frm_m<0b0000001, "fadd.d", Ext, /*Commutable*/1>; + defm FADD_D : FPALU_rr_frm_m<0b0000001, "fadd.d", Ext, Commutable=1>; defm FSUB_D : FPALU_rr_frm_m<0b0000101, "fsub.d", Ext>; } let SchedRW = [WriteFMul64, ReadFMul64, ReadFMul64] in - defm FMUL_D : FPALU_rr_frm_m<0b0001001, "fmul.d", Ext, /*Commutable*/1>; + defm FMUL_D : FPALU_rr_frm_m<0b0001001, "fmul.d", Ext, Commutable=1>; let SchedRW = [WriteFDiv64, ReadFDiv64, ReadFDiv64] in defm FDIV_D : FPALU_rr_frm_m<0b0001101, "fdiv.d", Ext>; @@ -107,8 +107,8 @@ } let SchedRW = [WriteFMinMax64, ReadFMinMax64, ReadFMinMax64] in { - defm FMIN_D : FPALU_rr_m<0b0010101, 0b000, "fmin.d", Ext, /*Commutable*/1>; - defm FMAX_D : FPALU_rr_m<0b0010101, 0b001, "fmax.d", Ext, /*Commutable*/1>; + defm FMIN_D : FPALU_rr_m<0b0010101, 0b000, "fmin.d", Ext, Commutable=1>; + defm FMAX_D : FPALU_rr_m<0b0010101, 0b001, "fmax.d", Ext, Commutable=1>; } defm FCVT_S_D : FPUnaryOp_r_frm_m<0b0100000, 0b00001, Ext, Ext.F32Ty, @@ -120,7 +120,7 @@ Sched<[WriteFCvtF32ToF64, ReadFCvtF32ToF64]>; let SchedRW = [WriteFCmp64, ReadFCmp64, ReadFCmp64] in { - defm FEQ_D : FPCmp_rr_m<0b1010001, 0b010, "feq.d", Ext, /*Commutable*/1>; + defm FEQ_D : FPCmp_rr_m<0b1010001, 0b010, "feq.d", Ext, Commutable=1>; defm FLT_D : FPCmp_rr_m<0b1010001, 0b001, "flt.d", Ext>; defm FLE_D : FPCmp_rr_m<0b1010001, 0b000, "fle.d", Ext>; } diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td @@ -268,12 +268,12 @@ } let SchedRW = [WriteFAdd32, ReadFAdd32, ReadFAdd32] in { - defm FADD_S : FPALU_rr_frm_m<0b0000000, "fadd.s", Ext, /*Commutable*/1>; + defm FADD_S : FPALU_rr_frm_m<0b0000000, "fadd.s", Ext, Commutable=1>; defm FSUB_S : FPALU_rr_frm_m<0b0000100, "fsub.s", Ext>; } let SchedRW = [WriteFMul32, ReadFMul32, ReadFMul32] in - defm FMUL_S : FPALU_rr_frm_m<0b0001000, "fmul.s", Ext, /*Commutable*/1>; + defm FMUL_S : FPALU_rr_frm_m<0b0001000, "fmul.s", Ext, Commutable=1>; let SchedRW = [WriteFDiv32, ReadFDiv32, ReadFDiv32] in defm FDIV_S : FPALU_rr_frm_m<0b0001100, "fdiv.s", Ext>; @@ -290,8 +290,8 @@ } let SchedRW = [WriteFMinMax32, ReadFMinMax32, ReadFMinMax32] in { - defm FMIN_S : FPALU_rr_m<0b0010100, 0b000, "fmin.s", Ext, /*Commutable*/1>; - defm FMAX_S : FPALU_rr_m<0b0010100, 0b001, "fmax.s", Ext, /*Commutable*/1>; + defm FMIN_S : FPALU_rr_m<0b0010100, 0b000, "fmin.s", Ext, Commutable=1>; + defm FMAX_S : FPALU_rr_m<0b0010100, 0b001, "fmax.s", Ext, Commutable=1>; } let IsSignExtendingOpW = 1 in @@ -305,7 +305,7 @@ Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>; let SchedRW = [WriteFCmp32, ReadFCmp32, ReadFCmp32] in { - defm FEQ_S : FPCmp_rr_m<0b1010000, 0b010, "feq.s", Ext, /*Commutable*/1>; + defm FEQ_S : FPCmp_rr_m<0b1010000, 0b010, "feq.s", Ext, Commutable=1>; defm FLT_S : FPCmp_rr_m<0b1010000, 0b001, "flt.s", Ext>; defm FLE_S : FPCmp_rr_m<0b1010000, 0b000, "fle.s", Ext>; } diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoM.td b/llvm/lib/Target/RISCV/RISCVInstrInfoM.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoM.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoM.td @@ -25,13 +25,13 @@ //===----------------------------------------------------------------------===// let Predicates = [HasStdExtMOrZmmul] in { -def MUL : ALU_rr<0b0000001, 0b000, "mul", /*Commutable*/1>, +def MUL : ALU_rr<0b0000001, 0b000, "mul", Commutable=1>, Sched<[WriteIMul, ReadIMul, ReadIMul]>; -def MULH : ALU_rr<0b0000001, 0b001, "mulh", /*Commutable*/1>, +def MULH : ALU_rr<0b0000001, 0b001, "mulh", Commutable=1>, Sched<[WriteIMul, ReadIMul, ReadIMul]>; def MULHSU : ALU_rr<0b0000001, 0b010, "mulhsu">, Sched<[WriteIMul, ReadIMul, ReadIMul]>; -def MULHU : ALU_rr<0b0000001, 0b011, "mulhu", /*Commutable*/1>, +def MULHU : ALU_rr<0b0000001, 0b011, "mulhu", Commutable=1>, Sched<[WriteIMul, ReadIMul, ReadIMul]>; } // Predicates = [HasStdExtMOrZmmul] @@ -47,7 +47,7 @@ } // Predicates = [HasStdExtM] let Predicates = [HasStdExtMOrZmmul, IsRV64], IsSignExtendingOpW = 1 in { -def MULW : ALUW_rr<0b0000001, 0b000, "mulw", /*Commutable*/1>, +def MULW : ALUW_rr<0b0000001, 0b000, "mulw", Commutable=1>, Sched<[WriteIMul32, ReadIMul32, ReadIMul32]>; } // Predicates = [HasStdExtMOrZmmul, IsRV64] diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td @@ -2387,7 +2387,7 @@ multiclass VPseudoVSQR_V { foreach m = MxListF in { defvar mx = m.MX; - defvar sews = SchedSEWSet.val; + defvar sews = SchedSEWSet.val; let VLMul = m.value in foreach e = sews in { @@ -2742,7 +2742,7 @@ multiclass VPseudoVFDIV_VV_VF { foreach m = MxListF in { defvar mx = m.MX; - defvar sews = SchedSEWSet.val; + defvar sews = SchedSEWSet.val; foreach e = sews in { defvar WriteVFDivV_MX_E = !cast("WriteVFDivV_" # mx # "_E" # e); defvar ReadVFDivV_MX_E = !cast("ReadVFDivV_" # mx # "_E" # e); @@ -3083,11 +3083,11 @@ defvar ReadVICALUV_MX = !cast("ReadVICALUV_" # mx); defvar ReadVICALUX_MX = !cast("ReadVICALUX_" # mx); - defm "" : VPseudoBinaryV_VM, + defm "" : VPseudoBinaryV_VM, Sched<[WriteVICALUV_MX, ReadVICALUV_MX, ReadVICALUV_MX, ReadVMask]>; - defm "" : VPseudoBinaryV_XM, + defm "" : VPseudoBinaryV_XM, Sched<[WriteVICALUX_MX, ReadVICALUV_MX, ReadVICALUX_MX, ReadVMask]>; - defm "" : VPseudoBinaryV_IM, + defm "" : VPseudoBinaryV_IM, Sched<[WriteVICALUI_MX, ReadVICALUV_MX, ReadVMask]>; } } @@ -3100,9 +3100,9 @@ defvar ReadVICALUV_MX = !cast("ReadVICALUV_" # mx); defvar ReadVICALUX_MX = !cast("ReadVICALUX_" # mx); - defm "" : VPseudoBinaryV_VM, + defm "" : VPseudoBinaryV_VM, Sched<[WriteVICALUV_MX, ReadVICALUV_MX, ReadVICALUV_MX, ReadVMask]>; - defm "" : VPseudoBinaryV_XM, + defm "" : VPseudoBinaryV_XM, Sched<[WriteVICALUX_MX, ReadVICALUV_MX, ReadVICALUX_MX, ReadVMask]>; } } @@ -3116,11 +3116,11 @@ defvar ReadVICALUV_MX = !cast("ReadVICALUV_" # mx); defvar ReadVICALUX_MX = !cast("ReadVICALUX_" # mx); - defm "" : VPseudoBinaryV_VM, + defm "" : VPseudoBinaryV_VM, Sched<[WriteVICALUV_MX, ReadVICALUV_MX, ReadVICALUV_MX]>; - defm "" : VPseudoBinaryV_XM, + defm "" : VPseudoBinaryV_XM, Sched<[WriteVICALUX_MX, ReadVICALUV_MX, ReadVICALUX_MX]>; - defm "" : VPseudoBinaryV_IM, + defm "" : VPseudoBinaryV_IM, Sched<[WriteVICALUI_MX, ReadVICALUV_MX]>; } } @@ -3133,9 +3133,9 @@ defvar ReadVICALUV_MX = !cast("ReadVICALUV_" # mx); defvar ReadVICALUX_MX = !cast("ReadVICALUX_" # mx); - defm "" : VPseudoBinaryV_VM, + defm "" : VPseudoBinaryV_VM, Sched<[WriteVICALUV_MX, ReadVICALUV_MX, ReadVICALUV_MX]>; - defm "" : VPseudoBinaryV_XM, + defm "" : VPseudoBinaryV_XM, Sched<[WriteVICALUX_MX, ReadVICALUV_MX, ReadVICALUX_MX]>; } } @@ -3230,18 +3230,18 @@ multiclass VPseudoTernaryV_VV_AAXA { defm _VV : VPseudoTernaryWithPolicy; + Constraint, Commutable=1>; } multiclass VPseudoTernaryV_VX_AAXA { defm "_VX" : VPseudoTernaryWithPolicy; + Constraint, Commutable=1>; } multiclass VPseudoTernaryV_VF_AAXA { defm "_V" # f.FX : VPseudoTernaryWithPolicy; + Commutable=1>; } multiclass VPseudoTernaryW_VV { @@ -3493,7 +3493,7 @@ multiclass VPseudoVWRED_VS { foreach m = MxListWRed in { defvar mx = m.MX; - foreach e = SchedSEWSet.val in { + foreach e = SchedSEWSet.val in { defvar WriteVIWRedV_From_MX_E = !cast("WriteVIWRedV_From_" # mx # "_E" # e); defm _VS : VPseudoTernaryWithTailPolicy, Sched<[WriteVIWRedV_From_MX_E, ReadVIWRedV, ReadVIWRedV, @@ -3505,7 +3505,7 @@ multiclass VPseudoVFRED_VS { foreach m = MxListF in { defvar mx = m.MX; - foreach e = SchedSEWSet.val in { + foreach e = SchedSEWSet.val in { defvar WriteVFRedV_From_MX_E = !cast("WriteVFRedV_From_" # mx # "_E" # e); defm _VS : VPseudoTernaryWithTailPolicy, Sched<[WriteVFRedV_From_MX_E, ReadVFRedV, ReadVFRedV, ReadVFRedV, @@ -3529,7 +3529,7 @@ multiclass VPseudoVFREDO_VS { foreach m = MxListF in { defvar mx = m.MX; - foreach e = SchedSEWSet.val in { + foreach e = SchedSEWSet.val in { defvar WriteVFRedOV_From_MX_E = !cast("WriteVFRedOV_From_" # mx # "_E" # e); defm _VS : VPseudoTernaryWithTailPolicy, Sched<[WriteVFRedOV_From_MX_E, ReadVFRedOV, ReadVFRedOV, @@ -3541,7 +3541,7 @@ multiclass VPseudoVFWRED_VS { foreach m = MxListFWRed in { defvar mx = m.MX; - foreach e = SchedSEWSet.val in { + foreach e = SchedSEWSet.val in { defvar WriteVFWRedV_From_MX_E = !cast("WriteVFWRedV_From_" # mx # "_E" # e); defm _VS : VPseudoTernaryWithTailPolicy, Sched<[WriteVFWRedV_From_MX_E, ReadVFWRedV, ReadVFWRedV, @@ -5223,9 +5223,9 @@ VPatBinaryV_IM_TAIL; multiclass VPatBinaryM_VM_XM_IM - : VPatBinaryV_VM, - VPatBinaryV_XM, - VPatBinaryV_IM; + : VPatBinaryV_VM, + VPatBinaryV_XM, + VPatBinaryV_IM; multiclass VPatBinaryM_V_X_I : VPatBinaryV_V, @@ -5237,8 +5237,8 @@ VPatBinaryV_XM_TAIL; multiclass VPatBinaryM_VM_XM - : VPatBinaryV_VM, - VPatBinaryV_XM; + : VPatBinaryV_VM, + VPatBinaryV_XM; multiclass VPatBinaryM_V_X : VPatBinaryV_V, @@ -6535,10 +6535,10 @@ //===----------------------------------------------------------------------===// // 11.11. Vector Integer Divide Instructions //===----------------------------------------------------------------------===// -defm : VPatBinaryV_VV_VX<"int_riscv_vdivu", "PseudoVDIVU", AllIntegerVectors, /*isSEWAware*/ 1>; -defm : VPatBinaryV_VV_VX<"int_riscv_vdiv", "PseudoVDIV", AllIntegerVectors, /*isSEWAware*/ 1>; -defm : VPatBinaryV_VV_VX<"int_riscv_vremu", "PseudoVREMU", AllIntegerVectors, /*isSEWAware*/ 1>; -defm : VPatBinaryV_VV_VX<"int_riscv_vrem", "PseudoVREM", AllIntegerVectors, /*isSEWAware*/ 1>; +defm : VPatBinaryV_VV_VX<"int_riscv_vdivu", "PseudoVDIVU", AllIntegerVectors, isSEWAware=1>; +defm : VPatBinaryV_VV_VX<"int_riscv_vdiv", "PseudoVDIV", AllIntegerVectors, isSEWAware=1>; +defm : VPatBinaryV_VV_VX<"int_riscv_vremu", "PseudoVREMU", AllIntegerVectors, isSEWAware=1>; +defm : VPatBinaryV_VV_VX<"int_riscv_vrem", "PseudoVREM", AllIntegerVectors, isSEWAware=1>; //===----------------------------------------------------------------------===// // 11.12. Vector Widening Integer Multiply Instructions @@ -6661,8 +6661,8 @@ // 13.4. Vector Single-Width Floating-Point Multiply/Divide Instructions //===----------------------------------------------------------------------===// defm : VPatBinaryV_VV_VX<"int_riscv_vfmul", "PseudoVFMUL", AllFloatVectors>; -defm : VPatBinaryV_VV_VX<"int_riscv_vfdiv", "PseudoVFDIV", AllFloatVectors, /*isSEWAware*/ 1>; -defm : VPatBinaryV_VX<"int_riscv_vfrdiv", "PseudoVFRDIV", AllFloatVectors, /*isSEWAware*/ 1>; +defm : VPatBinaryV_VV_VX<"int_riscv_vfdiv", "PseudoVFDIV", AllFloatVectors, isSEWAware=1>; +defm : VPatBinaryV_VX<"int_riscv_vfrdiv", "PseudoVFRDIV", AllFloatVectors, isSEWAware=1>; //===----------------------------------------------------------------------===// // 13.5. Vector Widening Floating-Point Multiply @@ -6692,7 +6692,7 @@ //===----------------------------------------------------------------------===// // 13.8. Vector Floating-Point Square-Root Instruction //===----------------------------------------------------------------------===// -defm : VPatUnaryV_V<"int_riscv_vfsqrt", "PseudoVFSQRT", AllFloatVectors, /*isSEWAware*/ 1>; +defm : VPatUnaryV_V<"int_riscv_vfsqrt", "PseudoVFSQRT", AllFloatVectors, isSEWAware=1>; //===----------------------------------------------------------------------===// // 13.9. Vector Floating-Point Reciprocal Square-Root Estimate Instruction @@ -6740,12 +6740,9 @@ // We can use vmerge.vvm to support vector-vector vfmerge. // NOTE: Clang previously used int_riscv_vfmerge for vector-vector, but now uses // int_riscv_vmerge. Support both for compatibility. -defm : VPatBinaryV_VM_TAIL<"int_riscv_vmerge", "PseudoVMERGE", - /*CarryOut = */0, /*vtilist=*/AllFloatVectors>; -defm : VPatBinaryV_VM_TAIL<"int_riscv_vfmerge", "PseudoVMERGE", - /*CarryOut = */0, /*vtilist=*/AllFloatVectors>; -defm : VPatBinaryV_XM_TAIL<"int_riscv_vfmerge", "PseudoVFMERGE", - /*CarryOut = */0, /*vtilist=*/AllFloatVectors>; +defm : VPatBinaryV_VM_TAIL<"int_riscv_vmerge", "PseudoVMERGE", vtilist=AllFloatVectors>; +defm : VPatBinaryV_VM_TAIL<"int_riscv_vfmerge", "PseudoVMERGE", vtilist=AllFloatVectors>; +defm : VPatBinaryV_XM_TAIL<"int_riscv_vfmerge", "PseudoVFMERGE", vtilist=AllFloatVectors>; foreach fvti = AllFloatVectors in { defvar instr = !cast("PseudoVMERGE_VIM_"#fvti.LMul.MX); @@ -6823,16 +6820,16 @@ //===----------------------------------------------------------------------===// // 14.3. Vector Single-Width Floating-Point Reduction Instructions //===----------------------------------------------------------------------===// -defm : VPatReductionV_VS<"int_riscv_vfredosum", "PseudoVFREDOSUM", /*IsFloat=*/1>; -defm : VPatReductionV_VS<"int_riscv_vfredusum", "PseudoVFREDUSUM", /*IsFloat=*/1>; -defm : VPatReductionV_VS<"int_riscv_vfredmin", "PseudoVFREDMIN", /*IsFloat=*/1>; -defm : VPatReductionV_VS<"int_riscv_vfredmax", "PseudoVFREDMAX", /*IsFloat=*/1>; +defm : VPatReductionV_VS<"int_riscv_vfredosum", "PseudoVFREDOSUM", IsFloat=1>; +defm : VPatReductionV_VS<"int_riscv_vfredusum", "PseudoVFREDUSUM", IsFloat=1>; +defm : VPatReductionV_VS<"int_riscv_vfredmin", "PseudoVFREDMIN", IsFloat=1>; +defm : VPatReductionV_VS<"int_riscv_vfredmax", "PseudoVFREDMAX", IsFloat=1>; //===----------------------------------------------------------------------===// // 14.4. Vector Widening Floating-Point Reduction Instructions //===----------------------------------------------------------------------===// -defm : VPatReductionW_VS<"int_riscv_vfwredusum", "PseudoVFWREDUSUM", /*IsFloat=*/1>; -defm : VPatReductionW_VS<"int_riscv_vfwredosum", "PseudoVFWREDOSUM", /*IsFloat=*/1>; +defm : VPatReductionW_VS<"int_riscv_vfwredusum", "PseudoVFWREDUSUM", IsFloat=1>; +defm : VPatReductionW_VS<"int_riscv_vfwredosum", "PseudoVFWREDOSUM", IsFloat=1>; //===----------------------------------------------------------------------===// // 15. Vector Mask Instructions diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVSDPatterns.td @@ -841,10 +841,10 @@ } // 11.11. Vector Integer Divide Instructions -defm : VPatBinarySDNode_VV_VX; -defm : VPatBinarySDNode_VV_VX; -defm : VPatBinarySDNode_VV_VX; -defm : VPatBinarySDNode_VV_VX; +defm : VPatBinarySDNode_VV_VX; +defm : VPatBinarySDNode_VV_VX; +defm : VPatBinarySDNode_VV_VX; +defm : VPatBinarySDNode_VV_VX; // 11.12. Vector Widening Integer Multiply Instructions defm : VPatWidenBinarySDNode_VV_VX; -defm : VPatBinaryFPSDNode_VV_VF; -defm : VPatBinaryFPSDNode_R_VF; +defm : VPatBinaryFPSDNode_VV_VF; +defm : VPatBinaryFPSDNode_R_VF; // 13.5. Vector Widening Floating-Point Multiply Instructions defm : VPatWidenBinaryFPSDNode_VV_VF; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVVLPatterns.td @@ -1697,10 +1697,10 @@ } // 11.11. Vector Integer Divide Instructions -defm : VPatBinaryVL_VV_VX; -defm : VPatBinaryVL_VV_VX; -defm : VPatBinaryVL_VV_VX; -defm : VPatBinaryVL_VV_VX; +defm : VPatBinaryVL_VV_VX; +defm : VPatBinaryVL_VV_VX; +defm : VPatBinaryVL_VV_VX; +defm : VPatBinaryVL_VV_VX; // 11.12. Vector Widening Integer Multiply Instructions defm : VPatBinaryWVL_VV_VX; @@ -1838,8 +1838,8 @@ // 13.4. Vector Single-Width Floating-Point Multiply/Divide Instructions defm : VPatBinaryFPVL_VV_VF; -defm : VPatBinaryFPVL_VV_VF; -defm : VPatBinaryFPVL_R_VF; +defm : VPatBinaryFPVL_VV_VF; +defm : VPatBinaryFPVL_R_VF; // 13.5. Vector Widening Floating-Point Multiply Instructions defm : VPatBinaryFPWVL_VV_VF; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZb.td @@ -397,25 +397,25 @@ } // Predicates = [HasStdExtZbb] let Predicates = [HasStdExtZbc] in { -def CLMULR : ALU_rr<0b0000101, 0b010, "clmulr", /*Commutable*/1>, +def CLMULR : ALU_rr<0b0000101, 0b010, "clmulr", Commutable=1>, Sched<[WriteCLMUL, ReadCLMUL, ReadCLMUL]>; } // Predicates = [HasStdExtZbc] let Predicates = [HasStdExtZbcOrZbkc] in { -def CLMUL : ALU_rr<0b0000101, 0b001, "clmul", /*Commutable*/1>, +def CLMUL : ALU_rr<0b0000101, 0b001, "clmul", Commutable=1>, Sched<[WriteCLMUL, ReadCLMUL, ReadCLMUL]>; -def CLMULH : ALU_rr<0b0000101, 0b011, "clmulh", /*Commutable*/1>, +def CLMULH : ALU_rr<0b0000101, 0b011, "clmulh", Commutable=1>, Sched<[WriteCLMUL, ReadCLMUL, ReadCLMUL]>; } // Predicates = [HasStdExtZbcOrZbkc] let Predicates = [HasStdExtZbb] in { -def MIN : ALU_rr<0b0000101, 0b100, "min", /*Commutable*/1>, +def MIN : ALU_rr<0b0000101, 0b100, "min", Commutable=1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; -def MINU : ALU_rr<0b0000101, 0b101, "minu", /*Commutable*/1>, +def MINU : ALU_rr<0b0000101, 0b101, "minu", Commutable=1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; -def MAX : ALU_rr<0b0000101, 0b110, "max", /*Commutable*/1>, +def MAX : ALU_rr<0b0000101, 0b110, "max", Commutable=1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; -def MAXU : ALU_rr<0b0000101, 0b111, "maxu", /*Commutable*/1>, +def MAXU : ALU_rr<0b0000101, 0b111, "maxu", Commutable=1>, Sched<[WriteIALU, ReadIALU, ReadIALU]>; } // Predicates = [HasStdExtZbb] diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZfa.td @@ -89,8 +89,8 @@ Sched<[WriteFLI32]>; let SchedRW = [WriteFMinMax32, ReadFMinMax32, ReadFMinMax32] in { -def FMINM_S: FPALU_rr<0b0010100, 0b010, "fminm.s", FPR32, /*Commutable*/ 1>; -def FMAXM_S: FPALU_rr<0b0010100, 0b011, "fmaxm.s", FPR32, /*Commutable*/ 1>; +def FMINM_S: FPALU_rr<0b0010100, 0b010, "fminm.s", FPR32, Commutable=1>; +def FMAXM_S: FPALU_rr<0b0010100, 0b011, "fmaxm.s", FPR32, Commutable=1>; } def FROUND_S : FPUnaryOp_r_frm<0b0100000, 0b00100, FPR32, FPR32, "fround.s">, @@ -111,8 +111,8 @@ Sched<[WriteFLI64]>; let SchedRW = [WriteFMinMax64, ReadFMinMax64, ReadFMinMax64] in { -def FMINM_D: FPALU_rr<0b0010101, 0b010, "fminm.d", FPR64, /*Commutable*/ 1>; -def FMAXM_D: FPALU_rr<0b0010101, 0b011, "fmaxm.d", FPR64, /*Commutable*/ 1>; +def FMINM_D: FPALU_rr<0b0010101, 0b010, "fminm.d", FPR64, Commutable=1>; +def FMAXM_D: FPALU_rr<0b0010101, 0b011, "fmaxm.d", FPR64, Commutable=1>; } def FROUND_D : FPUnaryOp_r_frm<0b0100001, 0b00100, FPR64, FPR64, "fround.d">, @@ -152,8 +152,8 @@ let Predicates = [HasStdExtZfa, HasStdExtZfh] in { let SchedRW = [WriteFMinMax16, ReadFMinMax16, ReadFMinMax16] in { -def FMINM_H: FPALU_rr<0b0010110, 0b010, "fminm.h", FPR16, /*Commutable*/ 1>; -def FMAXM_H: FPALU_rr<0b0010110, 0b011, "fmaxm.h", FPR16, /*Commutable*/ 1>; +def FMINM_H: FPALU_rr<0b0010110, 0b010, "fminm.h", FPR16, Commutable=1>; +def FMAXM_H: FPALU_rr<0b0010110, 0b011, "fmaxm.h", FPR16, Commutable=1>; } def FROUND_H : FPUnaryOp_r_frm<0b0100010, 0b00100, FPR16, FPR16, "fround.h">, diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td @@ -93,11 +93,11 @@ } let SchedRW = [WriteFAdd16, ReadFAdd16, ReadFAdd16] in { - defm FADD_H : FPALU_rr_frm_m<0b0000010, "fadd.h", Ext, /*Commutable*/1>; + defm FADD_H : FPALU_rr_frm_m<0b0000010, "fadd.h", Ext, Commutable=1>; defm FSUB_H : FPALU_rr_frm_m<0b0000110, "fsub.h", Ext>; } let SchedRW = [WriteFMul16, ReadFMul16, ReadFMul16] in - defm FMUL_H : FPALU_rr_frm_m<0b0001010, "fmul.h", Ext, /*Commutable*/1>; + defm FMUL_H : FPALU_rr_frm_m<0b0001010, "fmul.h", Ext, Commutable=1>; let SchedRW = [WriteFDiv16, ReadFDiv16, ReadFDiv16] in defm FDIV_H : FPALU_rr_frm_m<0b0001110, "fdiv.h", Ext>; @@ -114,8 +114,8 @@ } let SchedRW = [WriteFMinMax16, ReadFMinMax16, ReadFMinMax16] in { - defm FMIN_H : FPALU_rr_m<0b0010110, 0b000, "fmin.h", Ext, /*Commutable*/1>; - defm FMAX_H : FPALU_rr_m<0b0010110, 0b001, "fmax.h", Ext, /*Commutable*/1>; + defm FMIN_H : FPALU_rr_m<0b0010110, 0b000, "fmin.h", Ext, Commutable=1>; + defm FMAX_H : FPALU_rr_m<0b0010110, 0b001, "fmax.h", Ext, Commutable=1>; } let IsSignExtendingOpW = 1 in @@ -159,7 +159,7 @@ foreach Ext = ZfhExts in { let SchedRW = [WriteFCmp16, ReadFCmp16, ReadFCmp16] in { - defm FEQ_H : FPCmp_rr_m<0b1010010, 0b010, "feq.h", Ext, /*Commutable*/1>; + defm FEQ_H : FPCmp_rr_m<0b1010010, 0b010, "feq.h", Ext, Commutable=1>; defm FLT_H : FPCmp_rr_m<0b1010010, 0b001, "flt.h", Ext>; defm FLE_H : FPCmp_rr_m<0b1010010, 0b000, "fle.h", Ext>; } diff --git a/llvm/lib/Target/RISCV/RISCVSchedSiFive7.td b/llvm/lib/Target/RISCV/RISCVSchedSiFive7.td --- a/llvm/lib/Target/RISCV/RISCVSchedSiFive7.td +++ b/llvm/lib/Target/RISCV/RISCVSchedSiFive7.td @@ -731,7 +731,7 @@ } } foreach mx = SchedMxListF in { - foreach sew = SchedSEWSet.val in { + foreach sew = SchedSEWSet.val in { defvar Cycles = !mul(SiFive7GetDivOrSqrtFactor.c, !div(SiFive7GetCyclesOnePerElement.c, 4)); defvar IsWorstCase = SiFive7IsWorstCaseMXSEW.c; diff --git a/llvm/lib/Target/RISCV/RISCVScheduleV.td b/llvm/lib/Target/RISCV/RISCVScheduleV.td --- a/llvm/lib/Target/RISCV/RISCVScheduleV.td +++ b/llvm/lib/Target/RISCV/RISCVScheduleV.td @@ -170,21 +170,21 @@ : LMULSEWReadAdvanceImpl; multiclass LMULSEWSchedWritesWRed - : LMULSEWSchedWritesImpl; + : LMULSEWSchedWritesImpl; multiclass LMULSEWWriteResWRed resources> - : LMULSEWWriteResImpl; + : LMULSEWWriteResImpl; multiclass LMULSEWSchedWritesFWRed - : LMULSEWSchedWritesImpl; + : LMULSEWSchedWritesImpl; multiclass LMULSEWWriteResFWRed resources> - : LMULSEWWriteResImpl; + : LMULSEWWriteResImpl; -multiclass LMULSEWSchedWritesF : LMULSEWSchedWritesImpl; -multiclass LMULSEWSchedReadsF : LMULSEWSchedReadsImpl; +multiclass LMULSEWSchedWritesF : LMULSEWSchedWritesImpl; +multiclass LMULSEWSchedReadsF : LMULSEWSchedReadsImpl; multiclass LMULSEWWriteResF resources> - : LMULSEWWriteResImpl; + : LMULSEWWriteResImpl; multiclass LMULSEWReadAdvanceF writes = []> - : LMULSEWReadAdvanceImpl; + : LMULSEWReadAdvanceImpl; multiclass LMULSchedWritesW : LMULSchedWritesImpl; multiclass LMULSchedReadsW : LMULSchedReadsImpl; diff --git a/llvm/test/TableGen/named-arguments.td b/llvm/test/TableGen/named-arguments.td new file mode 100644 --- /dev/null +++ b/llvm/test/TableGen/named-arguments.td @@ -0,0 +1,133 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// 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 +// RUN: not llvm-tblgen -DERROR6 %s 2>&1 | FileCheck --check-prefix=ERROR6 %s +// RUN: not llvm-tblgen -DERROR7 %s 2>&1 | FileCheck --check-prefix=ERROR7 %s + +class TestClass { + int value = !add(a, b, c); +} +// CHECK: def testClass1 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testClass2 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testClass3 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testClass4 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testClass5 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testClass6 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testClass7 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testClass8 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +def testClass1: TestClass<1>; +def testClass2: TestClass<1, 2>; +def testClass3: TestClass<1, 2, 3>; +def testClass4: TestClass<1, b=2>; +def testClass5: TestClass<1, c=3>; +def testClass6: TestClass<1, b=2, c=3>; +def testClass7: TestClass<1, c=3, b=2>; +def testClass8: TestClass; + +multiclass TestMultiClass { + def "": TestClass; +} + +// CHECK: def testMultiClass1 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testMultiClass2 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testMultiClass3 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testMultiClass4 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testMultiClass5 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testMultiClass6 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testMultiClass7 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def testMultiClass8 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +defm testMultiClass1: TestMultiClass<1>; +defm testMultiClass2: TestMultiClass<1, 2>; +defm testMultiClass3: TestMultiClass<1, 2, 3>; +defm testMultiClass4: TestMultiClass<1, b=2>; +defm testMultiClass5: TestMultiClass<1, c=3>; +defm testMultiClass6: TestMultiClass<1, b=2, c=3>; +defm testMultiClass7: TestMultiClass<1, c=3, b=2>; +defm testMultiClass8: TestMultiClass; + +class TestSubroutine{ + int value=!add(a, b); +} + +// CHECK: def testSubroutine { +// CHECK-NEXT: int value1 = 2; +// CHECK-NEXT: int value2 = 2; +// CHECK-NEXT: int value3 = 2; +// CHECK-NEXT: } +def testSubroutine { + int value1=TestSubroutine<1>.value; + int value2=TestSubroutine<1, b=1>.value; + int value3=TestSubroutine.value; +} + +#ifdef ERROR1 +// ERROR1: Argument "d" doesn't exist +def testError1: TestClass<1, d=3>; +#endif + +#ifdef ERROR2 +// ERROR2: The name of named argument should be a valid identifier +def testError2: TestClass<1, 3=0>; +#endif + +#ifdef ERROR3 +// ERROR3: Positional argument should be put before named argument +def testError3: TestClass<1, b=1, 2>; +#endif + +#ifdef ERROR4 +// ERROR4: The value of named argument should be initialized, but we got '?' +def testError4: TestClass<1, b=?>; +#endif + +#ifdef ERROR5 +// ERROR5: We can only specify the template argument 'TestClass:a' once +def testError5: TestClass<1, a=1>; +#endif + +#ifdef ERROR6 +// ERROR6: We can only specify the template argument 'TestMultiClass::a' once +defm testError6: TestMultiClass<1, a=1>; +#endif + +#ifdef ERROR7 +// ERROR7: We can only specify the template argument 'TestSubroutine:a' once +def testError7 { + int value=TestSubroutine<1, a=1>.value; +} +#endif 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