Skip to content

Commit 217e756

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 708567a commit 217e756

File tree

5 files changed

+95
-12
lines changed

5 files changed

+95
-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: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3240,13 +3240,19 @@ bool TGParser::ParseTemplateArgValueList(
32403240
///
32413241
/// Declaration ::= FIELD? Type ID ('=' Value)?
32423242
///
3243-
Init *TGParser::ParseDeclaration(Record *CurRec,
3244-
bool ParsingTemplateArgs) {
3243+
Init *TGParser::ParseDeclaration(Record *CurRec, bool ParsingTemplateArgs,
3244+
bool AllowAuto = false) {
32453245
// Read the field prefix if present.
32463246
bool HasField = consume(tgtok::Field);
32473247

3248-
RecTy *Type = ParseType();
3249-
if (!Type) return nullptr;
3248+
RecTy *Type;
3249+
if (AllowAuto && consume(tgtok::Auto)) {
3250+
Type = nullptr;
3251+
} else {
3252+
Type = ParseType();
3253+
if (!Type)
3254+
return nullptr;
3255+
}
32503256

32513257
if (Lex.getCode() != tgtok::Id) {
32523258
TokError("Expected identifier in declaration");
@@ -3268,6 +3274,30 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
32683274
Init *DeclName = StringInit::get(Records, Str);
32693275
Lex.Lex();
32703276

3277+
bool HasValue = consume(tgtok::equal);
3278+
3279+
// When 'auto' is used, parse the value and infer the type based on the
3280+
// value's type.
3281+
SMLoc ValLoc;
3282+
Init *Val = nullptr;
3283+
if (!Type) {
3284+
if (!HasValue) {
3285+
// auto used without a value.
3286+
TokError("auto requires assigning a value");
3287+
return nullptr;
3288+
}
3289+
ValLoc = Lex.getLoc();
3290+
Val = ParseValue(CurRec, Type);
3291+
3292+
// Infer type from the value.
3293+
if (TypedInit *TI = dyn_cast_or_null<TypedInit>(Val)) {
3294+
Type = TI->getType();
3295+
} else {
3296+
Error(ValLoc, "unable to infer type");
3297+
return nullptr;
3298+
}
3299+
}
3300+
32713301
bool BadField;
32723302
if (!ParsingTemplateArgs) { // def, possibly in a multiclass
32733303
BadField = AddValue(CurRec, IdLoc,
@@ -3289,10 +3319,14 @@ Init *TGParser::ParseDeclaration(Record *CurRec,
32893319
if (BadField)
32903320
return nullptr;
32913321

3292-
// If a value is present, parse it and set new field's value.
3293-
if (consume(tgtok::equal)) {
3294-
SMLoc ValLoc = Lex.getLoc();
3295-
Init *Val = ParseValue(CurRec, Type);
3322+
// For the non-auto case, if a value is present, parse it.
3323+
if (!Val && HasValue) {
3324+
ValLoc = Lex.getLoc();
3325+
Val = ParseValue(CurRec, Type);
3326+
}
3327+
3328+
// Set the new field's value.
3329+
if (HasValue) {
32963330
if (!Val ||
32973331
SetValue(CurRec, ValLoc, DeclName, {}, Val,
32983332
/*AllowSelfAssignment=*/false, /*OverrideDefLoc=*/false)) {
@@ -3401,7 +3435,7 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) {
34013435
Record *TheRecToAddTo = CurRec ? CurRec : &CurMultiClass->Rec;
34023436

34033437
// Read the first declaration.
3404-
Init *TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
3438+
Init *TemplArg = ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/true);
34053439
if (!TemplArg)
34063440
return true;
34073441

@@ -3410,7 +3444,7 @@ bool TGParser::ParseTemplateArgList(Record *CurRec) {
34103444
while (consume(tgtok::comma)) {
34113445
// Read the following declarations.
34123446
SMLoc Loc = Lex.getLoc();
3413-
TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
3447+
TemplArg = ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/true);
34143448
if (!TemplArg)
34153449
return true;
34163450

@@ -3445,7 +3479,9 @@ bool TGParser::ParseBodyItem(Record *CurRec) {
34453479
return ParseDump(nullptr, CurRec);
34463480

34473481
if (Lex.getCode() != tgtok::Let) {
3448-
if (!ParseDeclaration(CurRec, false))
3482+
// Allow 'auto' when parsing declarations in the body of a def or class.
3483+
if (!ParseDeclaration(CurRec, /*ParsingTemplateArgs=*/false,
3484+
/*AllowAuto=*/true))
34493485
return true;
34503486

34513487
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)