SlideShare a Scribd company logo
Min-Yih “Min” Hsu @ LLVM Dev Meeting 2021
How to write a TableGen backend
“Min” Hsu
• Computer Science PhD Candidate
in University of California, Irvine

• Code owner of M68k LLVM backend

• Author of book “LLVM Techniques,
Tips and Best Practices” (2021)
$ whoami
2
TableGen Backend
3
TableGen in a nutshell
4
TableGen in a nutshell
• A Domain-Speci
fi
c Language (DSL) originated from the LLVM project.
• It’s Turing complete!
4
TableGen in a nutshell
• A Domain-Speci
fi
c Language (DSL) originated from the LLVM project.
• It’s Turing complete!
• Originally invented to describe the instruction table of an LLVM target.
4
TableGen in a nutshell
• A Domain-Speci
fi
c Language (DSL) originated from the LLVM project.
• It’s Turing complete!
• Originally invented to describe the instruction table of an LLVM target.
• Ex. The operands, assembly syntax, and ISel rules for each instruction.
4
TableGen in a nutshell
• A Domain-Speci
fi
c Language (DSL) originated from the LLVM project.
• It’s Turing complete!
• Originally invented to describe the instruction table of an LLVM target.
• Ex. The operands, assembly syntax, and ISel rules for each instruction.
• Now: Used in a wide variety of (completely) di
ff
erent areas inside LLVM.
4
TableGen in a nutshell
• A Domain-Speci
fi
c Language (DSL) originated from the LLVM project.
• It’s Turing complete!
• Originally invented to describe the instruction table of an LLVM target.
• Ex. The operands, assembly syntax, and ISel rules for each instruction.
• Now: Used in a wide variety of (completely) di
ff
erent areas inside LLVM.
• Instruction scheduling info.
4
TableGen in a nutshell
• A Domain-Speci
fi
c Language (DSL) originated from the LLVM project.
• It’s Turing complete!
• Originally invented to describe the instruction table of an LLVM target.
• Ex. The operands, assembly syntax, and ISel rules for each instruction.
• Now: Used in a wide variety of (completely) di
ff
erent areas inside LLVM.
• Instruction scheduling info.
• Declaring IR attributes.
4
TableGen in a nutshell
• A Domain-Speci
fi
c Language (DSL) originated from the LLVM project.
• It’s Turing complete!
• Originally invented to describe the instruction table of an LLVM target.
• Ex. The operands, assembly syntax, and ISel rules for each instruction.
• Now: Used in a wide variety of (completely) di
ff
erent areas inside LLVM.
• Instruction scheduling info.
• Declaring IR attributes.
• LLVM Option subsystem (e.g. Clang’s compiler
fl
ags).
4
class Stuff {


}


5
class Stuff {


}


5
Layout of a template
class Stuff {


}


5
Layout of a template
class Stuff {


string Name;


int Quantity;


string Description;


}


6
Layout of a template
class Stuff {


string Name;


int Quantity;


string Description;


}


6
Fields
Layout of a template
class Stuff {


string Name;


int Quantity;


string Description;


}


def water_bottle : Stuff {


}


7
Fields
Layout of a template
class Stuff {


string Name;


int Quantity;


string Description;


}


def water_bottle : Stuff {


}


7
A record created with template Stuff
Fields
Layout of a template
class Stuff {


string Name;


int Quantity;


string Description;


}


def water_bottle : Stuff {


}


7
A record created with template Stuff
Fields
Layout of a template
class Stuff {


string Name;


int Quantity;


string Description;


}


def water_bottle : Stuff {


let Name = "Water bottle";


let Quantity = 1;


let Description = "Stuff that helps you hydrate.";


}


8
A record created with template Stuff
Fields
Layout of a template
class Stuff {


string Name;


int Quantity;


string Description;


}


def water_bottle : Stuff {


let Name = "Water bottle";


let Quantity = 1;


let Description = "Stuff that helps you hydrate.";


}


def smart_phone : Stuff {


let Name "Smart phone";


let Quantity = 2;


let Description = "Stuff that keeps you from hydrating.";


}
9
Fields
Layout of a template
Another record created with template Stuff
A record created with template Stuff
class Stuff <string name, int quantity, string description> {


string Name = name;


int Quantity = quantity;


string Description = description;


}


10
class Stuff <string name, int quantity, string description> {


string Name = name;


int Quantity = quantity;


string Description = description;


}


def water_bottle : Stuff<"Water bottle", 1,


"Stuff that helps you hydrate.">;


def smart_phone : Stuff<"Smart phone", 2,


"Stuff that prevents you from hydrating.">;
11
12
class Person {


std::string Name;


int Age;


JobKind Job;


};


Person Me{"Min", 12, WEEBUS};


OOP v.s. TableGen
12
class Person {


std::string Name;


int Age;


JobKind Job;


};


Person Me{"Min", 12, WEEBUS};


Encapsulates data
OOP v.s. TableGen
13
class Person {


std::string Name;


int Age;


JobKind Job;


};


Person Me{"Min", 12, WEEBUS};


void foo(int N) {


Me.Name = "Max";


}


Encapsulates data
Records are immutable
OOP v.s. TableGen
14
class Person {


std::string Name;


int Age;


JobKind Job;


};


Person Me{"Min", 12, WEEBUS};


