diff --git a/CMakeLists.txt b/CMakeLists.txt index cf59148..2ad76c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,12 @@ cmake_minimum_required(VERSION 3.0) project(lily) +find_package(LLVM REQUIRED CONFIG) +llvm_map_components_to_libnames(LLVM_LIBS core x86asmparser x86asmprinter x86codegen) + set(CMAKE_CXX_STANDARD 14) -add_executable(lily src/main.cpp src/parser.cpp src/parser.c src/type.cpp src/type_manager.cpp src/ast.cpp src/type_checker.cpp src/pattern.cpp src/gmachine.cpp src/compiler.cpp) +add_executable(lily src/main.cpp src/parser.cpp src/parser.c src/type.cpp src/type_manager.cpp src/ast.cpp src/type_checker.cpp src/pattern.cpp src/gmachine.cpp src/compiler.cpp src/llvm.cpp) target_include_directories(lily PUBLIC src) +target_include_directories(lily PUBLIC ${LLVM_INCLUDE_DIRS}) +target_compile_definitions(lily PUBLIC ${LLVM_DEFINITIONS}) +target_link_libraries(lily ${LLVM_LIBS}) diff --git a/runtime.c b/runtime.c new file mode 100644 index 0000000..0b1c412 --- /dev/null +++ b/runtime.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include + +struct node_parent { + char tag; +}; + +struct stack { + int32_t size; + int32_t count; + struct node_parent** data; +}; + +struct node_app { + char tag; + struct node_parent* left; + struct node_parent* right; +}; + +struct node_num { + char tag; + int32_t value; +}; + +struct node_global { + char tag; + int32_t arity; + void (*function)(struct stack*); +}; + +struct node_ind { + char tag; + struct node_parent* next; +}; + +void stack_init(struct stack* stack) { + stack->size = 16; + stack->count = 0; + stack->data = malloc(sizeof(*stack->data) * stack->size); +} + +void stack_free(struct stack* stack) { + free(stack->data); +} + +void stack_push(struct stack* stack, struct node_parent* node) { + printf("pushing\n"); + assert(stack->count < stack->size); + stack->data[stack->count++] = node; + printf("new size: %d\n", stack->count); +} + +struct node_parent* stack_peek(struct stack* stack, int32_t offset) { + assert(offset + 1 <= stack->count); + return stack->data[stack->count - offset - 1]; +} + +struct node_parent* stack_pop(struct stack* stack) { + printf("popping\nnew size: %d\n", stack->count - 1); + assert(stack->count > 0); + return stack->data[--stack->count]; +} + +void stack_popn(struct stack* stack, int32_t count) { + assert(stack->count >= count); + stack->count -= count; + printf("popping %d\nnew size: %d\n", count, stack->count); +} + +void stack_update(struct stack* stack, int32_t offset) { + assert(stack->count >= offset + 2); + struct node_parent* to_replace = stack->data[stack->count - 1 - 1 - offset]; + struct node_parent* to_use = stack->data[stack->count - 1]; + memcpy(to_replace, to_use, sizeof(struct node_app)); + stack->count--; + printf("updating\nnew size: %d\n", stack->count); +} + +void stack_alloc(struct stack* stack, int32_t count) { + assert(stack->count + count <= stack->size); + for(int32_t i = 0; i < count; i++) { + stack->data[stack->count++] = malloc(sizeof(struct node_app)); + } +} + +void stack_slide(struct stack* stack, int32_t count) { + assert(stack->count > count); + stack->data[stack->count - 1 - count] = stack->data[stack->count - 1]; + stack->count -= count; +} + +void stack_set(struct stack* stack, int32_t index, struct node_parent* parent) { + assert(stack->count > index); + stack->data[stack->count - 1 - index] = parent; +} + +int32_t stack_size(struct stack* stack) { + return stack->count; +} + +struct node_parent* malloc_node_num(int32_t value) { + printf("alloced num %d\n", value); + struct node_num* node = malloc(sizeof(struct node_app)); + node->tag = 0; + node->value = value; + return (struct node_parent*) node; +} + +struct node_parent* malloc_node_app(struct node_parent* left, struct node_parent* right) { + printf("allocated application\n"); + struct node_app* node = malloc(sizeof(struct node_app)); + node->tag = 1; + node->left = left; + node->right = right; + return (struct node_parent*) node; +} +struct node_parent* malloc_node_global(int32_t arity, void (*function)(struct stack*)) { + printf("allocated global with arity %d\n", arity); + struct node_global* node = malloc(sizeof(struct node_app)); + node->tag = 2; + node->arity = arity; + node->function = function; + return (struct node_parent*) node; +} +struct node_parent* malloc_node_indirect(struct node_parent* target) { + printf("allocated indirection node\n"); + struct node_ind* node = malloc(sizeof(struct node_app)); + node->tag = 3; + node->next = target; + return (struct node_parent*) node; +} + +void unwind(struct stack* stack) { + while(1) { + assert(stack_size(stack) != 0); + struct node_parent* node = stack_peek(stack, 0); + if(node->tag == 0) { + return; + } else if(node->tag == 1) { + printf("unwinding an application\n"); + stack_push(stack, ((struct node_app*) node)->left); + } else if(node->tag == 2) { + struct node_global* global = (struct node_global*) node; + if(stack->size > global->arity) { + for(int i = 0; i < global->arity; i++) { + struct node_app* app = (struct node_app*) stack_peek(stack, i + 1); + stack_set(stack, i + 1, app->right); + } + global->function(stack); + } else { + stack_popn(stack, stack_size(stack) - 1); + return; + } + } else if(node->tag == 3) { + struct node_ind* ind = (struct node_ind*) node; + stack_pop(stack); + stack_push(stack, ind->next); + } + } +} + +struct node_parent* eval(struct node_parent* start) { + struct stack new_stack; + stack_init(&new_stack); + stack_push(&new_stack, start); + unwind(&new_stack); + struct node_parent* final_node = stack_pop(&new_stack); + stack_free(&new_stack); + return final_node; +} + +extern void main_supercomb(struct stack* stack); + +int main(int argc, char** argv) { + struct node_parent* result = eval(malloc_node_global(0, main_supercomb)); + if(result->tag == 0) { + printf("resulting number: %d\n", ((struct node_num*) result)->value); + } +} diff --git a/src/ast.cpp b/src/ast.cpp index 9c7efd7..2958fbd 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -95,7 +95,7 @@ namespace lily { } void ast_num::compile(instruction_manager& mgr, std::vector& into, std::shared_ptr env) { - into.push_back(mgr.add_instruction(3)); + into.push_back(mgr.add_instruction(num)); } void ast_var::compile(instruction_manager& mgr, std::vector& into, std::shared_ptr env) { diff --git a/src/gmachine.cpp b/src/gmachine.cpp index 1650522..c6a2094 100644 --- a/src/gmachine.cpp +++ b/src/gmachine.cpp @@ -86,4 +86,102 @@ namespace lily { os << "jump"; return os; } + + void instruction_slide::gen_llvm(llvm_context& ctx) { + llvm::Value* stack = ctx.get_current_function()->arg_begin(); + builder.CreateCall(stack_slide_func, { stack, get_int32_constant(amount) }); + } + + void instruction_alloc::gen_llvm(llvm_context& ctx) { + llvm::Value* stack = ctx.get_current_function()->arg_begin(); + builder.CreateCall(stack_alloc_func, { stack, get_int32_constant(amount) }); + } + + void instruction_pop::gen_llvm(llvm_context& ctx) { + llvm::Value* stack = ctx.get_current_function()->arg_begin(); + builder.CreateCall(stack_popn_func, { stack, get_int32_constant(amount) }); + } + + void instruction_unwind::gen_llvm(llvm_context& ctx) { + + } + + void instruction_push_global::gen_llvm(llvm_context& ctx) { + llvm::Value* stack = ctx.get_current_function()->arg_begin(); + llvm::Value* new_node = builder.CreateCall(malloc_node_global_func, + { get_int8_constant(2), ctx.get_supercombinator(name) }, "temp"); + // TODO get arity + builder.CreateCall(stack_push_func, { stack, new_node }); + } + + void instruction_push_int::gen_llvm(llvm_context& ctx) { + llvm::Value* stack = ctx.get_current_function()->arg_begin(); + llvm::Value* new_node = builder.CreateCall(malloc_node_num_func, + { get_int32_constant(value) }); + builder.CreateCall(stack_push_func, { stack, new_node }); + } + + void instruction_push_str::gen_llvm(llvm_context& ctx) { + + } + + void instruction_push::gen_llvm(llvm_context& ctx) { + llvm::Value* stack = ctx.get_current_function()->arg_begin(); + llvm::Value* peeked = builder.CreateCall(stack_peek_func, { stack, get_int32_constant(offset) }, "temp"); + builder.CreateCall(stack_push_func, { stack, peeked }); + } + + void instruction_mkapp::gen_llvm(llvm_context& ctx) { + llvm::Value* stack = ctx.get_current_function()->arg_begin(); + llvm::Value* func = builder.CreateCall(stack_pop_func, { stack }, "temp"); + llvm::Value* param = builder.CreateCall(stack_pop_func, { stack }, "temp"); + llvm::Value* app_node = builder.CreateCall(malloc_node_app_func, { func, param }, "temp"); + builder.CreateCall(stack_push_func, { stack, app_node }); + } + + void instruction_eval::gen_llvm(llvm_context& ctx) { + // ?? + } + + void instruction_op::gen_llvm(llvm_context& ctx) { + llvm::Value* stack = ctx.get_current_function()->arg_begin(); + llvm::Value* param1 = builder.CreateCall(stack_pop_func, { stack }, "temp"); + llvm::Value* param2 = builder.CreateCall(stack_pop_func, { stack }, "temp"); + llvm::Value* param1_node_num = builder.CreatePointerCast(param1, llvm::PointerType::getUnqual(node_num_type), "temp"); + llvm::Value* param2_node_num = builder.CreatePointerCast(param2, llvm::PointerType::getUnqual(node_num_type), "temp"); + llvm::Value* param1_intptr = builder.CreateGEP(param1_node_num, { get_int32_constant(0), get_int32_constant(1) }, "temp"); + llvm::Value* param2_intptr = builder.CreateGEP(param2_node_num, { get_int32_constant(0), get_int32_constant(1) }, "temp"); + llvm::Value* param1_int = builder.CreateLoad(llvm::IntegerType::get(context, 32), param1_intptr, "temp"); + llvm::Value* param2_int = builder.CreateLoad(llvm::IntegerType::get(context, 32), param2_intptr, "temp"); + llvm::Value* op_result; + switch(op) { + case binop::add: op_result = builder.CreateAdd(param2_int, param1_int, "temp"); break; + case binop::subtract: op_result = builder.CreateSub(param2_int, param1_int, "temp"); break; + case binop::times: op_result = builder.CreateMul(param2_int, param1_int, "temp"); break; + case binop::divide: op_result = builder.CreateSDiv(param2_int, param1_int, "temp"); break; + } + llvm::Value* new_node = builder.CreateCall(malloc_node_num_func, { op_result }, "temp"); + builder.CreateCall(stack_push_func, { stack, new_node }); + } + + void instruction_cond::gen_llvm(llvm_context& ctx) { + + } + + void instruction_update::gen_llvm(llvm_context& ctx) { + llvm::Value* stack = ctx.get_current_function()->arg_begin(); + builder.CreateCall(stack_update_func, { stack, get_int32_constant(offset) }); + } + + void instruction_pack::gen_llvm(llvm_context& ctx) { + + } + + void instruction_split::gen_llvm(llvm_context& ctx) { + + } + + void instruction_jump::gen_llvm(llvm_context& ctx) { + + } } diff --git a/src/gmachine.hpp b/src/gmachine.hpp index bc5466d..4440df5 100644 --- a/src/gmachine.hpp +++ b/src/gmachine.hpp @@ -2,11 +2,13 @@ #include #include #include "binop.hpp" +#include "llvm.hpp" namespace lily { struct instruction { - virtual std::ostream& to_stream(std::ostream& os) = 0; virtual ~instruction() = default; + virtual std::ostream& to_stream(std::ostream& os) = 0; + virtual void gen_llvm(llvm_context& ctx) = 0; }; std::ostream& operator<<(std::ostream& os, instruction& inst); @@ -16,6 +18,7 @@ namespace lily { instruction_slide(int a) : amount(a) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_alloc : instruction { @@ -23,6 +26,7 @@ namespace lily { instruction_alloc(int a) : amount(a) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_pop : instruction { @@ -30,10 +34,12 @@ namespace lily { instruction_pop(int a) : amount(a) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_unwind : instruction { std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_push_global : instruction { @@ -41,6 +47,7 @@ namespace lily { instruction_push_global(std::string n) : name(std::move(n)) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_push_int : instruction { @@ -48,6 +55,7 @@ namespace lily { instruction_push_int(int v) : value(v) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_push_str : instruction { @@ -55,6 +63,7 @@ namespace lily { instruction_push_str(std::string s) : str(std::move(s)) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_push : instruction { @@ -62,16 +71,19 @@ namespace lily { instruction_push(int o) : offset(o) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_mkapp : instruction { std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_eval : instruction { std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_op : instruction { @@ -79,12 +91,14 @@ namespace lily { instruction_op(binop o) : op(o) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_cond : instruction { std::vector true_branch; std::vector false_branch; std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_update : instruction { @@ -92,6 +106,7 @@ namespace lily { instruction_update(int o) : offset(o) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_pack : instruction { @@ -101,6 +116,7 @@ namespace lily { instruction_pack(int c, int a) : constructor(c), arity(a) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_split : instruction { @@ -108,11 +124,13 @@ namespace lily { instruction_split(int a) : arity(a) {} std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; struct instruction_jump : instruction { std::vector> instructions; std::ostream& to_stream(std::ostream& os); + void gen_llvm(llvm_context& ctx); }; class instruction_manager { diff --git a/src/llvm.cpp b/src/llvm.cpp new file mode 100644 index 0000000..e26620b --- /dev/null +++ b/src/llvm.cpp @@ -0,0 +1,237 @@ +#include "llvm.hpp" +#include "error.hpp" +#include "llvm/IR/Verifier.h" +#include "llvm/IR/LegacyPassManager.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" + +namespace lily { + llvm::LLVMContext context; + llvm::IRBuilder<> builder(context); + llvm::Module module("Lily", context); + + llvm::StructType* stack_type; + llvm::PointerType* stack_pointer_type; + + llvm::FunctionType* supercomb_function_type; + llvm::FunctionType* eval_function_type; + llvm::PointerType* supercomb_function_pointer_type; + + llvm::Function* stack_init_func; + llvm::Function* stack_free_func; + llvm::Function* stack_push_func; + llvm::Function* stack_peek_func; + llvm::Function* stack_pop_func; + llvm::Function* stack_popn_func; + llvm::Function* stack_update_func; + llvm::Function* stack_alloc_func; + llvm::Function* stack_slide_func; + llvm::Function* stack_size_func; + + llvm::Function* malloc_node_num_func; + llvm::Function* malloc_node_app_func; + llvm::Function* malloc_node_global_func; + llvm::Function* malloc_node_ind_func; + + llvm::IntegerType* tag_type; + llvm::PointerType* node_pointer_type; + llvm::StructType* node_parent_type; + llvm::StructType* node_num_type; + llvm::StructType* node_app_type; + llvm::StructType* node_global_type; + llvm::StructType* node_indirect_type; + + static void initialize_llvm() { + + } + + llvm::Value* get_int32_constant(int value) { + return llvm::ConstantInt::get(context, llvm::APInt(32, value)); + } + + llvm::Value* get_int64_constant(long int value) { + return llvm::ConstantInt::get(context, llvm::APInt(64, value)); + } + + llvm::Value* get_int8_constant(char value) { + return llvm::ConstantInt::get(context, llvm::APInt(8, value)); + } + + llvm::Value* get_type_size(llvm::Type* type) { + llvm::PointerType* pointer = llvm::PointerType::getUnqual(type); + llvm::Value* null = llvm::ConstantPointerNull::get(pointer); + llvm::Value* ptr = builder.CreateGEP(type, null, {get_int32_constant(1), get_int32_constant(0)}, "temp"); + llvm::Value* val = builder.CreatePtrToInt(ptr, llvm::IntegerType::get(context, 64), "temp"); + return val; + } + + static void initialize_functions() { + stack_init_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "stack_init", + &module); + stack_free_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "stack_free", + &module); + stack_push_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, node_pointer_type }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "stack_push", + &module); + stack_peek_func = llvm::Function::Create( + llvm::FunctionType::get(node_pointer_type, { stack_pointer_type, llvm::IntegerType::get(context, 32) }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "stack_peek", + &module); + stack_pop_func = llvm::Function::Create( + llvm::FunctionType::get(node_pointer_type, { stack_pointer_type }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "stack_pop", + &module); + stack_popn_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, llvm::IntegerType::get(context, 32) }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "stack_popn", + &module); + stack_update_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, llvm::IntegerType::get(context, 32) }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "stack_update", + &module); + stack_alloc_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, llvm::IntegerType::get(context, 32) }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "stack_alloc", + &module); + stack_slide_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, llvm::IntegerType::get(context, 32) }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "stack_slide", + &module); + malloc_node_num_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::PointerType::getUnqual(node_parent_type), { llvm::IntegerType::get(context, 32) }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "malloc_node_num", + &module); + malloc_node_app_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::PointerType::getUnqual(node_parent_type), { node_pointer_type, node_pointer_type }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "malloc_node_app", + &module); + malloc_node_global_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::PointerType::getUnqual(node_parent_type), { tag_type, supercomb_function_pointer_type }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "malloc_node_global", + &module); + malloc_node_ind_func = llvm::Function::Create( + llvm::FunctionType::get(llvm::PointerType::getUnqual(node_parent_type), { node_pointer_type }, false), + llvm::Function::LinkageTypes::ExternalLinkage, + "malloc_node_indirect", + &module); + } + + static void initialize_types() { + stack_type = llvm::StructType::create(context, "stack"); + stack_pointer_type = llvm::PointerType::getUnqual(stack_type); + + tag_type = llvm::IntegerType::get(context, 8); + node_parent_type = llvm::StructType::create(context, "node_parent"); + node_pointer_type = llvm::PointerType::getUnqual(node_parent_type); + node_num_type = llvm::StructType::create(context, "node_num"); + node_app_type = llvm::StructType::create(context, "node_app"); + node_global_type = llvm::StructType::create(context, "node_global"); + node_indirect_type = llvm::StructType::create(context, "node_indirect"); + + supercomb_function_type = llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type }, false); + supercomb_function_pointer_type = llvm::PointerType::getUnqual(supercomb_function_type); + + stack_type->setBody(llvm::IntegerType::get(context, 32), llvm::IntegerType::get(context, 32), llvm::PointerType::getUnqual(node_pointer_type)); + node_parent_type->setBody(tag_type); + node_num_type->setBody(tag_type, llvm::IntegerType::get(context, 32)); + node_app_type->setBody(tag_type, node_pointer_type, node_pointer_type); + node_global_type->setBody(tag_type, tag_type, supercomb_function_pointer_type); + node_indirect_type->setBody(tag_type, node_pointer_type); + } + + void llvm_generate(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()); + + module.setDataLayout(targetMachine->createDataLayout()); + 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(module); + file.close(); + } + } + } + } + + void llvm_init() { + static bool initialized = false; + if(!initialized) { + initialize_llvm(); + initialize_types(); + initialize_functions(); + initialized = true; + } + } + + llvm::Function* llvm_context::get_supercombinator(const std::string& name) { + if(!supercombinators.count(name)) throw error("unknown supercombinator"); + return supercombinators.find(name)->second; + } + + void llvm_context::add_supercombinator(const std::string& name) { + if(supercombinators.count(name)) throw error("re-creating supercombinator"); + llvm::Function* new_function = llvm::Function::Create( + supercomb_function_type, + llvm::Function::LinkageTypes::ExternalLinkage, + name + "_supercomb", + &module); + new_function->arg_begin()->setName("stack"); + supercombinators[name] = new_function; + } + + llvm::Function* llvm_context::get_current_function() { + return current_function; + } + + void llvm_context::set_current_function(llvm::Function* f) { + current_function = f; + } + +} diff --git a/src/llvm.hpp b/src/llvm.hpp new file mode 100644 index 0000000..8816b91 --- /dev/null +++ b/src/llvm.hpp @@ -0,0 +1,61 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace lily { + extern llvm::LLVMContext context; + extern llvm::IRBuilder<> builder; + extern llvm::Module module; + + extern llvm::StructType* stack_type; + extern llvm::PointerType* stack_pointer_type; + + extern llvm::FunctionType* supercomb_function_type; + extern llvm::FunctionType* eval_function_type; + extern llvm::PointerType* supercomb_function_pointer_type; + + extern llvm::Function* stack_init_func; + extern llvm::Function* stack_free_func; + extern llvm::Function* stack_push_func; + extern llvm::Function* stack_peek_func; + extern llvm::Function* stack_pop_func; + extern llvm::Function* stack_popn_func; + extern llvm::Function* stack_update_func; + extern llvm::Function* stack_alloc_func; + extern llvm::Function* stack_slide_func; + extern llvm::Function* stack_size_func; + + extern llvm::Function* malloc_node_num_func; + extern llvm::Function* malloc_node_app_func; + extern llvm::Function* malloc_node_global_func; + extern llvm::Function* malloc_node_ind_func; + + extern llvm::IntegerType* tag_type; + extern llvm::PointerType* node_pointer_type; + extern llvm::StructType* node_parent_type; + extern llvm::StructType* node_num_type; + extern llvm::StructType* node_app_type; + extern llvm::StructType* node_global_type; + extern llvm::StructType* node_indirect_type; + + llvm::Value* get_int32_constant(int value); + llvm::Value* get_int64_constant(int value); + llvm::Value* get_int8_constant(char value); + + void llvm_init(); + void llvm_generate(const std::string& filename); + + class llvm_context { + private: + std::map supercombinators; + llvm::Function* current_function; + public: + llvm::Function* get_supercombinator(const std::string& name); + void add_supercombinator(const std::string& name); + llvm::Function* get_current_function(); + void set_current_function(llvm::Function* f); + }; +} diff --git a/src/main.cpp b/src/main.cpp index d9f8868..2a4b19a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,22 +2,15 @@ #include "pattern.hpp" #include "parser.hpp" #include "gmachine.hpp" +#include "llvm.hpp" int main() { try { + lily::program_ptr prog = lily::parse( - "defn other x y = { 3 }\n" - "defn otherr x y = { let sum = { x + y } in { sum + sum } }\n" + "defn main = { 163 * 2 }" ); - std::map> into; - lily::instruction_manager mgr; - prog->compile(mgr, into); - for(auto& pair : into) { - std::cout << pair.first << std::endl; - for(auto& op : pair.second) { - std::cout << " " << *op << std::endl; - } - } + prog->gen_llvm(); } catch(lily::error& e) { std::cout << e.message << std::endl; } diff --git a/src/parser.cpp b/src/parser.cpp index d885b76..819c3f3 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4,6 +4,8 @@ extern "C" { #include "parser.hpp" #include "pattern.hpp" #include "type_checker.hpp" +#include "llvm.hpp" +#include "llvm/IR/Verifier.h" #include namespace lily { @@ -294,14 +296,13 @@ namespace lily { template static void generate_binop(instruction_manager& mgr, std::map>& into) { std::vector dest; - dest.push_back(mgr.add_instruction(1)); + dest.push_back(mgr.add_instruction(2)); dest.push_back(mgr.add_instruction()); - dest.push_back(mgr.add_instruction(1)); + dest.push_back(mgr.add_instruction(2)); dest.push_back(mgr.add_instruction()); dest.push_back(mgr.add_instruction(o)); dest.push_back(mgr.add_instruction(2)); dest.push_back(mgr.add_instruction(2)); - dest.push_back(mgr.add_instruction()); into[op_supercombinator(o)] = std::move(dest); } @@ -334,4 +335,34 @@ namespace lily { into[pair.first] = std::move(destination); } } + + void program::gen_llvm() { + llvm_init(); + llvm_context ctx; + instruction_manager mgr; + std::map> gcode; + + compile(mgr, gcode); + + for(auto& pair : gcode) { + ctx.add_supercombinator(pair.first); + } + + for(auto& pair : gcode) { + std::vector& comb_gcode = pair.second; + llvm::Function* current_function = ctx.get_supercombinator(pair.first); + ctx.set_current_function(current_function); + llvm::BasicBlock* new_block = + llvm::BasicBlock::Create(context, "entry", current_function); + builder.SetInsertPoint(new_block); + for(auto& op : comb_gcode) { + op->gen_llvm(ctx); + } + builder.CreateRetVoid(); + } + + llvm::verifyModule(module, &llvm::outs()); + llvm_generate("lily.o"); + module.print(llvm::outs(), NULL); + } } diff --git a/src/parser.hpp b/src/parser.hpp index b84422f..5f8d0d9 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -15,6 +15,7 @@ namespace lily { void check(); void compile(instruction_manager& mgr, std::map>& into); + void gen_llvm(); }; typedef std::unique_ptr program_ptr;