#include "instruction.hpp" #include "llvm_context.hpp" #include #include using namespace llvm; static void print_indent(int n, std::ostream& to) { while(n--) to << " "; } void instruction_pushint::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "PushInt(" << value << ")" << std::endl; } void instruction_pushint::gen_llvm(llvm_context& ctx, Function* f) const { ctx.create_push(f, ctx.create_num(f, ctx.create_i32(value))); } void instruction_pushglobal::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "PushGlobal(" << name << ")" << std::endl; } void instruction_pushglobal::gen_llvm(llvm_context& ctx, Function* f) const { auto& global_f = ctx.get_custom_function(name); auto arity = ctx.create_i32(global_f.arity); ctx.create_push(f, ctx.create_global(f, global_f.function, arity)); } void instruction_push::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "Push(" << offset << ")" << std::endl; } void instruction_push::gen_llvm(llvm_context& ctx, Function* f) const { ctx.create_push(f, ctx.create_peek(f, ctx.create_size(offset))); } void instruction_pop::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "Pop(" << count << ")" << std::endl; } void instruction_pop::gen_llvm(llvm_context& ctx, Function* f) const { ctx.create_popn(f, ctx.create_size(count)); } void instruction_mkapp::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "MkApp()" << std::endl; } void instruction_mkapp::gen_llvm(llvm_context& ctx, Function* f) const { auto left = ctx.create_pop(f); auto right = ctx.create_pop(f); ctx.create_push(f, ctx.create_app(f, left, right)); } void instruction_update::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "Update(" << offset << ")" << std::endl; } void instruction_update::gen_llvm(llvm_context& ctx, Function* f) const { ctx.create_update(f, ctx.create_size(offset)); } void instruction_pack::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "Pack(" << tag << ", " << size << ")" << std::endl; } void instruction_pack::gen_llvm(llvm_context& ctx, Function* f) const { ctx.create_pack(f, ctx.create_size(size), ctx.create_i8(tag)); } void instruction_split::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "Split()" << std::endl; } void instruction_split::gen_llvm(llvm_context& ctx, Function* f) const { ctx.create_split(f, ctx.create_size(size)); } void instruction_jump::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "Jump(" << std::endl; for(auto& instruction_set : branches) { for(auto& instruction : instruction_set) { instruction->print(indent + 2, to); } to << std::endl; } print_indent(indent, to); to << ")" << std::endl; } void instruction_jump::gen_llvm(llvm_context& ctx, Function* f) const { auto top_node = ctx.create_peek(f, ctx.create_size(0)); auto tag = ctx.unwrap_data_tag(top_node); auto safety_block = ctx.create_basic_block("safety", f); auto switch_op = ctx.get_builder().CreateSwitch(tag, safety_block, tag_mappings.size()); std::vector blocks; for(auto& branch : branches) { auto branch_block = ctx.create_basic_block("branch", f); ctx.get_builder().SetInsertPoint(branch_block); for(auto& instruction : branch) { instruction->gen_llvm(ctx, f); } ctx.get_builder().CreateBr(safety_block); blocks.push_back(branch_block); } for(auto& mapping : tag_mappings) { switch_op->addCase(ctx.create_i8(mapping.first), blocks[mapping.second]); } ctx.get_builder().SetInsertPoint(safety_block); } void instruction_slide::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "Slide(" << offset << ")" << std::endl; } void instruction_slide::gen_llvm(llvm_context& ctx, Function* f) const { ctx.create_slide(f, ctx.create_size(offset)); } void instruction_binop::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "BinOp(" << op_action(op) << ")" << std::endl; } void instruction_binop::gen_llvm(llvm_context& ctx, Function* f) const { auto left_int = ctx.unwrap_num(ctx.create_pop(f)); auto right_int = ctx.unwrap_num(ctx.create_pop(f)); llvm::Value* result; switch(op) { case PLUS: result = ctx.get_builder().CreateAdd(left_int, right_int); break; case MINUS: result = ctx.get_builder().CreateSub(left_int, right_int); break; case TIMES: result = ctx.get_builder().CreateMul(left_int, right_int); break; case DIVIDE: result = ctx.get_builder().CreateSDiv(left_int, right_int); break; } ctx.create_push(f, ctx.create_num(f, result)); } void instruction_eval::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "Eval()" << std::endl; } void instruction_eval::gen_llvm(llvm_context& ctx, Function* f) const { ctx.create_unwind(f); } void instruction_alloc::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "Alloc(" << amount << ")" << std::endl; } void instruction_alloc::gen_llvm(llvm_context& ctx, Function* f) const { ctx.create_alloc(f, ctx.create_size(amount)); } void instruction_unwind::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "Unwind()" << std::endl; } void instruction_unwind::gen_llvm(llvm_context& ctx, Function* f) const { // Nothing }