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
|
#include "cps/CodeGen.h"
#include "llvm/IR/Verifier.h"
using namespace llvm;
using namespace cps;
CodeGen::CodeGen() {
TheContext = std::make_unique<LLVMContext>();
TheModule = std::make_unique<Module>("cps_module", *TheContext);
Builder = std::make_unique<IRBuilder<>>(*TheContext);
SetupExternalFunctions();
}
void CodeGen::SetupExternalFunctions() {
// printf(i8*, ...)
std::vector<Type*> PrintfArgs;
PrintfArgs.push_back(PointerType::getUnqual(*TheContext));
FunctionType *PrintfType = FunctionType::get(Type::getInt32Ty(*TheContext), PrintfArgs, true);
PrintfFunc = TheModule->getOrInsertFunction("printf", PrintfType);
// scanf(i8*, ...)
FunctionType *ScanfType = FunctionType::get(Type::getInt32Ty(*TheContext), PrintfArgs, true);
ScanfFunc = TheModule->getOrInsertFunction("scanf", ScanfType);
// format %d\n and %d
PrintfFormatStr = Builder->CreateGlobalStringPtr("%d\n", "fmt_nl", 0, TheModule.get());
ScanfFormatStr = Builder->CreateGlobalStringPtr("%d", "fmt_in", 0, TheModule.get());
}
AllocaInst *CodeGen::CreateEntryBlockAlloca(Function *TheFunction, const std::string &VarName) {
IRBuilder<> TmpB(&TheFunction->getEntryBlock(), TheFunction->getEntryBlock().begin());
return TmpB.CreateAlloca(Type::getInt32Ty(*TheContext), nullptr, VarName);
}
void CodeGen::compile(const std::vector<std::unique_ptr<StmtAST>> &Statements) {
FunctionType *FT = FunctionType::get(Type::getInt32Ty(*TheContext), false);
Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get());
BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", F);
Builder->SetInsertPoint(BB);
for (const auto &Stmt : Statements) {
// DECLARE
if (auto *Decl = dynamic_cast<DeclareStmtAST*>(Stmt.get())) {
AllocaInst *Alloca = CreateEntryBlockAlloca(F, Decl->getName());
NamedValues[Decl->getName()] = Alloca;
// 0
Builder->CreateStore(ConstantInt::get(*TheContext, APInt(32, 0)), Alloca);
}
// ASSIGNMENT (x <- expr)
else if (auto *Assign = dynamic_cast<AssignStmtAST*>(Stmt.get())) {
Value *Val = emitExpr(Assign->getExpr());
if (Val) {
AllocaInst *Alloca = NamedValues[Assign->getName()];
if (Alloca) Builder->CreateStore(Val, Alloca);
}
}
// INPUT
else if (auto *In = dynamic_cast<InputStmtAST*>(Stmt.get())) {
AllocaInst *Alloca = NamedValues[In->getName()];
if (Alloca) {
std::vector<Value*> Args;
Args.push_back(ScanfFormatStr);
Args.push_back(Alloca);
Builder->CreateCall(ScanfFunc, Args);
}
}
// OUTPUT
else if (auto *Out = dynamic_cast<OutputStmtAST*>(Stmt.get())) {
Value *Val = emitExpr(Out->getExpr());
if (Val) {
// printf("%d\n", val)
std::vector<Value*> Args;
Args.push_back(PrintfFormatStr);
Args.push_back(Val);
Builder->CreateCall(PrintfFunc, Args);
}
}
}
// main return 0
Builder->CreateRet(ConstantInt::get(*TheContext, APInt(32, 0)));
verifyFunction(*F);
}
void CodeGen::print() {
TheModule->print(errs(), nullptr);
}
Value *CodeGen::emitExpr(ExprAST *Expr) {
if (!Expr) return nullptr;
if (auto *Num = dynamic_cast<NumberExprAST*>(Expr)) {
return ConstantInt::get(*TheContext, APInt(32, Num->getVal(), true));
}
if (auto *Var = dynamic_cast<VariableExprAST*>(Expr)) {
AllocaInst *A = NamedValues[Var->getName()];
if (!A) {
fprintf(stderr, "Error: Unknown variable name %s\n", Var->getName().c_str());
return nullptr;
}
return Builder->CreateLoad(Type::getInt32Ty(*TheContext), A, Var->getName().c_str());
}
if (auto *Bin = dynamic_cast<BinaryExprAST*>(Expr)) {
Value *L = emitExpr(Bin->getLHS());
Value *R = emitExpr(Bin->getRHS());
if (!L || !R) return nullptr;
switch (Bin->getOp()) {
case '+': return Builder->CreateAdd(L, R, "addtmp");
case '-': return Builder->CreateSub(L, R, "subtmp");
case '*': return Builder->CreateMul(L, R, "multmp");
case '/': return Builder->CreateSDiv(L, R, "divtmp");
default:
fprintf(stderr, "Error: Invalid binary operator\n");
return nullptr;
}
}
return nullptr;
}
|