[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