void foo(int N) {


Me.Name = "Max";


Person Rick{“Rick", N, SINGER};


}


Encapsulates data
Records are immutable
Constant values in
fi
elds
OOP v.s. TableGen
15
class Person {


std::string Name;


int Age;


JobKind Job;


};


Person Me{"Min", 12, WEEBUS};


void foo(int N) {


Me.Name = "Max";


Person Rick{“Rick", N, SINGER};


for (i = 0; i < N; ++i)


SomeList.emplace_back(Person{...});


}


Encapsulates data
Records are immutable
Constant values in
fi
elds
Constant number of records
OOP v.s. TableGen
16
Name Quantity Description
Water Bottle 1 …
Smart Phone 2 …
Table “Stu
f
”
Relational DB v.s. TableGen
16
Fields are similar to columns
Name Quantity Description
Water Bottle 1 …
Smart Phone 2 …
Table “Stu
f
”
Relational DB v.s. TableGen
16
Fields are similar to columns
Name Quantity Description
Water Bottle 1 …
Smart Phone 2 …
Table “Stu
f
”
Relational DB v.s. TableGen
Records do not belong to any table
16
Fields are similar to columns
Name Quantity Description
Water Bottle 1 …
Smart Phone 2 …
Table “Stu
f
”
Relational DB v.s. TableGen
Records do not belong to any table
Strong structure is not required
16
Fields are similar to columns
Name Quantity Description
Water Bottle 1 …
Smart Phone 2 …
Table “Stu
f
”
Relational DB v.s. TableGen
Records do not belong to any table
def foo {


string A = “foo”;


int B = 0;


}


def bar {


int Z = 1;


}


def zoo;
Strong structure is not required
TableGen data types
17
TableGen data types
• Primitive types (common): int, string, bool, bit
17
TableGen data types
• Primitive types (common): int, string, bool, bit
• Bit vector: bits<N>
17
TableGen data types
• Primitive types (common): int, string, bool, bit
• Bit vector: bits<N>
• List: list<T>
17
TableGen data types
• Primitive types (common): int, string, bool, bit
• Bit vector: bits<N>
• List: list<T>
• Direct Acyclic Graph (DAG): dag
17
TableGen data types
• Primitive types (common): int, string, bool, bit
• Bit vector: bits<N>
• List: list<T>
• Direct Acyclic Graph (DAG): dag
• Represent DAG data symbolically
17
TableGen data types
• Primitive types (common): int, string, bool, bit
• Bit vector: bits<N>
• List: list<T>
• Direct Acyclic Graph (DAG): dag
• Represent DAG data symbolically
• dag foo = (operator arg0, arg1, …)
17
How to use TableGen records?
18
How to use TableGen records?
19
def water_bottle : Stuff<"Water bottle", 1,


"A stuff that…”>;


def smart_phone : Stuff<"Smart phone", 2,


"A stuff that…”>;
How to use TableGen records?
19
def water_bottle : Stuff<"Water bottle", 1,


"A stuff that…”>;


def smart_phone : Stuff<"Smart phone", 2,


"A stuff that…”>;
How to use TableGen records?
19
def water_bottle : Stuff<"Water bottle", 1,


"A stuff that…”>;


def smart_phone : Stuff<"Smart phone", 2,


"A stuff that…”>;
How to use TableGen records?
19
def water_bottle : Stuff<"Water bottle", 1,


"A stuff that…”>;


def smart_phone : Stuff<"Smart phone", 2,


"A stuff that…”>;
TableGen backends
20
def water_bottle : Stuff<"Water bottle", 1,


"A stuff that…”>;


def smart_phone : Stuff<"Smart phone", 2,


"A stuff that…”>;
TableGen
Backend 1
TableGen
Backend 2
TableGen
Backend 3
TableGen backends
21
TableGen
Backend 1
TableGen
Backend 2
TableGen
Backend 3
TableGen
Parser
TableGen
Code
Output 1
Output 2
Output 3
TableGen usage in LLVM
An example in LLVM backend
22
llvm-tblgen
TableGen usage in LLVM
An example in LLVM backend
22
llvm-tblgen
InstrInfo TG Backend
DAGISel TG Backend
TableGen usage in LLVM
An example in LLVM backend
22
llvm-tblgen
InstrInfo TG Backend
DAGISel TG Backend
X86.td
TableGen usage in LLVM
An example in LLVM backend
22
llvm-tblgen
InstrInfo TG Backend
DAGISel TG Backend
X86GenInstrInfo.inc
X86GenDAGISel.inc
X86.td
TableGen usage in LLVM
An example in LLVM backend
22
llvm-tblgen
InstrInfo TG Backend
DAGISel TG Backend
X86GenInstrInfo.inc
X86GenDAGISel.inc
X86.td
Files contain C/C++ code
TableGen Backend Development
Why should I learn to write a TG backend?
24
Why should I learn to write a TG backend?
Despite being a DSL, TableGen is actually pretty versatile
24
Why should I learn to write a TG backend?
Despite being a DSL, TableGen is actually pretty versatile
Always require a specific TableGen backend
24
Why should I learn to write a TG backend?
Despite being a DSL, TableGen is actually pretty versatile
Always require a specific TableGen backend
LLVM has provided nice infrastructures to work with TableGen code
24
Project overview
25
Project overview
25
Recap: Comparison with Relational DB
Project overview
25
Recap: Comparison with Relational DB
A more
fl
exible way to represent static structural data
Project overview
SQLGen — Generate SQL from TableGen code
26
TableGen
Code
Project overview
SQLGen — Generate SQL from TableGen code
26
TableGen
Code
TG Backend
of SQLGen
TableGen
Parser
SQLGen
A standalone tool
Project overview
SQLGen — Generate SQL from TableGen code
26
TableGen
Code
TG Backend
of SQLGen
TableGen
Parser
SQLGen
SQL Code
A standalone tool
TableGen syntax in SQLGen
SQL table creation
27
CREATE TABLE Customer (


ID int,


Name varchar(255),


Affiliation varchar(255),


PRIMARY KEY (ID)


);
Generated SQL Code
Input TableGen Code
TableGen syntax in SQLGen
SQL table creation
27
CREATE TABLE Customer (


ID int,


Name varchar(255),


Affiliation varchar(255),


PRIMARY KEY (ID)


);
Generated SQL Code
Input TableGen Code
class Table {


int PrimaryKey = 0;


}
TableGen syntax in SQLGen
SQL table creation
27
CREATE TABLE Customer (


ID int,


Name varchar(255),


Affiliation varchar(255),


PRIMARY KEY (ID)


);
Generated SQL Code
Input TableGen Code
class Customer <string name,


string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
class Table {


int PrimaryKey = 0;


}
TableGen syntax in SQLGen
SQL table creation
27
CREATE TABLE Customer (


ID int,


Name varchar(255),


Affiliation varchar(255),


PRIMARY KEY (ID)


);
Generated SQL Code
Input TableGen Code
class Customer <string name,


string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
class Table {


int PrimaryKey = 0;


}
TableGen syntax in SQLGen
Inserting rows into a SQL table
28
INSERT INTO Customer (


ID,


Name,


Affiliation


)


VALUES (0, "John Smith", "UC Irvine");
Generated SQL Code
Input TableGen Code
TableGen syntax in SQLGen
Inserting rows into a SQL table
28
INSERT INTO Customer (


ID,


Name,


Affiliation


)


VALUES (0, "John Smith", "UC Irvine");
Generated SQL Code
Input TableGen Code
def john : Customer<"John Smith", "UC Irvine">;
TableGen syntax in SQLGen
Inserting rows into a SQL table
28
INSERT INTO Customer (


ID,


Name,


Affiliation


)


VALUES (0, "John Smith", "UC Irvine");
Generated SQL Code
Input TableGen Code
def john : Customer<"John Smith", "UC Irvine">;
class Customer <string name,


string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
SQLGen entry point
29
int main(int argc, char **argv) {


cl::ParseCommandLineOptions(argc, argv);


return llvm::TableGenMain(argv[0], &CallbackFunc);


}
SQLGen entry point
29
int main(int argc, char **argv) {


cl::ParseCommandLineOptions(argc, argv);


return llvm::TableGenMain(argv[0], &CallbackFunc);


}
bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records)
SQLGen entry point
29
int main(int argc, char **argv) {


cl::ParseCommandLineOptions(argc, argv);


return llvm::TableGenMain(argv[0], &CallbackFunc);


}
bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records)
• OS: Stream to the output
fi
le (i.e. Output stream to print the SQL code)
SQLGen entry point
29
int main(int argc, char **argv) {


cl::ParseCommandLineOptions(argc, argv);


return llvm::TableGenMain(argv[0], &CallbackFunc);


}
bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records)
• OS: Stream to the output
fi
le (i.e. Output stream to print the SQL code)
• Records: In-memory representation of the parsed TableGen code
Creating SQL Tables
TableGen syntax in SQLGen
Recap: SQL table creation
31
CREATE TABLE Customer (


ID int,


Name varchar(255),


Affiliation varchar(255),


PRIMARY KEY (ID)


);
Generated SQL Code
Input TableGen Code
class Customer <string name,


string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
class Table {


int PrimaryKey = 0;


}
Enumerating TableGen class-es
32
bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) {


const auto &Classes = Records.getClasses();


...


}
Enumerating TableGen class-es
32
bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) {


const auto &Classes = Records.getClasses();


...


}
std::map<std::string, std::unique_ptr<llvm::Record>>
Enumerating TableGen class-es
32
bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) {


const auto &Classes = Records.getClasses();


...


}
std::map<std::string, std::unique_ptr<llvm::Record>>
Enumerating TableGen class-es
32
bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) {


const auto &Classes = Records.getClasses();


...


}
std::map<std::string, std::unique_ptr<llvm::Record>>
33
llvm::Record
33
llvm::Record
TableGen record TableGen class
33
llvm::Record
int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";
TableGen record TableGen class
33
llvm::Record
int ID = 0;


string Name = ?;


string Affiliation = ?;
int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";
TableGen record TableGen class
33
llvm::Record
llvm::Record::isClass() == false llvm::Record::isClass() == true
int ID = 0;


string Name = ?;


string Affiliation = ?;
int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";
TableGen record TableGen class
34
def john : Customer<"John Smith", "UC Irvine">;
class Customer <string name, string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
35
def john {


int PrimaryKey = 0;


int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";


}
class Customer <string name, string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
35
def john {


int PrimaryKey = 0;


int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";


}
class Customer <string name, string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
35
def john {


int PrimaryKey = 0;


int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";


}
class Customer <string name, string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
36
def john {


int PrimaryKey = 0;


int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";


}
class Customer <string name, string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
llvm::Record
36
def john {


int PrimaryKey = 0;


int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";


}
class Customer <string name, string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
llvm::Record
llvm::RecordVal
37
const auto &Classes = Records.getClasses();


for (const auto &P : Classes) {


auto ClassName = P.first;


Record &ClassRecord = *P.second;


}
38
const auto &Classes = Records.getClasses();


for (const auto &P : Classes) {


auto ClassName = P.first;


Record &ClassRecord = *P.second;


if (!ClassRecord.isSubClassOf("Table"))


continue;


}
39
const auto &Classes = Records.getClasses();


for (const auto &P : Classes) {


auto ClassName = P.first;


Record &ClassRecord = *P.second;


if (!ClassRecord.isSubClassOf("Table"))


continue;


OS << "CREATE TABLE " << ClassName << " (";


OS << ");n";


}
CREATE TABLE Customer (


);
40
const auto &Classes = Records.getClasses();


for (const auto &P : Classes) {


auto ClassName = P.first;


Record &ClassRecord = *P.second;


if (!ClassRecord.isSubClassOf("Table"))


continue;


OS << "CREATE TABLE " << ClassName << " (";


for (const RecordVal &RV : ClassRecord.getValues()) {


}


OS << ");n";


}
CREATE TABLE Customer (


);
41
const auto &Classes = Records.getClasses();


for (const auto &P : Classes) {


auto ClassName = P.first;


Record &ClassRecord = *P.second;


if (!ClassRecord.isSubClassOf("Table"))


continue;


OS << "CREATE TABLE " << ClassName << " (";


for (const RecordVal &RV : ClassRecord.getValues()) {


OS << "t" << RV.getName() << " ";


}


OS << ");n";


}
CREATE TABLE Customer (


ID


Name


Affiliation


);
42
const auto &Classes = Records.getClasses();


for (const auto &P : Classes) {


auto ClassName = P.first;


Record &ClassRecord = *P.second;


if (!ClassRecord.isSubClassOf("Table"))


continue;


OS << "CREATE TABLE " << ClassName << " (";


for (const RecordVal &RV : ClassRecord.getValues()) {


OS << "t" << RV.getName() << " ";


if (isa<IntRecTy>(RV.getType()))


OS << "int,";


}


OS << ");n";


}
CREATE TABLE Customer (


ID int,


Name


Affiliation


);
43
const auto &Classes = Records.getClasses();


for (const auto &P : Classes) {


auto ClassName = P.first;


Record &ClassRecord = *P.second;


if (!ClassRecord.isSubClassOf("Table"))


continue;


OS << "CREATE TABLE " << ClassName << " (";


for (const RecordVal &RV : ClassRecord.getValues()) {


OS << "t" << RV.getName() << " ";


if (isa<IntRecTy>(RV.getType()))


OS << "int,";


if (isa<StringRecTy>(RV.getType()))


OS << "varchar(255),";


}


OS << ");n";


}
CREATE TABLE Customer (


ID int,


Name varchar(255),


Affiliation varchar(255),


);
44
def john {


int PrimaryKey = 0;


int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";


}
class Customer <string name, string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
llvm::Record
llvm::RecordVal
44
def john {


int PrimaryKey = 0;


int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";


}
class Customer <string name, string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
llvm::Record
llvm::RecordVal
llvm::Init
Common derived classes of llvm::Init
45
llvm::Init llvm::TypedInit
Common derived classes of llvm::Init
45
llvm::Init llvm::TypedInit
llvm::IntInit
llvm::StringInit
llvm::DagInit
Common derived classes of llvm::Init
45
llvm::Init llvm::TypedInit
llvm::IntInit
llvm::StringInit
llvm::DagInit
llvm::VarInit
Common derived classes of llvm::Init
45
llvm::Init llvm::TypedInit
llvm::IntInit
llvm::StringInit
llvm::DagInit
int PrimaryKey = 0;


