Get awful LLVM code generation working.
This commit is contained in:
		
							parent
							
								
									e579078f73
								
							
						
					
					
						commit
						37f5e53a59
					
				@ -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
									
								
							
							
						
						
									
										181
									
								
								runtime.c
									
									
									
									
									
										Normal 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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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) {
 | 
				
			||||||
 | 
				
			|||||||
@ -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) {
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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
									
								
							
							
						
						
									
										237
									
								
								src/llvm.cpp
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										61
									
								
								src/llvm.hpp
									
									
									
									
									
										Normal 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);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/main.cpp
									
									
									
									
									
								
							@ -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;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user