Skip to content

Commit b53c658

Browse files
wangpc-ppagozillon
authored andcommitted
[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: llvm#79570
1 parent 0053154 commit b53c658

File tree

7 files changed

+144
-4
lines changed

7 files changed

+144
-4
lines changed

llvm/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ Changes to building LLVM
5959
Changes to TableGen
6060
-------------------
6161

62+
- We can define type aliases via new keyword ``deftype``.
63+
6264
Changes to Interprocedural Optimizations
6365
----------------------------------------
6466

llvm/docs/TableGen/ProgRef.rst

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,8 @@ files.
570570
.. productionlist::
571571
TableGenFile: (`Statement` | `IncludeDirective`
572572
:| `PreprocessorDirective`)*
573-
Statement: `Assert` | `Class` | `Def` | `Defm` | `Defset` | `Defvar`
574-
:| `Dump` | `Foreach` | `If` | `Let` | `MultiClass`
573+
Statement: `Assert` | `Class` | `Def` | `Defm` | `Defset` | `Deftype`
574+
:| `Defvar` | `Dump` | `Foreach` | `If` | `Let` | `MultiClass`
575575

576576
The following sections describe each of these top-level statements.
577577

@@ -1215,6 +1215,20 @@ set.
12151215
Anonymous records created inside initialization expressions using the
12161216
``ClassID<...>`` syntax are not collected in the set.
12171217

1218+
``deftype`` --- define a type
1219+
--------------------------------
1220+
1221+
A ``deftype`` statement defines a type. The type can be used throughout the
1222+
statements that follow the definition.
1223+
1224+
.. productionlist::
1225+
Deftype: "deftype" `TokIdentifier` "=" `Type` ";"
1226+
1227+
The identifier on the left of the ``=`` is defined to be a type name
1228+
whose actual type is given by the type expression on the right of the ``=``.
1229+
1230+
Currently, only primitive types and type aliases are supported to be the source
1231+
type and `deftype` statements can only appear at the top level.
12181232

12191233
``defvar`` --- define a variable
12201234
--------------------------------

llvm/lib/TableGen/TGLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ tgtok::TokKind TGLexer::LexIdentifier() {
360360
.Case("foreach", tgtok::Foreach)
361361
.Case("defm", tgtok::Defm)
362362
.Case("defset", tgtok::Defset)
363+
.Case("deftype", tgtok::Deftype)
363364
.Case("multiclass", tgtok::MultiClass)
364365
.Case("field", tgtok::Field)
365366
.Case("let", tgtok::Let)

llvm/lib/TableGen/TGLexer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ enum TokKind {
9797
Def,
9898
Defm,
9999
Defset,
100+
Deftype,
100101
Defvar,
101102
Dump,
102103
Foreach,

llvm/lib/TableGen/TGParser.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,11 +1103,17 @@ RecTy *TGParser::ParseType() {
11031103
case tgtok::Dag:
11041104
Lex.Lex();
11051105
return DagRecTy::get(Records);
1106-
case tgtok::Id:
1106+
case tgtok::Id: {
1107+
auto I = TypeAliases.find(Lex.getCurStrVal());
1108+
if (I != TypeAliases.end()) {
1109+
Lex.Lex();
1110+
return I->second;
1111+
}
11071112
if (Record *R = ParseClassID())
11081113
return RecordRecTy::get(R);
11091114
TokError("unknown class name");
11101115
return nullptr;
1116+
}
11111117
case tgtok::Bits: {
11121118
if (Lex.Lex() != tgtok::less) { // Eat 'bits'
11131119
TokError("expected '<' after bits type");
@@ -3665,6 +3671,42 @@ bool TGParser::ParseDefset() {
36653671
return false;
36663672
}
36673673

3674+
/// ParseDeftype - Parse a defvar statement.
3675+
///
3676+
/// Deftype ::= DEFTYPE Id '=' Type ';'
3677+
///
3678+
bool TGParser::ParseDeftype() {
3679+
assert(Lex.getCode() == tgtok::Deftype);
3680+
Lex.Lex(); // Eat the 'deftype' token
3681+
3682+
if (Lex.getCode() != tgtok::Id)
3683+
return TokError("expected identifier");
3684+
3685+
const std::string TypeName = Lex.getCurStrVal();
3686+
if (TypeAliases.count(TypeName) || Records.getClass(TypeName))
3687+
return TokError("type of this name '" + TypeName + "' already exists");
3688+
3689+
Lex.Lex();
3690+
if (!consume(tgtok::equal))
3691+
return TokError("expected '='");
3692+
3693+
SMLoc Loc = Lex.getLoc();
3694+
RecTy *Type = ParseType();
3695+
if (!Type)
3696+
return true;
3697+
3698+
if (Type->getRecTyKind() == RecTy::RecordRecTyKind)
3699+
return Error(Loc, "cannot define type alias for class type '" +
3700+
Type->getAsString() + "'");
3701+
3702+
TypeAliases[TypeName] = Type;
3703+
3704+
if (!consume(tgtok::semi))
3705+
return TokError("expected ';'");
3706+
3707+
return false;
3708+
}
3709+
36683710
/// ParseDefvar - Parse a defvar statement.
36693711
///
36703712
/// Defvar ::= DEFVAR Id '=' Value ';'
@@ -3914,7 +3956,8 @@ bool TGParser::ParseClass() {
39143956
if (Lex.getCode() != tgtok::Id)
39153957
return TokError("expected class name after 'class' keyword");
39163958

3917-
Record *CurRec = Records.getClass(Lex.getCurStrVal());
3959+
const std::string &Name = Lex.getCurStrVal();
3960+
Record *CurRec = Records.getClass(Name);
39183961
if (CurRec) {
39193962
// If the body was previously defined, this is an error.
39203963
if (!CurRec->getValues().empty() ||
@@ -3931,6 +3974,10 @@ bool TGParser::ParseClass() {
39313974
CurRec = NewRec.get();
39323975
Records.addClass(std::move(NewRec));
39333976
}
3977+
3978+
if (TypeAliases.count(Name))
3979+
return TokError("there is already a defined type alias '" + Name + "'");
3980+
39343981
Lex.Lex(); // eat the name.
39353982

39363983
// A class definition introduces a new scope.
@@ -4265,6 +4312,7 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
42654312
/// Object ::= LETCommand '{' ObjectList '}'
42664313
/// Object ::= LETCommand Object
42674314
/// Object ::= Defset
4315+
/// Object ::= Deftype
42684316
/// Object ::= Defvar
42694317
/// Object ::= Assert
42704318
/// Object ::= Dump
@@ -4276,6 +4324,8 @@ bool TGParser::ParseObject(MultiClass *MC) {
42764324
case tgtok::Assert: return ParseAssert(MC);
42774325
case tgtok::Def: return ParseDef(MC);
42784326
case tgtok::Defm: return ParseDefm(MC);
4327+
case tgtok::Deftype:
4328+
return ParseDeftype();
42794329
case tgtok::Defvar: return ParseDefvar();
42804330
case tgtok::Dump:
42814331
return ParseDump(MC);

llvm/lib/TableGen/TGParser.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class TGParser {
143143
TGLexer Lex;
144144
std::vector<SmallVector<LetRecord, 4>> LetStack;
145145
std::map<std::string, std::unique_ptr<MultiClass>> MultiClasses;
146+
std::map<std::string, RecTy *> TypeAliases;
146147

147148
/// Loops - Keep track of any foreach loops we are within.
148149
///
@@ -264,6 +265,7 @@ class TGParser {
264265
bool ParseDefm(MultiClass *CurMultiClass);
265266
bool ParseDef(MultiClass *CurMultiClass);
266267
bool ParseDefset();
268+
bool ParseDeftype();
267269
bool ParseDefvar(Record *CurRec = nullptr);
268270
bool ParseDump(MultiClass *CurMultiClass, Record *CurRec = nullptr);
269271
bool ParseForeach(MultiClass *CurMultiClass);

llvm/test/TableGen/deftype.td

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: llvm-tblgen %s | FileCheck %s
2+
// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
3+
// RUN: not llvm-tblgen -DERROR2 %s 2>&1 | FileCheck --check-prefix=ERROR2 %s
4+
// RUN: not llvm-tblgen -DERROR3 %s 2>&1 | FileCheck --check-prefix=ERROR3 %s
5+
// RUN: not llvm-tblgen -DERROR4 %s 2>&1 | FileCheck --check-prefix=ERROR4 %s
6+
// RUN: not llvm-tblgen -DERROR5 %s 2>&1 | FileCheck --check-prefix=ERROR5 %s
7+
8+
class Class<int v> {
9+
int value = v;
10+
}
11+
12+
deftype StringAlias = string;
13+
deftype CodeAlias = code;
14+
deftype DagAlias = dag;
15+
deftype Boolean = bit;
16+
deftype Byte = bits<8>;
17+
deftype Integer = int;
18+
deftype IntList = list<int>;
19+
deftype ByteList = list<Byte>;
20+
deftype ClassList = list<Class>;
21+
// The type can be another type alias.
22+
deftype ClassListAlias = ClassList;
23+
24+
// CHECK: def test {
25+
// CHECK-NEXT: string str = "string";
26+
// CHECK-NEXT: string codeStr = "code";
27+
// CHECK-NEXT: dag dagExpr = ("string" "code");
28+
// CHECK-NEXT: bit bool = 0;
29+
// CHECK-NEXT: bits<8> byte = { 0, 1, 1, 1, 1, 0, 1, 1 };
30+
// CHECK-NEXT: int integer = 123;
31+
// CHECK-NEXT: list<int> ints = [1, 2, 3];
32+
// 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 }];
33+
// CHECK-NEXT: list<Class> defs = [anonymous_0, anonymous_1, anonymous_2];
34+
// CHECK-NEXT: }
35+
def test {
36+
StringAlias str = "string";
37+
CodeAlias codeStr = "code";
38+
DagAlias dagExpr = (str codeStr);
39+
Boolean bool = false;
40+
Byte byte = 123;
41+
Integer integer = 123;
42+
IntList ints = [1, 2, 3];
43+
ByteList bytes = [1, 2, 3];
44+
ClassListAlias defs = [Class<1>, Class<2>, Class<3>];
45+
}
46+
47+
#ifdef ERROR1
48+
// ERROR1: [[@LINE+1]]:9: error: type of this name 'Byte' already exists
49+
deftype Byte = bits<8>;
50+
#endif
51+
52+
#ifdef ERROR2
53+
// ERROR2: [[@LINE+1]]:9: error: type of this name 'Class' already exists
54+
deftype Class = int;
55+
#endif
56+
57+
#ifdef ERROR3
58+
// ERROR3: [[@LINE+1]]:22: error: cannot define type alias for class type 'Class'
59+
deftype ClassAlias = Class;
60+
#endif
61+
62+
#ifdef ERROR4
63+
// ERROR4: [[@LINE+1]]:7: error: there is already a defined type alias 'Byte'
64+
class Byte; // incomplete class definition.
65+
#endif
66+
67+
#ifdef ERROR5
68+
// ERROR5: [[@LINE+1]]:7: error: there is already a defined type alias 'Byte'
69+
class Byte {}
70+
#endif

0 commit comments

Comments
 (0)