Get awful LLVM code generation working.

This commit is contained in:
Danila Fedorin 2019-06-12 01:38:27 -07:00
parent e579078f73
commit 37f5e53a59
10 changed files with 643 additions and 17 deletions

View File

@ -1,6 +1,12 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(lily) project(lily)
find_package(LLVM REQUIRED CONFIG)
llvm_map_components_to_libnames(LLVM_LIBS core x86asmparser x86asmprinter x86codegen)
set(CMAKE_CXX_STANDARD 14) 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 src)
target_include_directories(lily PUBLIC ${LLVM_INCLUDE_DIRS})
target_compile_definitions(lily PUBLIC ${LLVM_DEFINITIONS})
target_link_libraries(lily ${LLVM_LIBS})

181
runtime.c Normal file
View File

@ -0,0 +1,181 @@
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <memory.h>
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);
}
}

View File

@ -95,7 +95,7 @@ namespace lily {
} }
void ast_num::compile(instruction_manager& mgr, std::vector<instruction*>& into, std::shared_ptr<compile_env> env) { void ast_num::compile(instruction_manager& mgr, std::vector<instruction*>& into, std::shared_ptr<compile_env> env) {
into.push_back(mgr.add_instruction<instruction_push_int>(3)); into.push_back(mgr.add_instruction<instruction_push_int>(num));
} }
void ast_var::compile(instruction_manager& mgr, std::vector<instruction*>& into, std::shared_ptr<compile_env> env) { void ast_var::compile(instruction_manager& mgr, std::vector<instruction*>& into, std::shared_ptr<compile_env> env) {

View File

@ -86,4 +86,102 @@ namespace lily {
os << "jump"; os << "jump";
return os; 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) {
}
} }

View File

