[llvm] [TableGen] Support automatic type deduction (PR #109434)

Rahul Joshi via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 24 09:50:12 PDT 2024


https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/109434

>From 0cdb0ed8384924a4c58cb3fc77f02824e8d76100 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Fri, 20 Sep 2024 06:21:13 -0700
Subject: [PATCH] [TableGen] Support automatic type deduction

Support 'auto' type when declaring class or def fields. Make 'auto'
a TableGen keyword and allow using it as a type when declaring class
or def fields. When auto is used, the field must have an initializer
from which its type can be infered.
---
 llvm/lib/TableGen/TGLexer.cpp  |  1 +
 llvm/lib/TableGen/TGLexer.h    |  1 +
 llvm/lib/TableGen/TGParser.cpp | 60 +++++++++++++++++++++++++++-------
 llvm/lib/TableGen/TGParser.h   |  3 +-
 llvm/test/TableGen/auto.td     | 44 +++++++++++++++++++++++++
 5 files changed, 97 insertions(+), 12 deletions(-)
 create mode 100644 llvm/test/TableGen/auto.td

diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index 8fe7f69ecf8e59..b45b037862ef60 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -383,6 +383,7 @@ tgtok::TokKind TGLexer::LexIdentifier() {
   StringRef Str(IdentStart, CurPtr-IdentStart);
 
   tgtok::TokKind Kind = StringSwitch<tgtok::TokKind>(Str)
+                            .Case("auto", tgtok::Auto)
                             .Case("int", tgtok::Int)
                             .Case("bit", tgtok::Bit)
                             .Case("bits", tgtok::Bits)
diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index 4fa4d84d0535d3..a87a2f36b9b699 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -75,6 +75,7 @@ enum TokKind {
 
   // Reserved keywords. ('ElseKW' is named to distinguish it from the
   // existing 'Else' that means the preprocessor #else.)
+  Auto,
   Bit,
   Bits,
   Code,
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 54c9a902ec27a1..08d4462140f19b 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -3262,13 +3262,19 @@ bool TGParser::ParseTemplateArgValueList(
 ///
 ///  Declaration ::= FIELD? Type ID ('=' Value)?
 ///
-Init *TGParser::ParseDeclaration(Record *CurRec,
-                                       bool ParsingTemplateArgs) {
+Init *TGParser::ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs,
+                                 bool AllowAuto = false) {
   // Read the field prefix if present.
   bool HasField = consume(tgtok::Field);
 
-  RecTy *Type = ParseType();
-  if (!Type) return nullptr;
+  RecTy *Type;
+  if (AllowAuto && consume(tgtok::Auto)) {
+    Type = nullptr;
+  } else {
+    Type = ParseType();
+    if (!Type)
+      return nullptr;
+  }
 
   if (Lex.getCode() != tgtok::Id) {
     TokError("Expected identifier in declaration");
@@ -3290,6 +3296,32 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
   Init *DeclName = StringInit::get(Records, Str);
   Lex.Lex();
 
+  bool HasValue = consume(tgtok::equal);
+
+  // When 'auto' is used, parse the value and infer the type based on the
+  // value's type.
+  SMLoc ValLoc;
+  Init *Val = nullptr;
+  if (!Type) {
+    if (!HasValue) {
+      // auto used without a value.
+      TokError("auto requires assigning a value");
+      return nullptr;
+    }
+    ValLoc = Lex.getLoc();
+    // When no item type is supplied to ParseValue, it will either infer the
+    // type from the value, or fail to parse
+    Val = ParseValue(CurRec);
+
+    // Infer type from the value.
+    if (TypedInit *TI = dyn_cast_or_null<TypedInit>(Val)) {
+      Type = TI->getType();
+    } else {
+      Error(ValLoc, "unable to infer type");
+      return nullptr;
+    }
+  }
+
   bool BadField;
   if (!ParsingTemplateArgs) { // def, possibly in a multiclass
     BadField = AddValue(CurRec, IdLoc,
@@ -3311,10 +3343,14 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
   if (BadField)
     return nullptr;
 
-  // If a value is present, parse it and set new field's value.
-  if (consume(tgtok::equal)) {
-    SMLoc ValLoc = Lex.getLoc();
-    Init *Val = ParseValue(CurRec, Type);
+  // For the non-auto case, if a value is present, parse it.
+  if (!Val && HasValue) {
+    ValLoc = Lex.getLoc();
+    Val = ParseValue(CurRec, Type);
+  }
+
+  // Set the new field's value.
+  if (HasValue) {
     if (!Val ||
         SetValue(CurRec, ValLoc, DeclName, {}, Val,
                  /*AllowSelfAssignment=*/false, /*OverrideDefLoc=*/false)) {
@@ -3423,7 +3459,7 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) {
   Record *TheRecToAddTo = CurRec ? CurRec : &CurMultiClass->Rec;
 
   // Read the first declaration.
-  Init *TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
+  Init *TemplArg = ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/true);
   if (!TemplArg)
     return true;
 
@@ -3432,7 +3468,7 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) {
   while (consume(tgtok::comma)) {
     // Read the following declarations.
     SMLoc Loc = Lex.getLoc();
-    TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
+    TemplArg = ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/true);
     if (!TemplArg)
       return true;
 
@@ -3467,7 +3503,9 @@ bool TGParser::ParseBodyItem(Record *CurRec) {
     return ParseDump(nullptr, CurRec);
 
   if (Lex.getCode() != tgtok::Let) {
-    if (!ParseDeclaration(CurRec, false))
+    // Allow 'auto' when parsing declarations in the body of a def or class.
+    if (!ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/false,
+                          /*AllowAuto=*/true))
       return true;
 
     if (!consume(tgtok::semi))
diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h
index b08e250870901a..7101cd43b53d56 100644
--- a/llvm/lib/TableGen/TGParser.h
+++ b/llvm/lib/TableGen/TGParser.h
@@ -280,7 +280,8 @@ class TGParser {
   bool ParseBodyItem(Record *CurRec);
 
   bool ParseTemplateArgList(Record *CurRec);
-  Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs);
+  Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs,
+                         bool AllowAuto);
   VarInit *ParseForeachDeclaration(Init *&ForeachListValue);
 
   SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm);
diff --git a/llvm/test/TableGen/auto.td b/llvm/test/TableGen/auto.td
new file mode 100644
index 00000000000000..b05af8d5c16a7d
--- /dev/null
+++ b/llvm/test/TableGen/auto.td
@@ -0,0 +1,44 @@
+// RUN: llvm-tblgen %s | FileCheck %s --check-prefix=CHECK-PASS
+// RUN: not llvm-tblgen -DBAD0 %s 2>&1 | FileCheck %s --check-prefix=CHECK-BAD0 -DFILE=%s
+// RUN: not llvm-tblgen -DBAD1 %s 2>&1 | FileCheck %s --check-prefix=CHECK-BAD1 -DFILE=%s
+
+// CHECK-PASS: int Arg = A:P;
+class A<int P> {
+  auto Arg = P;
+}
+
+def MyOp;
+
+// CHECK-PASS-LABEL: class B
+// CHECK-PASS:  int A = 10;
+// CHECK-PASS:  string B = "x";
+// CHECK-PASS:  list<int> C = [10, 10];
+// CHECK-PASS{LITERAL}:  list<list<int>> D = [[10, 10], [11, 11]];
+// CHECK-PASS:  list<A> F = [anonymous_0, anonymous_1];
+// CHECK-PASS:  bits<4> G = { 0, 1, 0, 1 };
+// CHECK-PASS:  code H = [{ printf(); }];
+// CHECK-PASS:  bits<1> I = { 0 };
+// CHECK-PASS:  dag K = (MyOp 10, 100);
+// CHECK-PASS:  int L = 10;
+class B {
+  auto A = 10;
+  auto B = "x";
+  auto C = [10,10];
+  auto D = [[10,10],[11,11]];
+#ifdef BAD0
+  // CHECK-BAD0: [[FILE]]:[[@LINE+1]]:12: error: unable to infer type
+  auto E = [];
+#endif  
+  auto F = [A<10>, A<11>];
+  auto G = {0,1,0,1};
+  auto H = [{ printf(); }];
+  // FIXME: This becomes `bits` and not `bit`.
+  auto I = 0b0;
+#ifdef BAD1
+  // CHECK-BAD1: [[FILE]]:[[@LINE+1]]:12: error: unable to infer type
+  auto J = ?;
+#endif  
+  auto K = (MyOp 10, 100);
+  auto L = A<10>.Arg;
+}
+



More information about the llvm-commits mailing list