added function backend

This commit is contained in:
Sven Vogel 2024-05-19 16:07:27 +02:00
parent 1e60890919
commit 2804fd552b
10 changed files with 340 additions and 88 deletions

View File

@ -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);
}

View File

@ -4,28 +4,42 @@
#include <ast/ast.h>
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_

View File

@ -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);
}
}

View File

@ -0,0 +1,75 @@
#include "ast/ast.h"
#include <llvm/function/function.h>
#include <llvm/types/type.h>
#include <string.h>
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;
}

View File

@ -0,0 +1,42 @@
#ifndef LLVM_FUNCTION_H_
#define LLVM_FUNCTION_H_
#include <ast/ast.h>
#include <llvm/types/type.h>
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_

View File

@ -1,52 +1,8 @@
#include <ast/ast.h>
#include <llvm/types/composite.h>
#include <string.h>
#include <sys/log.h>
#include <llvm-c/Core.h>
#include <llvm-c/Types.h>
#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) {
}

View File

@ -0,0 +1,53 @@
#ifndef LLVM_TYPE_H_
#define LLVM_TYPE_H_
#include <ast/ast.h>
#include <sys/log.h>
#include <llvm-c/Core.h>
#include <llvm-c/Types.h>
#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_

23
src/llvm/types/type.c Normal file
View File

@ -0,0 +1,23 @@
#include <llvm/types/composite.h>
#include <ast/ast.h>
#include <llvm/types/type.h>
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;
}

43
src/llvm/types/type.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef GEMSTONE_TYPE_H_
#define GEMSTONE_TYPE_H_
#include <ast/ast.h>
#include <llvm/types/composite.h>
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_

View File

@ -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);