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

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 20 10:35:41 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-tablegen

Author: Rahul Joshi (jurahul)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/109434.diff


5 Files Affected:

- (modified) llvm/lib/TableGen/TGLexer.cpp (+1) 
- (modified) llvm/lib/TableGen/TGLexer.h (+1) 
- (modified) llvm/lib/TableGen/TGParser.cpp (+47-11) 
- (modified) llvm/lib/TableGen/TGParser.h (+2-1) 
- (added) llvm/test/TableGen/auto.td (+44) 


``````````diff
diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index 62a884e01a5306..9f23f33ca6dbab 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 9adc03ccc72b85..f6d8f0c606da75 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 1a60c2a567a297..262bf2656e86ed 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -3240,13 +3240,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");
@@ -3268,6 +3274,30 @@ 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();
+    Val = ParseValue(CurRec, Type);
+
+    // 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,
@@ -3289,10 +3319,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)) {
@@ -3401,7 +3435,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;
 
@@ -3410,7 +3444,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;
 
@@ -3445,7 +3479,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;
+}
+

``````````

</details>


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


More information about the llvm-commits mailing list