2019-06-12 01:38:27 -07:00
|
|
|
#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;
|
|
|
|
|
2019-06-12 03:33:35 -07:00
|
|
|
llvm::Function* eval_func;
|
|
|
|
|
2019-06-12 01:38:27 -07:00
|
|
|
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(
|
2019-06-12 03:33:35 -07:00
|
|
|
llvm::FunctionType::get(node_pointer_type, { node_pointer_type }, false),
|
2019-06-12 01:38:27 -07:00
|
|
|
llvm::Function::LinkageTypes::ExternalLinkage,
|
|
|
|
"malloc_node_indirect",
|
|
|
|
&module);
|
2019-06-12 03:33:35 -07:00
|
|
|
eval_func = llvm::Function::Create(
|
|
|
|
llvm::FunctionType::get(node_pointer_type, { node_pointer_type }, false),
|
|
|
|
llvm::Function::LinkageTypes::ExternalLinkage,
|
|
|
|
"eval",
|
|
|
|
&module);
|
2019-06-12 01:38:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|