From 2804fd552bdb80ef7cc8b05674601672ac702f87 Mon Sep 17 00:00:00 2001 From: servostar Date: Sun, 19 May 2024 16:07:27 +0200 Subject: [PATCH] added function backend --- src/codegen/backend.c | 45 ++++++++++------ src/codegen/backend.h | 34 ++++++++++-- src/llvm/backend.c | 14 ++--- src/llvm/function/function.c | 75 ++++++++++++++++++++++++++ src/llvm/function/function.h | 42 +++++++++++++++ src/llvm/{type.c => types/composite.c} | 70 +++++++----------------- src/llvm/types/composite.h | 53 ++++++++++++++++++ src/llvm/types/type.c | 23 ++++++++ src/llvm/types/type.h | 43 +++++++++++++++ src/main.c | 29 ++++++---- 10 files changed, 340 insertions(+), 88 deletions(-) create mode 100644 src/llvm/function/function.c create mode 100644 src/llvm/function/function.h rename src/llvm/{type.c => types/composite.c} (77%) create mode 100644 src/llvm/types/composite.h create mode 100644 src/llvm/types/type.c create mode 100644 src/llvm/types/type.h diff --git a/src/codegen/backend.c b/src/codegen/backend.c index c305961..d2eccac 100644 --- a/src/codegen/backend.c +++ b/src/codegen/backend.c @@ -9,22 +9,35 @@ static struct CodegenBackend_t { const char* name; } CodegenBackend; +BackendError new_backend_error(BackendErrorKind kind) { + return new_backend_impl_error(kind, NULL, NULL); +} + +BackendError new_backend_impl_error(BackendErrorKind kind, AST_NODE_PTR node, const char* message) { + BackendError error; + error.kind = kind; + error.impl.ast_node = node; + error.impl.message = message; + + return error; +} + BackendError init_backend(void) { DEBUG("initializing backend: %s", CodegenBackend.name); if (CodegenBackend.init_func == NULL) { ERROR("backend: %s is not properly initialized", CodegenBackend.name); - return NoBackend; + return new_backend_error(NoBackend); } - size_t code = CodegenBackend.init_func(); + BackendError code = CodegenBackend.init_func(); - if (code) { + if (code.kind != Success) { ERROR("failed to initialize backend: %s with code: %ld", CodegenBackend.name, code); - return Other; + return code; } - return Success; + return new_backend_error(Success); } BackendError deinit_backend(void) { @@ -32,17 +45,17 @@ BackendError deinit_backend(void) { if (CodegenBackend.deinit_func == NULL) { ERROR("backend: %s is not properly initialized", CodegenBackend.name); - return NoBackend; + return new_backend_error(NoBackend); } - size_t code = CodegenBackend.deinit_func(); + BackendError code = CodegenBackend.deinit_func(); - if (code) { + if (code.kind != Success) { ERROR("failed to undo initialization of backend: %s with code: %ld", CodegenBackend.name, code); - return Other; + return code; } - return Success; + return new_backend_error(Success); } BackendError set_backend(const codegen_init init_func, const codegen_deinit deinit_func, const codegen codegen_func, const char* name) { @@ -51,7 +64,7 @@ BackendError set_backend(const codegen_init init_func, const codegen_deinit dein CodegenBackend.codegen_func = codegen_func; CodegenBackend.name = name; - return Success; + return new_backend_error(Success); } BackendError generate_code(const AST_NODE_PTR root, void** output) { @@ -59,14 +72,14 @@ BackendError generate_code(const AST_NODE_PTR root, void** output) { if (CodegenBackend.codegen_func == NULL) { ERROR("backend: %s is not properly initialized", CodegenBackend.name); - return NoBackend; + return new_backend_error(NoBackend); } - size_t code = CodegenBackend.codegen_func(root, output); - if (code) { + BackendError code = CodegenBackend.codegen_func(root, output); + if (code.kind) { ERROR("code generation of backend: %s failed with code: %ld", CodegenBackend.name, code); - return Other; + return code; } - return Success; + return new_backend_error(Success); } diff --git a/src/codegen/backend.h b/src/codegen/backend.h index 6e733c3..02cbc43 100644 --- a/src/codegen/backend.h +++ b/src/codegen/backend.h @@ -4,28 +4,42 @@ #include -typedef enum BackendError_t { +typedef struct BackendImplError_t { + // faulty AST node + AST_NODE_PTR ast_node; + // error message + const char* message; +} BackendImplError; + +typedef enum BackendErrorKind_t { Success, NoBackend, BackendAlreadySet, - Other + Unimplemented, + // some error occurred in the backend implementation + Implementation +} BackendErrorKind; + +typedef struct BackendError_t { + BackendErrorKind kind; + BackendImplError impl; } BackendError; /** * @brief Function called by the compiler backend to generate an intermediate format * from AST. Returns a custom container for its intermediate language. */ -typedef size_t (*codegen)(const AST_NODE_PTR, void**); +typedef BackendError (*codegen)(const AST_NODE_PTR, void**); /** * @brief Initialize the code generation backend. */ -typedef size_t (*codegen_init)(void); +typedef BackendError (*codegen_init)(void); /** * @brief Undo initialization of code generation backend. */ -typedef size_t (*codegen_deinit)(void); +typedef BackendError (*codegen_deinit)(void); /** * @brief Set the backend functions to use @@ -65,4 +79,14 @@ BackendError deinit_backend(void); [[nodiscard]] BackendError generate_code(const AST_NODE_PTR root, void** code); +/** + * @brief Create a new backend error + * + * @param kind must ne != Implementation + * @return BackendError + */ +BackendError new_backend_error(BackendErrorKind kind); + +BackendError new_backend_impl_error(BackendErrorKind kind, AST_NODE_PTR node, const char* message); + #endif // CODEGN_BACKEND_H_ diff --git a/src/llvm/backend.c b/src/llvm/backend.c index 2f7fc6d..6c31665 100644 --- a/src/llvm/backend.c +++ b/src/llvm/backend.c @@ -10,7 +10,7 @@ typedef enum LLVMBackendError_t { UnresolvedImport } LLVMBackendError; -static size_t llvm_backend_codegen(const AST_NODE_PTR, void**) { +static BackendError llvm_backend_codegen(const AST_NODE_PTR, void**) { // we start with a LLVM module LLVMContextRef context = LLVMContextCreate(); LLVMModuleRef module = LLVMModuleCreateWithNameInContext("gemstone application", context); @@ -20,21 +20,21 @@ static size_t llvm_backend_codegen(const AST_NODE_PTR, void**) { LLVMDisposeModule(module); LLVMContextDispose(context); - return Success; + return new_backend_error(Success); } -static size_t llvm_backend_codegen_init(void) { - return Success; +static BackendError llvm_backend_codegen_init(void) { + return new_backend_error(Success); } -static size_t llvm_backend_codegen_deinit(void) { - return 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 != Success) { + if (err.kind != Success) { PANIC("unable to init llvm backend: %ld", err); } } diff --git a/src/llvm/function/function.c b/src/llvm/function/function.c new file mode 100644 index 0000000..73daecc --- /dev/null +++ b/src/llvm/function/function.c @@ -0,0 +1,75 @@ + +#include "ast/ast.h" +#include +#include +#include + +static enum IO_Qualifier_t io_qualifier_from_string(const char* str) { + if (strcmp(str, "in") == 0) { + return In; + } + + return Out; +} + +static enum IO_Qualifier_t merge_qualifier(enum IO_Qualifier_t a, enum IO_Qualifier_t b) { + enum IO_Qualifier_t result = Unspec; + + if (a == In && b == Out) { + result = InOut; + } else if (a == Out && b == In) { + result = InOut; + } + + return result; +} + +static enum IO_Qualifier_t io_qualifier_from_ast_list(const AST_NODE_PTR node) { + // node is expected to be a list + if (node->kind != AST_List) { + PANIC("Node must be of type AST_List: %s", AST_node_to_string(node)); + } + + enum IO_Qualifier_t qualifier = Unspec; + + for (size_t i = 0; i < node->child_count; i++) { + + AST_NODE_PTR qualifier_node = AST_get_node(node, i); + + if (qualifier_node->kind != AST_Qualifyier) { + PANIC("Node must be of type AST_Qualifyier: %s", AST_node_to_string(node)); + } + + enum IO_Qualifier_t local_qualifier = io_qualifier_from_string(qualifier_node->value); + + if (qualifier == Unspec) { + qualifier = local_qualifier; + } else { + qualifier = merge_qualifier(qualifier, local_qualifier); + } + } + + if (qualifier == Unspec) + qualifier = In; + + return qualifier; +} + +GemstoneParam param_from_ast(const AST_NODE_PTR node) { + GemstoneParam param; + + // node is expected to be a parameter + if (node->kind != AST_Parameter) { + PANIC("Node must be of type AST_ParamList: %s", AST_node_to_string(node)); + } + + AST_NODE_PTR qualifier_list = AST_get_node(node, 0); + param.qualifier = io_qualifier_from_ast_list(qualifier_list); + + AST_NODE_PTR param_decl = AST_get_node(node, 1); + AST_NODE_PTR param_type = AST_get_node(param_decl, 0); + param.typename = get_type_from_ast(param_type); + param.name = AST_get_node(param_decl, 1)->value; + + return param; +} diff --git a/src/llvm/function/function.h b/src/llvm/function/function.h new file mode 100644 index 0000000..54df9a4 --- /dev/null +++ b/src/llvm/function/function.h @@ -0,0 +1,42 @@ + +#ifndef LLVM_FUNCTION_H_ +#define LLVM_FUNCTION_H_ + +#include +#include + +enum IO_Qualifier_t { + Unspec, + In, + Out, + InOut +}; + +typedef struct GemstoneParam_t { + const char* name; + enum IO_Qualifier_t qualifier; + GemstoneType typename; +} GemstoneParam; + +typedef struct GemstoneFun_t { + const char* name; + // TODO: add array of parameters +} GemstoneFun; + +/** + * @brief Convert an AST node into a function parameter struct + * + * @param node the node starting a function parameter + * @return GemstoneParam + */ +GemstoneParam param_from_ast(const AST_NODE_PTR node); + +/** + * @brief Convert an AST node into a function + * + * @param node the node starting a function + * @return GemstoneFun + */ +GemstoneFun fun_from_ast(const AST_NODE_PTR node); + +#endif // LLVM_FUNCTION_H_ diff --git a/src/llvm/type.c b/src/llvm/types/composite.c similarity index 77% rename from src/llvm/type.c rename to src/llvm/types/composite.c index c1b178e..416087b 100644 --- a/src/llvm/type.c +++ b/src/llvm/types/composite.c @@ -1,52 +1,8 @@ -#include +#include #include -#include -#include -#include -#define BITS_PER_BYTE 8 - -enum Sign_t { - Signed, - Unsigned -}; - -enum Precision_t { - ATOM = 1, - HALF = 2, - SINGLE = 4, - DOUBLE = 8, - QUAD = 16, - OCTO = 32 -}; - -enum Primitive_t { - Int, - Float -}; - -typedef struct CompositeType_t { - const char* name; - enum Sign_t sign; - enum Precision_t scale; - enum Primitive_t prim; -} Composite; - -typedef struct TypeScope_t { - // vector of composite data types - Composite* composites; - size_t composite_len; - size_t composite_cap; -} TypeScope; - -Composite* get_composite_type(const char* name); - -typedef struct CompositeType_t* COMPOSITE_REF; - -#define INVALID_COMPOSITE NULL - -LLVMTypeRef llvm_type_from_composite(LLVMContextRef context, const COMPOSITE_REF composite) { +LLVMTypeRef llvm_type_from_composite(LLVMContextRef context, const CompositeRef composite) { DEBUG("converting composite to LLVM type..."); LLVMTypeRef type = INVALID_COMPOSITE; @@ -61,6 +17,7 @@ LLVMTypeRef llvm_type_from_composite(LLVMContextRef context, const COMPOSITE_REF switch (composite->scale) { case HALF: type = LLVMHalfTypeInContext(context); + break; case SINGLE: type = LLVMDoubleTypeInContext(context); break; @@ -89,7 +46,7 @@ double get_scale_factor(const char* keyword) { PANIC("invalid scale factor: %s", keyword); } -enum Precision_t collapse_scale_list(const AST_NODE_PTR list) { +enum Scale_t collapse_scale_list(const AST_NODE_PTR list) { double sum = 1.0; for (size_t i = 0; i < list->child_count; i++) { @@ -99,7 +56,7 @@ enum Precision_t collapse_scale_list(const AST_NODE_PTR list) { } if (sum >= 1.0 && sum <= 32) { - return (enum Precision_t) sum; + return (enum Scale_t) sum; } PANIC("invalid combination of scale factors"); @@ -115,6 +72,18 @@ enum Sign_t string_to_sign(const char* keyword) { PANIC("invalid sign: %s", keyword); } +static enum Primitive_t resolve_primitive(const char* typename) { + + if (strcmp(typename, "int") == 0) { + return Int; + } else if (strcmp(typename, "float") == 0) { + return Float; + } + + // TODO: implement lookup of ident type + return Int; +} + struct CompositeType_t ast_type_to_composite(AST_NODE_PTR type) { size_t count = type->child_count; @@ -152,8 +121,7 @@ struct CompositeType_t ast_type_to_composite(AST_NODE_PTR type) { composite.scale = collapse_scale_list(AST_get_node(type, 0)); composite.prim = resolve_primitive(AST_get_node(type, 2)->value); } + + return composite; } -void generate_builtin_types(LLVMContextRef context) { - -} diff --git a/src/llvm/types/composite.h b/src/llvm/types/composite.h new file mode 100644 index 0000000..a8df186 --- /dev/null +++ b/src/llvm/types/composite.h @@ -0,0 +1,53 @@ + +#ifndef LLVM_TYPE_H_ +#define LLVM_TYPE_H_ + +#include +#include +#include +#include + +#define BITS_PER_BYTE 8 + +enum Sign_t { + Signed, + Unsigned +}; + +enum Scale_t { + ATOM = 1, + HALF = 2, + SINGLE = 4, + DOUBLE = 8, + QUAD = 16, + OCTO = 32 +}; + +enum Primitive_t { + Int, + Float +}; + +typedef struct CompositeType_t { + const char* name; + enum Sign_t sign; + enum Scale_t scale; + enum Primitive_t prim; +} Composite; + +typedef struct TypeScope_t { + // vector of composite data types + Composite* composites; + size_t composite_len; + size_t composite_cap; +} TypeScope; + +typedef struct CompositeType_t* CompositeRef; + +#define INVALID_COMPOSITE NULL + +LLVMTypeRef llvm_type_from_composite(LLVMContextRef context, const CompositeRef composite); + +struct CompositeType_t ast_type_to_composite(AST_NODE_PTR type); + +#endif // LLVM_TYPE_H_ diff --git a/src/llvm/types/type.c b/src/llvm/types/type.c new file mode 100644 index 0000000..2b8911d --- /dev/null +++ b/src/llvm/types/type.c @@ -0,0 +1,23 @@ + +#include +#include +#include + +GemstoneType get_type_from_ast(const AST_NODE_PTR type_node) { + if (type_node->kind != AST_Type) { + PANIC("Node must be of type AST_Type: %s", AST_node_to_string(type_node)); + } + + GemstoneType type; + + if (type_node->child_count > 1) { + // must be composite + type.kind = TypeComposite; + type.specs.composite = ast_type_to_composite(type_node); + } else { + // either custom type or box + // TODO: resolve concrete type from TypeScope + } + + return type; +} diff --git a/src/llvm/types/type.h b/src/llvm/types/type.h new file mode 100644 index 0000000..d7e2617 --- /dev/null +++ b/src/llvm/types/type.h @@ -0,0 +1,43 @@ + +#ifndef GEMSTONE_TYPE_H_ +#define GEMSTONE_TYPE_H_ + +#include +#include + +enum GemstoneTypeKind_t { + TypeComposite, + TypeReference, + TypeBox +}; + +struct GemstoneType_t; + +typedef struct GemstoneRefType_t { + struct GemstoneType_t* type; +} GemstoneRefType; + +typedef struct GemstoneType_t { + enum GemstoneTypeKind_t kind; + union GemstoneTypeSpecs_t { + Composite composite; + GemstoneRefType reference; + } specs; +} GemstoneType; + +struct TypeScope_t; + +typedef struct TypeScope_t { + // TODO: array of child scopes + // TODO: array of types +} TypeScope; + +/** + * @brief Convert a type declaration into a concrete type. + * + * @param type A type declaration (either identifier or composite) + * @return GemstoneType + */ +GemstoneType get_type_from_ast(const AST_NODE_PTR type); + +#endif // GEMSTONE_TYPE_H_ diff --git a/src/main.c b/src/main.c index a2078bc..e9c484b 100644 --- a/src/main.c +++ b/src/main.c @@ -53,6 +53,24 @@ void setup(void) { DEBUG("finished starting up gemstone..."); } +void run_backend_codegen() { + llvm_backend_init(); + + BackendError err; + err = init_backend(); + if (err.kind != Success) { + return; + } + + void* code = NULL; + err = generate_code(root, &code); + if (err.kind != Success) { + return; + } + + err = deinit_backend(); +} + int main(int argc, char *argv[]) { setup(); @@ -77,16 +95,9 @@ int main(int argc, char *argv[]) { root = AST_new_node(AST_Module, NULL); yyparse(); - llvm_backend_init(); + run_backend_codegen(); - init_backend(); - - void* code = NULL; - generate_code(root, &code); - - deinit_backend(); - - FILE *output = fopen("test.txt", "w"); + FILE *output = fopen("test.gv", "w"); AST_fprint_graphviz(output, root); fclose(output); AST_delete_node(root);