From 66c63456e206ffa9bda60efe7b168a391ad55216 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 10 Dec 2019 10:34:40 +0000 Subject: [PATCH] [TableGen] Permit dag operators to be unset. This is not a new semantic feature. The syntax `(? 1, 2, 3)` was disallowed by the parser in a dag //expression//, but there were already ways to sneak a `?` into the operator field of a dag //value//, e.g. by initializing it from a class template parameter which is then set to `?` by the instantiating `def`. This patch makes `?` in the operator slot syntactically legal, so it's now easy to construct dags with an unset operator. Also, the semantics of `!con` are relaxed so that it will allow a combination of set and unset operator fields in the dag nodes it's concatenating, with the restriction that all the operators that are //not// unset still have to agree with each other. Reviewers: hfinkel, nhaehnle Reviewed By: hfinkel, nhaehnle Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D71195 --- lib/TableGen/Record.cpp | 11 ++++++++--- lib/TableGen/TGParser.cpp | 3 ++- test/TableGen/unsetop.td | 24 ++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 test/TableGen/unsetop.td diff --git a/lib/TableGen/Record.cpp b/lib/TableGen/Record.cpp index 2ab7b98ca03..9405fb5ae4e 100644 --- a/lib/TableGen/Record.cpp +++ b/lib/TableGen/Record.cpp @@ -887,13 +887,18 @@ Init *BinOpInit::Fold(Record *CurRec) const { if (LHSs && RHSs) { DefInit *LOp = dyn_cast(LHSs->getOperator()); DefInit *ROp = dyn_cast(RHSs->getOperator()); - if (!LOp || !ROp) + if ((!LOp && !isa(LHSs->getOperator())) || + (!ROp && !isa(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 Args; SmallVector ArgNames; for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) { @@ -904,7 +909,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; } diff --git a/lib/TableGen/TGParser.cpp b/lib/TableGen/TGParser.cpp index c373e2899a5..2ac950b0b6f 100644 --- a/lib/TableGen/TGParser.cpp +++ b/lib/TableGen/TGParser.cpp @@ -2024,7 +2024,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) { TokError("expected identifier in dag init"); return nullptr; } diff --git a/test/TableGen/unsetop.td b/test/TableGen/unsetop.td new file mode 100644 index 00000000000..7a4f98aea45 --- /dev/null +++ b/test/TableGen/unsetop.td @@ -0,0 +1,24 @@ +// RUN: llvm-tblgen %s | FileCheck %s +// RUN: not llvm-tblgen -DERROR %s 2>&1 | FileCheck --check-prefix=ERROR %s + +def op; +def otherop; + +def test { + // CHECK: dag d = (? "hello":$world); + dag d = (? "hello":$world); + + // CHECK: dag undefNeither = (op 1, 2); + dag undefNeither = !con((op 1), (op 2)); + // CHECK: dag undefFirst = (op 1, 2); + dag undefFirst = !con((? 1), (op 2)); + // CHECK: dag undefSecond = (op 1, 2); + dag undefSecond = !con((op 1), (? 2)); + // CHECK: dag undefBoth = (? 1, 2); + dag undefBoth = !con((? 1), (? 2)); + +#ifdef ERROR + // ERROR: Concatenated Dag operators do not match: '(op 1)' vs. '(otherop 2)' + dag mismatch = !con((op 1), (otherop 2)); +#endif +}