@ -2,11 +2,13 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "binop.hpp" #include "binop.hpp"
#include "llvm.hpp"
namespace lily { namespace lily {
struct instruction { struct instruction {
virtual std::ostream& to_stream(std::ostream& os) = 0;
virtual ~instruction() = default; 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); std::ostream& operator<<(std::ostream& os, instruction& inst);
@ -16,6 +18,7 @@ namespace lily {
instruction_slide(int a) : amount(a) {} instruction_slide(int a) : amount(a) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_alloc : instruction { struct instruction_alloc : instruction {
@ -23,6 +26,7 @@ namespace lily {
instruction_alloc(int a) : amount(a) {} instruction_alloc(int a) : amount(a) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_pop : instruction { struct instruction_pop : instruction {
@ -30,10 +34,12 @@ namespace lily {
instruction_pop(int a) : amount(a) {} instruction_pop(int a) : amount(a) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_unwind : instruction { struct instruction_unwind : instruction {
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_push_global : instruction { struct instruction_push_global : instruction {
@ -41,6 +47,7 @@ namespace lily {
instruction_push_global(std::string n) : name(std::move(n)) {} instruction_push_global(std::string n) : name(std::move(n)) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_push_int : instruction { struct instruction_push_int : instruction {
@ -48,6 +55,7 @@ namespace lily {
instruction_push_int(int v) : value(v) {} instruction_push_int(int v) : value(v) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_push_str : instruction { struct instruction_push_str : instruction {
@ -55,6 +63,7 @@ namespace lily {
instruction_push_str(std::string s) : str(std::move(s)) {} instruction_push_str(std::string s) : str(std::move(s)) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_push : instruction { struct instruction_push : instruction {
@ -62,16 +71,19 @@ namespace lily {
instruction_push(int o) : offset(o) {} instruction_push(int o) : offset(o) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_mkapp : instruction { struct instruction_mkapp : instruction {
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_eval : instruction { struct instruction_eval : instruction {
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_op : instruction { struct instruction_op : instruction {
@ -79,12 +91,14 @@ namespace lily {
instruction_op(binop o) : op(o) {} instruction_op(binop o) : op(o) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_cond : instruction { struct instruction_cond : instruction {
std::vector<instruction*> true_branch; std::vector<instruction*> true_branch;
std::vector<instruction*> false_branch; std::vector<instruction*> false_branch;
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_update : instruction { struct instruction_update : instruction {
@ -92,6 +106,7 @@ namespace lily {
instruction_update(int o) : offset(o) {} instruction_update(int o) : offset(o) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_pack : instruction { struct instruction_pack : instruction {
@ -101,6 +116,7 @@ namespace lily {
instruction_pack(int c, int a) : instruction_pack(int c, int a) :
constructor(c), arity(a) {} constructor(c), arity(a) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_split : instruction { struct instruction_split : instruction {
@ -108,11 +124,13 @@ namespace lily {
instruction_split(int a) : arity(a) {} instruction_split(int a) : arity(a) {}
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
struct instruction_jump : instruction { struct instruction_jump : instruction {
std::vector<std::vector<instruction*>> instructions; std::vector<std::vector<instruction*>> instructions;
std::ostream& to_stream(std::ostream& os); std::ostream& to_stream(std::ostream& os);
void gen_llvm(llvm_context& ctx);
}; };
class instruction_manager { class instruction_manager {

237
src/llvm.cpp Normal file
View File

@ -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<llvm::Reloc::Model>());
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;
}
}

61
src/llvm.hpp Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include <map>
#include <vector>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/IRBuilder.h>
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<std::string, llvm::Function*> 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);
};
}

View File

@ -2,22 +2,15 @@
#include "pattern.hpp" #include "pattern.hpp"
#include "parser.hpp" #include "parser.hpp"
#include "gmachine.hpp" #include "gmachine.hpp"
#include "llvm.hpp"
int main() { int main() {
try { try {
lily::program_ptr prog = lily::parse( lily::program_ptr prog = lily::parse(
"defn other x y = { 3 }\n" "defn main = { 163 * 2 }"
"defn otherr x y = { let sum = { x + y } in { sum + sum } }\n"
); );
std::map<std::string, std::vector<lily::instruction*>> into; prog->gen_llvm();
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;
}
}
} catch(lily::error& e) { } catch(lily::error& e) {
std::cout << e.message << std::endl; std::cout << e.message << std::endl;
} }

View File

@ -4,6 +4,8 @@ extern "C" {
#include "parser.hpp" #include "parser.hpp"
#include "pattern.hpp" #include "pattern.hpp"
#include "type_checker.hpp" #include "type_checker.hpp"
#include "llvm.hpp"
#include "llvm/IR/Verifier.h"
#include <memory> #include <memory>
namespace lily { namespace lily {
@ -294,14 +296,13 @@ namespace lily {
template <binop o> template <binop o>
static void generate_binop(instruction_manager& mgr, std::map<std::string, std::vector<instruction*>>& into) { static void generate_binop(instruction_manager& mgr, std::map<std::string, std::vector<instruction*>>& into) {
std::vector<instruction*> dest; std::vector<instruction*> dest;
dest.push_back(mgr.add_instruction<instruction_push>(1)); dest.push_back(mgr.add_instruction<instruction_push>(2));
dest.push_back(mgr.add_instruction<instruction_eval>()); dest.push_back(mgr.add_instruction<instruction_eval>());
dest.push_back(mgr.add_instruction<instruction_push>(1)); dest.push_back(mgr.add_instruction<instruction_push>(2));
dest.push_back(mgr.add_instruction<instruction_eval>()); dest.push_back(mgr.add_instruction<instruction_eval>());
dest.push_back(mgr.add_instruction<instruction_op>(o)); dest.push_back(mgr.add_instruction<instruction_op>(o));
dest.push_back(mgr.add_instruction<instruction_update>(2)); dest.push_back(mgr.add_instruction<instruction_update>(2));
dest.push_back(mgr.add_instruction<instruction_pop>(2)); dest.push_back(mgr.add_instruction<instruction_pop>(2));
dest.push_back(mgr.add_instruction<instruction_unwind>());
into[op_supercombinator(o)] = std::move(dest); into[op_supercombinator(o)] = std::move(dest);
} }
@ -334,4 +335,34 @@ namespace lily {
into[pair.first] = std::move(destination); into[pair.first] = std::move(destination);
} }
} }
void program::gen_llvm() {
llvm_init();
llvm_context ctx;
instruction_manager mgr;
std::map<std::string, std::vector<instruction*>> gcode;
compile(mgr, gcode);
for(auto& pair : gcode) {
ctx.add_supercombinator(pair.first);
}
for(auto& pair : gcode) {
std::vector<instruction*>& 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);
}
} }

View File

@ -15,6 +15,7 @@ namespace lily {
void check(); void check();
void compile(instruction_manager& mgr, std::map<std::string, std::vector<instruction*>>& into); void compile(instruction_manager& mgr, std::map<std::string, std::vector<instruction*>>& into);
void gen_llvm();
}; };
typedef std::unique_ptr<program> program_ptr; typedef std::unique_ptr<program> program_ptr;