int ID = PrimaryKey;
llvm::VarInit
Common derived classes of llvm::Init
45
llvm::Init llvm::TypedInit
llvm::IntInit
llvm::StringInit
llvm::DagInit
int PrimaryKey = 0;


int ID = PrimaryKey;
llvm::VarInit
46
for (const auto &P : Classes) {


...


OS << "CREATE TABLE " << ClassName << " (";


for (const RecordVal &RV : ClassRecord.getValues()) {


OS << "t" << RV.getName() << " ";


...


Init *Val = RV.getValue();


if (auto *VI = dyn_cast<VarInit>(Val)) {


if (VI->getName() == "PrimaryKey")


OS << "PRIMARY KEY (" << RV.getName() << ")";


}


}


OS << ");n";


}
CREATE TABLE Customer (


ID int,


Name varchar(255),


Affiliation varchar(255),


PRIMARY KEY (ID)


);
46
for (const auto &P : Classes) {


...


OS << "CREATE TABLE " << ClassName << " (";


for (const RecordVal &RV : ClassRecord.getValues()) {


OS << "t" << RV.getName() << " ";


...


Init *Val = RV.getValue();


if (auto *VI = dyn_cast<VarInit>(Val)) {


if (VI->getName() == "PrimaryKey")


OS << "PRIMARY KEY (" << RV.getName() << ")";


}


}


OS << ");n";


}
CREATE TABLE Customer (


ID int,


Name varchar(255),


Affiliation varchar(255),


PRIMARY KEY (ID)


);
46
for (const auto &P : Classes) {


...


OS << "CREATE TABLE " << ClassName << " (";


for (const RecordVal &RV : ClassRecord.getValues()) {


OS << "t" << RV.getName() << " ";


...


Init *Val = RV.getValue();


if (auto *VI = dyn_cast<VarInit>(Val)) {


if (VI->getName() == "PrimaryKey")


OS << "PRIMARY KEY (" << RV.getName() << ")";


}


}


OS << ");n";


}
CREATE TABLE Customer (


ID int,


Name varchar(255),


Affiliation varchar(255),


PRIMARY KEY (ID)


);
SQL Row Insertion
TableGen syntax in SQLGen
Recap: Inserting rows into a SQL table
48
INSERT INTO Customer (


ID,


Name,


Affiliation


)


VALUES (0, "John Smith", "UC Irvine");
Generated SQL Code
Input TableGen Code
def john : Customer<"John Smith", "UC Irvine">;
class Customer <string name,


string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
Enumerating TableGen Records
49
bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) {


auto SQLRows = Records.getAllDerivedDefinitions("Table");


for (const Record *RowRecord : SQLRows) {


...


}


}
Enumerating TableGen Records
49
bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) {


auto SQLRows = Records.getAllDerivedDefinitions("Table");


for (const Record *RowRecord : SQLRows) {


...


}


}
50
def john {


int PrimaryKey = 0;


int ID = 0;


string Name = "John Smith";


string Affiliation = "UC Irvine";


}
class Customer <string name, string affiliation> : Table {


int ID = PrimaryKey;


string Name = name;


string Affiliation = affiliation;


}
llvm::Record
llvm::RecordVal
llvm::Init
Recap: In-memory representations for TableGen records / classes
51
for (const Record *RowRecord : SQLRows) {


OS << "INSERT INTO " << ClassName << " (n";


for (const RecordVal &RV : RowRecord->getValues()) {


}


OS << ")n";


}
INSERT INTO Customer (


)
52
for (const Record *RowRecord : SQLRows) {


OS << "INSERT INTO " << ClassName << " (n";


for (const RecordVal &RV : RowRecord->getValues()) {


auto Name = RV.getName();


OS << "t" << Name << ",n";


}


OS << ")n";


}
INSERT INTO Customer (


ID,


Name,


Affiliation


)
53
for (const Record *RowRecord : SQLRows) {


OS << "INSERT INTO " << ClassName << " (n";


for (const RecordVal &RV : RowRecord->getValues()) {


auto Name = RV.getName();


OS << "t" << Name << ",n";


}


OS << ")n";


OS << "VALUES (";


for (const RecordVal &RV : RowRecord->getValues()) {


const Init *Val = RV.getValue();


OS << Val->getAsString() << ", ";


}


OS << ");n";


}
INSERT INTO Customer (


ID,


Name,


Affiliation


)


VALUES (0, "John Smith", "UC Irvine");
53
for (const Record *RowRecord : SQLRows) {


OS << "INSERT INTO " << ClassName << " (n";


for (const RecordVal &RV : RowRecord->getValues()) {


auto Name = RV.getName();


OS << "t" << Name << ",n";


}


OS << ")n";


OS << "VALUES (";


for (const RecordVal &RV : RowRecord->getValues()) {


const Init *Val = RV.getValue();


OS << Val->getAsString() << ", ";


}


OS << ");n";


}
INSERT INTO Customer (


ID,


Name,


Affiliation


)


VALUES (0, "John Smith", "UC Irvine");
Making SQL Queries
TableGen syntax in SQLGen
Making queries
55
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
Generated SQL Code
Input TableGen Code
class Query <string table,


dag query_fields, dag condition> {


string TableName = table;


dag Fields = query_fields;


dag WhereClause = condition;


}
TableGen syntax in SQLGen
Making queries
55
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
Generated SQL Code
Input TableGen Code
class Query <string table,


dag query_fields, dag condition> {


string TableName = table;


dag Fields = query_fields;


dag WhereClause = condition;


}
TableGen syntax in SQLGen
Making queries
55
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
Generated SQL Code
Input TableGen Code
class Query <string table,


dag query_fields, dag condition> {


string TableName = table;


dag Fields = query_fields;


dag WhereClause = condition;


}
TableGen syntax in SQLGen
Making queries
55
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
Generated SQL Code
Input TableGen Code
class Query <string table,


dag query_fields, dag condition> {


string TableName = table;


dag Fields = query_fields;


dag WhereClause = condition;


}
TableGen syntax in SQLGen
Making queries
56
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
Generated SQL Code
Input TableGen Code
def : Query<"Customer", (fields "Affiliation"),


(eq "Name", "John Smith":$str)>;
class Query <string table,


dag query_fields, dag condition> {


string TableName = table;


dag Fields = query_fields;


dag WhereClause = condition;


}
TableGen syntax in SQLGen
Making queries
56
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
Generated SQL Code
Input TableGen Code
def : Query<"Customer", (fields "Affiliation"),


(eq "Name", "John Smith":$str)>;
class Query <string table,


dag query_fields, dag condition> {


string TableName = table;


dag Fields = query_fields;


dag WhereClause = condition;


}
Anonymous record
TableGen syntax in SQLGen
Making queries
56
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
Generated SQL Code
Input TableGen Code
def : Query<"Customer", (fields "Affiliation"),


(eq "Name", "John Smith":$str)>;
class Query <string table,


dag query_fields, dag condition> {


string TableName = table;


dag Fields = query_fields;


dag WhereClause = condition;


}
Anonymous record
Example of the dag type
An expression tree
57
def plus;


def minus;


def var_x : Var {...}


dag expr = (plus 9, ("mul" 4, (minus var_x, 3)));
Modeling expression: 9 + 4 * (x - 3)
Example of the dag type
An expression tree
57
def plus;


def minus;


def var_x : Var {...}


dag expr = (plus 9, ("mul" 4, (minus var_x, 3)));
plus
9
Modeling expression: 9 + 4 * (x - 3)
Example of the dag type
An expression tree
57
def plus;


def minus;


def var_x : Var {...}


dag expr = (plus 9, ("mul" 4, (minus var_x, 3)));
plus
9 “mul”
4
Modeling expression: 9 + 4 * (x - 3)
Example of the dag type
An expression tree
57
def plus;


def minus;


def var_x : Var {...}


dag expr = (plus 9, ("mul" 4, (minus var_x, 3)));
plus
9 “mul”
4 minus
3
var_x
Modeling expression: 9 + 4 * (x - 3)
Making SQL queries
More examples
58
SELECT Person, Amount FROM Orders


WHERE Amount > 8;
def : Query<"Orders", (fields "Person", "Amount"),


(gt "Amount", 8)>
TableGen
SQL
Making SQL queries
More examples
58
SELECT Person, Amount FROM Orders


WHERE Amount > 8;
def : Query<"Orders", (fields "Person", "Amount"),


(gt "Amount", 8)>
TableGen
SQL
SELECT ProductName, Person FROM Orders


WHERE Amount > 8 AND Person <> 1;
def : Query<"Orders", (fields "ProductName", "Person"),


(and (gt "Amount", 8), (ne "Person", 1))>;
TableGen
SQL
TableGen syntax in SQLGen
Making queries
59
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
Generated SQL Code
Input TableGen Code
def : Query<"Customer", (fields "Affiliation"),


(eq "Name", "John Smith":$str)>;
class Query <string table,


dag query_fields, dag condition> {


string TableName = table;


dag Fields = query_fields;


dag WhereClause = condition;


}
TableGen syntax in SQLGen
Making queries
59
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
Generated SQL Code
Input TableGen Code
def : Query<"Customer", (fields "Affiliation"),


(eq "Name", "John Smith":$str)>;
class Query <string table,


dag query_fields, dag condition> {


string TableName = table;


dag Fields = query_fields;


dag WhereClause = condition;


}
TableGen syntax in SQLGen
Making queries
59
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
Generated SQL Code
Input TableGen Code
def : Query<"Customer", (fields "Affiliation"),


