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