Update the Programmer's Reference document.
Add a test. Update a couple of tests with an improved error message.
Differential Revision: https://reviews.llvm.org/D90635
begin with an integer. In case of ambiguity, a token is interpreted as a
numeric literal rather than an identifier.
-TableGen has the following reserved words, which cannot be used as
+TableGen has the following reserved keywords, which cannot be used as
identifiers::
bit bits class code dag
- def else foreach defm defset
- defvar field if in include
- int let list multiclass string
- then
+ def else false foreach defm
+ defset defvar field if in
+ include int let list multiclass
+ string then true
.. warning::
The ``field`` reserved word is deprecated.
strings and then are indistinguishable from them.
.. productionlist::
- SimpleValue2: "?"
+ SimpleValue2: "true" | "false"
+
+The ``true`` and ``false`` literals are essentially syntactic sugar for the
+integer values 1 and 0. They improve the readability of TableGen files when
+boolean values are used in field values, bit sequences, ``if`` statements.
+etc. When parsed, these literals are converted to integers.
+
+.. productionlist::
+ SimpleValue3: "?"
A question mark represents an uninitialized value.
.. productionlist::
- SimpleValue3: "{" [`ValueList`] "}"
+ SimpleValue4: "{" [`ValueList`] "}"
ValueList: `ValueListNE`
ValueListNE: `Value` ("," `Value`)*
must represent a total of *n* bits.
.. productionlist::
- SimpleValue4: "[" `ValueList` "]" ["<" `Type` ">"]
+ SimpleValue5: "[" `ValueList` "]" ["<" `Type` ">"]
This value is a list initializer (note the brackets). The values in brackets
are the elements of the list. The optional :token:`Type` can be used to
sometimes not when the value is the empty list (``[]``).
.. productionlist::
- SimpleValue5: "(" `DagArg` [`DagArgList`] ")"
+ SimpleValue6: "(" `DagArg` [`DagArgList`] ")"
DagArgList: `DagArg` ("," `DagArg`)*
DagArg: `Value` [":" `TokVarName`] | `TokVarName`
See `Directed acyclic graphs (DAGs)`_ for more details.
.. productionlist::
- SimpleValue6: `TokIdentifier`
+ SimpleValue7: `TokIdentifier`
The resulting value is the value of the entity named by the identifier. The
possible identifiers are described here, but the descriptions will make more
def Foo#i;
.. productionlist::
- SimpleValue7: `ClassID` "<" `ValueListNE` ">"
+ SimpleValue8: `ClassID` "<" `ValueListNE` ">"
This form creates a new anonymous record definition (as would be created by an
unnamed ``def`` inheriting from the given class with the given template
See `Using Classes as Subroutines`_ for more information.
.. productionlist::
- SimpleValue8: `BangOperator` ["<" `Type` ">"] "(" `ValueListNE` ")"
+ SimpleValue9: `BangOperator` ["<" `Type` ">"] "(" `ValueListNE` ")"
:| `CondOperator` "(" `CondClause` ("," `CondClause`)* ")"
CondClause: `Value` ":" `Value`
case EOF:
// Lex next token, if we just left an include file.
// Note that leaving an include file means that the next
- // symbol is located at the end of 'include "..."'
+ // symbol is located at the end of the 'include "..."'
// construct, so LexToken() is called with default
// false parameter.
if (processEOF())
while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_')
++CurPtr;
- // Check to see if this identifier is a keyword.
+ // Check to see if this identifier is a reserved keyword.
StringRef Str(IdentStart, CurPtr-IdentStart);
- if (Str == "include") {
- if (LexInclude()) return tgtok::Error;
- return Lex();
- }
-
tgtok::TokKind Kind = StringSwitch<tgtok::TokKind>(Str)
.Case("int", tgtok::Int)
.Case("bit", tgtok::Bit)
.Case("dag", tgtok::Dag)
.Case("class", tgtok::Class)
.Case("def", tgtok::Def)
+ .Case("true", tgtok::TrueVal)
+ .Case("false", tgtok::FalseVal)
.Case("foreach", tgtok::Foreach)
.Case("defm", tgtok::Defm)
.Case("defset", tgtok::Defset)
.Case("let", tgtok::Let)
.Case("in", tgtok::In)
.Case("defvar", tgtok::Defvar)
+ .Case("include", tgtok::Include)
.Case("if", tgtok::If)
.Case("then", tgtok::Then)
.Case("else", tgtok::ElseKW)
.Default(tgtok::Id);
- if (Kind == tgtok::Id)
- CurStrVal.assign(Str.begin(), Str.end());
+ // A couple of tokens require special processing.
+ switch (Kind) {
+ case tgtok::Include:
+ if (LexInclude()) return tgtok::Error;
+ return Lex();
+ case tgtok::Id:
+ CurStrVal.assign(Str.begin(), Str.end());
+ break;
+ default:
+ break;
+ }
+
return Kind;
}
paste, // #
dotdotdot, // ...
- // 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, Defvar, If, Then, ElseKW,
+ // Reserved keywords. ('ElseKW' is named to distinguish it from the
+ // existing 'Else' that means the preprocessor #else.)
+ Bit, Bits, Class, Code, Dag, Def, Defm, Defset, Defvar, ElseKW, FalseKW,
+ Field, Foreach, If, In, Include, Int, Let, List, MultiClass,
+ String, Then, TrueKW,
- // !keywords.
+ // Bang operators.
XConcat, XADD, XSUB, XMUL, XNOT, XAND, XOR, XXOR, XSRA, XSRL, XSHL,
XListConcat, XListSplat, XStrConcat, XInterleave, XCast, XSubst, XForEach,
XFoldl, XHead, XTail, XSize, XEmpty, XIf, XCond, XEq, XIsA, XDag, XNe,
XLe, XLt, XGe, XGt, XSetDagOp, XGetDagOp,
+ // Boolean literals.
+ TrueVal, FalseVal,
+
// Integer value.
IntVal,
IDParseMode Mode) {
Init *R = nullptr;
switch (Lex.getCode()) {
- default: TokError("Unknown token when parsing a value"); break;
- case tgtok::IntVal: R = IntInit::get(Lex.getCurIntVal()); Lex.Lex(); break;
+ default: TokError("Unknown or reserved token when parsing a value"); break;
+
+ case tgtok::TrueVal:
+ R = IntInit::get(1);
+ Lex.Lex();
+ break;
+ case tgtok::FalseVal:
+ R = IntInit::get(0);
+ Lex.Lex();
+ break;
+ case tgtok::IntVal:
+ R = IntInit::get(Lex.getCurIntVal());
+ Lex.Lex();
+ break;
case tgtok::BinaryIntVal: {
auto BinaryVal = Lex.getCurBinaryIntVal();
SmallVector<Init*, 16> Bits(BinaryVal.second);
if (!RHSResult)
return nullptr;
Result = BinOpInit::getListConcat(LHS, RHSResult);
+ break;
}
break;
}
// Check that !cond works well with bit conditional values.
-// CHECK: a = 6
-// CHECK: a = 5
-
-class A<bit b = 1> {
- bit True = 1;
- int a = !cond(b: 5, True : 6);
- bit c = !cond(b: 0, True : 1);
- bits<1> d = !cond(b: 0, True : 1);
+class A<bit b = true> {
+ int a = !cond(b: 5, true : 6);
+ bit c = !cond(b: false, true : true);
+ bits<1> d = !cond(b: 0, true : 1);
}
-def X : A<0>;
+// CHECK: def X
+// CHECK: a = 6
+// CHECK: c = 1
+// CHECK: d = { 1 }
+
+// CHECK: def Y
+// CHECK: a = 5
+// CHECK: c = 0
+// CHECK: d = { 0 }
+
+def X : A<false>;
def Y : A;
def Constants : ConstantsImpl;
-// CHECK-NOT: error: Unknown token when parsing a value
-// CHECK: [[FILE]]:[[@LINE+3]]:22: error: Unknown token when parsing a value
+// CHECK-NOT: error: Unknown or reserved token when parsing a value
+// CHECK: [[FILE]]:[[@LINE+3]]:22: error: Unknown or reserved token when parsing a value
// CHECK: [[FILE]]:[[@LINE+2]]:22: error: expected integer value as end of range
// CHECK: [[FILE]]:[[@LINE+1]]:22: error: expected declaration in for
foreach Index = 0 - in {
def list_paste {
list<string> the_list = list1 # in;
}
-// ERROR1: error: Unknown token when parsing a value
+// ERROR1: error: Unknown or reserved token when parsing a value
#endif
#ifdef ERROR2
def name_paste#in {
}
-// ERROR2: error: Unknown token when parsing a value
+// ERROR2: error: Unknown or reserved token when parsing a value
#endif
--- /dev/null
+// RUN: llvm-tblgen %s | FileCheck %s
+// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
+
+// Tests for the true and false literals.
+
+defvar otherwise = true;
+defvar do_it = true;
+
+// CHECK: def rec1
+// CHECK: bit flag1 = 1;
+// CHECK: bit flag2 = 0;
+// CHECK: int true_int = 1;
+
+def rec1 {
+ bit flag1 = true;
+ bit flag2 = false;
+ int true_int = true;
+}
+
+// CHECK: def rec2_true
+
+if true then
+ def rec2_true {}
+else
+ def rec2_bad {}
+
+// CHECK: def rec3_false
+
+if false then
+ def rec3_bad {}
+else
+ def rec3_false {}
+
+// CHECK: def rec4
+// CHECK: int value = 52;
+
+def rec4 {
+ int value = !add(10, !if(!and(do_it, true), 42, 0));
+}
+
+// CHECK: def rec5
+// CHECK: string name = "snork";
+
+def rec5 {
+ string name = !cond(false: "foo",
+ !not(do_it): "bar",
+ otherwise: "snork");
+}
+
+// CHECK: def rec6
+// CHECK: bit xorFF = 0;
+// CHECK: bit xorFT = 1;
+// CHECK: bit xorTF = 1;
+// CHECK: bit xorTT = 0;
+
+def rec6 {
+ bit xorFF = !xor(false, false);
+ bit xorFT = !xor(false, true);
+ bit xorTF = !xor(true, false);
+ bit xorTT = !xor(true, true);
+}
+
+// CHECK: def rec7
+// CHECK: bits<3> flags = { 1, 0, 1 };
+
+def rec7 {
+ bits<3> flags = { true, false, true };
+}
+
+#ifdef ERROR1
+// ERROR1: Record name '1' is not a string
+
+def true {}
+#endif
+