xref: /llvm-project/llvm/utils/TableGen/jupyter/tablegen_tutorial_part_1.md (revision 5850124ffd78e3a53f4a1abdd574c8ec507b964c)
1## Introduction to TableGen Part 1: Classes, Defs, Basic Types and Let
2
3**Note:** The content in this notebook is adapted from [this document](https://llvm.org/docs/TableGen/index.html). Refer to it if you want more details.
4
5This tutorial will cover:
6* Classes
7* Defs
8* Basic types
9* `let` in various forms
10* Class template arguments
11
12## What is TableGen?
13
14TableGen is a language used in LLVM to automate the generation of certain types of code. Usually repetitive code that has a common structure. TableGen is used to generate "records" that are then processed by a "backend" into domain specific code.
15
16The compiler for TableGen is the binary `llvm-tblgen`. This contains the logic to convert TableGen source into records that can then be passed to a TableGen backend.
17
18TableGen allows you to define Classes and Defs (which are instances of classes) but it doesn't encode what to do with that structure. That's what the backend does. The backend converts this structure into something useful, for example C++ code.
19
20These backends are included in the `llvm-tblgen` binary and you can choose which one to run using a command line option. If you don't choose a backend you get a dump of the structure, and that is what this notebook will be showing.
21
22This tutorial will focus on the language itself only. The only thing you need to know now is that in addition to `llvm-tblgen` you will see other `*-tblgen` like `clang-tblgen`. The difference between them is the backends they include.
23
24The default output from `llvm-tblgen` looks like this:
25
26
27```tablegen
28%config cellreset on
29
30// Empty source file
31```
32
33    ------------- Classes -----------------
34    ------------- Defs -----------------
35
36
37**Note:** `%config` is not a TableGen command but a "magic" command to the Jupyter kernel for this notebook. By default new cells include the content of previously run cells, but for this notebook we mostly want each to be isolated. On occasion we will use the `%noreset` magic to override this.
38
39No source means no classes and no defs. Let's add a class.
40
41## Classes
42
43
44```tablegen
45class C {}
46```
47
48    ------------- Classes -----------------
49    class C {
50    }
51    ------------- Defs -----------------
52
53
54Followed by a def (definition).
55
56
57```tablegen
58%noreset
59
60def X: C;
61```
62
63    ------------- Classes -----------------
64    class C {
65    }
66    ------------- Defs -----------------
67    def X {	// C
68    }
69
70
71`def` creates an instance of a class. Typically, the main loop of a TableGen backend will look for all defs that are instances of a certain class.
72
73For example if I am generating register information I would look for all defs that are instances of `RegisterInfo` in the example below.
74
75
76```tablegen
77class RegisterInfo {}
78def X0: RegisterInfo {}
79def X1: RegisterInfo {}
80```
81
82    ------------- Classes -----------------
83    class RegisterInfo {
84    }
85    ------------- Defs -----------------
86    def X0 {	// RegisterInfo
87    }
88    def X1 {	// RegisterInfo
89    }
90
91
92## Inheritance
93
94Like many other languages with classes, a class in TableGen can inherit properties of another class.
95
96
97```tablegen
98class C {}
99class D : C {}
100```
101
102    ------------- Classes -----------------
103    class C {
104    }
105    class D {	// C
106    }
107    ------------- Defs -----------------
108
109
110Inheritance is done by putting the class you want to inherit from after `:`, before the opening `{`.
111
112You'll know that `D` inherits from `C` by the `// C` comment on the `class D {` line in the output.
113
114Not very interesting though, what are we actually inheriting? The members of the parent class.
115
116
117```tablegen
118class C {
119    int a;
120}
121class D : C {}
122```
123
124    ------------- Classes -----------------
125    class C {
126      int a = ?;
127    }
128    class D {	// C
129      int a = ?;
130    }
131    ------------- Defs -----------------
132
133
134Note that `D` now has the `a` member which was defined in the class `C`.
135
136You can inherit from multiple classes. In that case the order that that happens in matches the order you write the class names after the `:`.
137
138
139```tablegen
140class C {
141    int a = 1;
142}
143class D {
144    int a = 2;
145}
146class E : C, D {}
147```
148
149    ------------- Classes -----------------
150    class C {
151      int a = 1;
152    }
153    class D {
154      int a = 2;
155    }
156    class E {	// C D
157      int a = 2;
158    }
159    ------------- Defs -----------------
160
161
162Class `E` first inherits from class `C`. This gives `E` a member `a` with value `1`. Then it inherits from class `D` which also has a member `a` but with a value of `2`. Meaning the final value of `E`'s `a` is `2`.
163
164When a member has the same name this is handled on a "last one in wins" basis. Assuming the types match.
165
166
167```tablegen
168class C {
169    string a = "";
170}
171class D {
172    int a = 2;
173}
174class E : C, D {}
175```
176
177    <stdin>:7:14: error: New definition of 'a' of type 'int' is incompatible with previous definition of type 'string'
178    class E : C, D {}
179                 ^
180
181
182When they don't match, we get an error. Luckily for us, we're about to learn all about types.
183
184## Types
185
186TableGen is statically typed with error checking to prevent you from assigning things with mismatched types.
187
188
189```tablegen
190class C {
191    int a;
192    bit b = 0;
193    string s = "Hello";
194}
195```
196
197    ------------- Classes -----------------
198    class C {
199      int a = ?;
200      bit b = 0;
201      string s = "Hello";
202    }
203    ------------- Defs -----------------
204
205
206Here we've created a class C with integer, bit (1 or 0) and string members. See [here](https://llvm.org/docs/TableGen/ProgRef.html#types) for a full list of types.
207
208Note that you do not have to give a member a default value, it can be left uninitialised.
209
210
211```tablegen
212%noreset
213
214def X: C {}
215```
216
217    ------------- Classes -----------------
218    class C {
219      int a = ?;
220      bit b = 0;
221      string s = "Hello";
222    }
223    ------------- Defs -----------------
224    def X {	// C
225      int a = ?;
226      bit b = 0;
227      string s = "Hello";
228    }
229
230
231When you make an instance of a class using `def`, that instance gets all the members of the class. Their values will be as set in the class, unless otherwise overridden.
232
233In the case of `a` it also keeps the undefined value. Any backend using that definition would have to check for that case.
234
235
236```tablegen
237%noreset
238
239def Y {
240    int a = "abc"
241}
242```
243
244    <stdin>:10:13: error: Field 'a' of type 'int' is incompatible with value '"abc"' of type 'string'
245        int a = "abc"
246                ^
247    <stdin>:11:1: error: expected ';' after declaration
248    }
249    ^
250
251
252Here we see the type checking in action. Member `a` has type `int` so we cannot assign a `string` to it.
253
254## Let
255
256If we want to override those member values we can use `let` ([documented here](https://llvm.org/docs/TableGen/ProgRef.html#let-override-fields-in-classes-or-records)). This can be done in a couple of ways. The first is where you mark the scope of the `let` using `in {}`.
257
258`let <name>=<value> in {`
259
260The code below says that within the `{}` after the `let`, all `a` should have the value 5.
261
262
263```tablegen
264class C {
265    int a = 9;
266}
267let a=5 in {
268    def X: C {}
269}
270```
271
272    ------------- Classes -----------------
273    class C {
274      int a = 9;
275    }
276    ------------- Defs -----------------
277    def X {	// C
278      int a = 5;
279    }
280
281
282For multiple names, separate them with a comma.
283
284
285```tablegen
286class C {
287    int a;
288    int b;
289}
290let a=5, b=6 in {
291    def X: C {}
292}
293```
294
295    ------------- Classes -----------------
296    class C {
297      int a = ?;
298      int b = ?;
299    }
300    ------------- Defs -----------------
301    def X {	// C
302      int a = 5;
303      int b = 6;
304    }
305
306
307You can also use `let` within a `def`. This means the scope of the `let` is the same as the scope of the `def` (the def's `{...}`).
308
309
310```tablegen
311class C {
312    int a = 9;
313}
314def X: C {
315    let a=5;
316}
317def Y: C {}
318```
319
320    ------------- Classes -----------------
321    class C {
322      int a = 9;
323    }
324    ------------- Defs -----------------
325    def X {	// C
326      int a = 5;
327    }
328    def Y {	// C
329      int a = 9;
330    }
331
332
333Note that `Y` has `a` as `9` because the `let` was only applied to `X`.
334
335It is an error to try to `let` a name that hasn't been defined or to give it a value of the incorrect type.
336
337
338```tablegen
339class C {
340    int a = 9;
341}
342def X: C {
343    let a="Hello";
344}
345```
346
347    <stdin>:5:9: error: Field 'a' of type 'int' is incompatible with value '"Hello"' of type 'string'
348        let a="Hello";
349            ^
350
351
352Above, the member `a` was defined but with a type of `int`. We therefore cannot `let` it have a value of type `string`.
353
354
355```tablegen
356class C {
357    int a = 9;
358}
359def X: C {
360    let b=5;
361}
362```
363
364    <stdin>:5:11: error: Value 'b' unknown!
365        let b=5;
366              ^
367
368
369Above, class `C` only has one member, `a`. Therefore we get an error trying to override the value of `b` which doesn't exist.
370
371If you have multiple let, the outer scope is applied first then on down to the narrowest scope.
372
373
374```tablegen
375class Base {
376    int var=4;
377}
378let var=5 in {
379    def X: Base {}
380    let var=6 in {
381        def Y: Base {}
382    }
383    def Z: Base { let var=7; }
384}
385```
386
387    ------------- Classes -----------------
388    class Base {
389      int var = 4;
390    }
391    ------------- Defs -----------------
392    def X {	// Base
393      int var = 5;
394    }
395    def Y {	// Base
396      int var = 6;
397    }
398    def Z {	// Base
399      int var = 7;
400    }
401
402
403The first `let` is at what we call the "top level". That means the outer most scope in terms of the source code. A bit like a global variable in a C file.
404
405This is applied first and changes `var` from `4` to `5` for all classes within that `let` (`4` came from the definition of `Base`).
406
407def `X` is within the global `let`, therefore `var` is `5` within `X`.
408
409Then we have a `let` inside the global `let`. This one changes `var` from `5` to `6`. The scope of the `let` only contains the def `Y` therefore within `Y`, `var` is `6`.
410
411Finally def `Z` is within the global `let`, so `var` starts as `5`. `Z` has an inner `let` that changes `var` to `7`.
412
413That example is quite complex just to demonstrate the feature. Let's look at something more practical.
414
415
416```tablegen
417class Register {
418    int size=4;
419}
420let size=8 in {
421    def X0: Register {}
422    // Repeats 30 times for X1...X31
423}
424def W0: Register {}
425// Repeats 30 times for W1...W31
426```
427
428    ------------- Classes -----------------
429    class Register {
430      int size = 4;
431    }
432    ------------- Defs -----------------
433    def W0 {	// Register
434      int size = 4;
435    }
436    def X0 {	// Register
437      int size = 8;
438    }
439
440
441(for anyone curious that's AArch64's register naming)
442
443The use case here is that we are describing registers. Some are 32 bits wide and some are 64 bits wide.
444
445We start by setting a default value of `size` which is 4 (4x8=32 bits) in the class `Register`. Then using a top level `let` we override that value and set it to 8 for all the 64 bit registers at once. So we don't need to do `size=8` over and over again.
446
447## Classes As Class Members
448
449In addition to the built in types, class members can be user defined classes.
450
451
452```tablegen
453class Inner {}
454class Outer {
455    Inner i;
456}
457```
458
459    ------------- Classes -----------------
460    class Inner {
461    }
462    class Outer {
463      Inner i = ?;
464    }
465    ------------- Defs -----------------
466
467
468Of course that raises the question, how do we construct an instance of `Inner` to use as the value?
469
470We simply use a `def` like we have done before.
471
472
473```tablegen
474class Inner {}
475def AnInner: Inner {}
476class Outer {
477    Inner i = AnInner;
478}
479def AnOuter: Outer {}
480```
481
482    ------------- Classes -----------------
483    class Inner {
484    }
485    class Outer {
486      Inner i = AnInner;
487    }
488    ------------- Defs -----------------
489    def AnInner {	// Inner
490    }
491    def AnOuter {	// Outer
492      Inner i = AnInner;
493    }
494
495
496## Class Template Arguments
497
498Class template arguments are used to pass parameters to classes when you `def` them.
499
500
501```tablegen
502class C <int a, int b> {
503    int c = a;
504    int d = b;
505}
506def X: C<0, 1> {}
507```
508
509    ------------- Classes -----------------
510    class C<int C:a = ?, int C:b = ?> {
511      int c = C:a;
512      int d = C:b;
513    }
514    ------------- Defs -----------------
515    def X {	// C
516      int c = 0;
517      int d = 1;
518    }
519
520
521This means that to `def` a `C` we must now provide 2 arguments that have type `int` (type checking applies here as it does elsewhere).
522
523This is going to look familiar if you have written C++. In C++ it might look like:
524```
525template<int a, int b>
526class C {
527    int c = a;
528    int d = b;
529};
530C<0, 1> X;
531```
532
533If templates aren't your thing, another way to think of them is as parameters to the constructor of a class.
534
535For instance Python code might look like this:
536```
537class C(object):
538    def __init__(self, a, b):
539        self.c = a
540        self.d = b
541
542print(C(0, 1).c)
543# prints "0"
544```
545
546
547```tablegen
548class C <int a, int b> {
549    int c = a;
550    int d = b;
551}
552def X: C<0> {}
553```
554
555    <stdin>:5:8: error: value not specified for template argument 'C:b'
556    def X: C<0> {}
557           ^
558    <stdin>:1:21: note: declared in 'C'
559    class C <int a, int b> {
560                        ^
561
562
563When not enough arguments are provided, you get an error.
564
565Below is what happens when one of those arguments is of the wrong type.
566
567
568```tablegen
569class C <int a, int b> {
570    int c = a;
571    int d = b;
572}
573def X: C<0, "hello"> {}
574```
575
576    <stdin>:5:8: error: Value specified for template argument 'C:b' is of type string; expected type int: "hello"
577    def X: C<0, "hello"> {}
578           ^
579
580
581You can also provide default values for template arguments.
582
583
584```tablegen
585class C <int a=10> {
586    int b = a;
587}
588def X: C<> {}
589```
590
591    ------------- Classes -----------------
592    class C<int C:a = 10> {
593      int b = C:a;
594    }
595    ------------- Defs -----------------
596    def X {	// C
597      int b = 10;
598    }
599
600
601Using class template arguments you can enforce a structure on the user of the classes. In our previous register example I could use this to require the the user pass a value for the size.
602
603The code below makes the size argument mandatory but the alias optional.
604
605
606```tablegen
607class Register<int _size, string _alias=""> {
608    int size = _size;
609    string alias = _alias;
610}
611def X0: Register<8> {}
612def X29: Register<8, "frame pointer"> {}
613```
614
615    ------------- Classes -----------------
616    class Register<int Register:_size = ?, string Register:_alias = ""> {
617      int size = Register:_size;
618      string alias = Register:_alias;
619    }
620    ------------- Defs -----------------
621    def X0 {	// Register
622      int size = 8;
623      string alias = "";
624    }
625    def X29 {	// Register
626      int size = 8;
627      string alias = "frame pointer";
628    }
629
630
631**Note:** You can't reuse the name between the template argument and the class member.
632Here I have added `_` to the template argument but there's no required style.
633
634For `X0` we don't pass an alias so we get the default of `""`, which would mean there is no alias.
635
636For `X29` we've passed a value for the alias, which overrides the default value.
637
638In C++, the equivalent would be:
639```
640// Constructor for class Register
641Register(int size, const char* alias=nullptr) :
642```
643
644Or in Python:
645```
646def __init__(self, size, alias=""):
647```
648