G

G Programming Language
git clone http://git.omkov.net/G
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2022-03-27 10:52:12
Commitaf7cced8bd1c8b0e4115d10b679876174792068f
Parent06863d51b24798c94fc08458c425880887a5a1e4

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