| author | |
| committer | |
| log | e74a7264ad3b221dfef0c959c1fdd6275f7c70ef |
| tree | 915b1d379b4dbe803f89d26242ba1d876229a9fa |
| parent | 954afe5d9a5ae634f7db22641ebac6e755cdaba7 |
6 files changed, 90 insertions(+), 0 deletions(-)
src/all_types.hpp+2| ... | @@ -347,6 +347,8 @@ enum CastOp { | ... | @@ -347,6 +347,8 @@ enum CastOp { |
| 347 | CastOpPureErrorWrap, | 347 | CastOpPureErrorWrap, |
| 348 | CastOpPointerReinterpret, | 348 | CastOpPointerReinterpret, |
| 349 | CastOpErrToInt, | 349 | CastOpErrToInt, |
| 350 | CastOpIntToFloat, | ||
| 351 | CastOpFloatToInt, | ||
| 350 | }; | 352 | }; |
| 351 | 353 | ||
| 352 | struct AstNodeFnCallExpr { | 354 | struct AstNodeFnCallExpr { |
src/analyze.cpp+26| ... | @@ -3417,6 +3417,14 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex | ... | @@ -3417,6 +3417,14 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex |
| 3417 | const_val->ok = true; | 3417 | const_val->ok = true; |
| 3418 | break; | 3418 | break; |
| 3419 | } | 3419 | } |
| 3420 | case CastOpIntToFloat: | ||
| 3421 | bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum); | ||
| 3422 | const_val->ok = true; | ||
| 3423 | break; | ||
| 3424 | case CastOpFloatToInt: | ||
| 3425 | bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum); | ||
| 3426 | const_val->ok = true; | ||
| 3427 | break; | ||
| 3420 | } | 3428 | } |
| 3421 | } | 3429 | } |
| 3422 | 3430 | ||
| ... | @@ -3478,6 +3486,24 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -3478,6 +3486,24 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 3478 | return wanted_type; | 3486 | return wanted_type; |
| 3479 | } | 3487 | } |
| 3480 | 3488 | ||
| 3489 | // explicit cast from int to float | ||
| 3490 | if (wanted_type->id == TypeTableEntryIdFloat && | ||
| 3491 | actual_type->id == TypeTableEntryIdInt) | ||
| 3492 | { | ||
| 3493 | node->data.fn_call_expr.cast_op = CastOpIntToFloat; | ||
| 3494 | eval_const_expr_implicit_cast(g, node, expr_node); | ||
| 3495 | return wanted_type; | ||
| 3496 | } | ||
| 3497 | |||
| 3498 | // explicit cast from float to int | ||
| 3499 | if (wanted_type->id == TypeTableEntryIdInt && | ||
| 3500 | actual_type->id == TypeTableEntryIdFloat) | ||
| 3501 | { | ||
| 3502 | node->data.fn_call_expr.cast_op = CastOpFloatToInt; | ||
| 3503 | eval_const_expr_implicit_cast(g, node, expr_node); | ||
| 3504 | return wanted_type; | ||
| 3505 | } | ||
| 3506 | |||
| 3481 | // explicit cast from fixed size array to unknown size array | 3507 | // explicit cast from fixed size array to unknown size array |
| 3482 | if (wanted_type->id == TypeTableEntryIdStruct && | 3508 | if (wanted_type->id == TypeTableEntryIdStruct && |
| 3483 | wanted_type->data.structure.is_unknown_size_array && | 3509 | wanted_type->data.structure.is_unknown_size_array && |
src/bignum.cpp+24| ... | @@ -120,6 +120,30 @@ void bignum_negate(BigNum *dest, BigNum *op) { | ... | @@ -120,6 +120,30 @@ void bignum_negate(BigNum *dest, BigNum *op) { |
| 120 | } | 120 | } |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | void bignum_cast_to_float(BigNum *dest, BigNum *op) { | ||
| 124 | assert(op->kind == BigNumKindInt); | ||
| 125 | dest->kind = BigNumKindFloat; | ||
| 126 | |||
| 127 | dest->data.x_float = op->data.x_uint; | ||
| 128 | |||
| 129 | if (op->is_negative) { | ||
| 130 | dest->data.x_float = -dest->data.x_float; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | void bignum_cast_to_int(BigNum *dest, BigNum *op) { | ||
| 135 | assert(op->kind == BigNumKindFloat); | ||
| 136 | dest->kind = BigNumKindInt; | ||
| 137 | |||
| 138 | if (op->data.x_float >= 0) { | ||
| 139 | dest->data.x_uint = op->data.x_float; | ||
| 140 | dest->is_negative = false; | ||
| 141 | } else { | ||
| 142 | dest->data.x_uint = -op->data.x_float; | ||
| 143 | dest->is_negative = true; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 123 | bool bignum_sub(BigNum *dest, BigNum *op1, BigNum *op2) { | 147 | bool bignum_sub(BigNum *dest, BigNum *op1, BigNum *op2) { |
| 124 | BigNum op2_negated; | 148 | BigNum op2_negated; |
| 125 | bignum_negate(&op2_negated, op2); | 149 | bignum_negate(&op2_negated, op2); |
src/bignum.hpp+2| ... | @@ -44,6 +44,8 @@ bool bignum_shl(BigNum *dest, BigNum *op1, BigNum *op2); | ... | @@ -44,6 +44,8 @@ bool bignum_shl(BigNum *dest, BigNum *op1, BigNum *op2); |
| 44 | bool bignum_shr(BigNum *dest, BigNum *op1, BigNum *op2); | 44 | bool bignum_shr(BigNum *dest, BigNum *op1, BigNum *op2); |
| 45 | 45 | ||
| 46 | void bignum_negate(BigNum *dest, BigNum *op); | 46 | void bignum_negate(BigNum *dest, BigNum *op); |
| 47 | void bignum_cast_to_float(BigNum *dest, BigNum *op); | ||
| 48 | void bignum_cast_to_int(BigNum *dest, BigNum *op); | ||
| 47 | 49 | ||
| 48 | // returns the result of the comparison | 50 | // returns the result of the comparison |
| 49 | bool bignum_cmp_eq(BigNum *op1, BigNum *op2); | 51 | bool bignum_cmp_eq(BigNum *op1, BigNum *op2); |
src/codegen.cpp+19| ... | @@ -478,6 +478,25 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { | ... | @@ -478,6 +478,25 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 478 | 478 | ||
| 479 | return cast_expr->tmp_ptr; | 479 | return cast_expr->tmp_ptr; |
| 480 | } | 480 | } |
| 481 | case CastOpIntToFloat: | ||
| 482 | assert(actual_type->id == TypeTableEntryIdInt); | ||
| 483 | if (actual_type->data.integral.is_signed) { | ||
| 484 | add_debug_source_node(g, node); | ||
| 485 | return LLVMBuildSIToFP(g->builder, expr_val, wanted_type->type_ref, ""); | ||
| 486 | } else { | ||
| 487 | add_debug_source_node(g, node); | ||
| 488 | return LLVMBuildUIToFP(g->builder, expr_val, wanted_type->type_ref, ""); | ||
| 489 | } | ||
| 490 | case CastOpFloatToInt: | ||
| 491 | assert(wanted_type->id == TypeTableEntryIdInt); | ||
| 492 | if (wanted_type->data.integral.is_signed) { | ||
| 493 | add_debug_source_node(g, node); | ||
| 494 | return LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, ""); | ||
| 495 | } else { | ||
| 496 | add_debug_source_node(g, node); | ||
| 497 | return LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, ""); | ||
| 498 | } | ||
| 499 | |||
| 481 | } | 500 | } |
| 482 | zig_unreachable(); | 501 | zig_unreachable(); |
| 483 | } | 502 | } |
test/run_tests.cpp+17| ... | @@ -1483,6 +1483,23 @@ export fn main(args: c_int, argv: &&u8) -> c_int { | ... | @@ -1483,6 +1483,23 @@ export fn main(args: c_int, argv: &&u8) -> c_int { |
| 1483 | return 0; | 1483 | return 0; |
| 1484 | } | 1484 | } |
| 1485 | )SOURCE", ""); | 1485 | )SOURCE", ""); |
| 1486 | |||
| 1487 | |||
| 1488 | |||
| 1489 | add_simple_case("casting between float and integer types", R"SOURCE( | ||
| 1490 | #link("c") | ||
| 1491 | export executable "test"; | ||
| 1492 | c_import { | ||
| 1493 | @c_include("stdio.h"); | ||
| 1494 | } | ||
| 1495 | export fn main(argc: c_int, argv: &&u8) -> c_int { | ||
| 1496 | const x : f64 = 3.25; | ||
| 1497 | const y = i32(x); | ||
| 1498 | const z = f64(y); | ||
| 1499 | printf(c"%.2f\n%d\n%.2f\n", x, y, z); | ||
| 1500 | return 0; | ||
| 1501 | } | ||
| 1502 | )SOURCE", "3.25\n3\n3.00\n"); | ||
| 1486 | } | 1503 | } |
| 1487 | 1504 | ||
| 1488 | 1505 |