diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
commit | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch) | |
tree | 4adf86a776049cbf7f69a1929c4babcbbef925eb /llvm/lib/TableGen | |
parent | 7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff) |
Notes
Diffstat (limited to 'llvm/lib/TableGen')
-rw-r--r-- | llvm/lib/TableGen/Main.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/TableGen/Record.cpp | 57 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGLexer.cpp | 16 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGLexer.h | 26 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGParser.cpp | 258 | ||||
-rw-r--r-- | llvm/lib/TableGen/TGParser.h | 74 |
6 files changed, 387 insertions, 46 deletions
diff --git a/llvm/lib/TableGen/Main.cpp b/llvm/lib/TableGen/Main.cpp index 48ded6c45a46..427bd6778577 100644 --- a/llvm/lib/TableGen/Main.cpp +++ b/llvm/lib/TableGen/Main.cpp @@ -73,7 +73,7 @@ static int createDependencyFile(const TGParser &Parser, const char *argv0) { EC.message() + "\n"); DepOut.os() << OutputFilename << ":"; for (const auto &Dep : Parser.getDependencies()) { - DepOut.os() << ' ' << Dep.first; + DepOut.os() << ' ' << Dep; } DepOut.os() << "\n"; DepOut.keep(); diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp index 835ef8c7141b..9db842dc678e 100644 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -788,6 +788,21 @@ Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const { if (StringInit *LHSs = dyn_cast<StringInit>(LHS)) return IntInit::get(LHSs->getValue().empty()); break; + + case GETOP: + if (DagInit *Dag = dyn_cast<DagInit>(LHS)) { + DefInit *DI = DefInit::get(Dag->getOperatorAsDef({})); + if (!DI->getType()->typeIsA(getType())) { + PrintFatalError(CurRec->getLoc(), + Twine("Expected type '") + + getType()->getAsString() + "', got '" + + DI->getType()->getAsString() + "' in: " + + getAsString() + "\n"); + } else { + return DI; + } + } + break; } return const_cast<UnOpInit *>(this); } @@ -809,6 +824,7 @@ std::string UnOpInit::getAsString() const { case TAIL: Result = "!tail"; break; case SIZE: Result = "!size"; break; case EMPTY: Result = "!empty"; break; + case GETOP: Result = "!getop"; break; } return Result + "(" + LHS->getAsString() + ")"; } @@ -887,13 +903,18 @@ Init *BinOpInit::Fold(Record *CurRec) const { if (LHSs && RHSs) { DefInit *LOp = dyn_cast<DefInit>(LHSs->getOperator()); DefInit *ROp = dyn_cast<DefInit>(RHSs->getOperator()); - if (!LOp || !ROp) + if ((!LOp && !isa<UnsetInit>(LHSs->getOperator())) || + (!ROp && !isa<UnsetInit>(RHSs->getOperator()))) break; - if (LOp->getDef() != ROp->getDef()) { + if (LOp && ROp && LOp->getDef() != ROp->getDef()) { PrintFatalError(Twine("Concatenated Dag operators do not match: '") + LHSs->getAsString() + "' vs. '" + RHSs->getAsString() + "'"); } + Init *Op = LOp ? LOp : ROp; + if (!Op) + Op = UnsetInit::get(); + SmallVector<Init*, 8> Args; SmallVector<StringInit*, 8> ArgNames; for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) { @@ -904,7 +925,7 @@ Init *BinOpInit::Fold(Record *CurRec) const { Args.push_back(RHSs->getArg(i)); ArgNames.push_back(RHSs->getArgName(i)); } - return DagInit::get(LHSs->getOperator(), nullptr, Args, ArgNames); + return DagInit::get(Op, nullptr, Args, ArgNames); } break; } @@ -975,6 +996,20 @@ Init *BinOpInit::Fold(Record *CurRec) const { break; } + case SETOP: { + DagInit *Dag = dyn_cast<DagInit>(LHS); + DefInit *Op = dyn_cast<DefInit>(RHS); + if (Dag && Op) { + SmallVector<Init*, 8> Args; + SmallVector<StringInit*, 8> ArgNames; + for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) { + Args.push_back(Dag->getArg(i)); + ArgNames.push_back(Dag->getArgName(i)); + } + return DagInit::get(Op, nullptr, Args, ArgNames); + } + break; + } case ADD: case MUL: case AND: @@ -1037,6 +1072,7 @@ std::string BinOpInit::getAsString() const { case LISTCONCAT: Result = "!listconcat"; break; case LISTSPLAT: Result = "!listsplat"; break; case STRCONCAT: Result = "!strconcat"; break; + case SETOP: Result = "!setop"; break; } return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")"; } @@ -2277,6 +2313,21 @@ Record *Record::getValueAsDef(StringRef FieldName) const { FieldName + "' does not have a def initializer!"); } +Record *Record::getValueAsOptionalDef(StringRef FieldName) const { + const RecordVal *R = getValue(FieldName); + if (!R || !R->getValue()) + PrintFatalError(getLoc(), "Record `" + getName() + + "' does not have a field named `" + FieldName + "'!\n"); + + if (DefInit *DI = dyn_cast<DefInit>(R->getValue())) + return DI->getDef(); + if (isa<UnsetInit>(R->getValue())) + return nullptr; + PrintFatalError(getLoc(), "Record `" + getName() + "', field `" + + FieldName + "' does not have either a def initializer or '?'!"); +} + + bool Record::getValueAsBit(StringRef FieldName) const { const RecordVal *R = getValue(FieldName); if (!R || !R->getValue()) diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp index da2286e41fe5..1a3f5a7392d5 100644 --- a/llvm/lib/TableGen/TGLexer.cpp +++ b/llvm/lib/TableGen/TGLexer.cpp @@ -350,6 +350,10 @@ tgtok::TokKind TGLexer::LexIdentifier() { .Case("field", tgtok::Field) .Case("let", tgtok::Let) .Case("in", tgtok::In) + .Case("defvar", tgtok::Defvar) + .Case("if", tgtok::If) + .Case("then", tgtok::Then) + .Case("else", tgtok::ElseKW) .Default(tgtok::Id); if (Kind == tgtok::Id) @@ -379,15 +383,7 @@ bool TGLexer::LexInclude() { return true; } - DependenciesMapTy::const_iterator Found = Dependencies.find(IncludedFile); - if (Found != Dependencies.end()) { - PrintError(getLoc(), - "File '" + IncludedFile + "' has already been included."); - SrcMgr.PrintMessage(Found->second, SourceMgr::DK_Note, - "previously included here"); - return true; - } - Dependencies.insert(std::make_pair(IncludedFile, getLoc())); + Dependencies.insert(IncludedFile); // Save the line number and lex buffer of the includer. CurBuf = SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(); CurPtr = CurBuf.begin(); @@ -567,6 +563,8 @@ tgtok::TokKind TGLexer::LexExclaim() { .Case("listconcat", tgtok::XListConcat) .Case("listsplat", tgtok::XListSplat) .Case("strconcat", tgtok::XStrConcat) + .Case("setop", tgtok::XSetOp) + .Case("getop", tgtok::XGetOp) .Default(tgtok::Error); return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator"); diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h index 3085ab2c0478..6d10af348674 100644 --- a/llvm/lib/TableGen/TGLexer.h +++ b/llvm/lib/TableGen/TGLexer.h @@ -19,8 +19,8 @@ #include "llvm/Support/DataTypes.h" #include "llvm/Support/SMLoc.h" #include <cassert> -#include <map> #include <memory> +#include <set> #include <string> namespace llvm { @@ -44,14 +44,15 @@ namespace tgtok { equal, question, // = ? paste, // # - // Keywords. + // Keywords. ('ElseKW' is named to distinguish it from the existing 'Else' + // that means the preprocessor #else.) Bit, Bits, Class, Code, Dag, Def, Foreach, Defm, Field, In, Int, Let, List, - MultiClass, String, Defset, + MultiClass, String, Defset, Defvar, If, Then, ElseKW, // !keywords. XConcat, XADD, XMUL, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XListSplat, XStrConcat, XCast, XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, - XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, + XIf, XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, XSetOp, XGetOp, // Integer value. IntVal, @@ -73,24 +74,25 @@ namespace tgtok { class TGLexer { SourceMgr &SrcMgr; - const char *CurPtr; + const char *CurPtr = nullptr; StringRef CurBuf; // Information about the current token. - const char *TokStart; - tgtok::TokKind CurCode; + const char *TokStart = nullptr; + tgtok::TokKind CurCode = tgtok::TokKind::Eof; std::string CurStrVal; // This is valid for ID, STRVAL, VARNAME, CODEFRAGMENT - int64_t CurIntVal; // This is valid for INTVAL. + int64_t CurIntVal = 0; // This is valid for INTVAL. /// CurBuffer - This is the current buffer index we're lexing from as managed /// by the SourceMgr object. - unsigned CurBuffer; + unsigned CurBuffer = 0; public: - typedef std::map<std::string, SMLoc> DependenciesMapTy; + typedef std::set<std::string> DependenciesSetTy; + private: /// Dependencies - This is the list of all included files. - DependenciesMapTy Dependencies; + DependenciesSetTy Dependencies; public: TGLexer(SourceMgr &SrcMgr, ArrayRef<std::string> Macros); @@ -99,7 +101,7 @@ public: return CurCode = LexToken(CurPtr == CurBuf.begin()); } - const DependenciesMapTy &getDependencies() const { + const DependenciesSetTy &getDependencies() const { return Dependencies; } diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp index c373e2899a5d..01cc1af34ab6 100644 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -391,9 +391,11 @@ bool TGParser::resolve(const ForeachLoop &Loop, SubstStack &Substs, bool Error = false; for (auto Elt : *LI) { - Substs.emplace_back(Loop.IterVar->getNameInit(), Elt); + if (Loop.IterVar) + Substs.emplace_back(Loop.IterVar->getNameInit(), Elt); Error = resolve(Loop.Entries, Substs, Final, Dest); - Substs.pop_back(); + if (Loop.IterVar) + Substs.pop_back(); if (Error) break; } @@ -482,7 +484,7 @@ bool TGParser::addDefOne(std::unique_ptr<Record> Rec) { static bool isObjectStart(tgtok::TokKind K) { return K == tgtok::Class || K == tgtok::Def || K == tgtok::Defm || K == tgtok::Let || K == tgtok::MultiClass || K == tgtok::Foreach || - K == tgtok::Defset; + K == tgtok::Defset || K == tgtok::Defvar || K == tgtok::If; } /// ParseObjectName - If a valid object name is specified, return it. If no @@ -869,11 +871,17 @@ Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc, } } + if (CurLocalScope) + if (Init *I = CurLocalScope->getVar(Name->getValue())) + return I; + // If this is in a foreach loop, make sure it's not a loop iterator for (const auto &L : Loops) { - VarInit *IterVar = dyn_cast<VarInit>(L->IterVar); - if (IterVar && IterVar->getNameInit() == Name) - return IterVar; + if (L->IterVar) { + VarInit *IterVar = dyn_cast<VarInit>(L->IterVar); + if (IterVar && IterVar->getNameInit() == Name) + return IterVar; + } } if (Mode == ParseNameMode) @@ -905,7 +913,8 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { case tgtok::XTail: case tgtok::XSize: case tgtok::XEmpty: - case tgtok::XCast: { // Value ::= !unop '(' Value ')' + case tgtok::XCast: + case tgtok::XGetOp: { // Value ::= !unop '(' Value ')' UnOpInit::UnaryOp Code; RecTy *Type = nullptr; @@ -941,6 +950,28 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { Code = UnOpInit::EMPTY; Type = IntRecTy::get(); break; + case tgtok::XGetOp: + Lex.Lex(); // eat the operation + if (Lex.getCode() == tgtok::less) { + // Parse an optional type suffix, so that you can say + // !getop<BaseClass>(someDag) as a shorthand for + // !cast<BaseClass>(!getop(someDag)). + Type = ParseOperatorType(); + + if (!Type) { + TokError("did not get type for unary operator"); + return nullptr; + } + + if (!isa<RecordRecTy>(Type)) { + TokError("type for !getop must be a record type"); + // but keep parsing, to consume the operand + } + } else { + Type = RecordRecTy::get({}); + } + Code = UnOpInit::GETOP; + break; } if (Lex.getCode() != tgtok::l_paren) { TokError("expected '(' after unary operator"); @@ -1055,7 +1086,8 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { case tgtok::XGt: case tgtok::XListConcat: case tgtok::XListSplat: - case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')' + case tgtok::XStrConcat: + case tgtok::XSetOp: { // Value ::= !binop '(' Value ',' Value ')' tgtok::TokKind OpTok = Lex.getCode(); SMLoc OpLoc = Lex.getLoc(); Lex.Lex(); // eat the operation @@ -1080,6 +1112,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break; case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break; case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break; + case tgtok::XSetOp: Code = BinOpInit::SETOP; break; } RecTy *Type = nullptr; @@ -1088,6 +1121,7 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { default: llvm_unreachable("Unhandled code!"); case tgtok::XConcat: + case tgtok::XSetOp: Type = DagRecTy::get(); ArgType = DagRecTy::get(); break; @@ -1146,7 +1180,6 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { InitList.push_back(ParseValue(CurRec, ArgType)); if (!InitList.back()) return nullptr; - // All BinOps require their arguments to be of compatible types. RecTy *ListType = cast<TypedInit>(InitList.back())->getType(); if (!ArgType) { ArgType = ListType; @@ -1212,6 +1245,18 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { ArgType = Resolved; } + // Deal with BinOps whose arguments have different types, by + // rewriting ArgType in between them. + switch (Code) { + case BinOpInit::SETOP: + // After parsing the first dag argument, switch to expecting + // a record, with no restriction on its superclasses. + ArgType = RecordRecTy::get({}); + break; + default: + break; + } + if (Lex.getCode() != tgtok::comma) break; Lex.Lex(); // eat the ',' @@ -2024,7 +2069,8 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, } case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')' Lex.Lex(); // eat the '(' - if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast) { + if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast && + Lex.getCode() != tgtok::question && Lex.getCode() != tgtok::XGetOp) { TokError("expected identifier in dag init"); return nullptr; } @@ -2062,7 +2108,8 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, case tgtok::XTail: case tgtok::XSize: case tgtok::XEmpty: - case tgtok::XCast: // Value ::= !unop '(' Value ')' + case tgtok::XCast: + case tgtok::XGetOp: // Value ::= !unop '(' Value ')' case tgtok::XIsA: case tgtok::XConcat: case tgtok::XDag: @@ -2081,7 +2128,8 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, case tgtok::XGt: case tgtok::XListConcat: case tgtok::XListSplat: - case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')' + case tgtok::XStrConcat: + case tgtok::XSetOp: // Value ::= !binop '(' Value ',' Value ')' case tgtok::XIf: case tgtok::XCond: case tgtok::XFoldl: @@ -2555,7 +2603,11 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) { /// /// BodyItem ::= Declaration ';' /// BodyItem ::= LET ID OptionalBitList '=' Value ';' +/// BodyItem ::= Defvar bool TGParser::ParseBodyItem(Record *CurRec) { + if (Lex.getCode() == tgtok::Defvar) + return ParseDefvar(); + if (Lex.getCode() != tgtok::Let) { if (!ParseDeclaration(CurRec, false)) return true; @@ -2618,10 +2670,15 @@ bool TGParser::ParseBody(Record *CurRec) { // Eat the '{'. Lex.Lex(); + // An object body introduces a new scope for local variables. + TGLocalVarScope *BodyScope = PushLocalScope(); + while (Lex.getCode() != tgtok::r_brace) if (ParseBodyItem(CurRec)) return true; + PopLocalScope(BodyScope); + // Eat the '}'. Lex.Lex(); return false; @@ -2760,6 +2817,45 @@ bool TGParser::ParseDefset() { return false; } +/// ParseDefvar - Parse a defvar statement. +/// +/// Defvar ::= DEFVAR Id '=' Value ';' +/// +bool TGParser::ParseDefvar() { + assert(Lex.getCode() == tgtok::Defvar); + Lex.Lex(); // Eat the 'defvar' token + + if (Lex.getCode() != tgtok::Id) + return TokError("expected identifier"); + StringInit *DeclName = StringInit::get(Lex.getCurStrVal()); + if (CurLocalScope) { + if (CurLocalScope->varAlreadyDefined(DeclName->getValue())) + return TokError("local variable of this name already exists"); + } else { + if (Records.getGlobal(DeclName->getValue())) + return TokError("def or global variable of this name already exists"); + } + + if (Lex.Lex() != tgtok::equal) // Eat the identifier + return TokError("expected '='"); + Lex.Lex(); // Eat the '=' + + Init *Value = ParseValue(nullptr); + if (!Value) + return true; + + if (Lex.getCode() != tgtok::semi) + return TokError("expected ';'"); + Lex.Lex(); // Eat the ';' + + if (CurLocalScope) + CurLocalScope->addVar(DeclName->getValue(), Value); + else + Records.addExtraGlobal(DeclName->getValue(), Value); + + return false; +} + /// ParseForeach - Parse a for statement. Return the record corresponding /// to it. This returns true on error. /// @@ -2785,6 +2881,9 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) { // Create a loop object and remember it. Loops.push_back(std::make_unique<ForeachLoop>(Loc, IterName, ListValue)); + // A foreach loop introduces a new scope for local variables. + TGLocalVarScope *ForeachScope = PushLocalScope(); + if (Lex.getCode() != tgtok::l_brace) { // FOREACH Declaration IN Object if (ParseObject(CurMultiClass)) @@ -2805,6 +2904,8 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) { Lex.Lex(); // Eat the } } + PopLocalScope(ForeachScope); + // Resolve the loop or store it for later resolution. std::unique_ptr<ForeachLoop> Loop = std::move(Loops.back()); Loops.pop_back(); @@ -2812,6 +2913,115 @@ bool TGParser::ParseForeach(MultiClass *CurMultiClass) { return addEntry(std::move(Loop)); } +/// ParseIf - Parse an if statement. +/// +/// If ::= IF Value THEN IfBody +/// If ::= IF Value THEN IfBody ELSE IfBody +/// +bool TGParser::ParseIf(MultiClass *CurMultiClass) { + SMLoc Loc = Lex.getLoc(); + assert(Lex.getCode() == tgtok::If && "Unknown tok"); + Lex.Lex(); // Eat the 'if' token. + + // Make a temporary object to record items associated with the for + // loop. + Init *Condition = ParseValue(nullptr); + if (!Condition) + return true; + + if (Lex.getCode() != tgtok::Then) + return TokError("Unknown tok"); + Lex.Lex(); // Eat the 'then' + + // We have to be able to save if statements to execute later, and they have + // to live on the same stack as foreach loops. The simplest implementation + // technique is to convert each 'then' or 'else' clause *into* a foreach + // loop, over a list of length 0 or 1 depending on the condition, and with no + // iteration variable being assigned. + + ListInit *EmptyList = ListInit::get({}, BitRecTy::get()); + ListInit *SingletonList = ListInit::get({BitInit::get(1)}, BitRecTy::get()); + RecTy *BitListTy = ListRecTy::get(BitRecTy::get()); + + // The foreach containing the then-clause selects SingletonList if + // the condition is true. + Init *ThenClauseList = + TernOpInit::get(TernOpInit::IF, Condition, SingletonList, EmptyList, + BitListTy) + ->Fold(nullptr); + Loops.push_back(std::make_unique<ForeachLoop>(Loc, nullptr, ThenClauseList)); + + if (ParseIfBody(CurMultiClass, "then")) + return true; + + std::unique_ptr<ForeachLoop> Loop = std::move(Loops.back()); + Loops.pop_back(); + + if (addEntry(std::move(Loop))) + return true; + + // Now look for an optional else clause. The if-else syntax has the usual + // dangling-else ambiguity, and by greedily matching an else here if we can, + // we implement the usual resolution of pairing with the innermost unmatched + // if. + if (Lex.getCode() == tgtok::ElseKW) { + Lex.Lex(); // Eat the 'else' + + // The foreach containing the else-clause uses the same pair of lists as + // above, but this time, selects SingletonList if the condition is *false*. + Init *ElseClauseList = + TernOpInit::get(TernOpInit::IF, Condition, EmptyList, SingletonList, + BitListTy) + ->Fold(nullptr); + Loops.push_back( + std::make_unique<ForeachLoop>(Loc, nullptr, ElseClauseList)); + + if (ParseIfBody(CurMultiClass, "else")) + return true; + + Loop = std::move(Loops.back()); + Loops.pop_back(); + + if (addEntry(std::move(Loop))) + return true; + } + + return false; +} + +/// ParseIfBody - Parse the then-clause or else-clause of an if statement. +/// +/// IfBody ::= Object +/// IfBody ::= '{' ObjectList '}' +/// +bool TGParser::ParseIfBody(MultiClass *CurMultiClass, StringRef Kind) { + TGLocalVarScope *BodyScope = PushLocalScope(); + + if (Lex.getCode() != tgtok::l_brace) { + // A single object. + if (ParseObject(CurMultiClass)) + return true; + } else { + SMLoc BraceLoc = Lex.getLoc(); + // A braced block. + Lex.Lex(); // eat the '{'. + + // Parse the object list. + if (ParseObjectList(CurMultiClass)) + return true; + + if (Lex.getCode() != tgtok::r_brace) { + TokError("expected '}' at end of '" + Kind + "' clause"); + return Error(BraceLoc, "to match this '{'"); + } + + Lex.Lex(); // Eat the } + } + + PopLocalScope(BodyScope); + return false; +} + /// ParseClass - Parse a tblgen class definition. /// /// ClassInst ::= CLASS ID TemplateArgList? ObjectBody @@ -2917,6 +3127,8 @@ bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) { return TokError("expected 'in' at end of top-level 'let'"); Lex.Lex(); + TGLocalVarScope *LetScope = PushLocalScope(); + // If this is a scalar let, just handle it now if (Lex.getCode() != tgtok::l_brace) { // LET LetList IN Object @@ -2938,6 +3150,8 @@ bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) { Lex.Lex(); } + PopLocalScope(LetScope); + // Outside this let scope, this let block is not active. LetStack.pop_back(); return false; @@ -3011,21 +3225,28 @@ bool TGParser::ParseMultiClass() { if (Lex.Lex() == tgtok::r_brace) // eat the '{'. return TokError("multiclass must contain at least one def"); + // A multiclass body introduces a new scope for local variables. + TGLocalVarScope *MulticlassScope = PushLocalScope(); + while (Lex.getCode() != tgtok::r_brace) { switch (Lex.getCode()) { default: - return TokError("expected 'let', 'def', 'defm' or 'foreach' in " - "multiclass body"); + return TokError("expected 'let', 'def', 'defm', 'defvar', 'foreach' " + "or 'if' in multiclass body"); case tgtok::Let: case tgtok::Def: case tgtok::Defm: + case tgtok::Defvar: case tgtok::Foreach: + case tgtok::If: if (ParseObject(CurMultiClass)) return true; break; } } Lex.Lex(); // eat the '}'. + + PopLocalScope(MulticlassScope); } CurMultiClass = nullptr; @@ -3167,19 +3388,24 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) { /// Object ::= DefMInst /// Object ::= LETCommand '{' ObjectList '}' /// Object ::= LETCommand Object +/// Object ::= Defset +/// Object ::= Defvar bool TGParser::ParseObject(MultiClass *MC) { switch (Lex.getCode()) { default: - return TokError("Expected class, def, defm, defset, multiclass, let or " - "foreach"); + return TokError("Expected class, def, defm, defset, multiclass, let, " + "foreach or if"); case tgtok::Let: return ParseTopLevelLet(MC); case tgtok::Def: return ParseDef(MC); case tgtok::Foreach: return ParseForeach(MC); + case tgtok::If: return ParseIf(MC); case tgtok::Defm: return ParseDefm(MC); case tgtok::Defset: if (MC) return TokError("defset is not allowed inside multiclass"); return ParseDefset(); + case tgtok::Defvar: + return ParseDefvar(); case tgtok::Class: if (MC) return TokError("class is not allowed inside multiclass"); diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h index af2b639f8d59..c66c79771298 100644 --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -56,6 +56,10 @@ namespace llvm { /// ForeachLoop - Record the iteration state associated with a for loop. /// This is used to instantiate items in the loop body. + /// + /// IterVar is allowed to be null, in which case no iteration variable is + /// defined in the loop at all. (This happens when a ForeachLoop is + /// constructed by desugaring an if statement.) struct ForeachLoop { SMLoc Loc; VarInit *IterVar; @@ -70,10 +74,50 @@ namespace llvm { struct DefsetRecord { SMLoc Loc; - RecTy *EltTy; + RecTy *EltTy = nullptr; SmallVector<Init *, 16> Elements; }; +class TGLocalVarScope { + // A scope to hold local variable definitions from defvar. + std::map<std::string, Init *, std::less<>> vars; + std::unique_ptr<TGLocalVarScope> parent; + +public: + TGLocalVarScope() = default; + TGLocalVarScope(std::unique_ptr<TGLocalVarScope> parent) + : parent(std::move(parent)) {} + + std::unique_ptr<TGLocalVarScope> extractParent() { + // This is expected to be called just before we are destructed, so + // it doesn't much matter what state we leave 'parent' in. + return std::move(parent); + } + + Init *getVar(StringRef Name) const { + auto It = vars.find(Name); + if (It != vars.end()) + return It->second; + if (parent) + return parent->getVar(Name); + return nullptr; + } + + bool varAlreadyDefined(StringRef Name) const { + // When we check whether a variable is already defined, for the purpose of + // reporting an error on redefinition, we don't look up to the parent + // scope, because it's all right to shadow an outer definition with an + // inner one. + return vars.find(Name) != vars.end(); + } + + void addVar(StringRef Name, Init *I) { + bool Ins = vars.insert(std::make_pair(Name, I)).second; + (void)Ins; + assert(Ins && "Local variable already exists"); + } +}; + struct MultiClass { Record Rec; // Placeholder for template args and Name. std::vector<RecordsEntry> Entries; @@ -99,6 +143,10 @@ class TGParser { /// current value. MultiClass *CurMultiClass; + /// CurLocalScope - Innermost of the current nested scopes for 'defvar' local + /// variables. + std::unique_ptr<TGLocalVarScope> CurLocalScope; + // Record tracker RecordKeeper &Records; @@ -114,9 +162,9 @@ class TGParser { }; public: - TGParser(SourceMgr &SrcMgr, ArrayRef<std::string> Macros, + TGParser(SourceMgr &SM, ArrayRef<std::string> Macros, RecordKeeper &records) - : Lex(SrcMgr, Macros), CurMultiClass(nullptr), Records(records) {} + : Lex(SM, Macros), CurMultiClass(nullptr), Records(records) {} /// ParseFile - Main entrypoint for parsing a tblgen file. These parser /// routines return true on error, or false on success. @@ -129,11 +177,24 @@ public: bool TokError(const Twine &Msg) const { return Error(Lex.getLoc(), Msg); } - const TGLexer::DependenciesMapTy &getDependencies() const { + const TGLexer::DependenciesSetTy &getDependencies() const { return Lex.getDependencies(); } -private: // Semantic analysis methods. + TGLocalVarScope *PushLocalScope() { + CurLocalScope = std::make_unique<TGLocalVarScope>(std::move(CurLocalScope)); + // Returns a pointer to the new scope, so that the caller can pass it back + // to PopLocalScope which will check by assertion that the pushes and pops + // match up properly. + return CurLocalScope.get(); + } + void PopLocalScope(TGLocalVarScope *ExpectedStackTop) { + assert(ExpectedStackTop == CurLocalScope.get() && + "Mismatched pushes and pops of local variable scopes"); + CurLocalScope = CurLocalScope->extractParent(); + } + +private: // Semantic analysis methods. bool AddValue(Record *TheRec, SMLoc Loc, const RecordVal &RV); bool SetValue(Record *TheRec, SMLoc Loc, Init *ValName, ArrayRef<unsigned> BitList, Init *V, @@ -161,7 +222,10 @@ private: // Parser methods. bool ParseDefm(MultiClass *CurMultiClass); bool ParseDef(MultiClass *CurMultiClass); bool ParseDefset(); + bool ParseDefvar(); bool ParseForeach(MultiClass *CurMultiClass); + bool ParseIf(MultiClass *CurMultiClass); + bool ParseIfBody(MultiClass *CurMultiClass, StringRef Kind); bool ParseTopLevelLet(MultiClass *CurMultiClass); void ParseLetList(SmallVectorImpl<LetRecord> &Result); |