132 lines
4.1 KiB
C
132 lines
4.1 KiB
C
|
|
#include <codegen/backend.h>
|
|
#include <llvm-c/Core.h>
|
|
#include <llvm-c/Types.h>
|
|
#include <llvm/llvm-ir/types.h>
|
|
#include <llvm/llvm-ir/variables.h>
|
|
#include <set/types.h>
|
|
#include <sys/log.h>
|
|
|
|
#include "expr.h"
|
|
|
|
BackendError impl_global_declaration(LLVMBackendCompileUnit* unit,
|
|
LLVMGlobalScope* scope,
|
|
VariableDeclaration* decl,
|
|
const char* name) {
|
|
DEBUG("implementing global declaration: %s", name);
|
|
BackendError err = SUCCESS;
|
|
LLVMTypeRef llvm_type = NULL;
|
|
err = get_type_impl(unit, scope, decl->type, &llvm_type);
|
|
|
|
if (err.kind != Success) {
|
|
return err;
|
|
}
|
|
|
|
DEBUG("creating global variable...");
|
|
LLVMValueRef global = LLVMAddGlobal(unit->module, llvm_type, name);
|
|
|
|
LLVMValueRef initial_value = NULL;
|
|
err = get_type_default_value(unit, scope, decl->type, &initial_value);
|
|
|
|
if (err.kind == Success) {
|
|
DEBUG("setting default value...");
|
|
LLVMSetInitializer(global, initial_value);
|
|
g_hash_table_insert(scope->variables, (gpointer)name, global);
|
|
} else {
|
|
ERROR("unable to initialize global variable: %s", err.impl.message);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
BackendError impl_global_definiton(LLVMBackendCompileUnit* unit,
|
|
LLVMGlobalScope* scope,
|
|
VariableDefiniton* def, const char* name) {
|
|
DEBUG("implementing global definition: %s", name);
|
|
BackendError err = SUCCESS;
|
|
LLVMTypeRef llvm_type = NULL;
|
|
err = get_type_impl(unit, scope, def->declaration.type, &llvm_type);
|
|
|
|
if (err.kind != Success) {
|
|
return err;
|
|
}
|
|
|
|
DEBUG("creating global variable...");
|
|
LLVMValueRef global = LLVMAddGlobal(unit->module, llvm_type, name);
|
|
|
|
// FIXME: resolve initializer expression!
|
|
LLVMValueRef initial_value = NULL;
|
|
err = get_const_type_value(unit, scope, &def->initializer->impl.constant, &initial_value);
|
|
|
|
if (err.kind == Success) {
|
|
DEBUG("setting default value");
|
|
LLVMSetInitializer(global, initial_value);
|
|
g_hash_table_insert(scope->variables, (gpointer)name, global);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
BackendError impl_global_variable(LLVMBackendCompileUnit* unit,
|
|
Variable* gemstone_var, const char* alias,
|
|
LLVMGlobalScope* scope) {
|
|
DEBUG("implementing global variable: %s", alias);
|
|
BackendError err = SUCCESS;
|
|
|
|
switch (gemstone_var->kind) {
|
|
case VariableKindDeclaration:
|
|
err = impl_global_declaration(
|
|
unit, scope, &gemstone_var->impl.declaration, alias);
|
|
break;
|
|
case VariableKindDefinition:
|
|
err = impl_global_definiton(unit, scope,
|
|
&gemstone_var->impl.definiton, alias);
|
|
break;
|
|
case VariableKindBoxMember:
|
|
err = new_backend_impl_error(Implementation, gemstone_var->nodePtr,
|
|
"member variable cannot be ");
|
|
break;
|
|
default:
|
|
PANIC("invalid variable kind: %ld", gemstone_var->kind);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
BackendError impl_global_variables(LLVMBackendCompileUnit* unit,
|
|
LLVMGlobalScope* scope,
|
|
GHashTable* variables) {
|
|
DEBUG("implementing global variables...");
|
|
GHashTableIter iterator;
|
|
g_hash_table_iter_init(&iterator, variables);
|
|
|
|
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_global_variable(unit, (Variable*)val, (const char*)key, scope);
|
|
|
|
if (err.kind != Success) {
|
|
break;
|
|
}
|
|
|
|
variable_count++;
|
|
}
|
|
|
|
DEBUG("implemented %ld global variables", variable_count);
|
|
|
|
return err;
|
|
}
|
|
|
|
LLVMValueRef get_global_variable(LLVMGlobalScope* scope, char* name) {
|
|
if (g_hash_table_contains(scope->variables, name)) {
|
|
return g_hash_table_lookup(scope->variables, name);
|
|
}
|
|
|
|
return NULL;
|
|
}
|