From ba7d786271388b7c882d0be7ffa27829bc3b2302 Mon Sep 17 00:00:00 2001 From: Sam Schweigel Date: Mon, 17 Mar 2025 16:13:58 -0700 Subject: [PATCH] Fix fptrunc Float64 -> Float16 rounding through Float32 Widening from Float32 to Float64 and then rounding (by any method) to Float16 will not introduce any error, but going from Float64 -> Float32 -> Float16 will round incorrectly if the intermediate Float32 is halfway between two Float16s. Fixes #57805. Co-authored-by: Jameson Nash --- src/runtime_intrinsics.c | 4 ++-- test/intrinsics.jl | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index f5b281f9e92ed..09f55f1d1f1d8 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -1629,8 +1629,8 @@ cvt_iintrinsic(LLVMFPtoUI, fptoui) #define fintrinsic_read_float32(p) *(float *)p #define fintrinsic_read_float64(p) *(double *)p -#define fintrinsic_write_float16(p, x) *(uint16_t *)p = float_to_half(x) -#define fintrinsic_write_bfloat16(p, x) *(uint16_t *)p = float_to_bfloat(x) +#define fintrinsic_write_float16(p, x) *(uint16_t *)p = double_to_half(x) +#define fintrinsic_write_bfloat16(p, x) *(uint16_t *)p = double_to_bfloat(x) #define fintrinsic_write_float32(p, x) *(float *)p = x #define fintrinsic_write_float64(p, x) *(double *)p = x diff --git a/test/intrinsics.jl b/test/intrinsics.jl index 12867908bf5a4..ee1da6d7a45ae 100644 --- a/test/intrinsics.jl +++ b/test/intrinsics.jl @@ -304,6 +304,17 @@ end @test_intrinsic Core.Intrinsics.fptrunc Float16 Float32(3.3) Float16(3.3) @test_intrinsic Core.Intrinsics.fptrunc Float16 Float64(3.3) Float16(3.3) + # #57805 - cases where rounding Float64 -> Float32 -> Float16 would fail + # 2^-25 * 0b1.0000000000000000000000000000000000000001 binary + # 0 01111100110 0000000000000000000000000000000000000001000000000000 + # 2^-25 * 0b1.0 binary + # 0 01100110 00000000000000000000000 + # 2^-14 * 0b0.0000000001 (subnormal) + # 0 00000 0000000001 (correct) + # 0 00000 0000000000 (incorrect) + @test_intrinsic Core.Intrinsics.fptrunc Float16 0x1.0000000001p-25 Float16(6.0e-8) + @test_intrinsic Core.Intrinsics.fptrunc Float16 -0x1.0000000001p-25 Float16(-6.0e-8) + # float_to_half/bfloat_to_float special cases @test_intrinsic Core.Intrinsics.fptrunc Float16 Inf32 Inf16 @test_intrinsic Core.Intrinsics.fptrunc Float16 -Inf32 -Inf16