[llvm] acf6811 - [TableGen] Support type aliases via new keyword deftype

via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 2 01:41:51 PST 2024


Author: Wang Pengcheng
Date: 2024-02-02T17:41:47+08:00
New Revision: acf6811d0f2b6b453be46ddf7e046e1346991c98

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

LOG: [TableGen] Support type aliases via new keyword deftype

We can use `deftype` (not using `typedef` here to be consistent
with `def`, `defm`, `defset`, `defvar`, etc) to define type aliases.

Currently, only primitive types and type aliases are supported to be
the source type and `deftype` statements can only appear at the top
level.

Reviewers: fpetrogalli, Artem-B, nhaehnle, jroelofs

Reviewed By: jroelofs, nhaehnle, Artem-B

Pull Request: https://github.com/llvm/llvm-project/pull/79570

Added: 
    llvm/test/TableGen/deftype.td

Modified: 
    llvm/docs/ReleaseNotes.rst
    llvm/docs/TableGen/ProgRef.rst
    llvm/lib/TableGen/TGLexer.cpp
    llvm/lib/TableGen/TGLexer.h
    llvm/lib/TableGen/TGParser.cpp
    llvm/lib/TableGen/TGParser.h

Removed: 
    


################################################################################
diff  --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index ad5b2ec1219e0..93c906642c5aa 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -59,6 +59,8 @@ Changes to building LLVM
 Changes to TableGen
 -------------------
 
+- We can define type aliases via new keyword ``deftype``.
+
 Changes to Interprocedural Optimizations
 ----------------------------------------
 

diff  --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index 59ddef975c487..45fda317ef643 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -570,8 +570,8 @@ files.
 .. productionlist::
    TableGenFile: (`Statement` | `IncludeDirective`
             :| `PreprocessorDirective`)*
-   Statement: `Assert` | `Class` | `Def` | `Defm` | `Defset` | `Defvar`
-            :| `Dump`  | `Foreach` | `If` | `Let` | `MultiClass`
+   Statement: `Assert` | `Class` | `Def` | `Defm` | `Defset` | `Deftype`
+            :| `Defvar` | `Dump`  | `Foreach` | `If` | `Let` | `MultiClass`
 
 The following sections describe each of these top-level statements.
 
@@ -1215,6 +1215,20 @@ set.
 Anonymous records created inside initialization expressions using the
 ``ClassID<...>`` syntax are not collected in the set.
 
+``deftype`` --- define a type
+--------------------------------
+
+A ``deftype`` statement defines a type. The type can be used throughout the
+statements that follow the definition.
+
+.. productionlist::
+   Deftype: "deftype" `TokIdentifier` "=" `Type` ";"
+
+The identifier on the left of the ``=`` is defined to be a type name
+whose actual type is given by the type expression on the right of the ``=``.
+
+Currently, only primitive types and type aliases are supported to be the source
+type and `deftype` statements can only appear at the top level.
 
 ``defvar`` --- define a variable
 --------------------------------

