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> LetStack; std::map> MultiClasses; + std::map 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 value = v; +} + +deftype StringAlias = string; +deftype CodeAlias = code; +deftype DagAlias = dag; +deftype Boolean = bit; +deftype Byte = bits<8>; +deftype Integer = int; +deftype IntList = list; +deftype ByteList = list; +deftype ClassList = list; +// 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 ints = [1, 2, 3]; +// CHECK-NEXT: list> 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 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