Finish implementation of compiler
This commit is contained in:
parent
9aef499deb
commit
64227f2873
|
@ -1,5 +1,6 @@
|
||||||
#include "ast.hpp"
|
#include "ast.hpp"
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include "binop.hpp"
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
|
||||||
static void print_indent(int n, std::ostream& to) {
|
static void print_indent(int n, std::ostream& to) {
|
||||||
|
@ -104,7 +105,7 @@ void ast_binop::compile(const env_ptr& env, std::vector<instruction_ptr>& into)
|
||||||
right->compile(env, into);
|
right->compile(env, into);
|
||||||
left->compile(env_ptr(new env_offset(1, env)), into);
|
left->compile(env_ptr(new env_offset(1, env)), into);
|
||||||
|
|
||||||
into.push_back(instruction_ptr(new instruction_pushglobal(op_name(op))));
|
into.push_back(instruction_ptr(new instruction_pushglobal(op_action(op))));
|
||||||
into.push_back(instruction_ptr(new instruction_mkapp()));
|
into.push_back(instruction_ptr(new instruction_mkapp()));
|
||||||
into.push_back(instruction_ptr(new instruction_mkapp()));
|
into.push_back(instruction_ptr(new instruction_mkapp()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#include "definition.hpp"
|
#include "definition.hpp"
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
#include "ast.hpp"
|
#include "ast.hpp"
|
||||||
|
#include "llvm_context.hpp"
|
||||||
|
#include <llvm/IR/DerivedTypes.h>
|
||||||
|
#include <llvm/IR/Function.h>
|
||||||
|
#include <llvm/IR/Type.h>
|
||||||
|
|
||||||
void definition_defn::typecheck_first(type_mgr& mgr, type_env& env) {
|
void definition_defn::typecheck_first(type_mgr& mgr, type_env& env) {
|
||||||
return_type = mgr.new_type();
|
return_type = mgr.new_type();
|
||||||
|
@ -50,6 +54,18 @@ void definition_defn::compile() {
|
||||||
body->compile(new_env, instructions);
|
body->compile(new_env, instructions);
|
||||||
instructions.push_back(instruction_ptr(new instruction_update(params.size())));
|
instructions.push_back(instruction_ptr(new instruction_update(params.size())));
|
||||||
}
|
}
|
||||||
|
void definition_defn::gen_llvm_first(llvm_context& ctx) {
|
||||||
|
generated_function = ctx.create_custom_function(name, params.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void definition_defn::gen_llvm_second(llvm_context& ctx) {
|
||||||
|
ctx.builder.SetInsertPoint(&generated_function->getEntryBlock());
|
||||||
|
for(auto& instruction : instructions) {
|
||||||
|
instruction->gen_llvm(ctx, generated_function);
|
||||||
|
}
|
||||||
|
ctx.create_popn(generated_function, ctx.create_size(params.size()));
|
||||||
|
ctx.builder.CreateRetVoid();
|
||||||
|
}
|
||||||
|
|
||||||
void definition_data::typecheck_first(type_mgr& mgr, type_env& env) {
|
void definition_data::typecheck_first(type_mgr& mgr, type_env& env) {
|
||||||
type_data* this_type = new type_data(name);
|
type_data* this_type = new type_data(name);
|
||||||
|
@ -57,6 +73,7 @@ void definition_data::typecheck_first(type_mgr& mgr, type_env& env) {
|
||||||
int next_tag = 0;
|
int next_tag = 0;
|
||||||
|
|
||||||
for(auto& constructor : constructors) {
|
for(auto& constructor : constructors) {
|
||||||
|
constructor->tag = next_tag;
|
||||||
this_type->constructors[constructor->name] = { next_tag++ };
|
this_type->constructors[constructor->name] = { next_tag++ };
|
||||||
|
|
||||||
type_ptr full_type = return_type;
|
type_ptr full_type = return_type;
|
||||||
|
@ -80,3 +97,20 @@ void definition_data::resolve(const type_mgr& mgr) {
|
||||||
void definition_data::compile() {
|
void definition_data::compile() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void definition_data::gen_llvm_first(llvm_context& ctx) {
|
||||||
|
for(auto& constructor : constructors) {
|
||||||
|
auto new_function =
|
||||||
|
ctx.create_custom_function(constructor->name, constructor->types.size());
|
||||||
|
ctx.builder.SetInsertPoint(&new_function->getEntryBlock());
|
||||||
|
ctx.create_pack(new_function,
|
||||||
|
ctx.create_size(constructor->types.size()),
|
||||||
|
ctx.create_i8(constructor->tag)
|
||||||
|
);
|
||||||
|
ctx.builder.CreateRetVoid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void definition_data::gen_llvm_second(llvm_context& ctx) {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "instruction.hpp"
|
#include "instruction.hpp"
|
||||||
|
#include "llvm_context.hpp"
|
||||||
#include "type_env.hpp"
|
#include "type_env.hpp"
|
||||||
|
|
||||||
struct ast;
|
struct ast;
|
||||||
|
@ -14,6 +15,8 @@ struct definition {
|
||||||
virtual void typecheck_second(type_mgr& mgr, const type_env& env) const = 0;
|
virtual void typecheck_second(type_mgr& mgr, const type_env& env) const = 0;
|
||||||
virtual void resolve(const type_mgr& mgr) = 0;
|
virtual void resolve(const type_mgr& mgr) = 0;
|
||||||
virtual void compile() = 0;
|
virtual void compile() = 0;
|
||||||
|
virtual void gen_llvm_first(llvm_context& ctx) = 0;
|
||||||
|
virtual void gen_llvm_second(llvm_context& ctx) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using definition_ptr = std::unique_ptr<definition>;
|
using definition_ptr = std::unique_ptr<definition>;
|
||||||
|
@ -21,6 +24,7 @@ using definition_ptr = std::unique_ptr<definition>;
|
||||||
struct constructor {
|
struct constructor {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<std::string> types;
|
std::vector<std::string> types;
|
||||||
|
int8_t tag;
|
||||||
|
|
||||||
constructor(std::string n, std::vector<std::string> ts)
|
constructor(std::string n, std::vector<std::string> ts)
|
||||||
: name(std::move(n)), types(std::move(ts)) {}
|
: name(std::move(n)), types(std::move(ts)) {}
|
||||||
|
@ -38,6 +42,8 @@ struct definition_defn : public definition {
|
||||||
|
|
||||||
std::vector<instruction_ptr> instructions;
|
std::vector<instruction_ptr> instructions;
|
||||||
|
|
||||||
|
llvm::Function* generated_function;
|
||||||
|
|
||||||
definition_defn(std::string n, std::vector<std::string> p, ast_ptr b)
|
definition_defn(std::string n, std::vector<std::string> p, ast_ptr b)
|
||||||
: name(std::move(n)), params(std::move(p)), body(std::move(b)) {
|
: name(std::move(n)), params(std::move(p)), body(std::move(b)) {
|
||||||
|
|
||||||
|
@ -47,6 +53,8 @@ struct definition_defn : public definition {
|
||||||
void typecheck_second(type_mgr& mgr, const type_env& env) const;
|
void typecheck_second(type_mgr& mgr, const type_env& env) const;
|
||||||
void resolve(const type_mgr& mgr);
|
void resolve(const type_mgr& mgr);
|
||||||
void compile();
|
void compile();
|
||||||
|
void gen_llvm_first(llvm_context& ctx);
|
||||||
|
void gen_llvm_second(llvm_context& ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct definition_data : public definition {
|
struct definition_data : public definition {
|
||||||
|
@ -60,4 +68,6 @@ struct definition_data : public definition {
|
||||||
void typecheck_second(type_mgr& mgr, const type_env& env) const;
|
void typecheck_second(type_mgr& mgr, const type_env& env) const;
|
||||||
void resolve(const type_mgr& mgr);
|
void resolve(const type_mgr& mgr);
|
||||||
void compile();
|
void compile();
|
||||||
|
void gen_llvm_first(llvm_context& ctx);
|
||||||
|
void gen_llvm_second(llvm_context& ctx);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "instruction.hpp"
|
#include "instruction.hpp"
|
||||||
#include "llvm_context.hpp"
|
#include "llvm_context.hpp"
|
||||||
|
#include <llvm/IR/BasicBlock.h>
|
||||||
#include <llvm/IR/Function.h>
|
#include <llvm/IR/Function.h>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
@ -23,7 +24,9 @@ void instruction_pushglobal::print(int indent, std::ostream& to) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void instruction_pushglobal::gen_llvm(llvm_context& ctx, Function* f) const {
|
void instruction_pushglobal::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||||
// TODO
|
auto& global_f = ctx.custom_functions.at("f_" + name);
|
||||||
|
auto arity = ctx.create_i32(global_f->arity);
|
||||||
|
ctx.create_push(f, ctx.create_global(global_f->function, arity));
|
||||||
}
|
}
|
||||||
|
|
||||||
void instruction_push::print(int indent, std::ostream& to) const {
|
void instruction_push::print(int indent, std::ostream& to) const {
|
||||||
|
@ -87,7 +90,27 @@ void instruction_jump::print(int indent, std::ostream& to) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void instruction_jump::gen_llvm(llvm_context& ctx, Function* f) const {
|
void instruction_jump::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||||
// TODO
|
auto top_node = ctx.create_peek(f, ctx.create_size(0));
|
||||||
|
auto tag = ctx.unwrap_data_tag(top_node);
|
||||||
|
auto safety_block = BasicBlock::Create(ctx.ctx, "safety", f);
|
||||||
|
auto switch_op = ctx.builder.CreateSwitch(tag, safety_block, tag_mappings.size());
|
||||||
|
std::vector<BasicBlock*> blocks;
|
||||||
|
|
||||||
|
for(auto& branch : branches) {
|
||||||
|
auto branch_block = BasicBlock::Create(ctx.ctx, "branch", f);
|
||||||
|
ctx.builder.SetInsertPoint(branch_block);
|
||||||
|
for(auto& instruction : branch) {
|
||||||
|
instruction->gen_llvm(ctx, f);
|
||||||
|
}
|
||||||
|
ctx.builder.CreateBr(safety_block);
|
||||||
|
blocks.push_back(branch_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& mapping : tag_mappings) {
|
||||||
|
switch_op->addCase(ctx.create_i8(mapping.first), blocks[mapping.second]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.builder.SetInsertPoint(safety_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void instruction_slide::print(int indent, std::ostream& to) const {
|
void instruction_slide::print(int indent, std::ostream& to) const {
|
||||||
|
@ -105,8 +128,8 @@ void instruction_binop::print(int indent, std::ostream& to) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void instruction_binop::gen_llvm(llvm_context& ctx, Function* f) const {
|
void instruction_binop::gen_llvm(llvm_context& ctx, Function* f) const {
|
||||||
auto left_int = ctx.unwrap_num(ctx.create_pop(f));
|
auto left_int = ctx.unwrap_num(ctx.create_eval(ctx.create_pop(f)));
|
||||||
auto right_int = ctx.unwrap_num(ctx.create_pop(f));
|
auto right_int = ctx.unwrap_num(ctx.create_eval(ctx.create_pop(f)));
|
||||||
llvm::Value* result;
|
llvm::Value* result;
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case PLUS: result = ctx.builder.CreateAdd(left_int, right_int); break;
|
case PLUS: result = ctx.builder.CreateAdd(left_int, right_int); break;
|
||||||
|
|
|
@ -67,49 +67,49 @@ void llvm_context::create_functions() {
|
||||||
functions["stack_pop"] = Function::Create(
|
functions["stack_pop"] = Function::Create(
|
||||||
FunctionType::get(node_ptr_type, { stack_ptr_type }, false),
|
FunctionType::get(node_ptr_type, { stack_ptr_type }, false),
|
||||||
Function::LinkageTypes::ExternalLinkage,
|
Function::LinkageTypes::ExternalLinkage,
|
||||||
"stack_push",
|
"stack_pop",
|
||||||
&module
|
&module
|
||||||
);
|
);
|
||||||
functions["stack_peek"] = Function::Create(
|
functions["stack_peek"] = Function::Create(
|
||||||
FunctionType::get(node_ptr_type, { stack_ptr_type, sizet_type }, false),
|
FunctionType::get(node_ptr_type, { stack_ptr_type, sizet_type }, false),
|
||||||
Function::LinkageTypes::ExternalLinkage,
|
Function::LinkageTypes::ExternalLinkage,
|
||||||
"stack_push",
|
"stack_peek",
|
||||||
&module
|
&module
|
||||||
);
|
);
|
||||||
functions["stack_popn"] = Function::Create(
|
functions["stack_popn"] = Function::Create(
|
||||||
FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false),
|
FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false),
|
||||||
Function::LinkageTypes::ExternalLinkage,
|
Function::LinkageTypes::ExternalLinkage,
|
||||||
"stack_push",
|
"stack_popn",
|
||||||
&module
|
&module
|
||||||
);
|
);
|
||||||
functions["stack_slide"] = Function::Create(
|
functions["stack_slide"] = Function::Create(
|
||||||
FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false),
|
FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false),
|
||||||
Function::LinkageTypes::ExternalLinkage,
|
Function::LinkageTypes::ExternalLinkage,
|
||||||
"stack_push",
|
"stack_slide",
|
||||||
&module
|
&module
|
||||||
);
|
);
|
||||||
functions["stack_update"] = Function::Create(
|
functions["stack_update"] = Function::Create(
|
||||||
FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false),
|
FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false),
|
||||||
Function::LinkageTypes::ExternalLinkage,
|
Function::LinkageTypes::ExternalLinkage,
|
||||||
"stack_push",
|
"stack_update",
|
||||||
&module
|
&module
|
||||||
);
|
);
|
||||||
functions["stack_alloc"] = Function::Create(
|
functions["stack_alloc"] = Function::Create(
|
||||||
FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false),
|
FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false),
|
||||||
Function::LinkageTypes::ExternalLinkage,
|
Function::LinkageTypes::ExternalLinkage,
|
||||||
"stack_push",
|
"stack_alloc",
|
||||||
&module
|
&module
|
||||||
);
|
);
|
||||||
functions["stack_pack"] = Function::Create(
|
functions["stack_pack"] = Function::Create(
|
||||||
FunctionType::get(void_type, { stack_ptr_type, sizet_type, tag_type }, false),
|
FunctionType::get(void_type, { stack_ptr_type, sizet_type, tag_type }, false),
|
||||||
Function::LinkageTypes::ExternalLinkage,
|
Function::LinkageTypes::ExternalLinkage,
|
||||||
"stack_push",
|
"stack_pack",
|
||||||
&module
|
&module
|
||||||
);
|
);
|
||||||
functions["stack_split"] = Function::Create(
|
functions["stack_split"] = Function::Create(
|
||||||
FunctionType::get(node_ptr_type, { stack_ptr_type, sizet_type }, false),
|
FunctionType::get(node_ptr_type, { stack_ptr_type, sizet_type }, false),
|
||||||
Function::LinkageTypes::ExternalLinkage,
|
Function::LinkageTypes::ExternalLinkage,
|
||||||
"stack_push",
|
"stack_split",
|
||||||
&module
|
&module
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -147,13 +147,13 @@ void llvm_context::create_functions() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* llvm_context::create_i8(int8_t i) {
|
ConstantInt* llvm_context::create_i8(int8_t i) {
|
||||||
return ConstantInt::get(ctx, APInt(8, i));
|
return ConstantInt::get(ctx, APInt(8, i));
|
||||||
}
|
}
|
||||||
Value* llvm_context::create_i32(int32_t i) {
|
ConstantInt* llvm_context::create_i32(int32_t i) {
|
||||||
return ConstantInt::get(ctx, APInt(32, i));
|
return ConstantInt::get(ctx, APInt(32, i));
|
||||||
}
|
}
|
||||||
Value* llvm_context::create_size(size_t i) {
|
ConstantInt* llvm_context::create_size(size_t i) {
|
||||||
return ConstantInt::get(ctx, APInt(sizeof(size_t) * 8, i));
|
return ConstantInt::get(ctx, APInt(sizeof(size_t) * 8, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,8 +202,8 @@ Value* llvm_context::create_eval(Value* e) {
|
||||||
Value* llvm_context::unwrap_num(Value* v) {
|
Value* llvm_context::unwrap_num(Value* v) {
|
||||||
auto num_ptr_type = PointerType::getUnqual(struct_types.at("node_num"));
|
auto num_ptr_type = PointerType::getUnqual(struct_types.at("node_num"));
|
||||||
auto cast = builder.CreatePointerCast(v, num_ptr_type);
|
auto cast = builder.CreatePointerCast(v, num_ptr_type);
|
||||||
auto offset_0 = create_size(0);
|
auto offset_0 = create_i32(0);
|
||||||
auto offset_1 = create_size(1);
|
auto offset_1 = create_i32(1);
|
||||||
auto int_ptr = builder.CreateGEP(cast, { offset_0, offset_1 });
|
auto int_ptr = builder.CreateGEP(cast, { offset_0, offset_1 });
|
||||||
return builder.CreateLoad(int_ptr);
|
return builder.CreateLoad(int_ptr);
|
||||||
}
|
}
|
||||||
|
@ -212,6 +212,15 @@ Value* llvm_context::create_num(Value* v) {
|
||||||
return builder.CreateCall(alloc_num_f, { v });
|
return builder.CreateCall(alloc_num_f, { v });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value* llvm_context::unwrap_data_tag(Value* v) {
|
||||||
|
auto data_ptr_type = PointerType::getUnqual(struct_types.at("node_data"));
|
||||||
|
auto cast = builder.CreatePointerCast(v, data_ptr_type);
|
||||||
|
auto offset_0 = create_i32(0);
|
||||||
|
auto offset_1 = create_i32(1);
|
||||||
|
auto tag_ptr = builder.CreateGEP(cast, { offset_0, offset_1 });
|
||||||
|
return builder.CreateLoad(tag_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
Value* llvm_context::create_global(Value* f, Value* a) {
|
Value* llvm_context::create_global(Value* f, Value* a) {
|
||||||
auto alloc_global_f = functions.at("alloc_global");
|
auto alloc_global_f = functions.at("alloc_global");
|
||||||
return builder.CreateCall(alloc_global_f, { f, a });
|
return builder.CreateCall(alloc_global_f, { f, a });
|
||||||
|
@ -221,3 +230,23 @@ Value* llvm_context::create_app(Value* l, Value* r) {
|
||||||
auto alloc_app_f = functions.at("alloc_app");
|
auto alloc_app_f = functions.at("alloc_app");
|
||||||
return builder.CreateCall(alloc_app_f, { l, r });
|
return builder.CreateCall(alloc_app_f, { l, r });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::Function* llvm_context::create_custom_function(std::string name, int32_t arity) {
|
||||||
|
auto void_type = llvm::Type::getVoidTy(ctx);
|
||||||
|
auto function_type =
|
||||||
|
llvm::FunctionType::get(void_type, { stack_ptr_type }, false);
|
||||||
|
auto new_function = llvm::Function::Create(
|
||||||
|
function_type,
|
||||||
|
llvm::Function::LinkageTypes::ExternalLinkage,
|
||||||
|
"f_" + name,
|
||||||
|
&module
|
||||||
|
);
|
||||||
|
auto start_block = llvm::BasicBlock::Create(ctx, "entry", new_function);
|
||||||
|
|
||||||
|
auto new_custom_f = custom_function_ptr(new custom_function());
|
||||||
|
new_custom_f->arity = arity;
|
||||||
|
new_custom_f->function = new_function;
|
||||||
|
custom_functions["f_" + name] = std::move(new_custom_f);
|
||||||
|
|
||||||
|
return new_function;
|
||||||
|
}
|
||||||
|
|
|
@ -7,10 +7,18 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
struct llvm_context {
|
struct llvm_context {
|
||||||
|
struct custom_function {
|
||||||
|
llvm::Function* function;
|
||||||
|
int32_t arity;
|
||||||
|
};
|
||||||
|
|
||||||
|
using custom_function_ptr = std::unique_ptr<custom_function>;
|
||||||
|
|
||||||
llvm::LLVMContext ctx;
|
llvm::LLVMContext ctx;
|
||||||
llvm::IRBuilder<> builder;
|
llvm::IRBuilder<> builder;
|
||||||
llvm::Module module;
|
llvm::Module module;
|
||||||
|
|
||||||
|
std::map<std::string, custom_function_ptr> custom_functions;
|
||||||
std::map<std::string, llvm::Function*> functions;
|
std::map<std::string, llvm::Function*> functions;
|
||||||
std::map<std::string, llvm::StructType*> struct_types;
|
std::map<std::string, llvm::StructType*> struct_types;
|
||||||
|
|
||||||
|
@ -29,9 +37,9 @@ struct llvm_context {
|
||||||
void create_types();
|
void create_types();
|
||||||
void create_functions();
|
void create_functions();
|
||||||
|
|
||||||
llvm::Value* create_i8(int8_t);
|
llvm::ConstantInt* create_i8(int8_t);
|
||||||
llvm::Value* create_i32(int32_t);
|
llvm::ConstantInt* create_i32(int32_t);
|
||||||
llvm::Value* create_size(size_t);
|
llvm::ConstantInt* create_size(size_t);
|
||||||
|
|
||||||
llvm::Value* create_pop(llvm::Function*);
|
llvm::Value* create_pop(llvm::Function*);
|
||||||
llvm::Value* create_peek(llvm::Function*, llvm::Value*);
|
llvm::Value* create_peek(llvm::Function*, llvm::Value*);
|
||||||
|
@ -48,7 +56,11 @@ struct llvm_context {
|
||||||
llvm::Value* unwrap_num(llvm::Value*);
|
llvm::Value* unwrap_num(llvm::Value*);
|
||||||
llvm::Value* create_num(llvm::Value*);
|
llvm::Value* create_num(llvm::Value*);
|
||||||
|
|
||||||
|
llvm::Value* unwrap_data_tag(llvm::Value*);
|
||||||
|
|
||||||
llvm::Value* create_global(llvm::Value*, llvm::Value*);
|
llvm::Value* create_global(llvm::Value*, llvm::Value*);
|
||||||
|
|
||||||
llvm::Value* create_app(llvm::Value*, llvm::Value*);
|
llvm::Value* create_app(llvm::Value*, llvm::Value*);
|
||||||
|
|
||||||
|
llvm::Function* create_custom_function(std::string name, int32_t arity);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
#include "ast.hpp"
|
#include "ast.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "binop.hpp"
|
||||||
#include "definition.hpp"
|
#include "definition.hpp"
|
||||||
|
#include "instruction.hpp"
|
||||||
|
#include "llvm_context.hpp"
|
||||||
#include "parser.hpp"
|
#include "parser.hpp"
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
#include "type.hpp"
|
#include "type.hpp"
|
||||||
|
#include "llvm/IR/LegacyPassManager.h"
|
||||||
|
#include "llvm/IR/Verifier.h"
|
||||||
|
#include "llvm/Support/TargetSelect.h"
|
||||||
|
#include "llvm/Support/TargetRegistry.h"
|
||||||
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
#include "llvm/Support/FileSystem.h"
|
||||||
|
#include "llvm/Target/TargetOptions.h"
|
||||||
|
#include "llvm/Target/TargetMachine.h"
|
||||||
|
|
||||||
void yy::parser::error(const std::string& msg) {
|
void yy::parser::error(const std::string& msg) {
|
||||||
std::cout << "An error occured: " << msg << std::endl;
|
std::cout << "An error occured: " << msg << std::endl;
|
||||||
|
@ -56,6 +67,73 @@ void compile_program(const std::vector<definition_ptr>& prog) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gen_llvm_internal_op(llvm_context& ctx, binop op) {
|
||||||
|
auto new_function = ctx.create_custom_function(op_action(op), 2);
|
||||||
|
auto new_instruction = instruction_ptr(new instruction_binop(op));
|
||||||
|
ctx.builder.SetInsertPoint(&new_function->getEntryBlock());
|
||||||
|
new_instruction->gen_llvm(ctx, new_function);
|
||||||
|
ctx.builder.CreateRetVoid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void output_llvm(llvm_context& ctx, const std::string& filename) {
|
||||||
|
std::string targetTriple = llvm::sys::getDefaultTargetTriple();
|
||||||
|
|
||||||
|
llvm::InitializeNativeTarget();
|
||||||
|
llvm::InitializeNativeTargetAsmParser();
|
||||||
|
llvm::InitializeNativeTargetAsmPrinter();
|
||||||
|
|
||||||
|
std::string error;
|
||||||
|
const llvm::Target* target =
|
||||||
|
llvm::TargetRegistry::lookupTarget(targetTriple, error);
|
||||||
|
if (!target) {
|
||||||
|
std::cerr << error << std::endl;
|
||||||
|
} else {
|
||||||
|
std::string cpu = "generic";
|
||||||
|
std::string features = "";
|
||||||
|
llvm::TargetOptions options;
|
||||||
|
llvm::TargetMachine* targetMachine =
|
||||||
|
target->createTargetMachine(targetTriple, cpu, features,
|
||||||
|
options, llvm::Optional<llvm::Reloc::Model>());
|
||||||
|
|
||||||
|
ctx.module.setDataLayout(targetMachine->createDataLayout());
|
||||||
|
ctx.module.setTargetTriple(targetTriple);
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
llvm::raw_fd_ostream file(filename, ec, llvm::sys::fs::F_None);
|
||||||
|
if (ec) {
|
||||||
|
std::cerr << "Could not open output file: " << ec.message() << std::endl;
|
||||||
|
} else {
|
||||||
|
llvm::TargetMachine::CodeGenFileType type = llvm::TargetMachine::CGFT_ObjectFile;
|
||||||
|
llvm::legacy::PassManager pm;
|
||||||
|
if (targetMachine->addPassesToEmitFile(pm, file, NULL, type)) {
|
||||||
|
std::cerr << "Unable to emit target code" << std::endl;
|
||||||
|
} else {
|
||||||
|
pm.run(ctx.module);
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gen_llvm(const std::vector<definition_ptr>& prog) {
|
||||||
|
llvm_context ctx;
|
||||||
|
gen_llvm_internal_op(ctx, PLUS);
|
||||||
|
gen_llvm_internal_op(ctx, MINUS);
|
||||||
|
gen_llvm_internal_op(ctx, TIMES);
|
||||||
|
gen_llvm_internal_op(ctx, DIVIDE);
|
||||||
|
|
||||||
|
for(auto& definition : prog) {
|
||||||
|
definition->gen_llvm_first(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& definition : prog) {
|
||||||
|
definition->gen_llvm_second(ctx);
|
||||||
|
}
|
||||||
|
llvm::verifyModule(ctx.module);
|
||||||
|
ctx.module.print(llvm::outs(), nullptr);
|
||||||
|
output_llvm(ctx, "program.o");
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
yy::parser parser;
|
yy::parser parser;
|
||||||
type_mgr mgr;
|
type_mgr mgr;
|
||||||
|
@ -75,6 +153,7 @@ int main() {
|
||||||
try {
|
try {
|
||||||
typecheck_program(program, mgr, env);
|
typecheck_program(program, mgr, env);
|
||||||
compile_program(program);
|
compile_program(program);
|
||||||
|
gen_llvm(program);
|
||||||
} catch(unification_error& err) {
|
} catch(unification_error& err) {
|
||||||
std::cout << "failed to unify types: " << std::endl;
|
std::cout << "failed to unify types: " << std::endl;
|
||||||
std::cout << " (1) \033[34m";
|
std::cout << " (1) \033[34m";
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
|
||||||
struct node_base* alloc_node() {
|
struct node_base* alloc_node() {
|
||||||
|
@ -97,7 +98,7 @@ void stack_pack(struct stack* s, size_t n, int8_t t) {
|
||||||
|
|
||||||
struct node_base** data = malloc(sizeof(*data) * n);
|
struct node_base** data = malloc(sizeof(*data) * n);
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
memcpy(data, &s->data[s->count - 1 - n], n * sizeof(*data));
|
memcpy(data, &s->data[s->count - n], n * sizeof(*data));
|
||||||
|
|
||||||
struct node_data* new_node = (struct node_data*) alloc_node();
|
struct node_data* new_node = (struct node_data*) alloc_node();
|
||||||
new_node->array = data;
|
new_node->array = data;
|
||||||
|
@ -153,7 +154,30 @@ struct node_base* eval(struct node_base* n) {
|
||||||
|
|
||||||
extern void f_main(struct stack* s);
|
extern void f_main(struct stack* s);
|
||||||
|
|
||||||
|
void print_node(struct node_base* n) {
|
||||||
|
if(n->tag == NODE_APP) {
|
||||||
|
struct node_app* app = (struct node_app*) n;
|
||||||
|
print_node(app->left);
|
||||||
|
putchar(' ');
|
||||||
|
print_node(app->right);
|
||||||
|
} else if(n->tag == NODE_DATA) {
|
||||||
|
printf("(Packed)");
|
||||||
|
} else if(n->tag == NODE_GLOBAL) {
|
||||||
|
struct node_global* global = (struct node_global*) n;
|
||||||
|
printf("(Global: %p)", global->function);
|
||||||
|
} else if(n->tag == NODE_IND) {
|
||||||
|
print_node(((struct node_ind*) n)->next);
|
||||||
|
} else if(n->tag == NODE_NUM) {
|
||||||
|
struct node_num* num = (struct node_num*) n;
|
||||||
|
printf("%d", num->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
struct node_global* first_node = alloc_global(f_main, 0);
|
struct node_global* first_node = alloc_global(f_main, 0);
|
||||||
struct node_base* result = eval((struct node_base*) first_node);
|
struct node_base* result = eval((struct node_base*) first_node);
|
||||||
|
|
||||||
|
printf("Result: ");
|
||||||
|
print_node(result);
|
||||||
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,3 +187,5 @@ virtual void gen_llvm(llvm_context&, llvm::Function*) const;
|
||||||
```
|
```
|
||||||
|
|
||||||
{{< todo >}} Fix pointer type inconsistencies. {{< /todo >}}
|
{{< todo >}} Fix pointer type inconsistencies. {{< /todo >}}
|
||||||
|
{{< todo >}} Create + backport Pop instruction {{< /todo >}}
|
||||||
|
{{< todo >}} Explain forcing normal evaluation in binary operator {{< /todo >}}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user