1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
#include <utility>
#include <vector>
#include "LLVMVisitor.h"
LLVMRet LLVMVisitor::f_defun(const std::vector<Value*>& args) {
Name* fname = static_cast<Name*>(args[0]);
List* fargs = static_cast<List*>(args[1]);
/* Transform into IR of structure
* define @name(T arg1, T arg2) {
* ...
* ret T %reg
* }
*/
lreg.reset();
LLVMRet funcRet;
unsigned outbodySize = outBuf.size();
for (unsigned i = 2; i < args.size(); i++) {
funcRet = args[i]->Visit(*this);
}
std::map<std::string, LLVMRet> locals;
outFile << "define " << funcRet.type << " @" << fname->get_value() << "(";
for (Value* v : fargs->get_value()) {
std::string name = "%_" + static_cast<Name*>(v)->get_value();
// TODO: figure out argument type, based on usage
outFile << "i32 " << name;
locals.insert({ name, { "i32", name } });
if (v != fargs->get_value().back())
outFile << ", ";
}
outFile << ") {\n";
for (unsigned i = outbodySize; i < outBuf.size(); i++) {
outFile << outBuf[i];
}
while (outbodySize < outBuf.size()) {
outBuf.pop_back();
}
outFile << "\tret " << funcRet << "\n}\n\n";
return { funcRet.type, "@" + fname->get_value() };
}
LLVMRet LLVMVisitor::nameAsVar(const Name* name, std::map<std::string, LLVMRet>& locals) {
auto asLoc = locals.find("%_" + name->get_value());
if (asLoc != locals.end())
return asLoc->second;
auto asVar = vars_user.find("@" + name->get_value());
if (asVar != vars_user.end())
return asVar->second;
auto asFunc = funcs_user.find("@" + name->get_value());
if (asFunc != funcs_user.end())
return asFunc->second;
// TODO: try to figure out type (f_defun)
LLVMRet newLocal = { "i32", "%_" + name->get_value() };
locals.insert({ newLocal.addr, newLocal });
return newLocal;
}
LLVMRet LLVMVisitor::aritop(const std::string name, const std::vector<Value*>& args, unsigned astart) {
LLVMRet leftRet = args[astart]->Visit(*this);
LLVMRet rightRet = (args.size() - astart > 2) ? aritop(name, args, astart+1)
: args[astart+1]->Visit(*this);
Register r = lreg++;
outBuf.push_back(*r + " = " + ((leftRet.type == "double") ? "f" : "") + name + " " + leftRet.toStr() + ", " + rightRet.addr + "\n");
return { leftRet.type, *r };
}
LLVMRet LLVMVisitor::f_add(const std::vector<Value*>& args) {
return aritop("add", args);
}
LLVMRet LLVMVisitor::f_sub(const std::vector<Value*>& args) {
return aritop("sub", args);
}
LLVMRet LLVMVisitor::Visit(const Funcall& vfuncall) {
// Direct functions generate their own LLVM IR
auto directFuncIt = funcs_direct.find(vfuncall.get_funname());
if (directFuncIt != funcs_direct.end())
return directFuncIt->second(*this, vfuncall.get_args());
auto userFuncIt = funcs_user.find(vfuncall.get_funname());
if (userFuncIt == funcs_user.end())
throw std::runtime_error("Function isn't defined!");
/* Transform into IR of structure:
* %0 = call T @func(T %a1, T %a2)
*/
std::vector<LLVMRet> pargs;
for (Value* arg : vfuncall.get_args())
pargs.push_back(arg->Visit(*this));
std::string valReg = *(lreg++);
std::string out = valReg + " = call " + userFuncIt->second.toStr() + "(";
for (LLVMRet& arg : pargs) {
out += arg.toStr();
if (arg.addr != pargs.back().addr)
out += ", ";
}
outBuf.push_back(out += ")\n");
return { userFuncIt->second.type, valReg };
}
LLVMVisitor::LLVMVisitor(const char* fileName) : outFile(std::ofstream(fileName)), greg("@v"), lreg("%v"), funcs_direct(), funcs_user(), vars_user(), outBuf() {
if (!outFile.is_open())
throw std::runtime_error("Couldn't open file for writing!");
funcs_direct.insert({"+", &LLVMVisitor::f_add});
funcs_direct.insert({"-", &LLVMVisitor::f_sub});
funcs_direct.insert({"defun", &LLVMVisitor::f_defun});
}
void LLVMVisitor::insertMain() {
outFile << "define i32 @main() {\n";
for (std::string& codeline : outBuf) {
outFile << codeline;
}
outFile << "ret i32 0\n}\n";
}
LLVMRet LLVMVisitor::Visit(const Integer& vint) {
return { "i32", std::to_string(vint.get_value()) };
}
LLVMRet LLVMVisitor::Visit(const Float& vfloat) {
return { "double", std::to_string(vfloat.get_value()) };
}
LLVMRet LLVMVisitor::Visit(const Name& vname) {
return { "name", vname.get_value() };
}
LLVMRet LLVMVisitor::Visit(const List& vlist) {
return { "", "" }; // TODO
}
|