Start writing actual compillation code in compiler series

This commit is contained in:
Danila Fedorin 2019-11-05 00:42:33 -08:00
parent 81ee50d0d4
commit c79b5a4120
6 changed files with 260 additions and 7 deletions

View File

@ -206,7 +206,8 @@ void ast_case::compile(const env_ptr& env, std::vector<instruction_ptr>& into) c
new_env = env_ptr(new env_var(*it, new_env)); new_env = env_ptr(new env_var(*it, new_env));
} }
branch_instructions.push_back(instruction_ptr(new instruction_split())); branch_instructions.push_back(instruction_ptr(new instruction_split(
cpat->params.size())));
branch->expr->compile(new_env, branch_instructions); branch->expr->compile(new_env, branch_instructions);
branch_instructions.push_back(instruction_ptr(new instruction_slide( branch_instructions.push_back(instruction_ptr(new instruction_slide(
cpat->params.size()))); cpat->params.size())));

View File

@ -1,4 +1,8 @@
#include "instruction.hpp" #include "instruction.hpp"
#include "llvm_context.hpp"
#include <llvm/IR/Function.h>
using namespace llvm;
static void print_indent(int n, std::ostream& to) { static void print_indent(int n, std::ostream& to) {
while(n--) to << " "; while(n--) to << " ";
@ -9,36 +13,66 @@ void instruction_pushint::print(int indent, std::ostream& to) const {
to << "PushInt(" << value << ")" << std::endl; to << "PushInt(" << value << ")" << std::endl;
} }
void instruction_pushint::gen_llvm(llvm_context& ctx, Function* f) const {
ctx.create_push(f, ctx.create_num(ctx.create_i32(value)));
}
void instruction_pushglobal::print(int indent, std::ostream& to) const { void instruction_pushglobal::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "PushGlobal(" << name << ")" << std::endl; to << "PushGlobal(" << name << ")" << std::endl;
} }
void instruction_pushglobal::gen_llvm(llvm_context& ctx, Function* f) const {
// TODO
}
void instruction_push::print(int indent, std::ostream& to) const { void instruction_push::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "Push(" << offset << ")" << std::endl; to << "Push(" << offset << ")" << std::endl;
} }
void instruction_push::gen_llvm(llvm_context& ctx, Function* f) const {
ctx.create_push(f, ctx.create_peek(f, ctx.create_size(offset)));
}
void instruction_mkapp::print(int indent, std::ostream& to) const { void instruction_mkapp::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "MkApp()" << std::endl; to << "MkApp()" << std::endl;
} }
void instruction_mkapp::gen_llvm(llvm_context& ctx, Function* f) const {
auto left = ctx.create_pop(f);
auto right = ctx.create_pop(f);
ctx.create_push(f, ctx.create_app(left, right));
}
void instruction_update::print(int indent, std::ostream& to) const { void instruction_update::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "Update(" << offset << ")" << std::endl; to << "Update(" << offset << ")" << std::endl;
} }
void instruction_update::gen_llvm(llvm_context& ctx, Function* f) const {
ctx.create_update(f, ctx.create_size(offset));
}
void instruction_pack::print(int indent, std::ostream& to) const { void instruction_pack::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "Pack(" << tag << ", " << size << ")" << std::endl; to << "Pack(" << tag << ", " << size << ")" << std::endl;
} }
void instruction_pack::gen_llvm(llvm_context& ctx, Function* f) const {
ctx.create_pack(f, ctx.create_size(size), ctx.create_i8(tag));
}
void instruction_split::print(int indent, std::ostream& to) const { void instruction_split::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "Split()" << std::endl; to << "Split()" << std::endl;
} }
void instruction_split::gen_llvm(llvm_context& ctx, Function* f) const {
ctx.create_split(f, ctx.create_size(size));
}
void instruction_jump::print(int indent, std::ostream& to) const { void instruction_jump::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "Jump(" << std::endl; to << "Jump(" << std::endl;
@ -52,27 +86,60 @@ void instruction_jump::print(int indent, std::ostream& to) const {
to << ")" << std::endl; to << ")" << std::endl;
} }
void instruction_jump::gen_llvm(llvm_context& ctx, Function* f) const {
// TODO
}
void instruction_slide::print(int indent, std::ostream& to) const { void instruction_slide::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "Slide(" << offset << ")" << std::endl; to << "Slide(" << offset << ")" << std::endl;
} }
void instruction_slide::gen_llvm(llvm_context& ctx, Function* f) const {
ctx.create_slide(f, ctx.create_size(offset));
}
void instruction_binop::print(int indent, std::ostream& to) const { void instruction_binop::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "BinOp(" << op_action(op) << ")" << std::endl; to << "BinOp(" << op_action(op) << ")" << std::endl;
} }
void instruction_binop::gen_llvm(llvm_context& ctx, Function* f) const {
auto left_int = ctx.unwrap_num(ctx.create_pop(f));
auto right_int = ctx.unwrap_num(ctx.create_pop(f));
llvm::Value* result;
switch(op) {
case PLUS: result = ctx.builder.CreateAdd(left_int, right_int); break;
case MINUS: result = ctx.builder.CreateSub(left_int, right_int); break;
case TIMES: result = ctx.builder.CreateMul(left_int, right_int); break;
case DIVIDE: result = ctx.builder.CreateSDiv(left_int, right_int); break;
}
ctx.create_push(f, ctx.create_num(result));
}
void instruction_eval::print(int indent, std::ostream& to) const { void instruction_eval::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "Eval()" << std::endl; to << "Eval()" << std::endl;
} }
void instruction_eval::gen_llvm(llvm_context& ctx, Function* f) const {
ctx.create_push(f, ctx.create_eval(ctx.create_pop(f)));
}
void instruction_alloc::print(int indent, std::ostream& to) const { void instruction_alloc::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "Alloc(" << amount << ")" << std::endl; to << "Alloc(" << amount << ")" << std::endl;
} }
void instruction_alloc::gen_llvm(llvm_context& ctx, Function* f) const {
ctx.create_alloc(f, ctx.create_size(amount));
}
void instruction_unwind::print(int indent, std::ostream& to) const { void instruction_unwind::print(int indent, std::ostream& to) const {
print_indent(indent, to); print_indent(indent, to);
to << "Unwind()" << std::endl; to << "Unwind()" << std::endl;
} }
void instruction_unwind::gen_llvm(llvm_context& ctx, Function* f) const {
// Nothing
}

