Skip to content

Commit 0cdb0ed

Browse files
committed
[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.
1 parent 0de1e3e commit 0cdb0ed

File tree

5 files changed

+97
-12
lines changed

5 files changed

+97
-12
lines changed

llvm/lib/TableGen/TGLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ tgtok::TokKind TGLexer::LexIdentifier() {
383383
StringRef Str(IdentStart, CurPtr-IdentStart);
384384

385385
tgtok::TokKind Kind = StringSwitch<tgtok::TokKind>(Str)
386+
.Case("auto", tgtok::Auto)
386387
.Case("int", tgtok::Int)
387388
.Case("bit", tgtok::Bit)
388389
.Case("bits", tgtok::Bits)

llvm/lib/TableGen/TGLexer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ enum TokKind {
7575

7676
// Reserved keywords. ('ElseKW' is named to distinguish it from the
7777
// existing 'Else' that means the preprocessor #else.)
78+
Auto,
7879
Bit,
7980
Bits,
8081
Code,

llvm/lib/TableGen/TGParser.cpp

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3262,13 +3262,19 @@ bool TGParser::ParseTemplateArgValueList(
32623262
///
32633263
/// Declaration ::= FIELD? Type ID ('=' Value)?
32643264
///
3265-
Init *TGParser::ParseDeclaration(Record *CurRec,
3266-
bool ParsingTemplateArgs) {
3265+
Init *TGParser::ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs,
3266+
bool AllowAuto = false) {
32673267
// Read the field prefix if present.
32683268
bool HasField = consume(tgtok::Field);
32693269

3270-
RecTy *Type = ParseType();
3271-
if (!Type) return nullptr;
3270+
RecTy *Type;
3271+
if (AllowAuto && consume(tgtok::Auto)) {
3272+
Type = nullptr;
3273+
} else {
3274+
Type = ParseType();
3275+
if (!Type)
3276+
return nullptr;
3277+
}
32723278

32733279
if (Lex.getCode() != tgtok::Id) {
32743280
TokError("Expected identifier in declaration");
@@ -3290,6 +3296,32 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
32903296
Init *DeclName = StringInit::get(Records, Str);
32913297
Lex.Lex();
32923298

3299+
bool HasValue = consume(tgtok::equal);
3300+
3301+
// When 'auto' is used, parse the value and infer the type based on the
3302+
// value's type.
3303+
SMLoc ValLoc;
3304+
Init *Val = nullptr;
3305+
if (!Type) {
3306+
if (!HasValue) {
3307+
// auto used without a value.
3308+
TokError("auto requires assigning a value");
3309+
return nullptr;
3310+
}
3311+
ValLoc = Lex.getLoc();
3312+
// When no item type is supplied to ParseValue, it will either infer the
3313+
// type from the value, or fail to parse
3314+
Val = ParseValue(CurRec);
3315+
3316+
// Infer type from the value.
3317+
if (TypedInit *TI = dyn_cast_or_null<TypedInit>(Val)) {
3318+
Type = TI->getType();
3319+
} else {
3320+
Error(ValLoc, "unable to infer type");
3321+
return nullptr;
3322+
}
3323+
}
3324+
32933325
bool BadField;
32943326
if (!ParsingTemplateArgs) { // def, possibly in a multiclass
32953327
BadField = AddValue(CurRec, IdLoc,
@@ -3311,10 +3343,14 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
33113343
if (BadField)
33123344
return nullptr;
33133345

3314-
// If a value is present, parse it and set new field's value.
3315-
if (consume(tgtok::equal)) {
3316-
SMLoc ValLoc = Lex.getLoc();
3317-
Init *Val = ParseValue(CurRec, Type);
3346+
// For the non-auto case, if a value is present, parse it.
3347+
if (!Val && HasValue) {
3348+
ValLoc = Lex.getLoc();
3349+
Val = ParseValue(CurRec, Type);
3350+
}
3351+
3352+
// Set the new field's value.
3353+
if (HasValue) {
33183354
if (!Val ||
33193355
SetValue(CurRec, ValLoc, DeclName, {}, Val,
33203356
/*AllowSelfAssignment=*/false, /*OverrideDefLoc=*/false)) {
@@ -3423,7 +3459,7 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) {
34233459
Record *TheRecToAddTo = CurRec ? CurRec : &CurMultiClass->Rec;
34243460

34253461
// Read the first declaration.
3426-
Init *TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
3462+
Init *TemplArg = ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/true);
34273463
if (!TemplArg)
34283464
return true;
34293465

@@ -3432,7 +3468,7 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) {
34323468
while (consume(tgtok::comma)) {
34333469
// Read the following declarations.
34343470
SMLoc Loc = Lex.getLoc();
3435-
TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
3471+
TemplArg = ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/true);
34363472
if (!TemplArg)
34373473
return true;
34383474

@@ -3467,7 +3503,9 @@ bool TGParser::ParseBodyItem(Record *CurRec) {
34673503
return ParseDump(nullptr, CurRec);
34683504

34693505
if (Lex.getCode() != tgtok::Let) {
3470-
if (!ParseDeclaration(CurRec, false))
3506+
// Allow 'auto' when parsing declarations in the body of a def or class.
3507+
if (!ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/false,
3508+
/*AllowAuto=*/true))
34713509
return true;
34723510

34733511
if (!consume(tgtok::semi))

llvm/lib/TableGen/TGParser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@ class TGParser {
280280
bool ParseBodyItem(Record *CurRec);
281281

282282
bool ParseTemplateArgList(Record *CurRec);
283-
Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs);
283+
Init *ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs,
284+
bool AllowAuto);
284285
VarInit *ParseForeachDeclaration(Init *&ForeachListValue);
285286

286287
SubClassReference ParseSubClassReference(Record *CurRec, bool isDefm);

llvm/test/TableGen/auto.td

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: llvm-tblgen %s | FileCheck %s --check-prefix=CHECK-PASS
2+
// RUN: not llvm-tblgen -DBAD0 %s 2>&1 | FileCheck %s --check-prefix=CHECK-BAD0 -DFILE=%s
3+
// RUN: not llvm-tblgen -DBAD1 %s 2>&1 | FileCheck %s --check-prefix=CHECK-BAD1 -DFILE=%s
4+
5+
// CHECK-PASS: int Arg = A:P;
6+
class A<int P> {
7+
auto Arg = P;
8+
}
9+
10+
def MyOp;
11+
12+
// CHECK-PASS-LABEL: class B
13+
// CHECK-PASS: int A = 10;
14+
// CHECK-PASS: string B = "x";
15+
// CHECK-PASS: list<int> C = [10, 10];
16+
// CHECK-PASS{LITERAL}: list<list<int>> D = [[10, 10], [11, 11]];
17+
// CHECK-PASS: list<A> F = [anonymous_0, anonymous_1];
18+
// CHECK-PASS: bits<4> G = { 0, 1, 0, 1 };
19+
// CHECK-PASS: code H = [{ printf(); }];
20+
// CHECK-PASS: bits<1> I = { 0 };
21+
// CHECK-PASS: dag K = (MyOp 10, 100);
22+
// CHECK-PASS: int L = 10;
23+
class B {
24+
auto A = 10;
25+
auto B = "x";
26+
auto C = [10,10];
27+
auto D = [[10,10],[11,11]];
28+
#ifdef BAD0
29+
// CHECK-BAD0: [[FILE]]:[[@LINE+1]]:12: error: unable to infer type
30+
auto E = [];
31+
#endif
32+
auto F = [A<10>, A<11>];
33+
auto G = {0,1,0,1};
34+
auto H = [{ printf(); }];
35+
// FIXME: This becomes `bits` and not `bit`.
36+
auto I = 0b0;
37+
#ifdef BAD1
38+
// CHECK-BAD1: [[FILE]]:[[@LINE+1]]:12: error: unable to infer type
39+
auto J = ?;
40+
#endif
41+
auto K = (MyOp 10, 100);
42+
auto L = A<10>.Arg;
43+
}
44+

0 commit comments

Comments
 (0)