summaryrefslogtreecommitdiff
path: root/llvm/lib/TableGen
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
commit706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch)
tree4adf86a776049cbf7f69a1929c4babcbbef925eb /llvm/lib/TableGen
parent7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff)
Notes
Diffstat (limited to 'llvm/lib/TableGen')
-rw-r--r--llvm/lib/TableGen/Main.cpp2
-rw-r--r--llvm/lib/TableGen/Record.cpp57
-rw-r--r--llvm/lib/TableGen/TGLexer.cpp16
-rw-r--r--llvm/lib/TableGen/TGLexer.h26
-rw-r--r--llvm/lib/TableGen/TGParser.cpp258
-rw-r--r--llvm/lib/TableGen/TGParser.h74
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);