diff  --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index c811a67d930d4..545643234f699 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -360,6 +360,7 @@ tgtok::TokKind TGLexer::LexIdentifier() {
                             .Case("foreach", tgtok::Foreach)
                             .Case("defm", tgtok::Defm)
                             .Case("defset", tgtok::Defset)
+                            .Case("deftype", tgtok::Deftype)
                             .Case("multiclass", tgtok::MultiClass)
                             .Case("field", tgtok::Field)
                             .Case("let", tgtok::Let)

diff  --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index 2e2aa59f34408..25dcd9fbadef7 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -97,6 +97,7 @@ enum TokKind {
   Def,
   Defm,
   Defset,
+  Deftype,
   Defvar,
   Dump,
   Foreach,

diff  --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index e7dcb91ba20a6..f899fdb68f758 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1103,11 +1103,17 @@ RecTy *TGParser::ParseType() {
   case tgtok::Dag:
     Lex.Lex();
     return DagRecTy::get(Records);
-  case tgtok::Id:
+  case tgtok::Id: {
+    auto I = TypeAliases.find(Lex.getCurStrVal());
+    if (I != TypeAliases.end()) {
+      Lex.Lex();
+      return I->second;
+    }
     if (Record *R = ParseClassID())
       return RecordRecTy::get(R);
     TokError("unknown class name");
     return nullptr;
+  }
   case tgtok::Bits: {
     if (Lex.Lex() != tgtok::less) { // Eat 'bits'
       TokError("expected '<' after bits type");
@@ -3665,6 +3671,42 @@ bool TGParser::ParseDefset() {
   return false;
 }
 
+/// ParseDeftype - Parse a defvar statement.
+///
+///   Deftype ::= DEFTYPE Id '=' Type ';'
+///
+bool TGParser::ParseDeftype() {
+  assert(Lex.getCode() == tgtok::Deftype);
+  Lex.Lex(); // Eat the 'deftype' token
+
+  if (Lex.getCode() != tgtok::Id)
+    return TokError("expected identifier");
+
+  const std::string TypeName = Lex.getCurStrVal();
+  if (TypeAliases.count(TypeName) || Records.getClass(TypeName))
+    return TokError("type of this name '" + TypeName + "' already exists");
+
+  Lex.Lex();
+  if (!consume(tgtok::equal))
+    return TokError("expected '='");
+
+  SMLoc Loc = Lex.getLoc();
+  RecTy *Type = ParseType();
+  if (!Type)
+    return true;
+
+  if (Type->getRecTyKind() == RecTy::RecordRecTyKind)
+    return Error(Loc, "cannot define type alias for class type '" +
+                          Type->getAsString() + "'");
+
+  TypeAliases[TypeName] = Type;
+
+  if (!consume(tgtok::semi))
+    return TokError("expected ';'");
+
+  return false;
+}
+
 /// ParseDefvar - Parse a defvar statement.
 ///
 ///   Defvar ::= DEFVAR Id '=' Value ';'
@@ -3914,7 +3956,8 @@ bool TGParser::ParseClass() {
   if (Lex.getCode() != tgtok::Id)
     return TokError("expected class name after 'class' keyword");
 
-  Record *CurRec = Records.getClass(Lex.getCurStrVal());
+  const std::string &Name = Lex.getCurStrVal();
+  Record *CurRec = Records.getClass(Name);
   if (CurRec) {
     // If the body was previously defined, this is an error.
     if (!CurRec->getValues().empty() ||
@@ -3931,6 +3974,10 @@ bool TGParser::ParseClass() {
     CurRec = NewRec.get();
     Records.addClass(std::move(NewRec));
   }
+
+  if (TypeAliases.count(Name))
+    return TokError("there is already a defined type alias '" + Name + "'");
+
   Lex.Lex(); // eat the name.
 
   // A class definition introduces a new scope.
@@ -4265,6 +4312,7 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
 ///   Object ::= LETCommand '{' ObjectList '}'
 ///   Object ::= LETCommand Object
 ///   Object ::= Defset
+///   Object ::= Deftype
 ///   Object ::= Defvar
 ///   Object ::= Assert
 ///   Object ::= Dump
@@ -4276,6 +4324,8 @@ bool TGParser::ParseObject(MultiClass *MC) {
   case tgtok::Assert:  return ParseAssert(MC);
   case tgtok::Def:     return ParseDef(MC);
   case tgtok::Defm:    return ParseDefm(MC);
+  case tgtok::Deftype:
+    return ParseDeftype();
   case tgtok::Defvar:  return ParseDefvar();
   case tgtok::Dump:
     return ParseDump(MC);

diff  --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h
index 0929154fed3d4..b08e250870901 100644
--- a/llvm/lib/TableGen/TGParser.h
+++ b/llvm/lib/TableGen/TGParser.h
@@ -143,6 +143,7 @@ class TGParser {
   TGLexer Lex;
   std::vector<SmallVector<LetRecord, 4>> LetStack;
   std::map<std::string, std::unique_ptr<MultiClass>> MultiClasses;
+  std::map<std::string, RecTy *> TypeAliases;
 
   /// Loops - Keep track of any foreach loops we are within.
   ///
@@ -264,6 +265,7 @@ class TGParser {
   bool ParseDefm(MultiClass *CurMultiClass);
   bool ParseDef(MultiClass *CurMultiClass);
   bool ParseDefset();
+  bool ParseDeftype();
   bool ParseDefvar(Record *CurRec = nullptr);
   bool ParseDump(MultiClass *CurMultiClass, Record *CurRec = nullptr);
   bool ParseForeach(MultiClass *CurMultiClass);

diff  --git a/llvm/test/TableGen/deftype.td b/llvm/test/TableGen/deftype.td
new file mode 100644
index 0000000000000..7323fc77c35dc
--- /dev/null
+++ b/llvm/test/TableGen/deftype.td
@@ -0,0 +1,70 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
+// RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s
+// RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s
+// RUN: not llvm-tblgen -DERROR4 %s 2>&1 | FileCheck --check-prefix=ERROR4 %s
+// RUN: not llvm-tblgen -DERROR5 %s 2>&1 | FileCheck --check-prefix=ERROR5 %s
+
+class Class<int v> {
+  int value = v;
+}
+
+deftype StringAlias    = string;
+deftype CodeAlias      = code;
+deftype DagAlias       = dag;
+deftype Boolean        = bit;
+deftype Byte           = bits<8>;
+deftype Integer        = int;
+deftype IntList        = list<int>;
+deftype ByteList       = list<Byte>;
+deftype ClassList      = list<Class>;
+// The type can be another type alias.
+deftype ClassListAlias = ClassList;
+
+// CHECK:      def test {
+// CHECK-NEXT:   string str = "string";
+// CHECK-NEXT:   string codeStr = "code";
+// CHECK-NEXT:   dag dagExpr = ("string" "code");
+// CHECK-NEXT:   bit bool = 0;
+// CHECK-NEXT:   bits<8> byte = { 0, 1, 1, 1, 1, 0, 1, 1 };
+// CHECK-NEXT:   int integer = 123;
+// CHECK-NEXT:   list<int> ints = [1, 2, 3];
+// CHECK-NEXT:   list<bits<8>> bytes = [{ 0, 0, 0, 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 1, 1 }];
+// CHECK-NEXT:   list<Class> defs = [anonymous_0, anonymous_1, anonymous_2];
+// CHECK-NEXT: }
+def test {
+  StringAlias    str     = "string";
+  CodeAlias      codeStr = "code";
+  DagAlias       dagExpr = (str codeStr);
+  Boolean        bool    = false;
+  Byte           byte    = 123;
+  Integer        integer = 123;
+  IntList        ints    = [1, 2, 3];
+  ByteList       bytes   = [1, 2, 3];
+  ClassListAlias defs    = [Class<1>, Class<2>, Class<3>];
+}
+
+#ifdef ERROR1
+// ERROR1: [[@LINE+1]]:9: error: type of this name 'Byte' already exists
+deftype Byte = bits<8>;
+#endif
+
+#ifdef ERROR2
+// ERROR2: [[@LINE+1]]:9: error: type of this name 'Class' already exists
+deftype Class = int;
+#endif
+
+#ifdef ERROR3
+// ERROR3: [[@LINE+1]]:22: error: cannot define type alias for class type 'Class'
+deftype ClassAlias = Class;
+#endif
+
+#ifdef ERROR4
+// ERROR4: [[@LINE+1]]:7: error: there is already a defined type alias 'Byte'
+class Byte; // incomplete class definition.
+#endif
+
+#ifdef ERROR5
+// ERROR5: [[@LINE+1]]:7: error: there is already a defined type alias 'Byte'
+class Byte {}
+#endif


        


More information about the llvm-commits mailing list