From e74a7264ad3b221dfef0c959c1fdd6275f7c70ef Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 31 Jan 2016 21:05:17 -0700 Subject: [PATCH] support casting between int and float types --- src/all_types.hpp | 2 ++ src/analyze.cpp | 26 ++++++++++++++++++++++++++ src/bignum.cpp | 24 ++++++++++++++++++++++++ src/bignum.hpp | 2 ++ src/codegen.cpp | 19 +++++++++++++++++++ test/run_tests.cpp | 17 +++++++++++++++++ 6 files changed, 90 insertions(+) diff --git a/src/all_types.hpp b/src/all_types.hpp index 6f6d6cc2ee..9d00980c2a 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -347,6 +347,8 @@ enum CastOp { CastOpPureErrorWrap, CastOpPointerReinterpret, CastOpErrToInt, + CastOpIntToFloat, + CastOpFloatToInt, }; struct AstNodeFnCallExpr { diff --git a/src/analyze.cpp b/src/analyze.cpp index 756f12251e..785bad9ff2 100644 --- a/src/analyze.cpp +++ b/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 && diff --git a/src/bignum.cpp b/src/bignum.cpp index 4ec61308bb..56215179b8 100644 --- a/src/bignum.cpp +++ b/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); diff --git a/src/bignum.hpp b/src/bignum.hpp index e814c90697..047169085a 100644 --- a/src/bignum.hpp +++ b/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); diff --git a/src/codegen.cpp b/src/codegen.cpp index 01f3fe60c9..24608bc553 100644 --- a/src/codegen.cpp +++ b/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(); } diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 7cc8b0c565..e93145d4d0 100644 --- a/test/run_tests.cpp +++ b/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"); }