G

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

AuthorJakob Wakeling <[email protected]>
Date2023-07-10 23:33:32
Commitd2c465aaf479e4049cc7a79f14fc09a72a69f178
Parent8021c03df5a011b7a8978a9c49c21f6e97146f8f

Properly implement floating point arithmetic

Diffstat

M src/llvm.c | 105 +++++++++++++++++++++++++++++++++++++++++++++----------------------------------

1 files changed, 60 insertions, 45 deletions

diff --git a/src/llvm.c b/src/llvm.c
index b10a0da..b2a1eca 100644
--- a/src/llvm.c
+++ b/src/llvm.c
@@ -290,19 +290,32 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) {
 	}
 
 	case AK_OP_ADD: {
-		return LLVMBuildAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "add");
+		if      (is_int(ast_type(C[0], st))) { return LLVMBuildAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		else if (is_flt(ast_type(C[0], st))) { return LLVMBuildFAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
 	} break;
 	case AK_OP_SUB: {
-		return LLVMBuildSub(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "sub");
+		if      (is_int(ast_type(C[0], st))) { return LLVMBuildSub(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		else if (is_flt(ast_type(C[0], st))) { return LLVMBuildFSub(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
 	} break;
 	case AK_OP_MUL: {
-		return LLVMBuildMul(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "mul");
+		if      (is_int(ast_type(C[0], st))) { return LLVMBuildMul(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		else if (is_flt(ast_type(C[0], st))) { return LLVMBuildFMul(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
 	} break;
 	case AK_OP_DIV: {
-		return LLVMBuildSDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "div");
+		register type *t = ast_type(C[0], st);
+		if (is_int(t)) {
+			if (is_sign(t)) { return LLVMBuildSDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+			else            { return LLVMBuildUDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		}
+		else if (is_flt(t)) { return LLVMBuildFDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
 	} break;
 	case AK_OP_MOD: {
-		return LLVMBuildSRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "mod");
+		register type *t = ast_type(C[0], st);
+		if (is_int(t)) {
+			if (is_sign(t)) { return LLVMBuildSRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+			else            { return LLVMBuildURem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		}
+		else if (is_flt(t)) { return LLVMBuildFRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
 	} break;
 
 	case AK_EQ:  {
@@ -366,26 +379,43 @@ static LLVMValueRef llvm_expr(ast *a, syt *st, bool load) {
 		return LLVMBuildStore(llvm_builder, llvm_expr(C[1], st, true), llvm_expr(C[0], st, false));
 	} break;
 	case AK_AS_ADD: {
-		LLVMValueRef vr = LLVMBuildAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "");
-		return LLVMBuildStore(llvm_builder, vr, llvm_expr(C[0], st, false));
+		register type *t = ast_type(C[0], st); register LLVMValueRef v = NULL;
+		if      (is_int(t)) { v = LLVMBuildAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		else if (is_flt(t)) { v = LLVMBuildFAdd(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		return LLVMBuildStore(llvm_builder, v, llvm_expr(C[0], st, false));
 	} break;
 	case AK_AS_SUB: {
-		LLVMValueRef vr = LLVMBuildSub(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "");
-		return LLVMBuildStore(llvm_builder, vr, llvm_expr(C[0], st, false));
+		register type *t = ast_type(C[0], st); register LLVMValueRef v = NULL;
+		if      (is_int(t)) { v = LLVMBuildSub(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		else if (is_flt(t)) { v = LLVMBuildFSub(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		return LLVMBuildStore(llvm_builder, v, llvm_expr(C[0], st, false));
 	} break;
 	case AK_AS_MUL: {
-		LLVMValueRef vr = LLVMBuildMul(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "");
-		return LLVMBuildStore(llvm_builder, vr, llvm_expr(C[0], st, false));
+		register type *t = ast_type(C[0], st); register LLVMValueRef v = NULL;
+		if      (is_int(t)) { v = LLVMBuildMul(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		else if (is_flt(t)) { v = LLVMBuildFMul(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		return LLVMBuildStore(llvm_builder, v, llvm_expr(C[0], st, false));
 	} break;
 	case AK_AS_DIV: {
-		LLVMValueRef vr = LLVMBuildSDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "");
-		return LLVMBuildStore(llvm_builder, vr, llvm_expr(C[0], st, false));
+		register type *t = ast_type(C[0], st); register LLVMValueRef v = NULL;
+		if (is_int(t)) {
+			if (is_sign(t)) { v = LLVMBuildSDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+			else            { v = LLVMBuildUDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		}
+		else if (is_flt(t)) { v = LLVMBuildFDiv(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		return LLVMBuildStore(llvm_builder, v, llvm_expr(C[0], st, false));
 	} break;
 	case AK_AS_MOD: {
-		LLVMValueRef vr = LLVMBuildSRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), "");
-		return LLVMBuildStore(llvm_builder, vr, llvm_expr(C[0], st, false));
+		register type *t = ast_type(C[0], st); register LLVMValueRef v = NULL;
+		if (is_int(t)) {
+			if (is_sign(t)) { v = LLVMBuildSRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+			else            { v = LLVMBuildURem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		}
+		else if (is_flt(t)) { v = LLVMBuildFRem(llvm_builder, llvm_expr(C[0], st, true), llvm_expr(C[1], st, true), ""); }
+		return LLVMBuildStore(llvm_builder, v, llvm_expr(C[0], st, false));
 	} break;
-	default: { note(file_name, A.ln, A.cl, -1, "Unhandled AST kind %s (llvm:llvm_expr)", ast_ks[a->k]); } break;
+	
+	default: { panic("Unhandled AST kind \"%s\" (llvm:llvm_expr)", ast_ks[a->k]); } break;
 	}
 
 	return NULL;
@@ -404,40 +434,26 @@ static LLVMValueRef llvm_expr_cast(ast *a, syt *st) {
 	type *expr_type = ast_type(C[1], st);
 
 	if (is_ptr(expr_type)) {
-		if (is_int(a->t)) {
-			return LLVMBuildPtrToInt(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "");
-		}
+		if (is_int(a->t)) { return LLVMBuildPtrToInt(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), ""); }
 	}
 	else if (is_bool(expr_type)) {
-		if (is_int(a->t)) {
-			return LLVMBuildIntCast2(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), is_sign(a->t), "");
-		}
+		if (is_int(a->t)) { return LLVMBuildIntCast2(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), is_sign(a->t), ""); }
 	}
 	else if (is_int(expr_type)) {
 		if (is_bool(a->t) || is_int(a->t)) {
 			return LLVMBuildIntCast2(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), is_sign(a->t), "");
 		}
 		else if (is_flt(a->t)) {
-			if (is_sign(expr_type)) {
-				return LLVMBuildSIToFP(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "stof");
-			}
-			else {
-				return LLVMBuildUIToFP(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "utof");
-			}
+			if (is_sign(expr_type)) { return LLVMBuildSIToFP(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "stof"); }
+			else                    { return LLVMBuildUIToFP(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "utof"); }
 		}
 	}
 	else if (is_flt(expr_type)) {
-		if (is_flt(a->t)) {
-			return LLVMBuildFPCast(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "cast");
-		}
-		else if (is_int(a->t)) {
-			if (is_sign(a->t)) {
-				return LLVMBuildFPToSI(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "ftos");
-			}
-			else {
-				return LLVMBuildFPToUI(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "ftou");
-			}
+		if (is_int(a->t)) {
+			if (is_sign(a->t)) { return LLVMBuildFPToSI(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "ftos"); }
+			else               { return LLVMBuildFPToUI(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "ftou"); }
 		}
+		else if (is_flt(a->t)) { return LLVMBuildFPCast(llvm_builder, llvm_expr(C[1], st, true), llvm_type(a->t), "cast"); }
 	}
 	else if (expr_type->k == TY_ARR) {
 		if (is_ptr(a->t)) {
@@ -446,7 +462,7 @@ static LLVMValueRef llvm_expr_cast(ast *a, syt *st) {
 		}
 	}
 
-	note(file_name, A.ln, A.cl, -1, "Unhandled cast \"%s\" -> \"%s\" (llvm:llvm_expr_cast)", expr_type->s, A.t->s);
+	panic("Unhandled cast \"%s\" -> \"%s\" (llvm:llvm_expr_cast)", expr_type->s, A.t->s);
 
 	return NULL;
 }
@@ -465,7 +481,7 @@ static LLVMValueRef llvm_expr_hash(ast *a, syt *st) {
 	LLVMValueRef inline_asm = NULL;
 
 	/* TODO check architecture */
-	{ /* x86-64 */
+	/* x86-64 */ {
 		assert(CL <= 7);
 
 		char constraints[128] = "={rax}";
@@ -545,11 +561,8 @@ static LLVMValueRef llvm_ival(type *t) {
 	switch (t->k) {
 	case TY_PTR:  { return LLVMConstNull(llvm_type(t->base)); } break;
 	case TY_ARR:  {
-		LLVMValueRef *va = calloc(t->l, sizeof (LLVMValueRef));
-		LLVMValueRef bv = llvm_ival(t->base);
-		
+		LLVMValueRef va[t->l], bv = llvm_ival(t->base);
 		for (UINT i = 0; i < t->l; i += 1) { va[i] = bv; }
-		
 		return LLVMConstArray(llvm_type(t->base), va, t->l);
 	} break;
 	case TY_BOOL: { return LLVMConstInt(LLVMIntType(1),   0, false); } break;