(eq "Name", "John Smith":$str)>;
class Query <string table,


dag query_fields, dag condition> {


string TableName = table;


dag Fields = query_fields;


dag WhereClause = condition;


}
An argument with tag
60
auto SQLQueries = Records.getAllDerivedDefinitions("Query");


for (const Record *Query : SQLQueries) {


OS << "SELECT ";


}
SELECT
61
auto SQLQueries = Records.getAllDerivedDefinitions("Query");


for (const Record *Query : SQLQueries) {


auto TableName = Query->getValueAsString("TableName");


OS << "SELECT ";


OS << " FROM " << TableName << "n";


}
SELECT Affiliation FROM Customer
62
auto SQLQueries = Records.getAllDerivedDefinitions("Query");


for (const Record *Query : SQLQueries) {


auto TableName = Query->getValueAsString("TableName");


const DagInit *Fields = Query->getValueAsDag("Fields");


OS << "SELECT ";


for (const Init *Arg : Fields->getArgs())


OS << Arg->getAsUnquotedString() << ",";


OS << " FROM " << TableName << "n";


}
SELECT Affiliation FROM Customer
63
void visitWhereClause(const DagInit *Term, raw_ostream &OS) {


}
SELECT Affiliation FROM Customer


WHERE
(eq "Name", "John Smith":$str)
TableGen
SQL
64
void visitWhereClause(const DagInit *Term, raw_ostream &OS) {


for (int i = 0; i < Term->arg_size(); ++i) {


const Init *Arg = Term->getArg(i);


}


}
SELECT Affiliation FROM Customer


WHERE
(eq "Name", "John Smith":$str)
TableGen
SQL
65
void visitWhereClause(const DagInit *Term, raw_ostream &OS) {


for (int i = 0; i < Term->arg_size(); ++i) {


const Init *Arg = Term->getArg(i);


if (const auto *ArgDag = dyn_cast<DagInit>(Arg))


visitWhereClause(ArgDag, OS);


}


}
SELECT Affiliation FROM Customer


WHERE
(eq "Name", "John Smith":$str)
TableGen
SQL
66
void visitWhereClause(const DagInit *Term, raw_ostream &OS) {


for (int i = 0; i < Term->arg_size(); ++i) {


const Init *Arg = Term->getArg(i);


if (const auto *ArgDag = dyn_cast<DagInit>(Arg))


visitWhereClause(ArgDag, OS);


else {


if (Term->getArgName(i) == "str")


OS << Arg->getAsString();


else


OS << Arg->getAsUnquotedString();


}


}


}
SELECT Affiliation FROM Customer


WHERE Name “John Smith";
(eq "Name", "John Smith":$str)
TableGen
SQL
66
void visitWhereClause(const DagInit *Term, raw_ostream &OS) {


for (int i = 0; i < Term->arg_size(); ++i) {


const Init *Arg = Term->getArg(i);


if (const auto *ArgDag = dyn_cast<DagInit>(Arg))


visitWhereClause(ArgDag, OS);


else {


if (Term->getArgName(i) == "str")


OS << Arg->getAsString();


else


OS << Arg->getAsUnquotedString();


}


}


}
SELECT Affiliation FROM Customer


WHERE Name “John Smith";
(eq "Name", "John Smith":$str)
TableGen
SQL
67
void visitWhereClause(const DagInit *Term, raw_ostream &OS) {


const Init *Operator = Term->getOperator();


for (int i = 0; i < Term->arg_size(); ++i) {


const Init *Arg = Term->getArg(i);


if (const auto *ArgDag = dyn_cast<DagInit>(Arg))


visitWhereClause(ArgDag, OS);


else {


if (Term->getArgName(i) == "str")


OS << Arg->getAsString();


else


OS << Arg->getAsUnquotedString();


}


if (i < Term->arg_size() - 1)


printOperator(Operator);


}


}
SELECT Affiliation FROM Customer


WHERE Name = "John Smith";
(eq "Name", "John Smith":$str)
TableGen
SQL
Epilogue
Recap: Why should I learn to write a TG backend?
Despite being a DSL, TableGen is actually pretty versatile

Always require a specific TableGen backend

LLVM has provided nice infrastructures to work with TableGen code
69
Other useful TableGen syntax
The multiclass - creating multiple records at once

TableGen operators (a.k.a bang operators) - e.g. !add, !mul, !or

Bits slice

String concatenation via ‘#’

Casting from string to a record

70
Sample code
71
https://github.com/mshockwave/SQLGen
• Hierarchical records via FOREIGN KEY

• Ordering
fi
elds via ORDER BY

• Using LLVM LIT for testing
Some additional features / highlights…
Thank you!
72
GitHub: mshockwave

Email: minyihh@uci.edu 

25% book discount code: 25MINLLVM
Redeem:
Nov 15 ~ Nov 20, 2021

More Related Content

What's hot (20)

PPTX
LLVM Backend Porting
Shiva Chen
 
PPTX
LLVM Instruction Selection
Shiva Chen
 
PDF
Part II: LLVM Intermediate Representation
Wei-Ren Chen
 
PDF
BusyBox for Embedded Linux
Emertxe Information Technologies Pvt Ltd
 
PDF
Instruction Combine in LLVM
Wang Hsiangkai
 
PPTX
Linux kernel debugging
Hao-Ran Liu
 
PDF
The Spectre of Meltdowns
Andriy Berestovskyy
 
PPT
LLVM
guest3e5046
 
PDF
Q2.12: Debugging with GDB
Linaro
 
PPTX
Linux kernel
Goutam Sahoo
 
PDF
Kernel com requisitos temporais
Rodrigo Almeida
 
PDF
Kernel Recipes 2019 - Faster IO through io_uring
Anne Nicolas
 
PPT
Gcc porting
Shiva Chen
 
PDF
BPF Internals (eBPF)
Brendan Gregg
 
PDF
Virtual Machine Constructions for Dummies
National Cheng Kung University
 
PDF
TMUX Rocks!
Kent Chen
 
PPTX
Essentials of Multithreaded System Programming in C++
Shuo Chen
 
PDF
Desenvolvimento de drivers para sistemas embarcados
Rodrigo Almeida
 
PDF
Linux Huge Pages
Geraldo Netto
 
PDF
Introduction to FreeRTOS
ICS
 
LLVM Backend Porting
Shiva Chen
 
LLVM Instruction Selection
Shiva Chen
 
Part II: LLVM Intermediate Representation
Wei-Ren Chen
 
BusyBox for Embedded Linux
Emertxe Information Technologies Pvt Ltd
 
Instruction Combine in LLVM
Wang Hsiangkai
 
Linux kernel debugging
Hao-Ran Liu
 
The Spectre of Meltdowns
Andriy Berestovskyy
 
Q2.12: Debugging with GDB
Linaro
 
Linux kernel
Goutam Sahoo
 
Kernel com requisitos temporais
Rodrigo Almeida
 
Kernel Recipes 2019 - Faster IO through io_uring
Anne Nicolas
 
Gcc porting
Shiva Chen
 
BPF Internals (eBPF)
Brendan Gregg
 
Virtual Machine Constructions for Dummies
National Cheng Kung University
 
TMUX Rocks!
Kent Chen
 
Essentials of Multithreaded System Programming in C++
Shuo Chen
 
Desenvolvimento de drivers para sistemas embarcados
Rodrigo Almeida
 
Linux Huge Pages
Geraldo Netto
 
Introduction to FreeRTOS
ICS
 

Similar to How to write a TableGen backend (20)

PDF
C++ plus data structures, 3rd edition (2003)
SHC
 
PDF
DevLOVE Beautiful Development - 第一幕 陽の巻
都元ダイスケ Miyamoto
 
PDF
C Plus Data Structures Subsequent Dale Nell B
noyzdapat39
 
PDF
Go Faster With Native Compilation
PGConf APAC
 
PDF
Go faster with_native_compilation Part-2
Rajeev Rastogi (KRR)
 
PDF
TI1220 Lecture 14: Domain-Specific Languages
Eelco Visser
 
PDF
Relaxing global-as-view in mediated data integration from linked data
Alessandro Adamou
 
PDF
BerlinMeetup22-TableGen.pdf
Stefan Gränitz
 
PPTX
Domain-Specific Languages
Javier Canovas
 
PDF
Go Faster With Native Compilation
Rajeev Rastogi (KRR)
 
