Author | Jakob Wakeling <[email protected]> |
Date | 2023-07-10 23:33:32 |
Commit | d2c465aaf479e4049cc7a79f14fc09a72a69f178 |
Parent | 8021c03df5a011b7a8978a9c49c21f6e97146f8f |
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;