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

PPTX
Basic Structural Modeling
PDF
STL in C++
PDF
Modern c++ (C++ 11/14)
PDF
Quick introduction to scala
PPT
DS_PPT.ppt
PPTX
Pointers,virtual functions and polymorphism cpp
PPT
OOP in C++
PPTX
Constructor and Destructors in C++
Basic Structural Modeling
STL in C++
Modern c++ (C++ 11/14)
Quick introduction to scala
DS_PPT.ppt
Pointers,virtual functions and polymorphism cpp
OOP in C++
Constructor and Destructors in C++

What's hot (20)

PPTX
LLVM Backend Porting
PPTX
JQuery selectors
PDF
LLVM Register Allocation
PPTX
LLVM Instruction Selection
PDF
LLVM Register Allocation (2nd Version)
PDF
PPTX
An introduction to ROP
PPTX
Introduction to Debuggers
PPTX
Introduction à Python
PPT
Langage Java et Programmation Orienté Objet
PDF
Physical Memory Models.pdf
PPTX
U-Boot Porting on New Hardware
PDF
Linux Kernel - Virtual File System
PPTX
PDF
Debugging linux kernel tools and techniques
PPT
Javascript built in String Functions
PDF
Kernel Recipes 2017 - 20 years of Linux Virtual Memory - Andrea Arcangeli
KEY
JavaOne 2012 - JVM JIT for Dummies
PDF
Part II: LLVM Intermediate Representation
PDF
Qemu JIT Code Generator and System Emulation
LLVM Backend Porting
JQuery selectors
LLVM Register Allocation
LLVM Instruction Selection
LLVM Register Allocation (2nd Version)
An introduction to ROP
Introduction to Debuggers
Introduction à Python
Langage Java et Programmation Orienté Objet
Physical Memory Models.pdf
U-Boot Porting on New Hardware
Linux Kernel - Virtual File System
Debugging linux kernel tools and techniques
Javascript built in String Functions
Kernel Recipes 2017 - 20 years of Linux Virtual Memory - Andrea Arcangeli
JavaOne 2012 - JVM JIT for Dummies
Part II: LLVM Intermediate Representation
Qemu JIT Code Generator and System Emulation
Ad

Similar to How to write a TableGen backend (20)

PDF
C++ plus data structures, 3rd edition (2003)
 
PDF
DevLOVE Beautiful Development - 第一幕 陽の巻
PDF
C Plus Data Structures Subsequent Dale Nell B
PDF
Go Faster With Native Compilation
PDF
Go faster with_native_compilation Part-2
PDF
TI1220 Lecture 14: Domain-Specific Languages
PDF
Relaxing global-as-view in mediated data integration from linked data
PDF
BerlinMeetup22-TableGen.pdf
PPTX
Domain-Specific Languages
PDF
Go Faster With Native Compilation
PDF
INTRODUCTION TO DATA STRUCTURES AND ALGORITHM
PDF
INTRODUCTION TO DATA STRUCTURES AND ALGORITHMS
PDF
Is there a perfect data-parallel programming language? (Experiments with More...
PPT
cse3330-spring12-Ch2 (2).ppt
PDF
1 c prog1
PPTX
DS ppt 123445544434t33vdbdbdbfgfPPtt.pptx
KEY
The Return of the Living Datalog
PPTX
Rapid Development of Data Generators Using Meta Generators in PDGF
PPT
PPT
Database system concepts
C++ plus data structures, 3rd edition (2003)
 
DevLOVE Beautiful Development - 第一幕 陽の巻
C Plus Data Structures Subsequent Dale Nell B
Go Faster With Native Compilation
Go faster with_native_compilation Part-2
TI1220 Lecture 14: Domain-Specific Languages
Relaxing global-as-view in mediated data integration from linked data
BerlinMeetup22-TableGen.pdf
Domain-Specific Languages
Go Faster With Native Compilation
INTRODUCTION TO DATA STRUCTURES AND ALGORITHM
INTRODUCTION TO DATA STRUCTURES AND ALGORITHMS
Is there a perfect data-parallel programming language? (Experiments with More...
cse3330-spring12-Ch2 (2).ppt
1 c prog1
DS ppt 123445544434t33vdbdbdbfgfPPtt.pptx
The Return of the Living Datalog
Rapid Development of Data Generators Using Meta Generators in PDGF
Database system concepts
Ad

More from Min-Yih Hsu (14)

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

Recently uploaded (20)

PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
System and Network Administraation Chapter 3
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PPTX
L1 - Introduction to python Backend.pptx
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
AI in Product Development-omnex systems
PDF
medical staffing services at VALiNTRY
PPTX
Introduction to Artificial Intelligence
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PDF
How Creative Agencies Leverage Project Management Software.pdf
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
CHAPTER 2 - PM Management and IT Context
System and Network Administraation Chapter 3
Operating system designcfffgfgggggggvggggggggg
Wondershare Filmora 15 Crack With Activation Key [2025
Design an Analysis of Algorithms II-SECS-1021-03
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
2025 Textile ERP Trends: SAP, Odoo & Oracle
L1 - Introduction to python Backend.pptx
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
AI in Product Development-omnex systems
medical staffing services at VALiNTRY
Introduction to Artificial Intelligence
Navsoft: AI-Powered Business Solutions & Custom Software Development
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
wealthsignaloriginal-com-DS-text-... (1).pdf
How to Choose the Right IT Partner for Your Business in Malaysia
Internet Downloader Manager (IDM) Crack 6.42 Build 41
How Creative Agencies Leverage Project Management Software.pdf

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: minyihh@uci.edu 25% book discount code: 25MINLLVM Redeem: Nov 15 ~ Nov 20, 2021