lily/src/llvm.cpp

272 lines
12 KiB
C++

#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::Function* malloc_node_data_func;
llvm::Function* pack_func;
llvm::Function* split_func;
llvm::Function* eval_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;
llvm::StructType* node_data_type;
static void initialize_llvm() {
}
llvm::ConstantInt* get_int32_constant(int value) {
return llvm::ConstantInt::get(context, llvm::APInt(32, value));
}
llvm::ConstantInt* get_int64_constant(long int value) {
return llvm::ConstantInt::get(context, llvm::APInt(64, value));
}
llvm::ConstantInt* 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(node_pointer_type, { node_pointer_type }, false),
llvm::Function::LinkageTypes::ExternalLinkage,
"malloc_node_indirect",
&module);
malloc_node_data_func = llvm::Function::Create(
llvm::FunctionType::get(node_pointer_type, { tag_type, llvm::IntegerType::get(context, 32) }, false),
llvm::Function::LinkageTypes::ExternalLinkage,
"malloc_node_data",
&module);
pack_func = llvm::Function::Create(
llvm::FunctionType::get(node_pointer_type, { stack_pointer_type, tag_type, llvm::IntegerType::get(context, 32) }, false),
llvm::Function::LinkageTypes::ExternalLinkage,
"pack",
&module);
split_func = llvm::Function::Create(
llvm::FunctionType::get(llvm::Type::getVoidTy(context), { stack_pointer_type, node_pointer_type, llvm::IntegerType::get(context, 32) }, false),
llvm::Function::LinkageTypes::ExternalLinkage,
"split",
&module);
eval_func = llvm::Function::Create(
llvm::FunctionType::get(node_pointer_type, { node_pointer_type }, false),
llvm::Function::LinkageTypes::ExternalLinkage,
"eval",
&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");
node_data_type = llvm::StructType::create(context, "node_data");
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);
node_data_type->setBody(tag_type, tag_type, llvm::PointerType::getUnqual(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_function(const std::string& name) {
if(!supercombinators.count(name)) throw error("unknown supercombinator");
return supercombinators.find(name)->second;
}
int llvm_context::get_supercombinator_arity(const std::string& name) {
if(!arities.count(name)) throw error("unknown supercombinator");
return arities.find(name)->second;
}
void llvm_context::add_supercombinator(const std::string& name, int arity) {
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;
arities[name] = arity;
}
llvm::Function* llvm_context::get_current_function() {
return current_function;
}
void llvm_context::set_current_function(llvm::Function* f) {
current_function = f;
}
}