Commit e74a7264ad

Andrew Kelley <superjoe30@gmail.com>
2016-02-01 05:05:17
support casting between int and float types
1 parent 954afe5
src/all_types.hpp
@@ -347,6 +347,8 @@ enum CastOp {
     CastOpPureErrorWrap,
     CastOpPointerReinterpret,
     CastOpErrToInt,
+    CastOpIntToFloat,
+    CastOpFloatToInt,
 };
 
 struct AstNodeFnCallExpr {
src/analyze.cpp
@@ -3417,6 +3417,14 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex
                 const_val->ok = true;
                 break;
             }
+        case CastOpIntToFloat:
+            bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum);
+            const_val->ok = true;
+            break;
+        case CastOpFloatToInt:
+            bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum);
+            const_val->ok = true;
+            break;
     }
 }
 
@@ -3478,6 +3486,24 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
         return wanted_type;
     }
 
+    // explicit cast from int to float
+    if (wanted_type->id == TypeTableEntryIdFloat &&
+        actual_type->id == TypeTableEntryIdInt)
+    {
+        node->data.fn_call_expr.cast_op = CastOpIntToFloat;
+        eval_const_expr_implicit_cast(g, node, expr_node);
+        return wanted_type;
+    }
+
+    // explicit cast from float to int
+    if (wanted_type->id == TypeTableEntryIdInt &&
+        actual_type->id == TypeTableEntryIdFloat)
+    {
+        node->data.fn_call_expr.cast_op = CastOpFloatToInt;
+        eval_const_expr_implicit_cast(g, node, expr_node);
+        return wanted_type;
+    }
+
     // explicit cast from fixed size array to unknown size array
     if (wanted_type->id == TypeTableEntryIdStruct &&
         wanted_type->data.structure.is_unknown_size_array &&
src/bignum.cpp
@@ -120,6 +120,30 @@ void bignum_negate(BigNum *dest, BigNum *op) {
     }
 }
 
+void bignum_cast_to_float(BigNum *dest, BigNum *op) {
+    assert(op->kind == BigNumKindInt);
+    dest->kind = BigNumKindFloat;
+
+    dest->data.x_float = op->data.x_uint;
+
+    if (op->is_negative) {
+        dest->data.x_float = -dest->data.x_float;
+    }
+}
+
+void bignum_cast_to_int(BigNum *dest, BigNum *op) {
+    assert(op->kind == BigNumKindFloat);
+    dest->kind = BigNumKindInt;
+
+    if (op->data.x_float >= 0) {
+        dest->data.x_uint = op->data.x_float;
+        dest->is_negative = false;
+    } else {
+        dest->data.x_uint = -op->data.x_float;
+        dest->is_negative = true;
+    }
+}
+
 bool bignum_sub(BigNum *dest, BigNum *op1, BigNum *op2) {
     BigNum op2_negated;
     bignum_negate(&op2_negated, op2);
src/bignum.hpp
@@ -44,6 +44,8 @@ bool bignum_shl(BigNum *dest, BigNum *op1, BigNum *op2);
 bool bignum_shr(BigNum *dest, BigNum *op1, BigNum *op2);
 
 void bignum_negate(BigNum *dest, BigNum *op);
+void bignum_cast_to_float(BigNum *dest, BigNum *op);
+void bignum_cast_to_int(BigNum *dest, BigNum *op);
 
 // returns the result of the comparison
 bool bignum_cmp_eq(BigNum *op1, BigNum *op2);
src/codegen.cpp
@@ -478,6 +478,25 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
 
                 return cast_expr->tmp_ptr;
             }
+        case CastOpIntToFloat:
+            assert(actual_type->id == TypeTableEntryIdInt);
+            if (actual_type->data.integral.is_signed) {
+                add_debug_source_node(g, node);
+                return LLVMBuildSIToFP(g->builder, expr_val, wanted_type->type_ref, "");
+            } else {
+                add_debug_source_node(g, node);
+                return LLVMBuildUIToFP(g->builder, expr_val, wanted_type->type_ref, "");
+            }
+        case CastOpFloatToInt:
+            assert(wanted_type->id == TypeTableEntryIdInt);
+            if (wanted_type->data.integral.is_signed) {
+                add_debug_source_node(g, node);
+                return LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
+            } else {
+                add_debug_source_node(g, node);
+                return LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
+            }
+
     }
     zig_unreachable();
 }
test/run_tests.cpp
@@ -1483,6 +1483,23 @@ export fn main(args: c_int, argv: &&u8) -> c_int {
     return 0;
 }
     )SOURCE", "");
+
+
+
+    add_simple_case("casting between float and integer types", R"SOURCE(
+#link("c")
+export executable "test";
+c_import {
+    @c_include("stdio.h");
+}
+export fn main(argc: c_int, argv: &&u8) -> c_int {
+    const x : f64 = 3.25;
+    const y = i32(x);
+    const z = f64(y);
+    printf(c"%.2f\n%d\n%.2f\n", x, y, z);
+    return 0;
+}
+    )SOURCE", "3.25\n3\n3.00\n");
 }