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
|
#include "cps/FunctionGen.h"
#include "llvm/IR/Verifier.h"
#include <iostream>
using namespace llvm;
using namespace cps;
Type *FunctionGen::getLLVMType(const std::string &TypeName) {
if (TypeName == "INTEGER") return Type::getInt64Ty(Context);
if (TypeName == "BOOLEAN") return Type::getInt1Ty(Context);
if (TypeName == "REAL") return Type::getDoubleTy(Context);
if (TypeName == "VOID") return Type::getVoidTy(Context);
return Type::getInt64Ty(Context);
}
void FunctionGen::createArgumentAllocas(Function *F, const std::vector<std::pair<std::string, std::string>> &Args) {
Function::arg_iterator AI = F->arg_begin();
for (unsigned Idx = 0, E = Args.size(); Idx != E; ++Idx, ++AI) {
std::string ArgName = Args[Idx].first;
std::string ArgTypeStr = Args[Idx].second;
Type *ArgType = getLLVMType(ArgTypeStr);
IRBuilder<> TmpB(&F->getEntryBlock(), F->getEntryBlock().begin());
AllocaInst *Alloca = TmpB.CreateAlloca(ArgType, nullptr, ArgName);
Value *ArgVal = &(*AI);
Builder.CreateStore(ArgVal, Alloca);
NamedValues[ArgName] = Alloca;
}
}
Function *FunctionGen::emitPrototype(PrototypeAST *Proto) {
std::vector<Type*> ArgTypes;
for (const auto &Arg : Proto->getArgs()) {
ArgTypes.push_back(getLLVMType(Arg.second));
}
Type *RetType = getLLVMType(Proto->getReturnType());
FunctionType *FT = FunctionType::get(RetType, ArgTypes, false);
Function *F = Function::Create(FT, Function::ExternalLinkage, Proto->getName(), &Module);
unsigned Idx = 0;
for (auto &Arg : F->args()) {
if (Idx < Proto->getArgs().size())
Arg.setName(Proto->getArgs()[Idx++].first);
}
return F;
}
Function *FunctionGen::emitFunctionDef(FunctionDefAST *FuncAST,
const std::function<void(StmtAST*)> &StmtEmitter) {
PrototypeAST *Proto = FuncAST->getProto();
Function *TheFunction = Module.getFunction(Proto->getName());
if (!TheFunction)
TheFunction = emitPrototype(Proto);
if (!TheFunction) return nullptr;
if (!TheFunction->empty()) {
fprintf(stderr, "Error: Function %s cannot be redefined.\n", Proto->getName().c_str());
return nullptr;
}
BasicBlock *BB = BasicBlock::Create(Context, "entry", TheFunction);
Builder.SetInsertPoint(BB);
std::map<std::string, llvm::AllocaInst*> OldNamedValues = NamedValues;
NamedValues.clear();
createArgumentAllocas(TheFunction, Proto->getArgs());
for (const auto &Stmt : FuncAST->getBody()) {
StmtEmitter(Stmt.get());
}
if (!Builder.GetInsertBlock()->getTerminator()) {
if (Proto->getReturnType() == "VOID")
Builder.CreateRetVoid();
else
Builder.CreateRet(Constant::getNullValue(TheFunction->getReturnType()));
}
verifyFunction(*TheFunction);
NamedValues = OldNamedValues;
return TheFunction;
}
static Value *GenerateCall(llvm::Module &Module, llvm::IRBuilder<> &Builder, llvm::LLVMContext &Context,
const std::string &CalleeName, const std::vector<llvm::Value*> &Args) {
Function *CalleeF = Module.getFunction(CalleeName);
if (!CalleeF) {
std::vector<Type*> ArgTypes;
for (auto *Val : Args) ArgTypes.push_back(Val->getType());
FunctionType *FT = FunctionType::get(Type::getInt64Ty(Context), ArgTypes, false);
CalleeF = Function::Create(FT, Function::ExternalLinkage, CalleeName, &Module);
}
if (CalleeF->arg_size() != Args.size()) {
fprintf(stderr, "Error: Incorrect # arguments passed to %s\n", CalleeName.c_str());
return nullptr;
}
if (CalleeF->getReturnType()->isVoidTy()) {
return Builder.CreateCall(CalleeF, Args);
}
return Builder.CreateCall(CalleeF, Args, "calltmp");
}
llvm::Value *FunctionGen::emitCallExpr(CallExprAST *Call, const std::vector<llvm::Value*> &Args) {
return GenerateCall(Module, Builder, Context, Call->getCallee(), Args);
}
void FunctionGen::emitCallStmt(CallStmtAST *Call, const std::vector<llvm::Value*> &Args) {
GenerateCall(Module, Builder, Context, Call->getCallee(), Args);
}
void FunctionGen::emitReturn(ReturnStmtAST *Ret, llvm::Value *RetVal) {
if (RetVal) {
Builder.CreateRet(RetVal);
} else {
Builder.CreateRetVoid();
}
}
|