Author | Jakob Wakeling <[email protected]> |
Date | 2022-03-27 10:52:12 |
Commit | af7cced8bd1c8b0e4115d10b679876174792068f |
Parent | 06863d51b24798c94fc08458c425880887a5a1e4 |
llvm: Align generation structure with EBNF
Diffstat
M | src/compile.c | | | 13 | +++++-------- |
A | src/llvm.c | | | 180 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/llvm.h | | | 13 | +++++++++++++ |
D | src/llvm/gen.c | | | 123 | -------------------------------------------------------------------------------- |
D | src/llvm/llvm.h | | | 20 | -------------------- |
D | src/llvm/type.c | | | 26 | -------------------------- |
M | src/parse.c | | | 3 | +++ |
7 files changed, 201 insertions, 177 deletions
diff --git a/src/compile.c b/src/compile.c index 53ac772..0c88ced 100644 --- a/src/compile.c +++ b/src/compile.c @@ -5,13 +5,11 @@ #include "compile.h" #include "init.h" -#include "llvm/llvm.h" +#include "llvm.h" #include "parse.h" #include "util/error.h" #include "util/util.h" -#include <llvm-c/Core.h> - #include <stdio.h> #include <stdlib.h> @@ -21,15 +19,14 @@ void compile(const char * file, char *src, UINT len) { initialise(); lex l = lex_init(file, src, len); - if (lflag) { lex_debug(&l); goto ret; } + if (lflag) { lex_debug(&l); goto end; } ast *a = parse(&l); - if (pflag) { ast_print(a, 0); goto ret; } + if (pflag) { ast_print(a, 0); goto end; } - llvm_test(a); + llvm(a); -ret:; - LLVMShutdown(); return; + end:; return; } void compile_file(const char *file) { diff --git a/src/llvm.c b/src/llvm.c new file mode 100644 index 0000000..c788ece --- /dev/null +++ b/src/llvm.c @@ -0,0 +1,180 @@ +// llvm.c +// LLVM source file for G +// Copyright (C) 2021, Jakob Wakeling +// All rights reserved. + +#include "llvm.h" +#include "parse.h" +#include "type.h" +#include "util/error.h" +#include "util/util.h" + +#include <llvm-c/Analysis.h> +#include <llvm-c/BitWriter.h> +#include <llvm-c/Core.h> +#include <llvm-c/Target.h> +#include <llvm-c/TargetMachine.h> +#include <llvm-c/Types.h> + +#include <stdio.h> + +static LLVMContextRef llvm_context = NULL; +static LLVMModuleRef llvm_module = NULL; +static LLVMBuilderRef llvm_builder = NULL; + +static LLVMValueRef llvm_stmt(ast *a); +static LLVMValueRef llvm_stmt_compound(ast *a); +static LLVMValueRef llvm_stmt_decl(ast *a); +static LLVMValueRef llvm_stmt_expr(ast *a); +static LLVMValueRef llvm_stmt_return(ast *a); +static LLVMValueRef llvm_stmt_if(ast *a); +static LLVMValueRef llvm_stmt_for(ast *a); + +static LLVMValueRef llvm_expr(ast *a); +static LLVMValueRef llvm_expr_proc(ast *a); + +static LLVMValueRef llvm_int(ast *a); + +static inline void llvm_init(void); +static inline void llvm_free(void); +static LLVMTypeRef llvm_type(type *t); + +/* Generate IR from an AST with LLVM. */ +void llvm(ast *a) { + llvm_init(); + + /* Generate IR for all child nodes */ + for (UINT i = 0; i < a->c.al; i += 1) { llvm_stmt_decl(a->c.a[i]); } + + if (LLVMWriteBitcodeToFile(llvm_module, "llvm.bc")) { + error(2, "LLVMWriteBitcodeToFile failure"); + } + + char *err; + LLVMVerifyModule(llvm_module, LLVMAbortProcessAction, &err); + LLVMDisposeMessage(err); + + char *triple = LLVMGetDefaultTargetTriple(); + LLVMSetTarget(llvm_module, triple); + + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargets(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllAsmParsers(); + LLVMInitializeAllAsmPrinters(); + + LLVMTargetRef target; LLVMGetTargetFromTriple(triple, &target, &err); + if (!target) { error(2, "LLVMGetTargetFromTriple: %s", err); } + + LLVMTargetMachineRef machine = LLVMCreateTargetMachine( + target, triple, "generic", "", LLVMCodeGenLevelNone, + LLVMRelocDefault, LLVMCodeModelDefault + ); + + LLVMTargetMachineEmitToFile(machine, llvm_module, "llvm.o", LLVMObjectFile, &err); + + LLVMDisposeTargetMachine(machine); llvm_free(); +} + +/* Generate IR for a statement. */ +static LLVMValueRef llvm_stmt(ast *a) { + switch (a->k) { + case AK_COMP: { return llvm_stmt_compound(a); } break; + case AK_DECL: { return llvm_stmt_decl(a); } break; + case AK_RETURN: { return llvm_stmt_return(a); } break; + case AK_IF: { return llvm_stmt_if(a); } break; + case AK_FOR: { return llvm_stmt_for(a); } break; + default: { error(2, "llvm_stmt: Unhandled AST kind %s", ast_ks[a->k]); } break; + } +} + +/* Generate IR for a compound statement. */ +static LLVMValueRef llvm_stmt_compound(ast *a) { + /* TODO actually implement this properly. */ + if ((a->c.a[0])->k == AK_RETURN) { + return llvm_int(a->c.a[0]->c.a[0]); + } + else { error(1, "llvm_compound else!"); } + + return NULL; +} + +/* Generate IR for a declaration statement. */ +static LLVMValueRef llvm_stmt_decl(ast *a) { + /* TODO actually implement this properly. */ + if (a->k == AK_DECL && a->c.a[0]->k == AK_PROC) { + return llvm_expr_proc(a->c.a[0]); + } + else { error(1, "llvm_decl else!"); } + + return NULL; +} + +/* Generate IR for an expression statement. */ +static LLVMValueRef llvm_stmt_expr(ast *a) { + +} + +/* Generate IR for a return statement. */ +static LLVMValueRef llvm_stmt_return(ast *a) { + +} + +/* Generate IR for an if statement. */ +static LLVMValueRef llvm_stmt_if(ast *a) { /* TODO */ } + +/* Generate IR for a for statement. */ +static LLVMValueRef llvm_stmt_for(ast *a) { /* TODO */ } + +/* Generate IR for an expression. */ +static LLVMValueRef llvm_expr(ast *a) { + +} + +/* Generate IR for a procedure. */ +static LLVMValueRef llvm_expr_proc(ast *a) { + LLVMTypeRef ft = LLVMFunctionType(llvm_type(a->t), NULL, 0, 0); + LLVMValueRef f = LLVMAddFunction(llvm_module, a->p->s, ft); + + LLVMBasicBlockRef bb = LLVMAppendBasicBlock(f, "entry"); + LLVMPositionBuilderAtEnd(llvm_builder, bb); + + LLVMValueRef r = llvm_stmt_compound(a->c.a[0]); if (!r) { return NULL; } + LLVMBuildRet(llvm_builder, r); return f; +} + +/* Generate IR for an integer. */ +static LLVMValueRef llvm_int(ast *a) { + return LLVMConstInt(LLVMIntType(64), a->v.v_int, false); +} + +/* Initialise LLVM. */ +static inline void llvm_init(void) { + llvm_context = LLVMGetGlobalContext(); + llvm_module = LLVMModuleCreateWithName("G"); + llvm_builder = LLVMCreateBuilder(); +} + +/* Uninitialise LLVM. */ +static inline void llvm_free(void) { + LLVMDisposeBuilder(llvm_builder); llvm_builder = NULL; + LLVMDisposeModule(llvm_module); llvm_module = NULL; + LLVMShutdown(); llvm_context = NULL; +} + +/* Return the appropriate LLVMTypeRef for a G type. */ +static LLVMTypeRef llvm_type(type *t) { + switch (t->k) { + case TY_UINT: case TY_SINT: { return LLVMIntType(64); } break; + case TY_U8: case TY_S8: { return LLVMIntType(8); } break; + case TY_U16: case TY_S16: { return LLVMIntType(16); } break; + case TY_U32: case TY_S32: { return LLVMIntType(32); } break; + case TY_U64: case TY_S64: { return LLVMIntType(64); } break; + case TY_U128: case TY_S128: { return LLVMIntType(128); } break; + case TY_F16: { return LLVMHalfType(); } break; + case TY_F32: { return LLVMFloatType(); } break; + case TY_F64: { return LLVMDoubleType(); } break; + case TY_F128: { return LLVMFP128Type(); } break; + default: { return NULL; } break; + } +} diff --git a/src/llvm.h b/src/llvm.h new file mode 100644 index 0000000..5e1e248 --- /dev/null +++ b/src/llvm.h @@ -0,0 +1,13 @@ +// llvm.h +// LLVM header file for G +// Copyright (C) 2021, Jakob Wakeling +// All rights reserved. + +#ifndef G_LLVM_H_CZUMSHFW +#define G_LLVM_H_CZUMSHFW + +#include "parse.h" + +extern void llvm(ast *a); + +#endif // G_LLVM_H_CZUMSHFW diff --git a/src/llvm/gen.c b/src/llvm/gen.c deleted file mode 100644 index 6324609..0000000 --- a/src/llvm/gen.c +++ /dev/null @@ -1,123 +0,0 @@ -// llvm/gen.c -// LLVM generator source file for G -// Copyright (C) 2021, Jakob Wakeling -// All rights reserved. - -#include "../parse.h" -#include "../type.h" -#include "../util/error.h" -#include "../util/util.h" -#include "llvm.h" - -#include <llvm-c/Analysis.h> -#include <llvm-c/BitWriter.h> -#include <llvm-c/Core.h> -#include <llvm-c/Target.h> -#include <llvm-c/TargetMachine.h> -#include <llvm-c/Types.h> - -#include <stdio.h> - -static LLVMContextRef llvm_context; -static LLVMModuleRef llvm_module; -static LLVMBuilderRef llvm_builder; - -static LLVMValueRef gen_decl(ast *a); - -static LLVMValueRef gen_compound(ast *a); - -static LLVMValueRef gen_proc(ast *a); - -static LLVMValueRef gen_return(ast *a); - -static LLVMValueRef gen_int(ast *a); - -void llvm_init(void) { - llvm_context = LLVMGetGlobalContext(); - llvm_module = LLVMModuleCreateWithName("G"); - llvm_builder = LLVMCreateBuilder(); -} - -void llvm_free(void) { - LLVMDisposeBuilder(llvm_builder); - LLVMDisposeModule(llvm_module); -} - -void llvm_test(ast *a) { - llvm_init(); gen_decl(a->c.a[0]); - - if (LLVMWriteBitcodeToFile(llvm_module, "llvm.bc")) { - error(11, "LLVMWriteBitcodeToFile failure!"); - } - - char *err; - LLVMVerifyModule(llvm_module, LLVMAbortProcessAction, &err); - LLVMDisposeMessage(err); - - char *triple = LLVMGetDefaultTargetTriple(); - LLVMSetTarget(llvm_module, triple); - - LLVMInitializeAllTargetInfos(); - LLVMInitializeAllTargets(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllAsmParsers(); - LLVMInitializeAllAsmPrinters(); - - LLVMTargetRef target; LLVMGetTargetFromTriple(triple, &target, &err); - if (!target) { error(11, "LLVMGetTargetFromName failure!"); } - - LLVMTargetMachineRef machine = LLVMCreateTargetMachine( - target, triple, "generic", "", - LLVMCodeGenLevelNone, LLVMRelocDefault, LLVMCodeModelDefault - ); - - LLVMTargetMachineEmitToFile( - machine, llvm_module, "llvm.o", LLVMObjectFile, &err - ); - - LLVMDisposeTargetMachine(machine); llvm_free(); -} - -/* Generate IR for a declaration. */ -static LLVMValueRef gen_decl(ast *a) { - /* TODO actually implement this properly. */ - if (a->k == AK_DECL && a->c.a[0]->k == AK_PROC) { - return gen_proc(a->c.a[0]); - } - else { error(1, "gen_decl else!"); } - - return NULL; -} - -/* Generate IR for a compound statement. */ -static LLVMValueRef gen_compound(ast *a) { - /* TODO actually implement this properly. */ - if ((a->c.a[0])->k == AK_RETURN) { - return gen_int(a->c.a[0]->c.a[0]); - } - else { error(1, "gen_compound else!"); } - - return NULL; -} - -/* Generate IR for a procedure. */ -static LLVMValueRef gen_proc(ast *a) { - LLVMTypeRef ft = LLVMFunctionType(llvm_type(a->t), NULL, 0, 0); - LLVMValueRef f = LLVMAddFunction(llvm_module, a->s, ft); - - LLVMBasicBlockRef bb = LLVMAppendBasicBlock(f, "entry"); - LLVMPositionBuilderAtEnd(llvm_builder, bb); - - LLVMValueRef r = gen_compound(a->c.a[0]); if (!r) { return NULL; } - LLVMBuildRet(llvm_builder, r); return f; -} - -/* Generate IR for a return statement. */ -static LLVMValueRef gen_return(ast *a) { - return NULL; -} - -/* Generate IR for an integer. */ -static LLVMValueRef gen_int(ast *a) { - return LLVMConstInt(LLVMInt64Type(), a->v.v_int, false); -} diff --git a/src/llvm/llvm.h b/src/llvm/llvm.h deleted file mode 100644 index 92ab8df..0000000 --- a/src/llvm/llvm.h +++ /dev/null @@ -1,20 +0,0 @@ -// llvm/llvm.h -// LLVM header file for G -// Copyright (C) 2021, Jakob Wakeling -// All rights reserved. - -#ifndef G_LLVM_LLVM_H_CZUMSHFW -#define G_LLVM_LLVM_H_CZUMSHFW - -#include "../parse.h" -#include "../type.h" -#include "../util/util.h" - -#include <llvm-c/Types.h> - -extern void llvm_init(void); -void llvm_test(ast *a); - -extern LLVMTypeRef llvm_type(type *t); - -#endif // G_LLVM_LLVM_H_CZUMSHFW diff --git a/src/llvm/type.c b/src/llvm/type.c deleted file mode 100644 index 6906d8b..0000000 --- a/src/llvm/type.c +++ /dev/null @@ -1,26 +0,0 @@ -// llvm/type.c -// LLVM type source file for G -// Copyright (C) 2021, Jakob Wakeling -// All rights reserved. - -#include "../type.h" - -#include <llvm-c/Core.h> -#include <llvm-c/Types.h> - -/* Return the appropriate LLVMTypeRef for a G type. */ -LLVMTypeRef llvm_type(type *t) { - switch (t->k) { - case TY_UINT: case TY_SINT: { return LLVMIntType(64); } break; - case TY_U8: case TY_S8: { return LLVMIntType(8); } break; - case TY_U16: case TY_S16: { return LLVMIntType(16); } break; - case TY_U32: case TY_S32: { return LLVMIntType(32); } break; - case TY_U64: case TY_S64: { return LLVMIntType(64); } break; - case TY_U128: case TY_S128: { return LLVMIntType(128); } break; - case TY_F16: { return LLVMHalfType(); } break; - case TY_F32: { return LLVMFloatType(); } break; - case TY_F64: { return LLVMDoubleType(); } break; - case TY_F128: { return LLVMFP128Type(); } break; - default: { return NULL; } break; - } -} diff --git a/src/parse.c b/src/parse.c index 2219623..313d6e2 100644 --- a/src/parse.c +++ b/src/parse.c @@ -124,6 +124,9 @@ static ast *parse_stmt_decl(lex *l, syt *st) { if (T.k == TK_COLON || T.k == TK_ASSIGN) { lex_next(l); ast_push(sm.a, parse_expr(l, st)); } else { error(1, "%s:%zu:%zu: error: expected ':' or '='", l->n, T.ln + 1, T.cl + 1); } + /* Store the parent AST node in the child */ + sm.a->c.a[0]->p = sm.a; + /* Parse a semicolon if one is required */ if (sm.a->c.a[0]->k != AK_PROC) { lex_kind(l, TK_SCOLON); }