authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-31 21:22:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-31 21:22:05-07:00
loga4e19f94f10445273b977e21e721d236a37c5cf4
tree842e06c40599c418b67553dfa6859c3dfcf220bc
parente74a7264ad3b221dfef0c959c1fdd6275f7c70ef

support casting between floats


4 files changed, 47 insertions(+), 14 deletions(-)

src/all_types.hpp+1-1
......@@ -340,7 +340,7 @@ enum CastOp {
340340 CastOpNoop, // fn call expr is a cast, but does nothing
341341 CastOpPtrToInt,
342342 CastOpIntToPtr,
343 CastOpIntWidenOrShorten,
343 CastOpWidenOrShorten,
344344 CastOpToUnknownSizeArray,
345345 CastOpMaybeWrap,
346346 CastOpErrorWrap,
src/analyze.cpp+15-5
......@@ -1681,6 +1681,14 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_
16811681 return true;
16821682 }
16831683
1684 // implicit float widening conversion
1685 if (expected_type->id == TypeTableEntryIdFloat &&
1686 actual_type->id == TypeTableEntryIdFloat &&
1687 expected_type->size_in_bits >= actual_type->size_in_bits)
1688 {
1689 return true;
1690 }
1691
16841692 // implicit constant sized array to unknown size array conversion
16851693 if (expected_type->id == TypeTableEntryIdStruct &&
16861694 expected_type->data.structure.is_unknown_size_array &&
......@@ -3366,7 +3374,7 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex
33663374 case CastOpNoCast:
33673375 zig_unreachable();
33683376 case CastOpNoop:
3369 case CastOpIntWidenOrShorten:
3377 case CastOpWidenOrShorten:
33703378 case CastOpPointerReinterpret:
33713379 *const_val = *other_val;
33723380 break;
......@@ -3477,11 +3485,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
34773485 return wanted_type;
34783486 }
34793487
3480 // explicit cast from any int to any other int
3481 if (wanted_type->id == TypeTableEntryIdInt &&
3482 actual_type->id == TypeTableEntryIdInt)
3488 // explicit widening or shortening cast
3489 if ((wanted_type->id == TypeTableEntryIdInt &&
3490 actual_type->id == TypeTableEntryIdInt) ||
3491 (wanted_type->id == TypeTableEntryIdFloat &&
3492 actual_type->id == TypeTableEntryIdFloat))
34833493 {
3484 node->data.fn_call_expr.cast_op = CastOpIntWidenOrShorten;
3494 node->data.fn_call_expr.cast_op = CastOpWidenOrShorten;
34853495 eval_const_expr_implicit_cast(g, node, expr_node);
34863496 return wanted_type;
34873497 }
src/codegen.cpp+23-7
......@@ -349,20 +349,36 @@ static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntr
349349static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type,
350350 TypeTableEntry *wanted_type, LLVMValueRef expr_val)
351351{
352 assert(actual_type->id == wanted_type->id);
352353 if (actual_type->size_in_bits == wanted_type->size_in_bits) {
353354 return expr_val;
354355 } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
355 if (actual_type->data.integral.is_signed) {
356 if (actual_type->id == TypeTableEntryIdFloat) {
356357 add_debug_source_node(g, source_node);
357 return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
358 return LLVMBuildFPExt(g->builder, expr_val, wanted_type->type_ref, "");
359 } else if (actual_type->id == TypeTableEntryIdInt) {
360 if (actual_type->data.integral.is_signed) {
361 add_debug_source_node(g, source_node);
362 return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
363 } else {
364 add_debug_source_node(g, source_node);
365 return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
366 }
358367 } else {
368 zig_unreachable();
369 }
370 } else if (actual_type->size_in_bits > wanted_type->size_in_bits) {
371 if (actual_type->id == TypeTableEntryIdFloat) {
359372 add_debug_source_node(g, source_node);
360 return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
373 return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, "");
374 } else if (actual_type->id == TypeTableEntryIdInt) {
375 add_debug_source_node(g, source_node);
376 return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
377 } else {
378 zig_unreachable();
361379 }
362380 } else {
363 assert(actual_type->size_in_bits > wanted_type->size_in_bits);
364 add_debug_source_node(g, source_node);
365 return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
381 zig_unreachable();
366382 }
367383}
368384
......@@ -455,7 +471,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
455471 case CastOpPointerReinterpret:
456472 add_debug_source_node(g, node);
457473 return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
458 case CastOpIntWidenOrShorten:
474 case CastOpWidenOrShorten:
459475 return gen_widen_or_shorten(g, node, actual_type, wanted_type, expr_val);
460476 case CastOpToUnknownSizeArray:
461477 {
test/run_tests.cpp+8-1
......@@ -1493,7 +1493,8 @@ c_import {
14931493 @c_include("stdio.h");
14941494}
14951495export fn main(argc: c_int, argv: &&u8) -> c_int {
1496 const x : f64 = 3.25;
1496 const small: f32 = 3.25;
1497 const x: f64 = small;
14971498 const y = i32(x);
14981499 const z = f64(y);
14991500 printf(c"%.2f\n%d\n%.2f\n", x, y, z);
......@@ -1945,6 +1946,12 @@ pub fn a(x: i32) -> i32 {x + 0}
19451946pub fn b(x: i32) -> i32 {x + 1}
19461947export fn c(x: i32) -> i32 {x + 2}
19471948 )SOURCE", 1, ".tmp_source.zig:2:37: error: expected type 'fn(i32) -> i32', got 'extern fn(i32) -> i32'");
1949
1950
1951 add_compile_fail_case("implicit cast from f64 to f32", R"SOURCE(
1952const x : f64 = 1.0;
1953const y : f32 = x;
1954 )SOURCE", 1, ".tmp_source.zig:3:17: error: expected type 'f32', got 'f64'");
19481955}
19491956
19501957//////////////////////////////////////////////////////////////////////////////