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