PDF
Is there a perfect data-parallel programming language? (Experiments with More...
Julian Hyde
 
PPT
cse3330-spring12-Ch2 (2).ppt
goodperson7
 
PDF
1 c prog1
CollegeStation
 
PPTX
DS ppt 123445544434t33vdbdbdbfgfPPtt.pptx
ssuser7b9bda1
 
KEY
The Return of the Living Datalog
Mike Fogus
 
PPTX
Rapid Development of Data Generators Using Meta Generators in PDGF
Tilmann Rabl
 
PPT
Bigtable
bhanupriyagupta19
 
PPT
Database system concepts
Kumar
 
PPT
Chapter02
sasa_eldoby
 
PDF
Code Generation
Eelco Visser
 
C++ plus data structures, 3rd edition (2003)
SHC
 
DevLOVE Beautiful Development - 第一幕 陽の巻
都元ダイスケ Miyamoto
 
C Plus Data Structures Subsequent Dale Nell B
noyzdapat39
 
Go Faster With Native Compilation
PGConf APAC
 
Go faster with_native_compilation Part-2
Rajeev Rastogi (KRR)
 
TI1220 Lecture 14: Domain-Specific Languages
Eelco Visser
 
Relaxing global-as-view in mediated data integration from linked data
Alessandro Adamou
 
BerlinMeetup22-TableGen.pdf
Stefan Gränitz
 
Domain-Specific Languages
Javier Canovas
 
Go Faster With Native Compilation
Rajeev Rastogi (KRR)
 
Is there a perfect data-parallel programming language? (Experiments with More...
Julian Hyde
 
cse3330-spring12-Ch2 (2).ppt
goodperson7
 
1 c prog1
CollegeStation
 
DS ppt 123445544434t33vdbdbdbfgfPPtt.pptx
ssuser7b9bda1
 
The Return of the Living Datalog
Mike Fogus
 
Rapid Development of Data Generators Using Meta Generators in PDGF
Tilmann Rabl
 
Database system concepts
Kumar
 
Chapter02
sasa_eldoby
 
Code Generation
Eelco Visser
 
Ad

More from Min-Yih Hsu (14)

PDF
Debug Information And Where They Come From
Min-Yih Hsu
 
PDF
MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
Min-Yih Hsu
 
PDF
Handling inline assembly in Clang and LLVM
Min-Yih Hsu
 
PDF
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
Min-Yih Hsu
 
PDF
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
Min-Yih Hsu
 
PDF
Paper Study - Demand-Driven Computation of Interprocedural Data Flow
Min-Yih Hsu
 
PDF
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
Min-Yih Hsu
 
PDF
Souper-Charging Peepholes with Target Machine Info
Min-Yih Hsu
 
PDF
From V8 to Modern Compilers
Min-Yih Hsu
 
PDF
Introduction to Khronos SYCL
Min-Yih Hsu
 
PDF
Trace Scheduling
Min-Yih Hsu
 
PDF
Polymer Start-Up (SITCON 2016)
Min-Yih Hsu
 
PDF
War of Native Speed on Web (SITCON2016)
Min-Yih Hsu
 
PDF
From Android NDK To AOSP
Min-Yih Hsu
 
Debug Information And Where They Come From
Min-Yih Hsu
 
MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
Min-Yih Hsu
 
Handling inline assembly in Clang and LLVM
Min-Yih Hsu
 
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
Min-Yih Hsu
 
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
Min-Yih Hsu
 
Paper Study - Demand-Driven Computation of Interprocedural Data Flow
Min-Yih Hsu
 
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
Min-Yih Hsu
 
Souper-Charging Peepholes with Target Machine Info
Min-Yih Hsu
 
From V8 to Modern Compilers
Min-Yih Hsu
 
Introduction to Khronos SYCL
Min-Yih Hsu
 
Trace Scheduling
Min-Yih Hsu
 
Polymer Start-Up (SITCON 2016)
Min-Yih Hsu
 
War of Native Speed on Web (SITCON2016)
Min-Yih Hsu
 
From Android NDK To AOSP
Min-Yih Hsu
 
Ad

Recently uploaded (20)

PPTX
Finding Your License Details in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PDF
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
PPTX
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
PDF
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
PPTX
Milwaukee Marketo User Group - Summer Road Trip: Mapping and Personalizing Yo...
bbedford2
 
PDF
IDM Crack with Internet Download Manager 6.42 Build 43 with Patch Latest 2025
bashirkhan333g
 
PPTX
Hardware(Central Processing Unit ) CU and ALU
RizwanaKalsoom2
 
PPTX
Agentic Automation: Build & Deploy Your First UiPath Agent
klpathrudu
 
PPTX
AEM User Group: India Chapter Kickoff Meeting
jennaf3
 
PPTX
Home Care Tools: Benefits, features and more
Third Rock Techkno
 
PDF
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
PPTX
Transforming Mining & Engineering Operations with Odoo ERP | Streamline Proje...
SatishKumar2651
 
PDF
Wondershare PDFelement Pro Crack for MacOS New Version Latest 2025
bashirkhan333g
 
PPTX
Foundations of Marketo Engage - Powering Campaigns with Marketo Personalization
bbedford2
 
PDF
MiniTool Partition Wizard Free Crack + Full Free Download 2025
bashirkhan333g
 
PDF
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
PPTX
OpenChain @ OSS NA - In From the Cold: Open Source as Part of Mainstream Soft...
Shane Coughlan
 
PPTX
Tally software_Introduction_Presentation
AditiBansal54083
 
PPTX
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
PDF
TheFutureIsDynamic-BoxLang witch Luis Majano.pdf
Ortus Solutions, Corp
 
Finding Your License Details in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
Milwaukee Marketo User Group - Summer Road Trip: Mapping and Personalizing Yo...
bbedford2
 
IDM Crack with Internet Download Manager 6.42 Build 43 with Patch Latest 2025
bashirkhan333g
 
Hardware(Central Processing Unit ) CU and ALU
RizwanaKalsoom2
 
Agentic Automation: Build & Deploy Your First UiPath Agent
klpathrudu
 
AEM User Group: India Chapter Kickoff Meeting
jennaf3
 
Home Care Tools: Benefits, features and more
Third Rock Techkno
 
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
Transforming Mining & Engineering Operations with Odoo ERP | Streamline Proje...
SatishKumar2651
 
Wondershare PDFelement Pro Crack for MacOS New Version Latest 2025
bashirkhan333g
 
Foundations of Marketo Engage - Powering Campaigns with Marketo Personalization
bbedford2
 
MiniTool Partition Wizard Free Crack + Full Free Download 2025
bashirkhan333g
 
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
OpenChain @ OSS NA - In From the Cold: Open Source as Part of Mainstream Soft...
Shane Coughlan
 
Tally software_Introduction_Presentation
AditiBansal54083
 
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
TheFutureIsDynamic-BoxLang witch Luis Majano.pdf
Ortus Solutions, Corp
 

How to write a TableGen backend

  • 1. Min-Yih “Min” Hsu @ LLVM Dev Meeting 2021 How to write a TableGen backend
  • 2. “Min” Hsu • Computer Science PhD Candidate in University of California, Irvine • Code owner of M68k LLVM backend • Author of book “LLVM Techniques, Tips and Best Practices” (2021) $ whoami 2
  • 4. TableGen in a nutshell 4
  • 5. TableGen in a nutshell • A Domain-Speci fi c Language (DSL) originated from the LLVM project. • It’s Turing complete! 4
  • 6. TableGen in a nutshell • A Domain-Speci fi c Language (DSL) originated from the LLVM project. • It’s Turing complete! • Originally invented to describe the instruction table of an LLVM target. 4
  • 7. TableGen in a nutshell • A Domain-Speci fi c Language (DSL) originated from the LLVM project. • It’s Turing complete! • Originally invented to describe the instruction table of an LLVM target. • Ex. The operands, assembly syntax, and ISel rules for each instruction. 4
  • 8. TableGen in a nutshell • A Domain-Speci fi c Language (DSL) originated from the LLVM project. • It’s Turing complete! • Originally invented to describe the instruction table of an LLVM target. • Ex. The operands, assembly syntax, and ISel rules for each instruction. • Now: Used in a wide variety of (completely) di ff erent areas inside LLVM. 4
  • 9. TableGen in a nutshell • A Domain-Speci fi c Language (DSL) originated from the LLVM project. • It’s Turing complete! • Originally invented to describe the instruction table of an LLVM target. • Ex. The operands, assembly syntax, and ISel rules for each instruction. • Now: Used in a wide variety of (completely) di ff erent areas inside LLVM. • Instruction scheduling info. 4
  • 10. TableGen in a nutshell • A Domain-Speci fi c Language (DSL) originated from the LLVM project. • It’s Turing complete! • Originally invented to describe the instruction table of an LLVM target. • Ex. The operands, assembly syntax, and ISel rules for each instruction. • Now: Used in a wide variety of (completely) di ff erent areas inside LLVM. • Instruction scheduling info. • Declaring IR attributes. 4
  • 11. TableGen in a nutshell • A Domain-Speci fi c Language (DSL) originated from the LLVM project. • It’s Turing complete! • Originally invented to describe the instruction table of an LLVM target. • Ex. The operands, assembly syntax, and ISel rules for each instruction. • Now: Used in a wide variety of (completely) di ff erent areas inside LLVM. • Instruction scheduling info. • Declaring IR attributes. • LLVM Option subsystem (e.g. Clang’s compiler fl ags). 4
  • 13. class Stuff { } 5 Layout of a template
  • 14. class Stuff { } 5 Layout of a template
  • 15. class Stuff { string Name; int Quantity; string Description; } 6 Layout of a template
  • 16. class Stuff { string Name; int Quantity; string Description; } 6 Fields Layout of a template
  • 17. class Stuff { string Name; int Quantity; string Description; } def water_bottle : Stuff { } 7 Fields Layout of a template
  • 18. class Stuff { string Name; int Quantity; string Description; } def water_bottle : Stuff { } 7 A record created with template Stuff Fields Layout of a template
  • 19. class Stuff { string Name; int Quantity; string Description; } def water_bottle : Stuff { } 7 A record created with template Stuff Fields Layout of a template
  • 20. class Stuff { string Name; int Quantity; string Description; } def water_bottle : Stuff { let Name = "Water bottle"; let Quantity = 1; let Description = "Stuff that helps you hydrate."; } 8 A record created with template Stuff Fields Layout of a template
  • 21. class Stuff { string Name; int Quantity; string Description; } def water_bottle : Stuff { let Name = "Water bottle"; let Quantity = 1; let Description = "Stuff that helps you hydrate."; } def smart_phone : Stuff { let Name "Smart phone"; let Quantity = 2; let Description = "Stuff that keeps you from hydrating."; } 9 Fields Layout of a template Another record created with template Stuff A record created with template Stuff
  • 22. class Stuff <string name, int quantity, string description> { string Name = name; int Quantity = quantity; string Description = description; } 10
  • 23. class Stuff <string name, int quantity, string description> { string Name = name; int Quantity = quantity; string Description = description; } def water_bottle : Stuff<"Water bottle", 1, "Stuff that helps you hydrate.">; def smart_phone : Stuff<"Smart phone", 2, "Stuff that prevents you from hydrating.">; 11
  • 24. 12 class Person { std::string Name; int Age; JobKind Job; }; Person Me{"Min", 12, WEEBUS}; OOP v.s. TableGen
  • 25. 12 class Person { std::string Name; int Age; JobKind Job; }; Person Me{"Min", 12, WEEBUS}; Encapsulates data OOP v.s. TableGen
  • 26. 13 class Person { std::string Name; int Age; JobKind Job; }; Person Me{"Min", 12, WEEBUS}; void foo(int N) { Me.Name = "Max"; } Encapsulates data Records are immutable OOP v.s. TableGen
  • 27. 14 class Person { std::string Name; int Age; JobKind Job; }; Person Me{"Min", 12, WEEBUS}; void foo(int N) { Me.Name = "Max"; Person Rick{“Rick", N, SINGER}; } Encapsulates data Records are immutable Constant values in fi elds OOP v.s. TableGen
  • 28. 15 class Person { std::string Name; int Age; JobKind Job; }; Person Me{"Min", 12, WEEBUS}; void foo(int N) { Me.Name = "Max"; Person Rick{“Rick", N, SINGER}; for (i = 0; i < N; ++i) SomeList.emplace_back(Person{...}); } Encapsulates data Records are immutable Constant values in fi elds Constant number of records OOP v.s. TableGen
  • 29. 16 Name Quantity Description Water Bottle 1 … Smart Phone 2 … Table “Stu f ” Relational DB v.s. TableGen
  • 30. 16 Fields are similar to columns Name Quantity Description Water Bottle 1 … Smart Phone 2 … Table “Stu f ” Relational DB v.s. TableGen
  • 31. 16 Fields are similar to columns Name Quantity Description Water Bottle 1 … Smart Phone 2 … Table “Stu f ” Relational DB v.s. TableGen Records do not belong to any table
  • 32. 16 Fields are similar to columns Name Quantity Description Water Bottle 1 … Smart Phone 2 … Table “Stu f ” Relational DB v.s. TableGen Records do not belong to any table Strong structure is not required
  • 33. 16 Fields are similar to columns Name Quantity Description Water Bottle 1 … Smart Phone 2 … Table “Stu f ” Relational DB v.s. TableGen Records do not belong to any table def foo { string A = “foo”; int B = 0; } def bar { int Z = 1; } def zoo; Strong structure is not required
  • 35. TableGen data types • Primitive types (common): int, string, bool, bit 17
  • 36. TableGen data types • Primitive types (common): int, string, bool, bit • Bit vector: bits<N> 17
  • 37. TableGen data types • Primitive types (common): int, string, bool, bit • Bit vector: bits<N> • List: list<T> 17
  • 38. TableGen data types • Primitive types (common): int, string, bool, bit • Bit vector: bits<N> • List: list<T> • Direct Acyclic Graph (DAG): dag 17
  • 39. TableGen data types • Primitive types (common): int, string, bool, bit • Bit vector: bits<N> • List: list<T> • Direct Acyclic Graph (DAG): dag • Represent DAG data symbolically 17
  • 40. TableGen data types • Primitive types (common): int, string, bool, bit • Bit vector: bits<N> • List: list<T> • Direct Acyclic Graph (DAG): dag • Represent DAG data symbolically • dag foo = (operator arg0, arg1, …) 17
  • 41. How to use TableGen records? 18
  • 42. How to use TableGen records? 19 def water_bottle : Stuff<"Water bottle", 1, "A stuff that…”>; def smart_phone : Stuff<"Smart phone", 2, "A stuff that…”>;
  • 43. How to use TableGen records? 19 def water_bottle : Stuff<"Water bottle", 1, "A stuff that…”>; def smart_phone : Stuff<"Smart phone", 2, "A stuff that…”>;
  • 44. How to use TableGen records? 19 def water_bottle : Stuff<"Water bottle", 1, "A stuff that…”>; def smart_phone : Stuff<"Smart phone", 2, "A stuff that…”>;
  • 45. How to use TableGen records? 19 def water_bottle : Stuff<"Water bottle", 1, "A stuff that…”>; def smart_phone : Stuff<"Smart phone", 2, "A stuff that…”>;
  • 46. TableGen backends 20 def water_bottle : Stuff<"Water bottle", 1, "A stuff that…”>; def smart_phone : Stuff<"Smart phone", 2, "A stuff that…”>; TableGen Backend 1 TableGen Backend 2 TableGen Backend 3
  • 47. TableGen backends 21 TableGen Backend 1 TableGen Backend 2 TableGen Backend 3 TableGen Parser TableGen Code Output 1 Output 2 Output 3
  • 48. TableGen usage in LLVM An example in LLVM backend 22 llvm-tblgen
  • 49. TableGen usage in LLVM An example in LLVM backend 22 llvm-tblgen InstrInfo TG Backend DAGISel TG Backend
  • 50. TableGen usage in LLVM An example in LLVM backend 22 llvm-tblgen InstrInfo TG Backend DAGISel TG Backend X86.td
  • 51. TableGen usage in LLVM An example in LLVM backend 22 llvm-tblgen InstrInfo TG Backend DAGISel TG Backend X86GenInstrInfo.inc X86GenDAGISel.inc X86.td
  • 52. TableGen usage in LLVM An example in LLVM backend 22 llvm-tblgen InstrInfo TG Backend DAGISel TG Backend X86GenInstrInfo.inc X86GenDAGISel.inc X86.td Files contain C/C++ code
  • 54. Why should I learn to write a TG backend? 24
  • 55. Why should I learn to write a TG backend? Despite being a DSL, TableGen is actually pretty versatile 24
  • 56. Why should I learn to write a TG backend? Despite being a DSL, TableGen is actually pretty versatile Always require a specific TableGen backend 24
  • 57. Why should I learn to write a TG backend? Despite being a DSL, TableGen is actually pretty versatile Always require a specific TableGen backend LLVM has provided nice infrastructures to work with TableGen code 24
  • 60. Project overview 25 Recap: Comparison with Relational DB A more fl exible way to represent static structural data
  • 61. Project overview SQLGen — Generate SQL from TableGen code 26 TableGen Code
  • 62. Project overview SQLGen — Generate SQL from TableGen code 26 TableGen Code TG Backend of SQLGen TableGen Parser SQLGen A standalone tool
  • 63. Project overview SQLGen — Generate SQL from TableGen code 26 TableGen Code TG Backend of SQLGen TableGen Parser SQLGen SQL Code A standalone tool
  • 64. TableGen syntax in SQLGen SQL table creation 27 CREATE TABLE Customer ( ID int, Name varchar(255), Affiliation varchar(255), PRIMARY KEY (ID) ); Generated SQL Code Input TableGen Code
  • 65. TableGen syntax in SQLGen SQL table creation 27 CREATE TABLE Customer ( ID int, Name varchar(255), Affiliation varchar(255), PRIMARY KEY (ID) ); Generated SQL Code Input TableGen Code class Table { int PrimaryKey = 0; }
  • 66. TableGen syntax in SQLGen SQL table creation 27 CREATE TABLE Customer ( ID int, Name varchar(255), Affiliation varchar(255), PRIMARY KEY (ID) ); Generated SQL Code Input TableGen Code class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; } class Table { int PrimaryKey = 0; }
  • 67. TableGen syntax in SQLGen SQL table creation 27 CREATE TABLE Customer ( ID int, Name varchar(255), Affiliation varchar(255), PRIMARY KEY (ID) ); Generated SQL Code Input TableGen Code class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; } class Table { int PrimaryKey = 0; }
  • 68. TableGen syntax in SQLGen Inserting rows into a SQL table 28 INSERT INTO Customer ( ID, Name, Affiliation ) VALUES (0, "John Smith", "UC Irvine"); Generated SQL Code Input TableGen Code
  • 69. TableGen syntax in SQLGen Inserting rows into a SQL table 28 INSERT INTO Customer ( ID, Name, Affiliation ) VALUES (0, "John Smith", "UC Irvine"); Generated SQL Code Input TableGen Code def john : Customer<"John Smith", "UC Irvine">;
  • 70. TableGen syntax in SQLGen Inserting rows into a SQL table 28 INSERT INTO Customer ( ID, Name, Affiliation ) VALUES (0, "John Smith", "UC Irvine"); Generated SQL Code Input TableGen Code def john : Customer<"John Smith", "UC Irvine">; class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; }
  • 71. SQLGen entry point 29 int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); return llvm::TableGenMain(argv[0], &CallbackFunc); }
  • 72. SQLGen entry point 29 int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); return llvm::TableGenMain(argv[0], &CallbackFunc); } bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records)
  • 73. SQLGen entry point 29 int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); return llvm::TableGenMain(argv[0], &CallbackFunc); } bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) • OS: Stream to the output fi le (i.e. Output stream to print the SQL code)
  • 74. SQLGen entry point 29 int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); return llvm::TableGenMain(argv[0], &CallbackFunc); } bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) • OS: Stream to the output fi le (i.e. Output stream to print the SQL code) • Records: In-memory representation of the parsed TableGen code
  • 76. TableGen syntax in SQLGen Recap: SQL table creation 31 CREATE TABLE Customer ( ID int, Name varchar(255), Affiliation varchar(255), PRIMARY KEY (ID) ); Generated SQL Code Input TableGen Code class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; } class Table { int PrimaryKey = 0; }
  • 77. Enumerating TableGen class-es 32 bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) { const auto &Classes = Records.getClasses(); ... }
  • 78. Enumerating TableGen class-es 32 bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) { const auto &Classes = Records.getClasses(); ... } std::map<std::string, std::unique_ptr<llvm::Record>>
  • 79. Enumerating TableGen class-es 32 bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) { const auto &Classes = Records.getClasses(); ... } std::map<std::string, std::unique_ptr<llvm::Record>>
  • 80. Enumerating TableGen class-es 32 bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) { const auto &Classes = Records.getClasses(); ... } std::map<std::string, std::unique_ptr<llvm::Record>>
  • 83. 33 llvm::Record int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; TableGen record TableGen class
  • 84. 33 llvm::Record int ID = 0; string Name = ?; string Affiliation = ?; int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; TableGen record TableGen class
  • 85. 33 llvm::Record llvm::Record::isClass() == false llvm::Record::isClass() == true int ID = 0; string Name = ?; string Affiliation = ?; int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; TableGen record TableGen class
  • 86. 34 def john : Customer<"John Smith", "UC Irvine">; class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; }
  • 87. 35 def john { int PrimaryKey = 0; int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; } class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; }
  • 88. 35 def john { int PrimaryKey = 0; int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; } class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; }
  • 89. 35 def john { int PrimaryKey = 0; int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; } class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; }
  • 90. 36 def john { int PrimaryKey = 0; int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; } class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; } llvm::Record
  • 91. 36 def john { int PrimaryKey = 0; int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; } class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; } llvm::Record llvm::RecordVal
  • 92. 37 const auto &Classes = Records.getClasses(); for (const auto &P : Classes) { auto ClassName = P.first; Record &ClassRecord = *P.second; }
  • 93. 38 const auto &Classes = Records.getClasses(); for (const auto &P : Classes) { auto ClassName = P.first; Record &ClassRecord = *P.second; if (!ClassRecord.isSubClassOf("Table")) continue; }
  • 94. 39 const auto &Classes = Records.getClasses(); for (const auto &P : Classes) { auto ClassName = P.first; Record &ClassRecord = *P.second; if (!ClassRecord.isSubClassOf("Table")) continue; OS << "CREATE TABLE " << ClassName << " ("; OS << ");n"; } CREATE TABLE Customer ( );
  • 95. 40 const auto &Classes = Records.getClasses(); for (const auto &P : Classes) { auto ClassName = P.first; Record &ClassRecord = *P.second; if (!ClassRecord.isSubClassOf("Table")) continue; OS << "CREATE TABLE " << ClassName << " ("; for (const RecordVal &RV : ClassRecord.getValues()) { } OS << ");n"; } CREATE TABLE Customer ( );
  • 96. 41 const auto &Classes = Records.getClasses(); for (const auto &P : Classes) { auto ClassName = P.first; Record &ClassRecord = *P.second; if (!ClassRecord.isSubClassOf("Table")) continue; OS << "CREATE TABLE " << ClassName << " ("; for (const RecordVal &RV : ClassRecord.getValues()) { OS << "t" << RV.getName() << " "; } OS << ");n"; } CREATE TABLE Customer ( ID Name Affiliation );
  • 97. 42 const auto &Classes = Records.getClasses(); for (const auto &P : Classes) { auto ClassName = P.first; Record &ClassRecord = *P.second; if (!ClassRecord.isSubClassOf("Table")) continue; OS << "CREATE TABLE " << ClassName << " ("; for (const RecordVal &RV : ClassRecord.getValues()) { OS << "t" << RV.getName() << " "; if (isa<IntRecTy>(RV.getType())) OS << "int,"; } OS << ");n"; } CREATE TABLE Customer ( ID int, Name Affiliation );
  • 98. 43 const auto &Classes = Records.getClasses(); for (const auto &P : Classes) { auto ClassName = P.first; Record &ClassRecord = *P.second; if (!ClassRecord.isSubClassOf("Table")) continue; OS << "CREATE TABLE " << ClassName << " ("; for (const RecordVal &RV : ClassRecord.getValues()) { OS << "t" << RV.getName() << " "; if (isa<IntRecTy>(RV.getType())) OS << "int,"; if (isa<StringRecTy>(RV.getType())) OS << "varchar(255),"; } OS << ");n"; } CREATE TABLE Customer ( ID int, Name varchar(255), Affiliation varchar(255), );
  • 99. 44 def john { int PrimaryKey = 0; int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; } class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; } llvm::Record llvm::RecordVal
  • 100. 44 def john { int PrimaryKey = 0; int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; } class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; } llvm::Record llvm::RecordVal llvm::Init
  • 101. Common derived classes of llvm::Init 45 llvm::Init llvm::TypedInit
  • 102. Common derived classes of llvm::Init 45 llvm::Init llvm::TypedInit llvm::IntInit llvm::StringInit llvm::DagInit
  • 103. Common derived classes of llvm::Init 45 llvm::Init llvm::TypedInit llvm::IntInit llvm::StringInit llvm::DagInit llvm::VarInit
  • 104. Common derived classes of llvm::Init 45 llvm::Init llvm::TypedInit llvm::IntInit llvm::StringInit llvm::DagInit int PrimaryKey = 0; int ID = PrimaryKey; llvm::VarInit
  • 105. Common derived classes of llvm::Init 45 llvm::Init llvm::TypedInit llvm::IntInit llvm::StringInit llvm::DagInit int PrimaryKey = 0; int ID = PrimaryKey; llvm::VarInit
  • 106. 46 for (const auto &P : Classes) { ... OS << "CREATE TABLE " << ClassName << " ("; for (const RecordVal &RV : ClassRecord.getValues()) { OS << "t" << RV.getName() << " "; ... Init *Val = RV.getValue(); if (auto *VI = dyn_cast<VarInit>(Val)) { if (VI->getName() == "PrimaryKey") OS << "PRIMARY KEY (" << RV.getName() << ")"; } } OS << ");n"; } CREATE TABLE Customer ( ID int, Name varchar(255), Affiliation varchar(255), PRIMARY KEY (ID) );
  • 107. 46 for (const auto &P : Classes) { ... OS << "CREATE TABLE " << ClassName << " ("; for (const RecordVal &RV : ClassRecord.getValues()) { OS << "t" << RV.getName() << " "; ... Init *Val = RV.getValue(); if (auto *VI = dyn_cast<VarInit>(Val)) { if (VI->getName() == "PrimaryKey") OS << "PRIMARY KEY (" << RV.getName() << ")"; } } OS << ");n"; } CREATE TABLE Customer ( ID int, Name varchar(255), Affiliation varchar(255), PRIMARY KEY (ID) );
  • 108. 46 for (const auto &P : Classes) { ... OS << "CREATE TABLE " << ClassName << " ("; for (const RecordVal &RV : ClassRecord.getValues()) { OS << "t" << RV.getName() << " "; ... Init *Val = RV.getValue(); if (auto *VI = dyn_cast<VarInit>(Val)) { if (VI->getName() == "PrimaryKey") OS << "PRIMARY KEY (" << RV.getName() << ")"; } } OS << ");n"; } CREATE TABLE Customer ( ID int, Name varchar(255), Affiliation varchar(255), PRIMARY KEY (ID) );
  • 110. TableGen syntax in SQLGen Recap: Inserting rows into a SQL table 48 INSERT INTO Customer ( ID, Name, Affiliation ) VALUES (0, "John Smith", "UC Irvine"); Generated SQL Code Input TableGen Code def john : Customer<"John Smith", "UC Irvine">; class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; }
  • 111. Enumerating TableGen Records 49 bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) { auto SQLRows = Records.getAllDerivedDefinitions("Table"); for (const Record *RowRecord : SQLRows) { ... } }
  • 112. Enumerating TableGen Records 49 bool CallbackFunc(raw_ostream &OS, RecordKeeper &Records) { auto SQLRows = Records.getAllDerivedDefinitions("Table"); for (const Record *RowRecord : SQLRows) { ... } }
  • 113. 50 def john { int PrimaryKey = 0; int ID = 0; string Name = "John Smith"; string Affiliation = "UC Irvine"; } class Customer <string name, string affiliation> : Table { int ID = PrimaryKey; string Name = name; string Affiliation = affiliation; } llvm::Record llvm::RecordVal llvm::Init Recap: In-memory representations for TableGen records / classes
  • 114. 51 for (const Record *RowRecord : SQLRows) { OS << "INSERT INTO " << ClassName << " (n"; for (const RecordVal &RV : RowRecord->getValues()) { } OS << ")n"; } INSERT INTO Customer ( )
  • 115. 52 for (const Record *RowRecord : SQLRows) { OS << "INSERT INTO " << ClassName << " (n"; for (const RecordVal &RV : RowRecord->getValues()) { auto Name = RV.getName(); OS << "t" << Name << ",n"; } OS << ")n"; } INSERT INTO Customer ( ID, Name, Affiliation )
  • 116. 53 for (const Record *RowRecord : SQLRows) { OS << "INSERT INTO " << ClassName << " (n"; for (const RecordVal &RV : RowRecord->getValues()) { auto Name = RV.getName(); OS << "t" << Name << ",n"; } OS << ")n"; OS << "VALUES ("; for (const RecordVal &RV : RowRecord->getValues()) { const Init *Val = RV.getValue(); OS << Val->getAsString() << ", "; } OS << ");n"; } INSERT INTO Customer ( ID, Name, Affiliation ) VALUES (0, "John Smith", "UC Irvine");
  • 117. 53 for (const Record *RowRecord : SQLRows) { OS << "INSERT INTO " << ClassName << " (n"; for (const RecordVal &RV : RowRecord->getValues()) { auto Name = RV.getName(); OS << "t" << Name << ",n"; } OS << ")n"; OS << "VALUES ("; for (const RecordVal &RV : RowRecord->getValues()) { const Init *Val = RV.getValue(); OS << Val->getAsString() << ", "; } OS << ");n"; } INSERT INTO Customer ( ID, Name, Affiliation ) VALUES (0, "John Smith", "UC Irvine");
  • 119. TableGen syntax in SQLGen Making queries 55 SELECT Affiliation FROM Customer WHERE Name = "John Smith"; Generated SQL Code Input TableGen Code class Query <string table, dag query_fields, dag condition> { string TableName = table; dag Fields = query_fields; dag WhereClause = condition; }
  • 120. TableGen syntax in SQLGen Making queries 55 SELECT Affiliation FROM Customer WHERE Name = "John Smith"; Generated SQL Code Input TableGen Code class Query <string table, dag query_fields, dag condition> { string TableName = table; dag Fields = query_fields; dag WhereClause = condition; }
  • 121. TableGen syntax in SQLGen Making queries 55 SELECT Affiliation FROM Customer WHERE Name = "John Smith"; Generated SQL Code Input TableGen Code class Query <string table, dag query_fields, dag condition> { string TableName = table; dag Fields = query_fields; dag WhereClause = condition; }
  • 122. TableGen syntax in SQLGen Making queries 55 SELECT Affiliation FROM Customer WHERE Name = "John Smith"; Generated SQL Code Input TableGen Code class Query <string table, dag query_fields, dag condition> { string TableName = table; dag Fields = query_fields; dag WhereClause = condition; }
  • 123. TableGen syntax in SQLGen Making queries 56 SELECT Affiliation FROM Customer WHERE Name = "John Smith"; Generated SQL Code Input TableGen Code def : Query<"Customer", (fields "Affiliation"), (eq "Name", "John Smith":$str)>; class Query <string table, dag query_fields, dag condition> { string TableName = table; dag Fields = query_fields; dag WhereClause = condition; }
  • 124. TableGen syntax in SQLGen Making queries 56 SELECT Affiliation FROM Customer WHERE Name = "John Smith"; Generated SQL Code Input TableGen Code def : Query<"Customer", (fields "Affiliation"), (eq "Name", "John Smith":$str)>; class Query <string table, dag query_fields, dag condition> { string TableName = table; dag Fields = query_fields; dag WhereClause = condition; } Anonymous record
  • 125. TableGen syntax in SQLGen Making queries 56 SELECT Affiliation FROM Customer WHERE Name = "John Smith"; Generated SQL Code Input TableGen Code def : Query<"Customer", (fields "Affiliation"), (eq "Name", "John Smith":$str)>; class Query <string table, dag query_fields, dag condition> { string TableName = table; dag Fields = query_fields; dag WhereClause = condition; } Anonymous record
  • 126. Example of the dag type An expression tree 57 def plus; def minus; def var_x : Var {...} dag expr = (plus 9, ("mul" 4, (minus var_x, 3))); Modeling expression: 9 + 4 * (x - 3)
  • 127. Example of the dag type An expression tree 57 def plus; def minus; def var_x : Var {...} dag expr = (plus 9, ("mul" 4, (minus var_x, 3))); plus 9 Modeling expression: 9 + 4 * (x - 3)
  • 128. Example of the dag type An expression tree 57 def plus; def minus; def var_x : Var {...} dag expr = (plus 9, ("mul" 4, (minus var_x, 3))); plus 9 “mul” 4 Modeling expression: 9 + 4 * (x - 3)
  • 129. Example of the dag type An expression tree 57 def plus; def minus; def var_x : Var {...} dag expr = (plus 9, ("mul" 4, (minus var_x, 3))); plus 9 “mul” 4 minus 3 var_x Modeling expression: 9 + 4 * (x - 3)
  • 130. Making SQL queries More examples 58 SELECT Person, Amount FROM Orders WHERE Amount > 8; def : Query<"Orders", (fields "Person", "Amount"), (gt "Amount", 8)> TableGen SQL
  • 131. Making SQL queries More examples 58 SELECT Person, Amount FROM Orders WHERE Amount > 8; def : Query<"Orders", (fields "Person", "Amount"), (gt "Amount", 8)> TableGen SQL SELECT ProductName, Person FROM Orders WHERE Amount > 8 AND Person <> 1; def : Query<"Orders", (fields "ProductName", "Person"), (and (gt "Amount", 8), (ne "Person", 1))>; TableGen SQL
  • 132. TableGen syntax in SQLGen Making queries 59 SELECT Affiliation FROM Customer WHERE Name = "John Smith"; Generated SQL Code Input TableGen Code def : Query<"Customer", (fields "Affiliation"), (eq "Name", "John Smith":$str)>; class Query <string table, dag query_fields, dag condition> { string TableName = table; dag Fields = query_fields; dag WhereClause = condition; }
  • 133. TableGen syntax in SQLGen Making queries 59 SELECT Affiliation FROM Customer WHERE Name = "John Smith"; Generated SQL Code Input TableGen Code def : Query<"Customer", (fields "Affiliation"), (eq "Name", "John Smith":$str)>; class Query <string table, dag query_fields, dag condition> { string TableName = table; dag Fields = query_fields; dag WhereClause = condition; }
  • 134. TableGen syntax in SQLGen Making queries 59 SELECT Affiliation FROM Customer WHERE Name = "John Smith"; Generated SQL Code Input TableGen Code def : Query<"Customer", (fields "Affiliation"), (eq "Name", "John Smith":$str)>; class Query <string table, dag query_fields, dag condition> { string TableName = table; dag Fields = query_fields; dag WhereClause = condition; } An argument with tag
  • 135. 60 auto SQLQueries = Records.getAllDerivedDefinitions("Query"); for (const Record *Query : SQLQueries) { OS << "SELECT "; } SELECT
  • 136. 61 auto SQLQueries = Records.getAllDerivedDefinitions("Query"); for (const Record *Query : SQLQueries) { auto TableName = Query->getValueAsString("TableName"); OS << "SELECT "; OS << " FROM " << TableName << "n"; } SELECT Affiliation FROM Customer
  • 137. 62 auto SQLQueries = Records.getAllDerivedDefinitions("Query"); for (const Record *Query : SQLQueries) { auto TableName = Query->getValueAsString("TableName"); const DagInit *Fields = Query->getValueAsDag("Fields"); OS << "SELECT "; for (const Init *Arg : Fields->getArgs()) OS << Arg->getAsUnquotedString() << ","; OS << " FROM " << TableName << "n"; } SELECT Affiliation FROM Customer
  • 138. 63 void visitWhereClause(const DagInit *Term, raw_ostream &OS) { } SELECT Affiliation FROM Customer WHERE (eq "Name", "John Smith":$str) TableGen SQL
  • 139. 64 void visitWhereClause(const DagInit *Term, raw_ostream &OS) { for (int i = 0; i < Term->arg_size(); ++i) { const Init *Arg = Term->getArg(i); } } SELECT Affiliation FROM Customer WHERE (eq "Name", "John Smith":$str) TableGen SQL
  • 140. 65 void visitWhereClause(const DagInit *Term, raw_ostream &OS) { for (int i = 0; i < Term->arg_size(); ++i) { const Init *Arg = Term->getArg(i); if (const auto *ArgDag = dyn_cast<DagInit>(Arg)) visitWhereClause(ArgDag, OS); } } SELECT Affiliation FROM Customer WHERE (eq "Name", "John Smith":$str) TableGen SQL
  • 141. 66 void visitWhereClause(const DagInit *Term, raw_ostream &OS) { for (int i = 0; i < Term->arg_size(); ++i) { const Init *Arg = Term->getArg(i); if (const auto *ArgDag = dyn_cast<DagInit>(Arg)) visitWhereClause(ArgDag, OS); else { if (Term->getArgName(i) == "str") OS << Arg->getAsString(); else OS << Arg->getAsUnquotedString(); } } } SELECT Affiliation FROM Customer WHERE Name “John Smith"; (eq "Name", "John Smith":$str) TableGen SQL
  • 142. 66 void visitWhereClause(const DagInit *Term, raw_ostream &OS) { for (int i = 0; i < Term->arg_size(); ++i) { const Init *Arg = Term->getArg(i); if (const auto *ArgDag = dyn_cast<DagInit>(Arg)) visitWhereClause(ArgDag, OS); else { if (Term->getArgName(i) == "str") OS << Arg->getAsString(); else OS << Arg->getAsUnquotedString(); } } } SELECT Affiliation FROM Customer WHERE Name “John Smith"; (eq "Name", "John Smith":$str) TableGen SQL
  • 143. 67 void visitWhereClause(const DagInit *Term, raw_ostream &OS) { const Init *Operator = Term->getOperator(); for (int i = 0; i < Term->arg_size(); ++i) { const Init *Arg = Term->getArg(i); if (const auto *ArgDag = dyn_cast<DagInit>(Arg)) visitWhereClause(ArgDag, OS); else { if (Term->getArgName(i) == "str") OS << Arg->getAsString(); else OS << Arg->getAsUnquotedString(); } if (i < Term->arg_size() - 1) printOperator(Operator); } } SELECT Affiliation FROM Customer WHERE Name = "John Smith"; (eq "Name", "John Smith":$str) TableGen SQL
  • 145. Recap: Why should I learn to write a TG backend? Despite being a DSL, TableGen is actually pretty versatile Always require a specific TableGen backend LLVM has provided nice infrastructures to work with TableGen code 69
  • 146. Other useful TableGen syntax The multiclass - creating multiple records at once TableGen operators (a.k.a bang operators) - e.g. !add, !mul, !or Bits slice String concatenation via ‘#’ Casting from string to a record 70
  • 147. Sample code 71 https://github.com/mshockwave/SQLGen • Hierarchical records via FOREIGN KEY • Ordering fi elds via ORDER BY • Using LLVM LIT for testing Some additional features / highlights…
  • 148. Thank you! 72 GitHub: mshockwave Email: [email protected] 25% book discount code: 25MINLLVM Redeem: Nov 15 ~ Nov 20, 2021