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 @@ -316,6 +316,7 @@ IK_VarInit, IK_VarBitInit, IK_VarDefInit, + IK_MappingInit, IK_LastTypedInit, IK_UnsetInit }; @@ -480,6 +481,45 @@ std::string getAsString() const override { return "?"; } }; +/// 'a=b' - Represents an mapping from a to b. +class MappingInit : public TypedInit, public FoldingSetNode { + Init *LHS; + Init *RHS; + MappingInit(Init *LHS, Init *RHS, RecTy* Ty) + : TypedInit(IK_MappingInit, Ty), LHS(LHS), RHS(RHS) {} + +public: + MappingInit(const MappingInit &) = delete; + MappingInit &operator=(const MappingInit &) = delete; + + static bool classof(const Init *I) { return I->getKind() == IK_MappingInit; } + + static MappingInit *get(Init *LHS, Init *RHS, RecTy* Ty); + + void Profile(FoldingSetNodeID &ID) const; + + Init *getBit(unsigned Bit) const override { + return const_cast(this); + } + + Init *getCastTo(RecTy *Ty) const override; + Init *convertInitializerTo(RecTy *Ty) const override; + + bool isComplete() const override { return false; } + + bool isConcrete() const override { return true; } + + Init *resolveReferences(Resolver &R) const override; + + Init *getLHS() const { return LHS; } + + Init *getRHS() const { return RHS; } + + std::string getAsString() const override { + return LHS->getAsString() + "=" + RHS->getAsString(); + } +}; + /// 'true'/'false' - Represent a concrete initializer for a bit. class BitInit final : public TypedInit { friend detail::RecordKeeperImpl; @@ -990,52 +1030,36 @@ /// !cond(condition_1: value1, ... , condition_n: value) /// Selects the first value for which condition is true. /// Otherwise reports an error. -class CondOpInit final : public TypedInit, public FoldingSetNode, - public TrailingObjects { - unsigned NumConds; +class CondOpInit final : public TypedInit, + public FoldingSetNode, + public TrailingObjects { + unsigned NumCases; RecTy *ValType; CondOpInit(unsigned NC, RecTy *Type) - : TypedInit(IK_CondOpInit, Type), - NumConds(NC), ValType(Type) {} - - size_t numTrailingObjects(OverloadToken) const { - return 2*NumConds; - } + : TypedInit(IK_CondOpInit, Type), NumCases(NC), ValType(Type) {} public: CondOpInit(const CondOpInit &) = delete; CondOpInit &operator=(const CondOpInit &) = delete; - static bool classof(const Init *I) { - return I->getKind() == IK_CondOpInit; - } + static bool classof(const Init *I) { return I->getKind() == IK_CondOpInit; } - static CondOpInit *get(ArrayRef C, ArrayRef V, - RecTy *Type); + static CondOpInit *get(ArrayRef Cases, RecTy *Type); void Profile(FoldingSetNodeID &ID) const; RecTy *getValType() const { return ValType; } - unsigned getNumConds() const { return NumConds; } - - Init *getCond(unsigned Num) const { - assert(Num < NumConds && "Condition number out of range!"); - return getTrailingObjects()[Num]; - } - - Init *getVal(unsigned Num) const { - assert(Num < NumConds && "Val number out of range!"); - return getTrailingObjects()[Num+NumConds]; - } + unsigned getNumCases() const { return NumCases; } - ArrayRef getConds() const { - return ArrayRef(getTrailingObjects(), NumConds); + MappingInit *getCase(unsigned Num) const { + assert(Num < NumCases && "Case number out of range!"); + return getTrailingObjects()[Num]; } - ArrayRef getVals() const { - return ArrayRef(getTrailingObjects() + NumConds, NumConds); + ArrayRef getCases() const { + return ArrayRef(getTrailingObjects(), NumCases); } Init *Fold(Record *CurRec) const; @@ -1046,20 +1070,14 @@ bool isComplete() const override; std::string getAsString() const override; - using const_case_iterator = SmallVectorImpl::const_iterator; - using const_val_iterator = SmallVectorImpl::const_iterator; - - inline const_case_iterator arg_begin() const { return getConds().begin(); } - inline const_case_iterator arg_end () const { return getConds().end(); } - - inline size_t case_size () const { return NumConds; } - inline bool case_empty() const { return NumConds == 0; } + using const_case_iterator = SmallVectorImpl::const_iterator; + using const_val_iterator = SmallVectorImpl::const_iterator; - inline const_val_iterator name_begin() const { return getVals().begin();} - inline const_val_iterator name_end () const { return getVals().end(); } + inline const_case_iterator case_begin() const { return getCases().begin(); } + inline const_case_iterator case_end() const { return getCases().end(); } - inline size_t val_size () const { return NumConds; } - inline bool val_empty() const { return NumConds == 0; } + inline size_t case_size() const { return NumCases; } + inline bool case_empty() const { return NumCases == 0; } Init *getBit(unsigned Bit) const override; }; 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 TheMappingInitPool; FoldingSet TheBitsInitPool; std::map TheIntInitPool; StringMap StringInitStringPool; @@ -364,6 +365,48 @@ return const_cast(this); } +static void ProfileMappingInit(FoldingSetNodeID &ID, Init *LHS, Init *RHS, RecTy* Ty) { + ID.AddPointer(LHS); + ID.AddPointer(RHS); + ID.AddPointer(Ty); +} + +void MappingInit::Profile(FoldingSetNodeID &ID) const { + ProfileMappingInit(ID, LHS, RHS, getType()); +} + +MappingInit *MappingInit::get(Init *LHS, Init *RHS, RecTy* Ty) { + FoldingSetNodeID ID; + ProfileMappingInit(ID, LHS, RHS, Ty); + + RecordKeeper &RK=RHS->getRecordKeeper(); + detail::RecordKeeperImpl &RKImpl = RK.getImpl(); + void *IP = nullptr; + if (MappingInit *I = RKImpl.TheMappingInitPool.FindNodeOrInsertPos(ID, IP)) + return I; + + MappingInit *I = new (RK.getImpl().Allocator) MappingInit(LHS, RHS, Ty); + RKImpl.TheMappingInitPool.InsertNode(I, IP); + return I; +} + +Init *MappingInit::getCastTo(RecTy *Ty) const { + return const_cast(this); +} + +Init *MappingInit::convertInitializerTo(RecTy *Ty) const { + return const_cast(this); +} + +Init *MappingInit::resolveReferences(Resolver &R) const { + Init *NewLHS = LHS->resolveReferences(R); + Init *NewRHS = RHS->resolveReferences(R); + if (NewLHS != LHS || NewRHS != RHS) + return MappingInit::get(NewLHS, NewRHS, getType()); + + return const_cast(this); +} + BitInit *BitInit::get(RecordKeeper &RK, bool V) { return V ? &RK.getImpl().TrueBitInit : &RK.getImpl().FalseBitInit; } @@ -2309,34 +2352,23 @@ } static void ProfileCondOpInit(FoldingSetNodeID &ID, - ArrayRef CondRange, - ArrayRef ValRange, - const RecTy *ValType) { - assert(CondRange.size() == ValRange.size() && - "Number of conditions and values must match!"); + ArrayRef Cases, + const RecTy *ValType) { ID.AddPointer(ValType); - ArrayRef::iterator Case = CondRange.begin(); - ArrayRef::iterator Val = ValRange.begin(); - - while (Case != CondRange.end()) { - ID.AddPointer(*Case++); - ID.AddPointer(*Val++); + for (auto *Case : Cases) { + ID.AddPointer(Case->getLHS()); + ID.AddPointer(Case->getRHS()); } } void CondOpInit::Profile(FoldingSetNodeID &ID) const { - ProfileCondOpInit(ID, ArrayRef(getTrailingObjects(), NumConds), - ArrayRef(getTrailingObjects() + NumConds, NumConds), + ProfileCondOpInit(ID, ArrayRef(getTrailingObjects(), NumCases), ValType); } -CondOpInit *CondOpInit::get(ArrayRef CondRange, - ArrayRef ValRange, RecTy *Ty) { - assert(CondRange.size() == ValRange.size() && - "Number of conditions and values must match!"); - +CondOpInit *CondOpInit::get(ArrayRef Cases, RecTy *Ty) { FoldingSetNodeID ID; - ProfileCondOpInit(ID, CondRange, ValRange, Ty); + ProfileCondOpInit(ID, Cases, Ty); detail::RecordKeeperImpl &RK = Ty->getRecordKeeper().getImpl(); void *IP = nullptr; @@ -2344,45 +2376,36 @@ return I; void *Mem = RK.Allocator.Allocate( - totalSizeToAlloc(2 * CondRange.size()), alignof(BitsInit)); - CondOpInit *I = new(Mem) CondOpInit(CondRange.size(), Ty); + totalSizeToAlloc(Cases.size()), alignof(BitsInit)); + CondOpInit *I = new (Mem) CondOpInit(Cases.size(), Ty); - std::uninitialized_copy(CondRange.begin(), CondRange.end(), - I->getTrailingObjects()); - std::uninitialized_copy(ValRange.begin(), ValRange.end(), - I->getTrailingObjects()+CondRange.size()); + std::uninitialized_copy(Cases.begin(), Cases.end(), + I->getTrailingObjects()); RK.TheCondOpInitPool.InsertNode(I, IP); return I; } Init *CondOpInit::resolveReferences(Resolver &R) const { - SmallVector NewConds; + SmallVector NewCases; bool Changed = false; - for (const Init *Case : getConds()) { - Init *NewCase = Case->resolveReferences(R); - NewConds.push_back(NewCase); + for (MappingInit *Case : getCases()) { + auto *NewCase = cast(Case->resolveReferences(R)); + NewCases.push_back(NewCase); Changed |= NewCase != Case; } - SmallVector NewVals; - for (const Init *Val : getVals()) { - Init *NewVal = Val->resolveReferences(R); - NewVals.push_back(NewVal); - Changed |= NewVal != Val; - } - if (Changed) - return (CondOpInit::get(NewConds, NewVals, - getValType()))->Fold(R.getCurrentRecord()); + return (CondOpInit::get(NewCases, getValType())) + ->Fold(R.getCurrentRecord()); return const_cast(this); } Init *CondOpInit::Fold(Record *CurRec) const { RecordKeeper &RK = getRecordKeeper(); - for ( unsigned i = 0; i < NumConds; ++i) { - Init *Cond = getCond(i); - Init *Val = getVal(i); + for (auto *Case : getCases()) { + Init *Cond = Case->getLHS(); + Init *Val = Case->getRHS(); if (IntInit *CondI = dyn_cast_or_null( Cond->convertInitializerTo(IntRecTy::get(RK)))) { @@ -2393,32 +2416,24 @@ } } - PrintFatalError(CurRec->getLoc(), - CurRec->getNameInitAsString() + - " does not have any true condition in:" + - this->getAsString()); + PrintFatalError( + CurRec->getLoc(), + CurRec->getNameInitAsString() + + " does not have any true condition in:" + this->getAsString()); return nullptr; } bool CondOpInit::isConcrete() const { - for (const Init *Case : getConds()) - if (!Case->isConcrete()) - return false; - - for (const Init *Val : getVals()) - if (!Val->isConcrete()) + for (const auto *Case : getCases()) + if (!Case->getLHS()->isConcrete() || !!Case->getRHS()->isConcrete()) return false; return true; } bool CondOpInit::isComplete() const { - for (const Init *Case : getConds()) - if (!Case->isComplete()) - return false; - - for (const Init *Val : getVals()) - if (!Val->isConcrete()) + for (const auto *Case : getCases()) + if (!Case->getLHS()->isComplete() || !!Case->getRHS()->isComplete()) return false; return true; @@ -2426,10 +2441,11 @@ std::string CondOpInit::getAsString() const { std::string Result = "!cond("; - for (unsigned i = 0; i < getNumConds(); i++) { - Result += getCond(i)->getAsString() + ": "; - Result += getVal(i)->getAsString(); - if (i != getNumConds()-1) + for (unsigned I = 0; I < getNumCases(); I++) { + const auto *Case = getCase(I); + Result += Case->getLHS()->getAsString() + ": "; + Result += Case->getRHS()->getAsString(); + if (I != getNumCases() - 1) Result += ", "; } return Result + ")"; 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 @@ -279,7 +279,8 @@ void ParseValueList(SmallVectorImpl &Result, Record *CurRec, RecTy *ItemType = nullptr); bool ParseTemplateArgValueList(SmallVectorImpl &Result, - Record *CurRec, Record *ArgsRec); + Record *CurRec, Record *ArgsRec, + bool IsMC = false); void ParseDagArgList( SmallVectorImpl> &Result, Record *CurRec); 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 @@ -735,7 +735,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; } @@ -772,7 +773,7 @@ } if (ParseTemplateArgValueList(Result.TemplateArgs, &CurMC->Rec, - &Result.MC->Rec)) { + &Result.MC->Rec, true)) { Result.MC = nullptr; // Error parsing value list. return Result; } @@ -2428,26 +2429,31 @@ } // Parse through '[Case: Val,]+' - SmallVector Case; - SmallVector Val; + SmallVector Cases; while (true) { if (consume(tgtok::r_paren)) break; - Init *V = ParseValue(CurRec); - if (!V) + Init *LHS = ParseValue(CurRec); + if (!LHS) return nullptr; - Case.push_back(V); if (!consume(tgtok::colon)) { TokError("expected ':' following a condition in !cond operator"); return nullptr; } - V = ParseValue(CurRec, ItemType); - if (!V) + Init *RHS = ParseValue(CurRec, ItemType); + if (!RHS) return nullptr; - Val.push_back(V); + + if (!isa(RHS)) { + TokError("unexpected uninitialized value in !cond operator"); + return nullptr; + } + + Cases.push_back( + MappingInit::get(LHS, RHS, cast(RHS)->getType())); if (consume(tgtok::r_paren)) break; @@ -2458,14 +2464,16 @@ } } - if (Case.size() < 1) { - TokError("there should be at least 1 'condition : value' in the !cond operator"); + if (Cases.size() < 1) { + TokError( + "there should be at least 1 'condition : value' in the !cond operator"); return nullptr; } // resolve type RecTy *Type = nullptr; - for (Init *V : Val) { + for (const auto *Case : Cases) { + Init *V = Case->getRHS(); RecTy *VTy = nullptr; if (TypedInit *Vt = dyn_cast(V)) VTy = Vt->getType(); @@ -2482,7 +2490,7 @@ RecTy *RType = resolveTypes(Type, VTy); if (!RType) { TokError(Twine("inconsistent types '") + Type->getAsString() + - "' and '" + VTy->getAsString() + "' for !cond"); + "' and '" + VTy->getAsString() + "' for !cond"); return nullptr; } Type = RType; @@ -2494,7 +2502,7 @@ TokError("could not determine type for !cond from its arguments"); return nullptr; } - return CondOpInit::get(Case, Val, Type)->Fold(CurRec); + return CondOpInit::get(Cases, Type)->Fold(CurRec); } /// ParseSimpleValue - Parse a tblgen value. This returns null on error. @@ -2574,8 +2582,11 @@ 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) // This is supposed to synthesize a new anonymous definition, deriving @@ -2851,6 +2862,7 @@ /// ValueSuffix ::= '{' BitList '}' /// ValueSuffix ::= '[' SliceElements ']' /// ValueSuffix ::= '.' ID +/// ValueSuffix ::= '=' Value /// Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { SMLoc LHSLoc = Lex.getLoc(); @@ -2954,7 +2966,28 @@ Lex.Lex(); // eat field name break; } + case tgtok::equal: { + if (Mode == ParseNameMode) + // This is the beginning of the declaration. + return Result; + + if (!isa(Result)) { + TokError("The name of named argument is invalid: '" + + Result->getAsString() + "'"); + return nullptr; + } + Lex.Lex(); // Eat the '='. + Init *LHS = Result; + Init *RHS = ParseValue(CurRec, ItemType, Mode); + if (!isa(RHS)) { + TokError("The value of named argument is invalid: '" + + RHS->getAsString() + "'"); + return nullptr; + } + + return MappingInit::get(LHS, RHS, cast(RHS)->getType()); + } case tgtok::paste: SMLoc PasteLoc = Lex.getLoc(); TypedInit *LHS = dyn_cast(Result); @@ -3118,41 +3151,70 @@ // 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) { - + Record *CurRec, Record *ArgsRec, + bool IsMC) { 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; - while (true) { - if (ArgIndex >= TArgs.size()) { - TokError("Too many template arguments: " + utostr(ArgIndex + 1)); - return true; - } - const RecordVal *Arg = ArgsRec->getValue(TArgs[ArgIndex]); + DenseMap ArgMap(TArgs.size()); + for (auto *ArgName : TArgs) { + ArgMap.insert({ArgName, ArgsRec->getValue(ArgName)->getValue()}); + } + + bool HasNamedArg = false; + for (auto *ArgName : TArgs) { + const RecordVal *Arg = ArgsRec->getValue(ArgName); assert(Arg && "Template argument record not found"); - ItemType = Arg->getType(); + SMLoc ValueLoc = Lex.getLoc(); + RecTy *ItemType = Arg->getType(); Init *Value = ParseValue(CurRec, ItemType); if (!Value) return true; - Result.push_back(Value); + if (MappingInit *Mapping = dyn_cast(Value)) { + ArgName = Mapping->getLHS(); + Value = Mapping->getRHS(); + Init *QualifiedName = + QualifyName(*ArgsRec, CurMultiClass, ArgName, IsMC ? "::" : ":"); + auto *NamedArg = ArgsRec->getValue(QualifiedName); + if (!NamedArg) { + Error(ValueLoc, + "Argument " + ArgName->getAsString() + " doesn't exist"); + return true; + } + Init *NamedArgValue = NamedArg->getValue(); + if (isa(NamedArgValue)) { + Error(ValueLoc, "Named argument isn't allowed for required argument"); + return true; + } + HasNamedArg = true; + } else { + if (HasNamedArg) { + Error(ValueLoc, + "Non-named argument should be put before named argument"); + return true; + } + } + ArgMap[ArgName] = Value; - if (consume(tgtok::greater)) // end of argument list? + if (consume(tgtok::greater)) { // end of argument list? + for (auto *Arg : TArgs) + Result.push_back(ArgMap[Arg]); return false; + } if (!consume(tgtok::comma)) return TokError("Expected comma before next argument"); - ++ArgIndex; } + TokError("Too many template arguments: " + utostr(TArgs.size() + 1)); + return true; } /// ParseDeclaration - Read a declaration, returning the name of field ID, or an 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,88 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s + +class TestClass { + int value = !add(a, b, c, d); +} +// CHECK: def test1 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test2 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test3 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test4 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test5 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test6 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test7 { +// 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>; + +// CHECK: def test1 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test2 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test3 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test4 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test5 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test6 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +// CHECK: def test7 { +// CHECK-NEXT: int value = 6; +// CHECK-NEXT: } +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: } +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>; \ No newline at end of file