View File

@ -1,15 +1,18 @@
#pragma once #pragma once
#include <llvm/IR/Function.h>
#include <string> #include <string>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <map> #include <map>
#include <ostream> #include <ostream>
#include "binop.hpp" #include "binop.hpp"
#include "llvm_context.hpp"
struct instruction { struct instruction {
virtual ~instruction() = default; virtual ~instruction() = default;
virtual void print(int indent, std::ostream& to) const = 0; virtual void print(int indent, std::ostream& to) const = 0;
virtual void gen_llvm(llvm_context& ctx, llvm::Function* f) const = 0;
}; };
using instruction_ptr = std::unique_ptr<instruction>; using instruction_ptr = std::unique_ptr<instruction>;
@ -21,6 +24,7 @@ struct instruction_pushint : public instruction {
: value(v) {} : value(v) {}
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_pushglobal : public instruction { struct instruction_pushglobal : public instruction {
@ -30,6 +34,7 @@ struct instruction_pushglobal : public instruction {
: name(std::move(n)) {} : name(std::move(n)) {}
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_push : public instruction { struct instruction_push : public instruction {
@ -39,10 +44,12 @@ struct instruction_push : public instruction {
: offset(o) {} : offset(o) {}
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_mkapp : public instruction { struct instruction_mkapp : public instruction {
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_update : public instruction { struct instruction_update : public instruction {
@ -52,6 +59,7 @@ struct instruction_update : public instruction {
: offset(o) {} : offset(o) {}
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_pack : public instruction { struct instruction_pack : public instruction {
@ -62,10 +70,17 @@ struct instruction_pack : public instruction {
: tag(t), size(s) {} : tag(t), size(s) {}
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_split : public instruction { struct instruction_split : public instruction {
int size;
instruction_split(int s)
: size(s) {}
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_jump : public instruction { struct instruction_jump : public instruction {
@ -73,6 +88,7 @@ struct instruction_jump : public instruction {
std::map<int, int> tag_mappings; std::map<int, int> tag_mappings;
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_slide : public instruction { struct instruction_slide : public instruction {
@ -82,6 +98,7 @@ struct instruction_slide : public instruction {
: offset(o) {} : offset(o) {}
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_binop : public instruction { struct instruction_binop : public instruction {
@ -91,10 +108,12 @@ struct instruction_binop : public instruction {
: op(o) {} : op(o) {}
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_eval : public instruction { struct instruction_eval : public instruction {
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_alloc : public instruction { struct instruction_alloc : public instruction {
@ -104,8 +123,10 @@ struct instruction_alloc : public instruction {
: amount(a) {} : amount(a) {}
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };
struct instruction_unwind : public instruction { struct instruction_unwind : public instruction {
void print(int indent, std::ostream& to) const; void print(int indent, std::ostream& to) const;
void gen_llvm(llvm_context& ctx, llvm::Function* f) const;
}; };

View File

@ -3,7 +3,7 @@
using namespace llvm; using namespace llvm;
void llvm_state::create_types() { void llvm_context::create_types() {
stack_type = StructType::create(ctx, "stack"); stack_type = StructType::create(ctx, "stack");
stack_ptr_type = PointerType::getUnqual(stack_type); stack_ptr_type = PointerType::getUnqual(stack_type);
tag_type = IntegerType::getInt8Ty(ctx); tag_type = IntegerType::getInt8Ty(ctx);
@ -14,11 +14,38 @@ void llvm_state::create_types() {
struct_types["node_ind"] = StructType::create(ctx, "node_ind"); struct_types["node_ind"] = StructType::create(ctx, "node_ind");
struct_types["node_data"] = StructType::create(ctx, "node_data"); struct_types["node_data"] = StructType::create(ctx, "node_data");
node_ptr_type = PointerType::getUnqual(struct_types.at("node_base")); node_ptr_type = PointerType::getUnqual(struct_types.at("node_base"));
function_type = FunctionType::get(Type::getVoidTy(ctx), { stack_ptr_type }, false);
struct_types.at("node_base")->setBody(
IntegerType::getInt32Ty(ctx)
);
struct_types.at("node_app")->setBody(
struct_types.at("node_base"),
node_ptr_type,
node_ptr_type
);
struct_types.at("node_num")->setBody(
struct_types.at("node_base"),
IntegerType::getInt32Ty(ctx)
);
struct_types.at("node_global")->setBody(
struct_types.at("node_base"),
FunctionType::get(Type::getVoidTy(ctx), { stack_ptr_type }, false)
);
struct_types.at("node_ind")->setBody(
struct_types.at("node_base"),
node_ptr_type
);
struct_types.at("node_data")->setBody(
struct_types.at("node_base"),
IntegerType::getInt8Ty(ctx),
PointerType::getUnqual(node_ptr_type)
);
} }
void llvm_state::create_functions() { void llvm_context::create_functions() {
auto void_type = Type::getVoidTy(ctx); auto void_type = Type::getVoidTy(ctx);
auto sizet_type = IntegerType::getInt64Ty(ctx); auto sizet_type = IntegerType::get(ctx, sizeof(size_t) * 8);
functions["stack_init"] = Function::Create( functions["stack_init"] = Function::Create(
FunctionType::get(void_type, { stack_ptr_type }, false), FunctionType::get(void_type, { stack_ptr_type }, false),
Function::LinkageTypes::ExternalLinkage, Function::LinkageTypes::ExternalLinkage,
@ -85,4 +112,112 @@ void llvm_state::create_functions() {
"stack_push", "stack_push",
&module &module
); );
auto int32_type = IntegerType::getInt32Ty(ctx);
functions["alloc_app"] = Function::Create(
FunctionType::get(node_ptr_type, { node_ptr_type, node_ptr_type }, false),
Function::LinkageTypes::ExternalLinkage,
"alloc_app",
&module
);
functions["alloc_num"] = Function::Create(
FunctionType::get(node_ptr_type, { int32_type }, false),
Function::LinkageTypes::ExternalLinkage,
"alloc_num",
&module
);
functions["alloc_global"] = Function::Create(
FunctionType::get(node_ptr_type, { function_type, int32_type }, false),
Function::LinkageTypes::ExternalLinkage,
"alloc_global",
&module
);
functions["alloc_ind"] = Function::Create(
FunctionType::get(node_ptr_type, { node_ptr_type }, false),
Function::LinkageTypes::ExternalLinkage,
"alloc_ind",
&module
);
functions["eval"] = Function::Create(
FunctionType::get(node_ptr_type, { node_ptr_type }, false),
Function::LinkageTypes::ExternalLinkage,
"eval",
&module
);
}
Value* llvm_context::create_i8(int8_t i) {
return ConstantInt::get(ctx, APInt(8, i));
}
Value* llvm_context::create_i32(int32_t i) {
return ConstantInt::get(ctx, APInt(32, i));
}
Value* llvm_context::create_size(size_t i) {
return ConstantInt::get(ctx, APInt(sizeof(size_t) * 8, i));
}
Value* llvm_context::create_pop(Function* f) {
auto pop_f = functions.at("stack_pop");
return builder.CreateCall(pop_f, { f->arg_begin() });
}
Value* llvm_context::create_peek(Function* f, Value* off) {
auto peek_f = functions.at("stack_peek");
return builder.CreateCall(peek_f, { f->arg_begin(), off });
}
void llvm_context::create_push(Function* f, Value* v) {
auto push_f = functions.at("stack_push");
builder.CreateCall(push_f, { f->arg_begin(), v });
}
void llvm_context::create_popn(Function* f, Value* off) {
auto popn_f = functions.at("stack_popn");
builder.CreateCall(popn_f, { f->arg_begin(), off });
}
void llvm_context::create_update(Function* f, Value* off) {
auto update_f = functions.at("stack_update");
builder.CreateCall(update_f, { f->arg_begin(), off });
}
void llvm_context::create_pack(Function* f, Value* c, Value* t) {
auto pack_f = functions.at("stack_pack");
builder.CreateCall(pack_f, { f->arg_begin(), c, t });
}
void llvm_context::create_split(Function* f, Value* c) {
auto split_f = functions.at("stack_split");
builder.CreateCall(split_f, { f->arg_begin(), c });
}
void llvm_context::create_slide(Function* f, Value* off) {
auto slide_f = functions.at("stack_slide");
builder.CreateCall(slide_f, { f->arg_begin(), off });
}
void llvm_context::create_alloc(Function* f, Value* n) {
auto alloc_f = functions.at("stack_alloc");
builder.CreateCall(alloc_f, { f->arg_begin(), n });
}
Value* llvm_context::create_eval(Value* e) {
auto eval_f = functions.at("eval");
return builder.CreateCall(eval_f, { e });
}
Value* llvm_context::unwrap_num(Value* v) {
auto num_ptr_type = PointerType::getUnqual(struct_types.at("node_num"));
auto cast = builder.CreatePointerCast(v, num_ptr_type);
auto offset_0 = create_size(0);
auto offset_1 = create_size(1);
auto int_ptr = builder.CreateGEP(cast, { offset_0, offset_1 });
return builder.CreateLoad(int_ptr);
}
Value* llvm_context::create_num(Value* v) {
auto alloc_num_f = functions.at("alloc_num");
return builder.CreateCall(alloc_num_f, { v });
}
Value* llvm_context::create_global(Value* f, Value* a) {
auto alloc_global_f = functions.at("alloc_global");
return builder.CreateCall(alloc_global_f, { f, a });
}
Value* llvm_context::create_app(Value* l, Value* r) {
auto alloc_app_f = functions.at("alloc_app");
return builder.CreateCall(alloc_app_f, { l, r });
} }

View File

@ -6,7 +6,7 @@
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <map> #include <map>
struct llvm_state { struct llvm_context {
llvm::LLVMContext ctx; llvm::LLVMContext ctx;
llvm::IRBuilder<> builder; llvm::IRBuilder<> builder;
llvm::Module module; llvm::Module module;
@ -18,8 +18,9 @@ struct llvm_state {
llvm::PointerType* stack_ptr_type; llvm::PointerType* stack_ptr_type;
llvm::PointerType* node_ptr_type; llvm::PointerType* node_ptr_type;
llvm::IntegerType* tag_type; llvm::IntegerType* tag_type;
llvm::FunctionType* function_type;
llvm_state() llvm_context()
: builder(ctx), module("bloglang", ctx) { : builder(ctx), module("bloglang", ctx) {
create_types(); create_types();
create_functions(); create_functions();
@ -27,4 +28,27 @@ struct llvm_state {
void create_types(); void create_types();
void create_functions(); void create_functions();
llvm::Value* create_i8(int8_t);
llvm::Value* create_i32(int32_t);
llvm::Value* create_size(size_t);
llvm::Value* create_pop(llvm::Function*);
llvm::Value* create_peek(llvm::Function*, llvm::Value*);
void create_push(llvm::Function*, llvm::Value*);
void create_popn(llvm::Function*, llvm::Value*);
void create_update(llvm::Function*, llvm::Value*);
void create_pack(llvm::Function*, llvm::Value*, llvm::Value*);
void create_split(llvm::Function*, llvm::Value*);
void create_slide(llvm::Function*, llvm::Value*);
void create_alloc(llvm::Function*, llvm::Value*);
llvm::Value* create_eval(llvm::Value*);
llvm::Value* unwrap_num(llvm::Value*);
llvm::Value* create_num(llvm::Value*);
llvm::Value* create_global(llvm::Value*, llvm::Value*);
llvm::Value* create_app(llvm::Value*, llvm::Value*);
}; };

View File

@ -55,6 +55,7 @@ a `Module` object, which represents some collection of code and declarations
{{< codeblock "C++" "compiler/08/llvm_context.hpp" >}} {{< codeblock "C++" "compiler/08/llvm_context.hpp" >}}
{{< todo >}} Consistently name context / state.{{< /todo >}} {{< todo >}} Consistently name context / state.{{< /todo >}}
{{< todo >}} Explain creation functions. {{< /todo >}}
We include the LLVM context, builder, and module as members We include the LLVM context, builder, and module as members
of the context struct. Since the builder and the module need of the context struct. Since the builder and the module need
@ -97,6 +98,8 @@ which you can extrapolate the rest:
{{< codelines "C++" "compiler/08/llvm_context.cpp" 7 11 >}} {{< codelines "C++" "compiler/08/llvm_context.cpp" 7 11 >}}
{{< todo >}} Also show struct body setters. {{< /todo >}}
Similarly, here are a few lines from `create_functions()`, which Similarly, here are a few lines from `create_functions()`, which
give a very good idea of the rest of that method: give a very good idea of the rest of that method:
@ -180,5 +183,7 @@ methods.
With these things in mind, here's the signature for `gen_llvm`: With these things in mind, here's the signature for `gen_llvm`:
```C++ ```C++
virtual void gen_llvm(const llvm_context&, llvm::Function*) const; virtual void gen_llvm(llvm_context&, llvm::Function*) const;
``` ```
{{< todo >}} Fix pointer type inconsistencies. {{< /todo >}}