diff --git a/src/llvm/parser.c b/src/llvm/parser.c index 7a6fd55..b115650 100644 --- a/src/llvm/parser.c +++ b/src/llvm/parser.c @@ -1,17 +1,72 @@ +#include +#include +#include #include +#include +#include +#include +#include BackendError parse_module(const Module* module, void**) { LLVMBackendCompileUnit* unit = malloc(sizeof(LLVMBackendCompileUnit)); // we start with a LLVM module unit->context = LLVMContextCreate(); - unit->module = LLVMModuleCreateWithNameInContext("gemstone application", unit->context); + unit->module = LLVMModuleCreateWithNameInContext("gemstone application", + unit->context); - + LLVMGlobalScope* global_scope = new_global_scope(); + + BackendError err = new_backend_error(Success); + + err = impl_types(unit, global_scope, module->types); + // NOTE: functions of boxes are not stored in the box itself, + // thus for a box we only implement the type + err = impl_types(unit, global_scope, module->boxes); + + err = impl_global_variables(unit, global_scope, module->variables); + + delete_global_scope(global_scope); LLVMDisposeModule(unit->module); LLVMContextDispose(unit->context); - return new_backend_error(Success); + free(unit); + + return err; +} + +LLVMGlobalScope* new_global_scope() { + LLVMGlobalScope* scope = malloc(sizeof(LLVMGlobalScope)); + + 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->types = g_hash_table_new(g_str_hash, g_str_equal); + + return scope; +} + +LLVMLocalScope* new_local_scope(LLVMGlobalScope* global_scope, + LLVMLocalScope* parent_scope) { + LLVMLocalScope* scope = malloc(sizeof(LLVMLocalScope)); + + scope->variables = g_hash_table_new(g_str_hash, g_str_equal); + scope->params = g_hash_table_new(g_str_hash, g_str_equal); + scope->global_scope = global_scope; + scope->parent_scope = parent_scope; + + return scope; +} + +void delete_local_scope(LLVMLocalScope* scope) { + g_hash_table_unref(scope->variables); + free(scope); +} + +void delete_global_scope(LLVMGlobalScope* scope) { + g_hash_table_unref(scope->functions); + g_hash_table_unref(scope->types); + g_hash_table_unref(scope->variables); + free(scope); } diff --git a/src/llvm/parser.h b/src/llvm/parser.h index ceb908c..9a51e60 100644 --- a/src/llvm/parser.h +++ b/src/llvm/parser.h @@ -1,5 +1,8 @@ -#include "set/types.h" +#ifndef LLVM_BACKEND_PARSE_H_ +#define LLVM_BACKEND_PARSE_H_ + +#include #include #include #include @@ -9,4 +12,29 @@ typedef struct LLVMBackendCompileUnit_t { LLVMModuleRef module; } LLVMBackendCompileUnit; +typedef struct LLVMGlobalScope_t { + GHashTable* types; + GHashTable* variables; + GHashTable* functions; +} LLVMGlobalScope; + +LLVMGlobalScope* new_global_scope(); + +void delete_global_scope(LLVMGlobalScope* scope); + +typedef struct LLVMLocalScope_t LLVMLocalScope; + +typedef struct LLVMLocalScope_t { + LLVMGlobalScope* global_scope; + LLVMLocalScope* parent_scope; + GHashTable* params; + GHashTable* variables; +} LLVMLocalScope; + +LLVMLocalScope* new_local_scope(LLVMGlobalScope* global_scope, LLVMLocalScope* parent_scope); + +void delete_local_scope(LLVMLocalScope* scope); + BackendError parse_module(const Module* module, void**); + +#endif // LLVM_BACKEND_PARSE_H_ diff --git a/src/llvm/types.c b/src/llvm/types.c new file mode 100644 index 0000000..87d87ca --- /dev/null +++ b/src/llvm/types.c @@ -0,0 +1,324 @@ +#include +#include +#include +#include +#include +#include + +BackendError impl_primtive_type(LLVMBackendCompileUnit* unit, + PrimitiveType primtive, + LLVMTypeRef* llvm_type) { + switch (primtive) { + case Int: + *llvm_type = LLVMInt32TypeInContext(unit->context); + break; + case Float: + *llvm_type = LLVMFloatTypeInContext(unit->context); + break; + default: + break; + } + + return SUCCESS; +} + +BackendError impl_integral_type(LLVMBackendCompileUnit* unit, Scale scale, + LLVMTypeRef* llvm_type) { + LLVMTypeRef integral_type = + LLVMIntTypeInContext(unit->context, (int)(4 * scale) * 8); + + *llvm_type = integral_type; + + return SUCCESS; +} + +BackendError impl_float_type(LLVMBackendCompileUnit* unit, Scale scale, + LLVMTypeRef* llvm_type) { + LLVMTypeRef float_type = NULL; + + switch ((int)(scale * 4)) { + case 2: + float_type = LLVMHalfTypeInContext(unit->context); + break; + case 4: + float_type = LLVMFloatTypeInContext(unit->context); + break; + case 8: + float_type = LLVMDoubleTypeInContext(unit->context); + break; + case 16: + float_type = LLVMFP128TypeInContext(unit->context); + break; + default: + break; + } + + if (float_type != NULL) { + *llvm_type = float_type; + return SUCCESS; + } + + return new_backend_impl_error(Implementation, NULL, + "floating point with scale not supported"); +} + +BackendError impl_composite_type(LLVMBackendCompileUnit* unit, + CompositeType* composite, + LLVMTypeRef* llvm_type) { + BackendError err = SUCCESS; + + switch (composite->primitive) { + case Int: + err = impl_integral_type(unit, composite->scale, llvm_type); + break; + case Float: + if (composite->sign == Signed) { + err = impl_float_type(unit, composite->scale, llvm_type); + } else { + err = new_backend_impl_error( + Implementation, composite->nodePtr, + "unsigned floating-point not supported"); + } + break; + default: + break; + } + + return err; +} + +BackendError impl_reference_type(LLVMBackendCompileUnit* unit, + LLVMGlobalScope* scope, + ReferenceType reference, + LLVMTypeRef* llvm_type); + +BackendError impl_box_type(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope, + BoxType* reference, LLVMTypeRef* llvm_type); + +BackendError get_type_impl(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope, + Type* gemstone_type, LLVMTypeRef* llvm_type) { + BackendError err = + new_backend_impl_error(Implementation, gemstone_type->nodePtr, + "No type implementation covers type"); + + switch (gemstone_type->kind) { + case TypeKindPrimitive: + err = impl_primtive_type(unit, gemstone_type->impl.primitive, + llvm_type); + break; + case TypeKindComposite: + err = impl_composite_type(unit, &gemstone_type->impl.composite, + llvm_type); + break; + case TypeKindReference: + err = impl_reference_type(unit, scope, + gemstone_type->impl.reference, llvm_type); + break; + case TypeKindBox: + err = + impl_box_type(unit, scope, &gemstone_type->impl.box, llvm_type); + break; + } + + return err; +} + +BackendError impl_box_type(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope, + BoxType* box, LLVMTypeRef* llvm_type) { + GHashTableIter iterator; + g_hash_table_iter_init(&iterator, box->member); + + gpointer key = NULL; + gpointer val = NULL; + + BackendError err; + + GArray* members = g_array_new(FALSE, FALSE, sizeof(LLVMTypeRef)); + + while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) { + Type* member_type = ((BoxMember*) val)->type; + + LLVMTypeRef llvm_type = NULL; + err = get_type_impl(unit, scope, member_type, &llvm_type); + + if (err.kind != Success) { + break; + } + + g_array_append_val(members, llvm_type); + } + + if (err.kind == Success) { + *llvm_type = + LLVMStructType((LLVMTypeRef*)members->data, members->len, 0); + } + + g_array_free(members, FALSE); + + return err; +} + +BackendError impl_reference_type(LLVMBackendCompileUnit* unit, + LLVMGlobalScope* scope, + ReferenceType reference, + LLVMTypeRef* llvm_type) { + BackendError err = SUCCESS; + LLVMTypeRef type = NULL; + err = get_type_impl(unit, scope, reference, &type); + + if (err.kind == Success) { + *llvm_type = LLVMPointerType(type, 0); + } + + return err; +} + +BackendError impl_type(LLVMBackendCompileUnit* unit, Type* gemstone_type, + const char* alias, LLVMGlobalScope* scope) { + BackendError err = SUCCESS; + + LLVMTypeRef llvm_type = NULL; + err = get_type_impl(unit, scope, gemstone_type, &llvm_type); + + if (err.kind == Success) { + g_hash_table_insert(scope->types, (gpointer)alias, llvm_type); + } + + return err; +} + +BackendError impl_types(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope, + GHashTable* types) { + GHashTableIter iterator; + g_hash_table_iter_init(&iterator, types); + + gpointer key = NULL; + gpointer val = NULL; + + BackendError err; + + while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) { + err = impl_type(unit, (Type*)val, (const char*)key, scope); + + if (err.kind != Success) { + break; + } + } + + return err; +} + +BackendError get_primitive_default_value(PrimitiveType type, + LLVMTypeRef llvm_type, + LLVMValueRef* llvm_value) { + switch (type) { + case Int: + *llvm_value = LLVMConstIntOfString(llvm_type, "0", 10); + break; + case Float: + *llvm_value = LLVMConstRealOfString(llvm_type, "0"); + break; + default: + return new_backend_impl_error(Implementation, NULL, + "unknown primitive type"); + } + + return SUCCESS; +} + +BackendError get_composite_default_value(CompositeType* composite, + LLVMTypeRef llvm_type, + LLVMValueRef* llvm_value) { + BackendError err = SUCCESS; + + switch (composite->primitive) { + case Int: + err = get_primitive_default_value(Int, llvm_type, llvm_value); + break; + case Float: + if (composite->sign == Signed) { + err = get_primitive_default_value(Float, llvm_type, llvm_value); + } else { + err = new_backend_impl_error( + Implementation, composite->nodePtr, + "unsigned floating-point not supported"); + } + break; + default: + break; + } + + return err; +} + +BackendError get_reference_default_value(LLVMTypeRef llvm_type, + LLVMValueRef* llvm_value) { + *llvm_value = LLVMConstPointerNull(llvm_type); + + return SUCCESS; +} + +BackendError get_box_default_value(LLVMBackendCompileUnit* unit, + LLVMGlobalScope* scope, BoxType* type, + LLVMValueRef* llvm_value) { + GHashTableIter iterator; + g_hash_table_iter_init(&iterator, type->member); + + gpointer key = NULL; + gpointer val = NULL; + + BackendError err; + + GArray* constants = g_array_new(FALSE, FALSE, sizeof(LLVMValueRef)); + + while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) { + Type* member_type = ((BoxMember*)val)->type; + + LLVMValueRef constant = NULL; + err = get_type_default_value(unit, scope, member_type, &constant); + + if (err.kind != Success) { + break; + } + } + + *llvm_value = LLVMConstStructInContext( + unit->context, (LLVMValueRef*) constants->data, constants->len, 0); + + g_array_free(constants, FALSE); + + return err; +} + +BackendError get_type_default_value(LLVMBackendCompileUnit* unit, + LLVMGlobalScope* scope, Type* gemstone_type, + LLVMValueRef* llvm_value) { + BackendError err = new_backend_impl_error( + Implementation, gemstone_type->nodePtr, "No default value for type"); + + LLVMTypeRef llvm_type = NULL; + get_type_impl(unit, scope, gemstone_type, &llvm_type); + if (err.kind != Success) { + return err; + } + + switch (gemstone_type->kind) { + case TypeKindPrimitive: + err = get_primitive_default_value(gemstone_type->impl.primitive, + llvm_type, llvm_value); + break; + case TypeKindComposite: + err = get_composite_default_value(&gemstone_type->impl.composite, + llvm_type, llvm_value); + break; + case TypeKindReference: + err = get_reference_default_value(llvm_type, llvm_value); + break; + case TypeKindBox: + err = get_box_default_value(unit, scope, &gemstone_type->impl.box, + llvm_value); + break; + } + + return err; +} diff --git a/src/llvm/types.h b/src/llvm/types.h new file mode 100644 index 0000000..c8a873b --- /dev/null +++ b/src/llvm/types.h @@ -0,0 +1,21 @@ + +#ifndef LLVM_BACKEND_TYPES_H_ +#define LLVM_BACKEND_TYPES_H_ + +#include +#include +#include +#include +#include + +BackendError impl_types(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope, + GHashTable* types); + +BackendError get_type_impl(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope, + Type* gemstone_type, LLVMTypeRef* llvm_type); + +BackendError get_type_default_value(LLVMBackendCompileUnit* unit, + LLVMGlobalScope* scope, Type* gemstone_type, + LLVMValueRef* llvm_value); + +#endif // LLVM_BACKEND_TYPES_H_ diff --git a/src/llvm/variables.c b/src/llvm/variables.c new file mode 100644 index 0000000..51d2170 --- /dev/null +++ b/src/llvm/variables.c @@ -0,0 +1,104 @@ + +#include +#include +#include +#include +#include +#include + +BackendError impl_global_declaration(LLVMBackendCompileUnit* unit, + LLVMGlobalScope* scope, + VariableDeclaration* decl, + const char* name) { + BackendError err = SUCCESS; + LLVMTypeRef llvm_type = NULL; + err = get_type_impl(unit, scope, &decl->type, &llvm_type); + + if (err.kind != Success) { + return err; + } + + 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) { + LLVMSetInitializer(global, initial_value); + g_hash_table_insert(scope->variables, (gpointer)name, global); + } + + return err; +} + +BackendError impl_global_definiton(LLVMBackendCompileUnit* unit, + LLVMGlobalScope* scope, + VariableDefiniton* def, + const char* 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; + } + + LLVMValueRef global = LLVMAddGlobal(unit->module, llvm_type, name); + + // FIXME: resolve initializer expression! + LLVMValueRef initial_value = NULL; + err = get_type_default_value(unit, scope, &def->declaration.type, &initial_value); + + if (err.kind == Success) { + 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) { + 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; + } + + return err; +} + +BackendError impl_global_variables(LLVMBackendCompileUnit* unit, + LLVMGlobalScope* scope, + GHashTable* variables) { + GHashTableIter iterator; + g_hash_table_iter_init(&iterator, variables); + + gpointer key = NULL; + gpointer val = NULL; + + BackendError err; + + 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; + } + } + + return err; +} diff --git a/src/llvm/variables.h b/src/llvm/variables.h new file mode 100644 index 0000000..346e856 --- /dev/null +++ b/src/llvm/variables.h @@ -0,0 +1,15 @@ + +#ifndef LLVM_BACKEND_VARIABLES_H_ +#define LLVM_BACKEND_VARIABLES_H_ + +#include +#include +#include +#include +#include + +BackendError impl_global_variables(LLVMBackendCompileUnit* unit, + LLVMGlobalScope* scope, + GHashTable* variables); + +#endif // LLVM_BACKEND_VARIABLES_H_