gemstone/src/llvm/backend.c

126 lines
3.3 KiB
C

#include <assert.h>
#include <ast/ast.h>
#include <codegen/backend.h>
#include <llvm-c/Core.h>
#include <llvm-c/TargetMachine.h>
#include <llvm/backend.h>
#include <llvm/parser.h>
#include <mem/cache.h>
#include <sys/log.h>
Target create_native_target() {
DEBUG("creating native target...");
Target target;
target.name.str = "tmp";
target.name.allocation = NONE;
target.triple.str = LLVMGetDefaultTargetTriple();
target.triple.allocation = LLVM;
assert(target.triple.str != NULL);
target.cpu.str = LLVMGetHostCPUName();
target.cpu.allocation = LLVM;
assert(target.cpu.str != NULL);
target.features.str = LLVMGetHostCPUFeatures();
target.features.allocation = LLVM;
assert(target.features.str != NULL);
target.opt = LLVMCodeGenLevelNone;
target.reloc = LLVMRelocDefault;
target.model = LLVMCodeModelDefault;
return target;
}
LLVMCodeGenOptLevel llvm_opt_from_int(int level) {
switch (level) {
case 1:
return LLVMCodeGenLevelLess;
case 2:
return LLVMCodeGenLevelDefault;
case 3:
return LLVMCodeGenLevelAggressive;
default:
break;
}
PANIC("invalid code generation optimization level: %d", level);
}
static char* create_target_output_name(const TargetConfig* config) {
char* prefix = "";
if (config->mode == Library) {
prefix = "lib";
}
char* name = g_strjoin("", prefix, config->name, NULL);
char* cached_name = mem_strdup(MemoryNamespaceLlvm, name);
g_free(name);
return cached_name;
}
Target create_target_from_config(const TargetConfig* config) {
DEBUG("Building target from configuration");
Target target = create_native_target();
target.name.str = create_target_output_name(config);
target.name.allocation = NONE; // freed later by compiler
target.opt = llvm_opt_from_int(config->optimization_level);
INFO("Configured target: %s/%d: (%s) on %s { %s }", target.name.str,
target.opt, target.triple.str, target.cpu.str, target.features.str);
return target;
}
static void delete_string(String string) {
DEBUG("deleting string...");
switch (string.allocation) {
case LLVM:
LLVMDisposeMessage(string.str);
break;
case LIBC:
free(string.str);
break;
case NONE:
break;
}
}
void delete_target(Target target) {
delete_string(target.name);
delete_string(target.cpu);
delete_string(target.features);
delete_string(target.triple);
}
typedef enum LLVMBackendError_t { UnresolvedImport } LLVMBackendError;
static BackendError llvm_backend_codegen(const Module* unit,
const TargetConfig* target) {
return parse_module(unit, target);
}
static BackendError llvm_backend_codegen_init(void) {
return new_backend_error(Success);
}
static BackendError llvm_backend_codegen_deinit(void) {
return new_backend_error(Success);
}
void llvm_backend_init() {
BackendError err =
set_backend(&llvm_backend_codegen_init, &llvm_backend_codegen_deinit,
&llvm_backend_codegen, "LLVM");
if (err.kind != Success) {
PANIC("unable to init llvm backend: %ld", err);
}
}