build bridge between compiler config and backend config
This commit is contained in:
parent
05634db44a
commit
54c7103df1
|
@ -181,7 +181,8 @@ void print_help(void) {
|
||||||
" --verbose print logs with level information or higher",
|
" --verbose print logs with level information or higher",
|
||||||
" --debug print debug logs (if not disabled at compile time)",
|
" --debug print debug logs (if not disabled at compile time)",
|
||||||
" --version print the version",
|
" --version print the version",
|
||||||
" --help print this hel dialog",
|
" --list-targets print a list of all available targets supported"
|
||||||
|
" --help print this help dialog"
|
||||||
};
|
};
|
||||||
|
|
||||||
for (unsigned int i = 0; i < sizeof(lines) / sizeof(const char *); i++) {
|
for (unsigned int i = 0; i < sizeof(lines) / sizeof(const char *); i++) {
|
||||||
|
|
|
@ -68,7 +68,7 @@ BackendError set_backend(const codegen_init init_func, const codegen_deinit dein
|
||||||
return new_backend_error(Success);
|
return new_backend_error(Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendError generate_code(const Module* root, void** output) {
|
BackendError generate_code(const Module* root, const TargetConfig* target) {
|
||||||
DEBUG("generating code with backend: %s", CodegenBackend.name);
|
DEBUG("generating code with backend: %s", CodegenBackend.name);
|
||||||
|
|
||||||
if (CodegenBackend.codegen_func == NULL) {
|
if (CodegenBackend.codegen_func == NULL) {
|
||||||
|
@ -76,7 +76,7 @@ BackendError generate_code(const Module* root, void** output) {
|
||||||
return new_backend_error(NoBackend);
|
return new_backend_error(NoBackend);
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendError code = CodegenBackend.codegen_func(root, output);
|
BackendError code = CodegenBackend.codegen_func(root, target);
|
||||||
if (code.kind) {
|
if (code.kind) {
|
||||||
ERROR("code generation of backend: %s failed with code: %ld", CodegenBackend.name, code);
|
ERROR("code generation of backend: %s failed with code: %ld", CodegenBackend.name, code);
|
||||||
return code;
|
return code;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <set/types.h>
|
#include <set/types.h>
|
||||||
#include <ast/ast.h>
|
#include <ast/ast.h>
|
||||||
|
#include <cfg/opt.h>
|
||||||
|
|
||||||
typedef struct BackendImplError_t {
|
typedef struct BackendImplError_t {
|
||||||
// faulty AST node
|
// faulty AST node
|
||||||
|
@ -30,7 +31,7 @@ typedef struct BackendError_t {
|
||||||
* @brief Function called by the compiler backend to generate an intermediate format
|
* @brief Function called by the compiler backend to generate an intermediate format
|
||||||
* from AST. Returns a custom container for its intermediate language.
|
* from AST. Returns a custom container for its intermediate language.
|
||||||
*/
|
*/
|
||||||
typedef BackendError (*codegen)(const Module*, void**);
|
typedef BackendError (*codegen)(const Module*, const TargetConfig* target);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize the code generation backend.
|
* @brief Initialize the code generation backend.
|
||||||
|
@ -78,7 +79,7 @@ BackendError deinit_backend(void);
|
||||||
* @return BackendError
|
* @return BackendError
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
BackendError generate_code(const Module* root, void** code);
|
BackendError generate_code(const Module* root, const TargetConfig* target);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new backend error
|
* @brief Create a new backend error
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include <io/files.h>
|
#include <io/files.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <cfg/opt.h>
|
#include <cfg/opt.h>
|
||||||
|
#include <codegen/backend.h>
|
||||||
|
#include <llvm/backend.h>
|
||||||
|
|
||||||
extern void yyrestart(FILE *);
|
extern void yyrestart(FILE *);
|
||||||
|
|
||||||
|
@ -125,6 +127,25 @@ static void print_ast_to_file(const AST_NODE_PTR ast, const TargetConfig *target
|
||||||
free((void *) path);
|
free((void *) path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void run_backend_codegen(const Module* module, const TargetConfig* target) {
|
||||||
|
DEBUG("initializing LLVM codegen backend...");
|
||||||
|
llvm_backend_init();
|
||||||
|
|
||||||
|
DEBUG("initiializing backend for codegen...");
|
||||||
|
BackendError err = init_backend();
|
||||||
|
if (err.kind != Success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("generating code...");
|
||||||
|
err = generate_code(module, target);
|
||||||
|
if (err.kind != Success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = deinit_backend();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Build the given target
|
* @brief Build the given target
|
||||||
* @param unit
|
* @param unit
|
||||||
|
@ -142,7 +163,9 @@ static void build_target(ModuleFileStack *unit, const TargetConfig *target) {
|
||||||
print_ast_to_file(ast, target);
|
print_ast_to_file(ast, target);
|
||||||
|
|
||||||
// TODO: parse AST to semantic values
|
// TODO: parse AST to semantic values
|
||||||
// TODO: backend codegen
|
Module* module = NULL;
|
||||||
|
|
||||||
|
run_backend_codegen(module, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,35 @@ Target create_native_target() {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
Target create_target_from_config() { PANIC("NOT IMPLEMENTED"); }
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
Target create_target_from_config(const TargetConfig* config) {
|
||||||
|
DEBUG("Building target from configuration");
|
||||||
|
|
||||||
|
Target target = create_native_target();
|
||||||
|
|
||||||
|
target.name.str = config->name;
|
||||||
|
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, target.opt,
|
||||||
|
target.triple, target.cpu, target.features);
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
static void delete_string(String string) {
|
static void delete_string(String string) {
|
||||||
DEBUG("deleting string...");
|
DEBUG("deleting string...");
|
||||||
|
@ -59,8 +87,9 @@ void delete_target(Target target) {
|
||||||
|
|
||||||
typedef enum LLVMBackendError_t { UnresolvedImport } LLVMBackendError;
|
typedef enum LLVMBackendError_t { UnresolvedImport } LLVMBackendError;
|
||||||
|
|
||||||
static BackendError llvm_backend_codegen(const Module* unit, void** output) {
|
static BackendError llvm_backend_codegen(const Module* unit,
|
||||||
return parse_module(unit, output);
|
const TargetConfig* target) {
|
||||||
|
return parse_module(unit, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static BackendError llvm_backend_codegen_init(void) {
|
static BackendError llvm_backend_codegen_init(void) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ typedef struct Target_t {
|
||||||
|
|
||||||
Target create_native_target();
|
Target create_native_target();
|
||||||
|
|
||||||
Target create_target_from_config();
|
Target create_target_from_config(const TargetConfig* config);
|
||||||
|
|
||||||
void delete_target(Target target);
|
void delete_target(Target target);
|
||||||
|
|
||||||
|
|
|
@ -300,7 +300,7 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
|
||||||
|
|
||||||
switch (expr->kind) {
|
switch (expr->kind) {
|
||||||
case ExpressionKindConstant:
|
case ExpressionKindConstant:
|
||||||
err = get_type_value(unit, scope->func_scope->global_scope,
|
err = get_const_type_value(unit, scope->func_scope->global_scope,
|
||||||
&expr->impl.constant, llvm_result);
|
&expr->impl.constant, llvm_result);
|
||||||
break;
|
break;
|
||||||
case ExpressionKindTransmute:
|
case ExpressionKindTransmute:
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
#include <codegen/backend.h>
|
#include <codegen/backend.h>
|
||||||
#include <llvm-c/Core.h>
|
#include <llvm-c/Core.h>
|
||||||
#include <llvm-c/Types.h>
|
#include <llvm-c/Types.h>
|
||||||
|
#include <llvm/func.h>
|
||||||
#include <llvm/parser.h>
|
#include <llvm/parser.h>
|
||||||
#include <llvm/types.h>
|
#include <llvm/types.h>
|
||||||
#include <set/types.h>
|
#include <set/types.h>
|
||||||
#include <sys/log.h>
|
#include <sys/log.h>
|
||||||
#include <llvm/func.h>
|
|
||||||
|
|
||||||
LLVMLocalScope* new_local_scope(LLVMLocalScope* parent) {
|
LLVMLocalScope* new_local_scope(LLVMLocalScope* parent) {
|
||||||
LLVMLocalScope* scope = malloc(sizeof(LLVMLocalScope));
|
LLVMLocalScope* scope = malloc(sizeof(LLVMLocalScope));
|
||||||
|
@ -24,7 +24,8 @@ void delete_local_scope(LLVMLocalScope* scope) {
|
||||||
free(scope);
|
free(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
static LLVMValueRef get_parameter(const LLVMFuncScope* scope, const char* name) {
|
static LLVMValueRef get_parameter(const LLVMFuncScope* scope,
|
||||||
|
const char* name) {
|
||||||
if (g_hash_table_contains(scope->params, name)) {
|
if (g_hash_table_contains(scope->params, name)) {
|
||||||
return g_hash_table_lookup(scope->params, name);
|
return g_hash_table_lookup(scope->params, name);
|
||||||
}
|
}
|
||||||
|
@ -108,7 +109,8 @@ BackendError impl_func_decl(LLVMBackendCompileUnit* unit,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendError impl_func(LLVMBackendCompileUnit* unit, LLVMGlobalScope* global_scope,
|
BackendError impl_func(LLVMBackendCompileUnit* unit,
|
||||||
|
LLVMGlobalScope* global_scope,
|
||||||
FunctionDefinition* fundef, const char* name) {
|
FunctionDefinition* fundef, const char* name) {
|
||||||
BackendError err = SUCCESS;
|
BackendError err = SUCCESS;
|
||||||
|
|
||||||
|
@ -125,18 +127,20 @@ BackendError impl_func(LLVMBackendCompileUnit* unit, LLVMGlobalScope* global_sco
|
||||||
func_scope->params = g_hash_table_new(g_str_hash, g_str_equal);
|
func_scope->params = g_hash_table_new(g_str_hash, g_str_equal);
|
||||||
|
|
||||||
// store function type in global scope
|
// store function type in global scope
|
||||||
g_hash_table_insert(global_scope->functions, (gpointer) name, llvm_func);
|
g_hash_table_insert(global_scope->functions, (gpointer)name, llvm_func);
|
||||||
|
|
||||||
// create function body builder
|
// create function body builder
|
||||||
LLVMBasicBlockRef body = LLVMAppendBasicBlockInContext(unit->context, llvm_func, "entry");
|
LLVMBasicBlockRef body =
|
||||||
|
LLVMAppendBasicBlockInContext(unit->context, llvm_func, "entry");
|
||||||
LLVMBuilderRef builder = LLVMCreateBuilderInContext(unit->context);
|
LLVMBuilderRef builder = LLVMCreateBuilderInContext(unit->context);
|
||||||
LLVMPositionBuilderAtEnd(builder, body);
|
LLVMPositionBuilderAtEnd(builder, body);
|
||||||
|
|
||||||
// create value references for parameter
|
// create value references for parameter
|
||||||
const size_t params = fundef->parameter->len;
|
const size_t params = fundef->parameter->len;
|
||||||
for (size_t i = 0; i < params; i++) {
|
for (size_t i = 0; i < params; i++) {
|
||||||
const Paramer* param = ((Paramer*) fundef->parameter) + i;
|
const Paramer* param = ((Paramer*)fundef->parameter) + i;
|
||||||
g_hash_table_insert(func_scope->params, (gpointer) param->name, LLVMGetParam(llvm_func, i));
|
g_hash_table_insert(func_scope->params, (gpointer)param->name,
|
||||||
|
LLVMGetParam(llvm_func, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: parse function body
|
// TODO: parse function body
|
||||||
|
@ -149,3 +153,29 @@ BackendError impl_func(LLVMBackendCompileUnit* unit, LLVMGlobalScope* global_sco
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BackendError impl_functions(LLVMBackendCompileUnit* unit,
|
||||||
|
LLVMGlobalScope* scope, GHashTable* functions) {
|
||||||
|
DEBUG("implementing functions...");
|
||||||
|
GHashTableIter iterator;
|
||||||
|
g_hash_table_iter_init(&iterator, functions);
|
||||||
|
|
||||||
|
gpointer key = NULL;
|
||||||
|
gpointer val = NULL;
|
||||||
|
|
||||||
|
BackendError err = SUCCESS;
|
||||||
|
|
||||||
|
size_t variable_count = 0;
|
||||||
|
while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) {
|
||||||
|
err =
|
||||||
|
impl_func(unit, scope, (FunctionDefinition*)val, (const char*)key);
|
||||||
|
|
||||||
|
if (err.kind != Success) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
variable_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
|
@ -28,4 +28,8 @@ void delete_local_scope(LLVMLocalScope*);
|
||||||
|
|
||||||
LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* name);
|
LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* name);
|
||||||
|
|
||||||
|
BackendError impl_functions(LLVMBackendCompileUnit* unit,
|
||||||
|
LLVMGlobalScope* scope,
|
||||||
|
GHashTable* variables);
|
||||||
|
|
||||||
#endif // LLVM_BACKEND_FUNC_H_
|
#endif // LLVM_BACKEND_FUNC_H_
|
||||||
|
|
|
@ -8,15 +8,15 @@
|
||||||
#include <llvm/parser.h>
|
#include <llvm/parser.h>
|
||||||
#include <llvm/types.h>
|
#include <llvm/types.h>
|
||||||
#include <llvm/variables.h>
|
#include <llvm/variables.h>
|
||||||
|
#include <llvm/func.h>
|
||||||
#include <set/types.h>
|
#include <set/types.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/log.h>
|
#include <sys/log.h>
|
||||||
|
|
||||||
#define EXPORT_IR 1
|
BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target,
|
||||||
|
const TargetConfig* config) {
|
||||||
BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target) {
|
|
||||||
DEBUG("exporting module to LLVM-IR...");
|
DEBUG("exporting module to LLVM-IR...");
|
||||||
|
|
||||||
BackendError err = SUCCESS;
|
BackendError err = SUCCESS;
|
||||||
|
@ -25,8 +25,8 @@ BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target) {
|
||||||
char* ir = LLVMPrintModuleToString(unit->module);
|
char* ir = LLVMPrintModuleToString(unit->module);
|
||||||
|
|
||||||
// construct file name
|
// construct file name
|
||||||
char* filename = alloca(strlen(target->name.str) + 4);
|
const char* filename =
|
||||||
sprintf(filename, "%s.ll", target->name.str);
|
make_file_path(target->name.str, ".ll", 1, config->archive_directory);
|
||||||
|
|
||||||
INFO("Writing LLVM-IR to %s", filename);
|
INFO("Writing LLVM-IR to %s", filename);
|
||||||
|
|
||||||
|
@ -49,13 +49,52 @@ BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target) {
|
||||||
|
|
||||||
INFO("%ld bytes written to %s", bytes, filename);
|
INFO("%ld bytes written to %s", bytes, filename);
|
||||||
|
|
||||||
|
free((char*)filename);
|
||||||
|
|
||||||
// clean up LLVM-IR string
|
// clean up LLVM-IR string
|
||||||
LLVMDisposeMessage(ir);
|
LLVMDisposeMessage(ir);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target) {
|
BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
|
||||||
|
LLVMTargetMachineRef target_machine,
|
||||||
|
LLVMCodeGenFileType file_type, char* error,
|
||||||
|
const TargetConfig* config) {
|
||||||
|
BackendError err = SUCCESS;
|
||||||
|
DEBUG("Generating code...");
|
||||||
|
|
||||||
|
const char* filename;
|
||||||
|
switch (file_type) {
|
||||||
|
case LLVMAssemblyFile:
|
||||||
|
filename = make_file_path(config->name, ".s", 1,
|
||||||
|
config->archive_directory);
|
||||||
|
break;
|
||||||
|
case LLVMObjectFile:
|
||||||
|
filename = make_file_path(config->name, ".o", 1,
|
||||||
|
config->archive_directory);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new_backend_impl_error(Implementation, NULL,
|
||||||
|
"invalid codegen file");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LLVMTargetMachineEmitToFile(target_machine, unit->module, filename,
|
||||||
|
file_type, &error) != 0) {
|
||||||
|
ERROR("failed to emit code: %s", error);
|
||||||
|
err =
|
||||||
|
new_backend_impl_error(Implementation, NULL, "failed to emit code");
|
||||||
|
LLVMDisposeMessage(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
free((void*)filename);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target,
|
||||||
|
const TargetConfig* config) {
|
||||||
|
BackendError err = SUCCESS;
|
||||||
DEBUG("exporting object file...");
|
DEBUG("exporting object file...");
|
||||||
|
|
||||||
INFO("Using target (%s): %s with features: %s", target->name.str,
|
INFO("Using target (%s): %s with features: %s", target->name.str,
|
||||||
|
@ -72,8 +111,8 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target) {
|
||||||
if (LLVMGetTargetFromTriple(target->triple.str, &llvm_target, &error) !=
|
if (LLVMGetTargetFromTriple(target->triple.str, &llvm_target, &error) !=
|
||||||
0) {
|
0) {
|
||||||
ERROR("failed to create target machine: %s", error);
|
ERROR("failed to create target machine: %s", error);
|
||||||
BackendError err = new_backend_impl_error(
|
err = new_backend_impl_error(Implementation, NULL,
|
||||||
Implementation, NULL, "unable to create target machine");
|
"unable to create target machine");
|
||||||
LLVMDisposeMessage(error);
|
LLVMDisposeMessage(error);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -83,19 +122,19 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target) {
|
||||||
llvm_target, target->triple.str, target->cpu.str, target->features.str,
|
llvm_target, target->triple.str, target->cpu.str, target->features.str,
|
||||||
target->opt, target->reloc, target->model);
|
target->opt, target->reloc, target->model);
|
||||||
|
|
||||||
LLVMCodeGenFileType file_type = LLVMObjectFile;
|
if (config->print_asm) {
|
||||||
|
err = emit_module_to_file(unit, target_machine, LLVMAssemblyFile, error,
|
||||||
|
config);
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG("Generating code...");
|
if (err.kind != Success) {
|
||||||
if (LLVMTargetMachineEmitToFile(target_machine, unit->module, "output",
|
|
||||||
file_type, &error) != 0) {
|
|
||||||
ERROR("failed to emit code: %s", error);
|
|
||||||
BackendError err =
|
|
||||||
new_backend_impl_error(Implementation, NULL, "failed to emit code");
|
|
||||||
LLVMDisposeMessage(error);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SUCCESS;
|
err = emit_module_to_file(unit, target_machine, LLVMObjectFile, error,
|
||||||
|
config);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void list_available_targets() {
|
void list_available_targets() {
|
||||||
|
@ -120,23 +159,25 @@ void list_available_targets() {
|
||||||
LLVMDisposeMessage(default_triple);
|
LLVMDisposeMessage(default_triple);
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendError export_module(LLVMBackendCompileUnit* unit, const Target* target) {
|
BackendError export_module(LLVMBackendCompileUnit* unit, const Target* target,
|
||||||
|
const TargetConfig* config) {
|
||||||
DEBUG("exporting module...");
|
DEBUG("exporting module...");
|
||||||
|
|
||||||
BackendError err = SUCCESS;
|
BackendError err = SUCCESS;
|
||||||
|
|
||||||
export_object(unit, target);
|
export_object(unit, target, config);
|
||||||
|
|
||||||
if (EXPORT_IR) {
|
if (config->print_ir) {
|
||||||
export_IR(unit, target);
|
export_IR(unit, target, config);
|
||||||
} else {
|
|
||||||
DEBUG("not exporting LLVM-IR");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BackendError build_module(LLVMBackendCompileUnit* unit, LLVMGlobalScope* global_scope, const Module* module) {
|
static BackendError build_module(LLVMBackendCompileUnit* unit,
|
||||||
|
LLVMGlobalScope* global_scope,
|
||||||
|
const Module* module) {
|
||||||
|
DEBUG("building module...");
|
||||||
BackendError err = SUCCESS;
|
BackendError err = SUCCESS;
|
||||||
|
|
||||||
err = impl_types(unit, global_scope, module->types);
|
err = impl_types(unit, global_scope, module->types);
|
||||||
|
@ -156,10 +197,13 @@ static BackendError build_module(LLVMBackendCompileUnit* unit, LLVMGlobalScope*
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: implement functions
|
||||||
|
err = impl_functions(unit, global_scope, module->functions);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
BackendError parse_module(const Module* module, void**) {
|
BackendError parse_module(const Module* module, const TargetConfig* config) {
|
||||||
DEBUG("generating code for module %p", module);
|
DEBUG("generating code for module %p", module);
|
||||||
if (module == NULL) {
|
if (module == NULL) {
|
||||||
ERROR("no module for codegen");
|
ERROR("no module for codegen");
|
||||||
|
@ -171,20 +215,19 @@ BackendError parse_module(const Module* module, void**) {
|
||||||
// we start with a LLVM module
|
// we start with a LLVM module
|
||||||
DEBUG("creating LLVM context and module");
|
DEBUG("creating LLVM context and module");
|
||||||
unit->context = LLVMContextCreate();
|
unit->context = LLVMContextCreate();
|
||||||
unit->module = LLVMModuleCreateWithNameInContext("gemstone application",
|
unit->module =
|
||||||
unit->context);
|
LLVMModuleCreateWithNameInContext(config->name, unit->context);
|
||||||
|
|
||||||
LLVMGlobalScope* global_scope = new_global_scope();
|
LLVMGlobalScope* global_scope = new_global_scope(module);
|
||||||
|
|
||||||
BackendError err = new_backend_error(Success);
|
|
||||||
|
|
||||||
DEBUG("generating code...");
|
DEBUG("generating code...");
|
||||||
|
|
||||||
err = build_module(unit, global_scope, module);
|
BackendError err = build_module(unit, global_scope, module);
|
||||||
if (err.kind == Success) {
|
if (err.kind == Success) {
|
||||||
Target target = create_native_target();
|
INFO("Module build successfully...");
|
||||||
|
Target target = create_target_from_config(config);
|
||||||
|
|
||||||
export_module(unit, &target);
|
export_module(unit, &target, config);
|
||||||
|
|
||||||
delete_target(target);
|
delete_target(target);
|
||||||
}
|
}
|
||||||
|
@ -199,10 +242,11 @@ BackendError parse_module(const Module* module, void**) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVMGlobalScope* new_global_scope() {
|
LLVMGlobalScope* new_global_scope(const Module* module) {
|
||||||
DEBUG("creating global scope...");
|
DEBUG("creating global scope...");
|
||||||
LLVMGlobalScope* scope = malloc(sizeof(LLVMGlobalScope));
|
LLVMGlobalScope* scope = malloc(sizeof(LLVMGlobalScope));
|
||||||
|
|
||||||
|
scope->module = (Module*) module;
|
||||||
scope->functions = g_hash_table_new(g_str_hash, g_str_equal);
|
scope->functions = g_hash_table_new(g_str_hash, g_str_equal);
|
||||||
scope->variables = g_hash_table_new(g_str_hash, g_str_equal);
|
scope->variables = g_hash_table_new(g_str_hash, g_str_equal);
|
||||||
scope->types = g_hash_table_new(g_str_hash, g_str_equal);
|
scope->types = g_hash_table_new(g_str_hash, g_str_equal);
|
||||||
|
|
|
@ -18,12 +18,16 @@ typedef struct LLVMGlobalScope_t {
|
||||||
GHashTable* variables;
|
GHashTable* variables;
|
||||||
// of type LLVMTypeRef
|
// of type LLVMTypeRef
|
||||||
GHashTable* functions;
|
GHashTable* functions;
|
||||||
|
// module definition
|
||||||
|
Module* module;
|
||||||
} LLVMGlobalScope;
|
} LLVMGlobalScope;
|
||||||
|
|
||||||
LLVMGlobalScope* new_global_scope();
|
LLVMGlobalScope* new_global_scope(const Module* module);
|
||||||
|
|
||||||
|
void list_available_targets();
|
||||||
|
|
||||||
void delete_global_scope(LLVMGlobalScope* scope);
|
void delete_global_scope(LLVMGlobalScope* scope);
|
||||||
|
|
||||||
BackendError parse_module(const Module* module, void**);
|
BackendError parse_module(const Module* module, const TargetConfig* config);
|
||||||
|
|
||||||
#endif // LLVM_BACKEND_PARSE_H_
|
#endif // LLVM_BACKEND_PARSE_H_
|
||||||
|
|
|
@ -103,6 +103,9 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Paramer* parameter = (Paramer*) call->function->parameter->data + i;
|
||||||
|
// TODO: create a pointer to LLVMValueRef in case parameter is `out`
|
||||||
|
|
||||||
g_array_append_vals(arguments, &llvm_arg, 1);
|
g_array_append_vals(arguments, &llvm_arg, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,9 @@ BackendError get_type_default_value(LLVMBackendCompileUnit* unit,
|
||||||
LLVMGlobalScope* scope, Type* gemstone_type,
|
LLVMGlobalScope* scope, Type* gemstone_type,
|
||||||
LLVMValueRef* llvm_value);
|
LLVMValueRef* llvm_value);
|
||||||
|
|
||||||
BackendError get_type_value(LLVMBackendCompileUnit* unit,
|
BackendError get_const_type_value(LLVMBackendCompileUnit* unit,
|
||||||
LLVMGlobalScope* scope, TypeValue* gemstone_value,
|
LLVMGlobalScope* scope,
|
||||||
LLVMValueRef* llvm_value);
|
TypeValue* gemstone_value,
|
||||||
|
LLVMValueRef* llvm_value);
|
||||||
|
|
||||||
#endif // LLVM_BACKEND_TYPES_H_
|
#endif // LLVM_BACKEND_TYPES_H_
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <lex/util.h>
|
#include <lex/util.h>
|
||||||
#include <cfg/opt.h>
|
#include <cfg/opt.h>
|
||||||
#include <compiler.h>
|
#include <compiler.h>
|
||||||
|
#include <llvm/parser.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Log a debug message to inform about beginning exit procedures
|
* @brief Log a debug message to inform about beginning exit procedures
|
||||||
|
@ -55,6 +56,11 @@ int main(int argc, char *argv[]) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_option_set("list-targets")) {
|
||||||
|
list_available_targets();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
run_compiler();
|
run_compiler();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue