#include "llvm.hpp" #include "error.hpp" #include "llvm/IR/Verifier.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/FileSystem.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetMachine.h" namespace lily { llvm::LLVMContext context; llvm::IRBuilder<> builder(context); llvm::Module module("Lily", context); llvm::StructType* stack_type; llvm::PointerType* stack_pointer_type; llvm::FunctionType* supercomb_function_type; llvm::FunctionType* eval_function_type; llvm::PointerType* supercomb_function_pointer_type; llvm::Function* stack_init_func; llvm::Function* stack_free_func; llvm::Function* stack_push_func; llvm::Function* stack_peek_func; llvm::Function* stack_pop_func; llvm::Function* stack_popn_func; llvm::Function* stack_update_func; llvm::Function* stack_alloc_func; llvm::Function* stack_slide_func; llvm::Function* stack_size_func; llvm::Function* malloc_node_num_func; llvm::Function* malloc_node_app_func; llvm::Function* malloc_node_global_func; llvm::Function* malloc_node_ind_func; llvm::IntegerType* tag_type; llvm::PointerType* node_pointer_type; llvm::StructType* node_parent_type; llvm::StructType* node_num_type; llvm::StructType* node_app_type; llvm::StructType* node_global_type; llvm::StructType* node_indirect_type; static void initialize_llvm() { } llvm::Value* get_int32_constant(int value) { return llvm::ConstantInt::get(context, llvm::APInt(32, value)); } llvm::Value* get_int64_constant(long int value) { return llvm::ConstantInt::get(context, llvm::APInt(64, value)); } llvm::Value* get_int8_constant(char value) { return llvm::ConstantInt::get(context, llvm::APInt(8, value)); } llvm::Value* get_type_size(llvm::Type* type) { llvm::PointerType* pointer = llvm::PointerType::getUnqual(type); llvm::Value* null = llvm::ConstantPointerNull::get(pointer); llvm::Value* ptr = builder.CreateGEP(type, null, {get_int32_constant(1), get_int32_constant(0)}, "temp"); llvm::Value* val = builder.CreatePtrToInt(ptr, llvm::IntegerType::get(context, 64), "temp"); return val; } static void initialize_functions() { stack_init_func = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type }, false), llvm::Function::LinkageTypes::ExternalLinkage, "stack_init", &module); stack_free_func = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type }, false), llvm::Function::LinkageTypes::ExternalLinkage, "stack_free", &module); stack_push_func = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, node_pointer_type }, false), llvm::Function::LinkageTypes::ExternalLinkage, "stack_push", &module); stack_peek_func = llvm::Function::Create( llvm::FunctionType::get(node_pointer_type, { stack_pointer_type, llvm::IntegerType::get(context, 32) }, false), llvm::Function::LinkageTypes::ExternalLinkage, "stack_peek", &module); stack_pop_func = llvm::Function::Create( llvm::FunctionType::get(node_pointer_type, { stack_pointer_type }, false), llvm::Function::LinkageTypes::ExternalLinkage, "stack_pop", &module); stack_popn_func = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, llvm::IntegerType::get(context, 32) }, false), llvm::Function::LinkageTypes::ExternalLinkage, "stack_popn", &module); stack_update_func = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, llvm::IntegerType::get(context, 32) }, false), llvm::Function::LinkageTypes::ExternalLinkage, "stack_update", &module); stack_alloc_func = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, llvm::IntegerType::get(context, 32) }, false), llvm::Function::LinkageTypes::ExternalLinkage, "stack_alloc", &module); stack_slide_func = llvm::Function::Create( llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, llvm::IntegerType::get(context, 32) }, false), llvm::Function::LinkageTypes::ExternalLinkage, "stack_slide", &module); malloc_node_num_func = llvm::Function::Create( llvm::FunctionType::get(llvm::PointerType::getUnqual(node_parent_type), { llvm::IntegerType::get(context, 32) }, false), llvm::Function::LinkageTypes::ExternalLinkage, "malloc_node_num", &module); malloc_node_app_func = llvm::Function::Create( llvm::FunctionType::get(llvm::PointerType::getUnqual(node_parent_type), { node_pointer_type, node_pointer_type }, false), llvm::Function::LinkageTypes::ExternalLinkage, "malloc_node_app", &module); malloc_node_global_func = llvm::Function::Create( llvm::FunctionType::get(llvm::PointerType::getUnqual(node_parent_type), { tag_type, supercomb_function_pointer_type }, false), llvm::Function::LinkageTypes::ExternalLinkage, "malloc_node_global", &module); malloc_node_ind_func = llvm::Function::Create( llvm::FunctionType::get(llvm::PointerType::getUnqual(node_parent_type), { node_pointer_type }, false), llvm::Function::LinkageTypes::ExternalLinkage, "malloc_node_indirect", &module); } static void initialize_types() { stack_type = llvm::StructType::create(context, "stack"); stack_pointer_type = llvm::PointerType::getUnqual(stack_type); tag_type = llvm::IntegerType::get(context, 8); node_parent_type = llvm::StructType::create(context, "node_parent"); node_pointer_type = llvm::PointerType::getUnqual(node_parent_type); node_num_type = llvm::StructType::create(context, "node_num"); node_app_type = llvm::StructType::create(context, "node_app"); node_global_type = llvm::StructType::create(context, "node_global"); node_indirect_type = llvm::StructType::create(context, "node_indirect"); supercomb_function_type = llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type }, false); supercomb_function_pointer_type = llvm::PointerType::getUnqual(supercomb_function_type); stack_type->setBody(llvm::IntegerType::get(context, 32), llvm::IntegerType::get(context, 32), llvm::PointerType::getUnqual(node_pointer_type)); node_parent_type->setBody(tag_type); node_num_type->setBody(tag_type, llvm::IntegerType::get(context, 32)); node_app_type->setBody(tag_type, node_pointer_type, node_pointer_type); node_global_type->setBody(tag_type, tag_type, supercomb_function_pointer_type); node_indirect_type->setBody(tag_type, node_pointer_type); } void llvm_generate(const std::string& filename) { std::string targetTriple = llvm::sys::getDefaultTargetTriple(); llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmParser(); llvm::InitializeNativeTargetAsmPrinter(); std::string error; const llvm::Target* target = llvm::TargetRegistry::lookupTarget(targetTriple, error); if (!target) { std::cerr << error << std::endl; } else { std::string cpu = "generic"; std::string features = ""; llvm::TargetOptions options; llvm::TargetMachine* targetMachine = target->createTargetMachine(targetTriple, cpu, features, options, llvm::Optional()); module.setDataLayout(targetMachine->createDataLayout()); module.setTargetTriple(targetTriple); std::error_code ec; llvm::raw_fd_ostream file(filename, ec, llvm::sys::fs::F_None); if (ec) { std::cerr << "Could not open output file: " << ec.message() << std::endl; } else { llvm::TargetMachine::CodeGenFileType type = llvm::TargetMachine::CGFT_ObjectFile; llvm::legacy::PassManager pm; if (targetMachine->addPassesToEmitFile(pm, file, NULL, type)) { std::cerr << "Unable to emit target code" << std::endl; } else { pm.run(module); file.close(); } } } } void llvm_init() { static bool initialized = false; if(!initialized) { initialize_llvm(); initialize_types(); initialize_functions(); initialized = true; } } llvm::Function* llvm_context::get_supercombinator(const std::string& name) { if(!supercombinators.count(name)) throw error("unknown supercombinator"); return supercombinators.find(name)->second; } void llvm_context::add_supercombinator(const std::string& name) { if(supercombinators.count(name)) throw error("re-creating supercombinator"); llvm::Function* new_function = llvm::Function::Create( supercomb_function_type, llvm::Function::LinkageTypes::ExternalLinkage, name + "_supercomb", &module); new_function->arg_begin()->setName("stack"); supercombinators[name] = new_function; } llvm::Function* llvm_context::get_current_function() { return current_function; } void llvm_context::set_current_function(llvm::Function* f) { current_function = f; } }