support casting between floats

master
Andrew Kelley 2016-01-31 21:22:05 -07:00
parent e74a7264ad
commit a4e19f94f1
4 changed files with 47 additions and 14 deletions

View File

@ -340,7 +340,7 @@ enum CastOp {
CastOpNoop, // fn call expr is a cast, but does nothing CastOpNoop, // fn call expr is a cast, but does nothing
CastOpPtrToInt, CastOpPtrToInt,
CastOpIntToPtr, CastOpIntToPtr,
CastOpIntWidenOrShorten, CastOpWidenOrShorten,
CastOpToUnknownSizeArray, CastOpToUnknownSizeArray,
CastOpMaybeWrap, CastOpMaybeWrap,
CastOpErrorWrap, CastOpErrorWrap,

View File

@ -1681,6 +1681,14 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_
return true; return true;
} }
// implicit float widening conversion
if (expected_type->id == TypeTableEntryIdFloat &&
actual_type->id == TypeTableEntryIdFloat &&
expected_type->size_in_bits >= actual_type->size_in_bits)
{
return true;
}
// implicit constant sized array to unknown size array conversion // implicit constant sized array to unknown size array conversion
if (expected_type->id == TypeTableEntryIdStruct && if (expected_type->id == TypeTableEntryIdStruct &&
expected_type->data.structure.is_unknown_size_array && 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
case CastOpNoCast: case CastOpNoCast:
zig_unreachable(); zig_unreachable();
case CastOpNoop: case CastOpNoop:
case CastOpIntWidenOrShorten: case CastOpWidenOrShorten:
case CastOpPointerReinterpret: case CastOpPointerReinterpret:
*const_val = *other_val; *const_val = *other_val;
break; break;
@ -3477,11 +3485,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
return wanted_type; return wanted_type;
} }
// explicit cast from any int to any other int // explicit widening or shortening cast
if (wanted_type->id == TypeTableEntryIdInt && if ((wanted_type->id == TypeTableEntryIdInt &&
actual_type->id == TypeTableEntryIdInt) actual_type->id == TypeTableEntryIdInt) ||
(wanted_type->id == TypeTableEntryIdFloat &&
actual_type->id == TypeTableEntryIdFloat))
{ {
node->data.fn_call_expr.cast_op = CastOpIntWidenOrShorten; node->data.fn_call_expr.cast_op = CastOpWidenOrShorten;
eval_const_expr_implicit_cast(g, node, expr_node); eval_const_expr_implicit_cast(g, node, expr_node);
return wanted_type; return wanted_type;
} }

View File

@ -349,9 +349,14 @@ static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntr
static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type, static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type,
TypeTableEntry *wanted_type, LLVMValueRef expr_val) TypeTableEntry *wanted_type, LLVMValueRef expr_val)
{ {
assert(actual_type->id == wanted_type->id);
if (actual_type->size_in_bits == wanted_type->size_in_bits) { if (actual_type->size_in_bits == wanted_type->size_in_bits) {
return expr_val; return expr_val;
} else if (actual_type->size_in_bits < wanted_type->size_in_bits) { } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
if (actual_type->id == TypeTableEntryIdFloat) {
add_debug_source_node(g, source_node);
return LLVMBuildFPExt(g->builder, expr_val, wanted_type->type_ref, "");
} else if (actual_type->id == TypeTableEntryIdInt) {
if (actual_type->data.integral.is_signed) { if (actual_type->data.integral.is_signed) {
add_debug_source_node(g, source_node); add_debug_source_node(g, source_node);
return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, ""); return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
@ -360,9 +365,20 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
} }
} else { } else {
assert(actual_type->size_in_bits > wanted_type->size_in_bits); zig_unreachable();
}
} else if (actual_type->size_in_bits > wanted_type->size_in_bits) {
if (actual_type->id == TypeTableEntryIdFloat) {
add_debug_source_node(g, source_node);
return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, "");
} else if (actual_type->id == TypeTableEntryIdInt) {
add_debug_source_node(g, source_node); add_debug_source_node(g, source_node);
return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
} else {
zig_unreachable();
}
} else {
zig_unreachable();
} }
} }
@ -455,7 +471,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
case CastOpPointerReinterpret: case CastOpPointerReinterpret:
add_debug_source_node(g, node); add_debug_source_node(g, node);
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, ""); return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpIntWidenOrShorten: case CastOpWidenOrShorten:
return gen_widen_or_shorten(g, node, actual_type, wanted_type, expr_val); return gen_widen_or_shorten(g, node, actual_type, wanted_type, expr_val);
case CastOpToUnknownSizeArray: case CastOpToUnknownSizeArray:
{ {

View File

@ -1493,7 +1493,8 @@ c_import {
@c_include("stdio.h"); @c_include("stdio.h");
} }
export fn main(argc: c_int, argv: &&u8) -> c_int { export fn main(argc: c_int, argv: &&u8) -> c_int {
const x : f64 = 3.25; const small: f32 = 3.25;
const x: f64 = small;
const y = i32(x); const y = i32(x);
const z = f64(y); const z = f64(y);
printf(c"%.2f\n%d\n%.2f\n", x, y, z); printf(c"%.2f\n%d\n%.2f\n", x, y, z);
@ -1945,6 +1946,12 @@ pub fn a(x: i32) -> i32 {x + 0}
pub fn b(x: i32) -> i32 {x + 1} pub fn b(x: i32) -> i32 {x + 1}
export fn c(x: i32) -> i32 {x + 2} export fn c(x: i32) -> i32 {x + 2}
)SOURCE", 1, ".tmp_source.zig:2:37: error: expected type 'fn(i32) -> i32', got 'extern fn(i32) -> i32'"); )SOURCE", 1, ".tmp_source.zig:2:37: error: expected type 'fn(i32) -> i32', got 'extern fn(i32) -> i32'");
add_compile_fail_case("implicit cast from f64 to f32", R"SOURCE(
const x : f64 = 1.0;
const y : f32 = x;
)SOURCE", 1, ".tmp_source.zig:3:17: error: expected type 'f32', got 'f64'");
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////