LLVM BitcodeEmitter completed for all statements.
Error handling is still missing.
This commit is contained in:
parent
4e883d148c
commit
2ce76a1dfd
|
@ -27,18 +27,54 @@
|
||||||
#include <llvm/IR/LLVMContext.h>
|
#include <llvm/IR/LLVMContext.h>
|
||||||
#include <llvm/IR/Module.h>
|
#include <llvm/IR/Module.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
using namespace monicelli;
|
using namespace monicelli;
|
||||||
using llvm::getGlobalContext;
|
using llvm::getGlobalContext;
|
||||||
|
|
||||||
|
|
||||||
struct BitcodeEmitter::Private {
|
struct BitcodeEmitter::Private {
|
||||||
llvm::Value *expval = nullptr;
|
llvm::Value *retval = nullptr;
|
||||||
llvm::Module *module = nullptr;
|
|
||||||
|
|
||||||
llvm::IRBuilder<> builder = llvm::IRBuilder<>(getGlobalContext());
|
llvm::IRBuilder<> builder = llvm::IRBuilder<>(getGlobalContext());
|
||||||
Scope<Id const*, llvm::Value*> scope;
|
Scope<std::string, llvm::AllocaInst*> scope;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
llvm::Type *LLVMType(Type const& type) {
|
||||||
|
switch (type) {
|
||||||
|
case Type::INT:
|
||||||
|
return llvm::Type::getInt64Ty(getGlobalContext());
|
||||||
|
case Type::CHAR:
|
||||||
|
return llvm::Type::getInt8Ty(getGlobalContext());
|
||||||
|
case Type::FLOAT:
|
||||||
|
return llvm::Type::getFloatTy(getGlobalContext());
|
||||||
|
case Type::BOOL:
|
||||||
|
return llvm::Type::getInt1Ty(getGlobalContext());
|
||||||
|
case Type::DOUBLE:
|
||||||
|
return llvm::Type::getDoubleTy(getGlobalContext());
|
||||||
|
case Type::VOID:
|
||||||
|
return llvm::Type::getVoidTy(getGlobalContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
llvm::AllocaInst* allocateVar(llvm::Function *func, Id const& name, llvm::Type *type) {
|
||||||
|
llvm::IRBuilder<> builder(&func->getEntryBlock(), func->getEntryBlock().begin());
|
||||||
|
return builder.CreateAlloca(type, 0, name.getValue().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
llvm::Value* isTrue(llvm::IRBuilder<> &builder, llvm::Value* test, llvm::Twine const& label="") {
|
||||||
|
return builder.CreateICmpNE(
|
||||||
|
test,
|
||||||
|
llvm::ConstantInt::get(getGlobalContext(), llvm::APInt(1, 0)),
|
||||||
|
label
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
BitcodeEmitter::BitcodeEmitter() {
|
BitcodeEmitter::BitcodeEmitter() {
|
||||||
module = std::unique_ptr<llvm::Module>(new llvm::Module("monicelli", getGlobalContext()));
|
module = std::unique_ptr<llvm::Module>(new llvm::Module("monicelli", getGlobalContext()));
|
||||||
d = new Private;
|
d = new Private;
|
||||||
|
@ -51,19 +87,65 @@ BitcodeEmitter::~BitcodeEmitter() {
|
||||||
void BitcodeEmitter::emit(Return const& node) {
|
void BitcodeEmitter::emit(Return const& node) {
|
||||||
if (node.getExpression()) {
|
if (node.getExpression()) {
|
||||||
node.getExpression()->emit(this);
|
node.getExpression()->emit(this);
|
||||||
d->builder.CreateRet(d->expval);
|
d->builder.CreateRet(d->retval);
|
||||||
} else {
|
} else {
|
||||||
d->builder.CreateRetVoid();
|
d->builder.CreateRetVoid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Loop const& node) {
|
void BitcodeEmitter::emit(Loop const& node) {
|
||||||
|
llvm::Function *father = d->builder.GetInsertBlock()->getParent();
|
||||||
|
|
||||||
|
llvm::BasicBlock *body = llvm::BasicBlock::Create(
|
||||||
|
getGlobalContext(), "loop", father
|
||||||
|
);
|
||||||
|
|
||||||
|
d->builder.CreateBr(body);
|
||||||
|
d->builder.SetInsertPoint(body);
|
||||||
|
|
||||||
|
d->scope.enter();
|
||||||
|
for (Statement const* statement: node.getBody()) {
|
||||||
|
statement->emit(this);
|
||||||
|
}
|
||||||
|
d->scope.leave();
|
||||||
|
|
||||||
|
node.getCondition().emit(this);
|
||||||
|
|
||||||
|
llvm::Value *loopTest = isTrue(d->builder, d->retval, "looptest");
|
||||||
|
|
||||||
|
llvm::BasicBlock *after = llvm::BasicBlock::Create(
|
||||||
|
getGlobalContext(), "afterloop", father
|
||||||
|
);
|
||||||
|
|
||||||
|
d->builder.CreateCondBr(loopTest, body, after);
|
||||||
|
d->builder.SetInsertPoint(after);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(VarDeclaration const& node) {
|
void BitcodeEmitter::emit(VarDeclaration const& node) {
|
||||||
|
llvm::Function *father = d->builder.GetInsertBlock()->getParent();
|
||||||
|
llvm::AllocaInst *alloc = allocateVar(
|
||||||
|
father, node.getId(), LLVMType(node.getType())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (node.getInitializer()) {
|
||||||
|
node.getInitializer()->emit(this);
|
||||||
|
d->builder.CreateStore(d->retval, alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO pointers
|
||||||
|
|
||||||
|
d->scope.push(node.getId().getValue(), alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Assignment const& node) {
|
void BitcodeEmitter::emit(Assignment const& node) {
|
||||||
|
node.getValue().emit(this);
|
||||||
|
auto var = d->scope.lookup(node.getName().getValue());
|
||||||
|
|
||||||
|
if (!var) {
|
||||||
|
// TODO undefined var
|
||||||
|
}
|
||||||
|
|
||||||
|
d->builder.CreateStore(d->retval, *var);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Print const& node) {
|
void BitcodeEmitter::emit(Print const& node) {
|
||||||
|
@ -79,54 +161,169 @@ void BitcodeEmitter::emit(Assert const& node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(FunctionCall const& node) {
|
void BitcodeEmitter::emit(FunctionCall const& node) {
|
||||||
|
llvm::Function *callee = module->getFunction(node.getName().getValue());
|
||||||
|
|
||||||
|
if (callee == 0) {
|
||||||
|
// TODO Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callee->arg_size() != node.getArgs().size()) {
|
||||||
|
// TODO Error
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<llvm::Value*> callargs;
|
||||||
|
for (Expression const* arg: node.getArgs()) {
|
||||||
|
arg->emit(this);
|
||||||
|
callargs.push_back(d->retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->retval = d->builder.CreateCall(callee, callargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Branch const& node) {
|
void BitcodeEmitter::emit(Branch const& node) {
|
||||||
}
|
Branch::Body const& body = node.getBody();
|
||||||
|
llvm::Function *func = d->builder.GetInsertBlock()->getParent();
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Main const& node) {
|
llvm::BasicBlock *thenbb = llvm::BasicBlock::Create(
|
||||||
d->scope.enter();
|
getGlobalContext(), "then", func
|
||||||
for (Statement const* statement: node.getBody()) {
|
);
|
||||||
statement->emit(this);
|
llvm::BasicBlock *elsebb = llvm::BasicBlock::Create(
|
||||||
|
getGlobalContext(), "else"
|
||||||
|
);
|
||||||
|
llvm::BasicBlock *mergebb = llvm::BasicBlock::Create(
|
||||||
|
getGlobalContext(), "endif"
|
||||||
|
);
|
||||||
|
|
||||||
|
BranchCase const* last = body.getCases().back();
|
||||||
|
|
||||||
|
for (BranchCase const* cas: body.getCases()) {
|
||||||
|
emitSemiExpression(node.getVar(), cas->getCondition());
|
||||||
|
d->builder.CreateCondBr(
|
||||||
|
isTrue(d->builder, d->retval, "condition"), thenbb, elsebb
|
||||||
|
);
|
||||||
|
d->builder.SetInsertPoint(thenbb);
|
||||||
|
d->scope.enter();
|
||||||
|
for (Statement const* statement: cas->getBody()) {
|
||||||
|
statement->emit(this);
|
||||||
|
}
|
||||||
|
d->scope.leave();
|
||||||
|
d->builder.CreateBr(mergebb);
|
||||||
|
|
||||||
|
func->getBasicBlockList().push_back(elsebb);
|
||||||
|
d->builder.SetInsertPoint(elsebb);
|
||||||
|
|
||||||
|
if (cas != last) {
|
||||||
|
thenbb = llvm::BasicBlock::Create(getGlobalContext(), "then", func);
|
||||||
|
elsebb = llvm::BasicBlock::Create(getGlobalContext(), "else");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
d->scope.leave();
|
|
||||||
|
if (body.getElse()) {
|
||||||
|
d->scope.enter();
|
||||||
|
for (Statement const* statement: *body.getElse()) {
|
||||||
|
statement->emit(this);
|
||||||
|
}
|
||||||
|
d->scope.leave();
|
||||||
|
d->builder.CreateBr(mergebb);
|
||||||
|
}
|
||||||
|
|
||||||
|
func->getBasicBlockList().push_back(mergebb);
|
||||||
|
d->builder.SetInsertPoint(mergebb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Function const& node) {
|
void BitcodeEmitter::emit(Function const& node) {
|
||||||
|
d->scope.enter();
|
||||||
|
|
||||||
|
std::vector<llvm::Type*> argtypes;
|
||||||
|
|
||||||
|
for (FunArg const* arg: node.getArgs()) {
|
||||||
|
argtypes.emplace_back(LLVMType(arg->getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::FunctionType *ftype = llvm::FunctionType::get(
|
||||||
|
LLVMType(node.getType()), argtypes, false
|
||||||
|
);
|
||||||
|
|
||||||
|
llvm::Function *func = llvm::Function::Create(
|
||||||
|
ftype, llvm::Function::ExternalLinkage, node.getName().getValue(), module.get()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (func->getName() != node.getName().getValue()) {
|
||||||
|
func->eraseFromParent();
|
||||||
|
func = module->getFunction(node.getName().getValue());
|
||||||
|
|
||||||
|
if (!func->empty()) {
|
||||||
|
// TODO redefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
if (func->arg_size() != node.getArgs().size()) {
|
||||||
|
// TODO different args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto argToEmit = func->arg_begin();
|
||||||
|
for (FunArg const* arg: node.getArgs()) {
|
||||||
|
argToEmit->setName(arg->getName().getValue());
|
||||||
|
++argToEmit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO check repeated arg names
|
||||||
|
|
||||||
|
llvm::BasicBlock *bb = llvm::BasicBlock::Create(
|
||||||
|
getGlobalContext(), "entry", func
|
||||||
|
);
|
||||||
|
d->builder.SetInsertPoint(bb);
|
||||||
|
|
||||||
|
auto argToAlloc = func->arg_begin();
|
||||||
|
for (FunArg const* arg: node.getArgs()) {
|
||||||
|
llvm::AllocaInst *alloc = allocateVar(
|
||||||
|
func, arg->getName(), LLVMType(arg->getType())
|
||||||
|
);
|
||||||
|
d->builder.CreateStore(argToAlloc, alloc);
|
||||||
|
d->scope.push(arg->getName().getValue(), alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Statement const* stat: node.getBody()) {
|
||||||
|
stat->emit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyFunction(*func);
|
||||||
|
|
||||||
|
d->scope.leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Module const& node) {}
|
void BitcodeEmitter::emit(Module const& node) {}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Program const& program) {
|
void BitcodeEmitter::emit(Program const& program) {
|
||||||
if (program.getMain()) {
|
|
||||||
program.getMain()->emit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Function const* function: program.getFunctions()) {
|
for (Function const* function: program.getFunctions()) {
|
||||||
function->emit(this);
|
function->emit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (program.getMain()) {
|
||||||
|
program.getMain()->emit(this);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO modules
|
// TODO modules
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Id const& node) {
|
void BitcodeEmitter::emit(Id const& node) {
|
||||||
auto value = d->scope.lookup(&node);
|
auto value = d->scope.lookup(node.getValue());
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
// TODO errore
|
// TODO variable not defined
|
||||||
}
|
}
|
||||||
|
|
||||||
d->expval = *value;
|
d->retval = d->builder.CreateLoad(*value, node.getValue().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Integer const& node) {
|
void BitcodeEmitter::emit(Integer const& node) {
|
||||||
d->expval = llvm::ConstantInt::get(
|
d->retval = llvm::ConstantInt::get(
|
||||||
getGlobalContext(), llvm::APInt(64, node.getValue(), true)
|
getGlobalContext(), llvm::APInt(64, node.getValue(), true)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitcodeEmitter::emit(Float const& node) {
|
void BitcodeEmitter::emit(Float const& node) {
|
||||||
d->expval = llvm::ConstantFP::get(
|
d->retval = llvm::ConstantFP::get(
|
||||||
getGlobalContext(), llvm::APFloat(node.getValue())
|
getGlobalContext(), llvm::APFloat(node.getValue())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -139,32 +336,25 @@ bool isFP(llvm::Value const* var) {
|
||||||
|
|
||||||
#define HANDLE(intop, fpop) \
|
#define HANDLE(intop, fpop) \
|
||||||
if (fp) { \
|
if (fp) { \
|
||||||
d->expval = d->builder.Create##fpop(left, right); \
|
d->retval = d->builder.Create##fpop(left, right); \
|
||||||
} else { \
|
} else { \
|
||||||
d->expval = d->builder.Create##intop(left, right); \
|
d->retval = d->builder.Create##intop(left, right); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HANDLE_INT_ONLY(op) \
|
#define HANDLE_INT_ONLY(op) \
|
||||||
if (fp) { \
|
if (fp) { \
|
||||||
d->expval = nullptr; \
|
d->retval = nullptr; \
|
||||||
} else { \
|
} else { \
|
||||||
d->expval = d->builder.Create##op(left, right); \
|
d->retval = d->builder.Create##op(left, right); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
// TODO Handle automatic casts
|
void createOp(BitcodeEmitter::Private *d, llvm::Value *left, Operator op, llvm::Value *right) {
|
||||||
void BitcodeEmitter::emit(BinaryExpression const& expression) {
|
|
||||||
expression.getLeft().emit(this);
|
|
||||||
llvm::Value *left = d->expval;
|
|
||||||
|
|
||||||
expression.getRight().emit(this);
|
|
||||||
llvm::Value *right = d->expval;
|
|
||||||
|
|
||||||
bool fp = isFP(left) || isFP(right);
|
bool fp = isFP(left) || isFP(right);
|
||||||
|
|
||||||
// TODO left->getType() != right->getType()
|
// TODO left->getType() != right->getType() Handle automatic casts
|
||||||
|
|
||||||
switch (expression.getOperator()) {
|
switch (op) {
|
||||||
case Operator::PLUS:
|
case Operator::PLUS:
|
||||||
HANDLE(Add, FAdd)
|
HANDLE(Add, FAdd)
|
||||||
break;
|
break;
|
||||||
|
@ -204,3 +394,23 @@ void BitcodeEmitter::emit(BinaryExpression const& expression) {
|
||||||
#undef HANDLE
|
#undef HANDLE
|
||||||
#undef HANDLE_INT_ONLY
|
#undef HANDLE_INT_ONLY
|
||||||
|
|
||||||
|
void BitcodeEmitter::emit(BinaryExpression const& expression) {
|
||||||
|
expression.getLeft().emit(this);
|
||||||
|
llvm::Value *left = d->retval;
|
||||||
|
|
||||||
|
expression.getRight().emit(this);
|
||||||
|
llvm::Value *right = d->retval;
|
||||||
|
|
||||||
|
createOp(d, left, expression.getOperator(), right);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitcodeEmitter::emitSemiExpression(Id const& left, SemiExpression const& right) {
|
||||||
|
left.emit(this);
|
||||||
|
llvm::Value *lhs = d->retval;
|
||||||
|
|
||||||
|
right.getLeft().emit(this);
|
||||||
|
llvm::Value *rhs = d->retval;
|
||||||
|
|
||||||
|
createOp(d, lhs, right.getOperator(), rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@ namespace llvm {
|
||||||
|
|
||||||
namespace monicelli {
|
namespace monicelli {
|
||||||
|
|
||||||
|
class SemiExpression;
|
||||||
|
|
||||||
class BitcodeEmitter: public Emitter {
|
class BitcodeEmitter: public Emitter {
|
||||||
public:
|
public:
|
||||||
BitcodeEmitter();
|
BitcodeEmitter();
|
||||||
|
@ -62,6 +64,8 @@ public:
|
||||||
struct Private;
|
struct Private;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void emitSemiExpression(Id const& left, SemiExpression const& right);
|
||||||
|
|
||||||
std::unique_ptr<llvm::Module> module;
|
std::unique_ptr<llvm::Module> module;
|
||||||
Private *d;
|
Private *d;
|
||||||
};
|
};
|
||||||
|
|
Reference in New Issue
Block a user