[llvm] ae2cb4f - [TableGen] Add true and false literals to represent booleans

Paul C. Anagnostopoulos via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 5 06:07:53 PST 2020


Author: Paul C. Anagnostopoulos
Date: 2020-11-05T09:07:21-05:00
New Revision: ae2cb4f4273f2f2039e5c720d741f1e18e81943d

URL: https://github.com/llvm/llvm-project/commit/ae2cb4f4273f2f2039e5c720d741f1e18e81943d
DIFF: https://github.com/llvm/llvm-project/commit/ae2cb4f4273f2f2039e5c720d741f1e18e81943d.diff

LOG: [TableGen] Add true and false literals to represent booleans

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

Added: 
    llvm/test/TableGen/true-false.td

Modified: 
    llvm/docs/TableGen/ProgRef.rst
    llvm/lib/TableGen/TGLexer.cpp
    llvm/lib/TableGen/TGLexer.h
    llvm/lib/TableGen/TGParser.cpp
    llvm/test/TableGen/condsbit.td
    llvm/test/TableGen/foreach-range-parse-errors0.td
    llvm/test/TableGen/paste-reserved.td

Removed: 
    


################################################################################
diff  --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index 4d2d44f10d68..4b8365139715 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -196,14 +196,14 @@ Note that, unlike most languages, TableGen allows :token:`TokIdentifier` to
 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.
@@ -362,12 +362,20 @@ simple value is the concatenation of the strings. Code fragments become
 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`)*
 
@@ -376,7 +384,7 @@ This value represents a sequence of bits, which can be used to initialize a
 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
@@ -385,7 +393,7 @@ from the given values. TableGen can usually infer the type, although
 sometimes not when the value is the empty list (``[]``).
 
 .. productionlist::
-   SimpleValue5: "(" `DagArg` [`DagArgList`] ")"
+   SimpleValue6: "(" `DagArg` [`DagArgList`] ")"
    DagArgList: `DagArg` ("," `DagArg`)*
    DagArg: `Value` [":" `TokVarName`] | `TokVarName`
 
@@ -394,7 +402,7 @@ This represents a DAG initializer (note the parentheses).  The first
 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
@@ -453,7 +461,7 @@ sense after reading the remainder of this guide.
        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
@@ -464,7 +472,7 @@ Invoking a class in this manner can provide a simple subroutine facility.
 See `Using Classes as Subroutines`_ for more information.
 
 .. productionlist::
-   SimpleValue8: `BangOperator` ["<" `Type` ">"] "(" `ValueListNE` ")"
+   SimpleValue9: `BangOperator` ["<" `Type` ">"] "(" `ValueListNE` ")"
               :| `CondOperator` "(" `CondClause` ("," `CondClause`)* ")"
    CondClause: `Value` ":" `Value`
 

diff  --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index 7693f82ba7cc..7cbf9de24b83 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -150,7 +150,7 @@ tgtok::TokKind TGLexer::LexToken(bool FileOrLineStart) {
   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())
@@ -338,14 +338,9 @@ tgtok::TokKind TGLexer::LexIdentifier() {
   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)
@@ -356,6 +351,8 @@ tgtok::TokKind TGLexer::LexIdentifier() {
     .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)
@@ -364,13 +361,24 @@ tgtok::TokKind TGLexer::LexIdentifier() {
     .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;
 }
 

diff  --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index eaba640061fd..cf336aad6f21 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -45,17 +45,21 @@ namespace tgtok {
     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,
 

diff  --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 4f64f4be5401..cab1921fdd2a 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1850,8 +1850,20 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
                                  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);
@@ -2267,6 +2279,7 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
           if (!RHSResult)
             return nullptr;
           Result = BinOpInit::getListConcat(LHS, RHSResult);
+          break;
         }
         break;
       }

diff  --git a/llvm/test/TableGen/condsbit.td b/llvm/test/TableGen/condsbit.td
index 1409c0a6b6c6..d0dda7cbfe6b 100644
--- a/llvm/test/TableGen/condsbit.td
+++ b/llvm/test/TableGen/condsbit.td
@@ -3,15 +3,21 @@
 
 // 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;

diff  --git a/llvm/test/TableGen/foreach-range-parse-errors0.td b/llvm/test/TableGen/foreach-range-parse-errors0.td
index a3e6a9eb9756..2da5ce056346 100644
--- a/llvm/test/TableGen/foreach-range-parse-errors0.td
+++ b/llvm/test/TableGen/foreach-range-parse-errors0.td
@@ -10,8 +10,8 @@ class ConstantsImpl {
 
 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 {

diff  --git a/llvm/test/TableGen/paste-reserved.td b/llvm/test/TableGen/paste-reserved.td
index 8e61e5526d20..222a8c202a60 100644
--- a/llvm/test/TableGen/paste-reserved.td
+++ b/llvm/test/TableGen/paste-reserved.td
@@ -9,7 +9,7 @@ defvar list1 = ["foo", "bar", "snork"];
 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
 
 
@@ -18,5 +18,5 @@ def list_paste {
 #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

diff  --git a/llvm/test/TableGen/true-false.td b/llvm/test/TableGen/true-false.td
new file mode 100644
index 000000000000..597ad9f5ecc8
--- /dev/null
+++ b/llvm/test/TableGen/true-false.td
@@ -0,0 +1,75 @@
+// 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
+


        


More information about the llvm-commits mailing list