summaryrefslogtreecommitdiffstats
path: root/llvm/lib/TableGen/TGParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/TableGen/TGParser.cpp')
-rw-r--r--llvm/lib/TableGen/TGParser.cpp122
1 files changed, 92 insertions, 30 deletions
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 0dd4da416d9..d839c2ad623 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -981,28 +981,59 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
Lex.Lex(); // eat the operation
BinOpInit::BinaryOp Code;
- RecTy *Type = nullptr;
-
switch (OpTok) {
default: llvm_unreachable("Unhandled code!");
- case tgtok::XConcat: Code = BinOpInit::CONCAT;Type = DagRecTy::get(); break;
- case tgtok::XADD: Code = BinOpInit::ADD; Type = IntRecTy::get(); break;
- case tgtok::XAND: Code = BinOpInit::AND; Type = IntRecTy::get(); break;
- case tgtok::XOR: Code = BinOpInit::OR; Type = IntRecTy::get(); break;
- case tgtok::XSRA: Code = BinOpInit::SRA; Type = IntRecTy::get(); break;
- case tgtok::XSRL: Code = BinOpInit::SRL; Type = IntRecTy::get(); break;
- case tgtok::XSHL: Code = BinOpInit::SHL; Type = IntRecTy::get(); break;
- case tgtok::XEq: Code = BinOpInit::EQ; Type = BitRecTy::get(); break;
+ case tgtok::XConcat: Code = BinOpInit::CONCAT; break;
+ case tgtok::XADD: Code = BinOpInit::ADD; break;
+ case tgtok::XAND: Code = BinOpInit::AND; break;
+ case tgtok::XOR: Code = BinOpInit::OR; break;
+ case tgtok::XSRA: Code = BinOpInit::SRA; break;
+ case tgtok::XSRL: Code = BinOpInit::SRL; break;
+ case tgtok::XSHL: Code = BinOpInit::SHL; break;
+ case tgtok::XEq: Code = BinOpInit::EQ; break;
+ case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break;
+ case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break;
+ }
+
+ RecTy *Type = nullptr;
+ RecTy *ArgType = nullptr;
+ switch (OpTok) {
+ default:
+ llvm_unreachable("Unhandled code!");
+ case tgtok::XConcat:
+ Type = DagRecTy::get();
+ ArgType = DagRecTy::get();
+ break;
+ case tgtok::XAND:
+ case tgtok::XOR:
+ case tgtok::XSRA:
+ case tgtok::XSRL:
+ case tgtok::XSHL:
+ case tgtok::XADD:
+ Type = IntRecTy::get();
+ ArgType = IntRecTy::get();
+ break;
+ case tgtok::XEq:
+ Type = BitRecTy::get();
+ // ArgType for Eq is not known at this point
+ break;
case tgtok::XListConcat:
- Code = BinOpInit::LISTCONCAT;
// We don't know the list type until we parse the first argument
+ ArgType = ItemType;
break;
case tgtok::XStrConcat:
- Code = BinOpInit::STRCONCAT;
Type = StringRecTy::get();
+ ArgType = StringRecTy::get();
break;
}
+ if (Type && ItemType && !Type->typeIsConvertibleTo(ItemType)) {
+ Error(OpLoc, Twine("expected value of type '") +
+ ItemType->getAsString() + "', got '" +
+ Type->getAsString() + "'");
+ return nullptr;
+ }
+
if (Lex.getCode() != tgtok::l_paren) {
TokError("expected '(' after binary operator");
return nullptr;
@@ -1011,14 +1042,51 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
SmallVector<Init*, 2> InitList;
- InitList.push_back(ParseValue(CurRec));
- if (!InitList.back()) return nullptr;
+ for (;;) {
+ SMLoc InitLoc = Lex.getLoc();
+ InitList.push_back(ParseValue(CurRec, ArgType));
+ if (!InitList.back()) return nullptr;
- while (Lex.getCode() == tgtok::comma) {
- Lex.Lex(); // eat the ','
+ // All BinOps require their arguments to be of compatible types.
+ TypedInit *TI = dyn_cast<TypedInit>(InitList.back());
+ if (!ArgType) {
+ ArgType = TI->getType();
- InitList.push_back(ParseValue(CurRec));
- if (!InitList.back()) return nullptr;
+ switch (Code) {
+ case BinOpInit::LISTCONCAT:
+ if (!isa<ListRecTy>(ArgType)) {
+ Error(InitLoc, Twine("expected a list, got value of type '") +
+ ArgType->getAsString() + "'");
+ return nullptr;
+ }
+ break;
+ case BinOpInit::EQ:
+ if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) &&
+ !ArgType->typeIsConvertibleTo(StringRecTy::get())) {
+ Error(InitLoc, Twine("expected int, bits, or string; got value of "
+ "type '") + ArgType->getAsString() + "'");
+ return nullptr;
+ }
+ break;
+ default: llvm_unreachable("other ops have fixed argument types");
+ }
+ } else {
+ RecTy *Resolved = resolveTypes(ArgType, TI->getType());
+ if (!Resolved) {
+ Error(InitLoc, Twine("expected value of type '") +
+ ArgType->getAsString() + "', got '" +
+ TI->getType()->getAsString() + "'");
+ return nullptr;
+ }
+ if (Code != BinOpInit::ADD && Code != BinOpInit::AND &&
+ Code != BinOpInit::OR && Code != BinOpInit::SRA &&
+ Code != BinOpInit::SRL && Code != BinOpInit::SHL)
+ ArgType = Resolved;
+ }
+
+ if (Lex.getCode() != tgtok::comma)
+ break;
+ Lex.Lex(); // eat the ','
}
if (Lex.getCode() != tgtok::r_paren) {
@@ -1027,20 +1095,14 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
}
Lex.Lex(); // eat the ')'
- // If we are doing !listconcat, we should know the type by now
- if (OpTok == tgtok::XListConcat) {
- if (TypedInit *Arg0 = dyn_cast<TypedInit>(InitList[0]))
- Type = Arg0->getType();
- else {
- InitList[0]->print(errs());
- Error(OpLoc, "expected a list");
- return nullptr;
- }
- }
+ if (Code == BinOpInit::LISTCONCAT)
+ Type = ArgType;
// We allow multiple operands to associative operators like !strconcat as
// shorthand for nesting them.
- if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT) {
+ if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT ||
+ Code == BinOpInit::CONCAT || Code == BinOpInit::ADD ||
+ Code == BinOpInit::AND || Code == BinOpInit::OR) {
while (InitList.size() > 2) {
Init *RHS = InitList.pop_back_val();
RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type))
@@ -1896,7 +1958,7 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
break;
default:
- Init *RHSResult = ParseValue(CurRec, ItemType, ParseNameMode);
+ Init *RHSResult = ParseValue(CurRec, nullptr, ParseNameMode);
RHS = dyn_cast<TypedInit>(RHSResult);
if (!RHS) {
Error(PasteLoc, "RHS of paste is not typed!");
OpenPOWER on IntegriCloud