From 5185b5619ac703755849da70d158b5a45e5673a7 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 14 May 2021 12:17:58 +0200 Subject: [PATCH] compiler-rt: Fix signedness mismatch in f128 mul impl The `1 - shift` expression was computed using small unsigned types and then casted to i32, producing either an underflow error or an incorrect result. Reported by `@notviri` in #8733 --- lib/std/special/compiler_rt/mulXf3.zig | 12 ++++++------ lib/std/special/compiler_rt/mulXf3_test.zig | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/std/special/compiler_rt/mulXf3.zig b/lib/std/special/compiler_rt/mulXf3.zig index a4c71529d1..20828badd3 100644 --- a/lib/std/special/compiler_rt/mulXf3.zig +++ b/lib/std/special/compiler_rt/mulXf3.zig @@ -98,8 +98,8 @@ fn mulXf3(comptime T: type, a: T, b: T) T { // one or both of a or b is denormal, the other (if applicable) is a // normal number. Renormalize one or both of a and b, and set scale to // include the necessary exponent adjustment. - if (aAbs < implicitBit) scale +%= normalize(T, &aSignificand); - if (bAbs < implicitBit) scale +%= normalize(T, &bSignificand); + if (aAbs < implicitBit) scale += normalize(T, &aSignificand); + if (bAbs < implicitBit) scale += normalize(T, &bSignificand); } // Or in the implicit significand bit. (If we fell through from the @@ -277,7 +277,7 @@ fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeInfo(T const shift = @clz(Z, significand.*) - @clz(Z, implicitBit); significand.* <<= @intCast(std.math.Log2Int(Z), shift); - return 1 - shift; + return @as(i32, 1) - shift; } fn wideRightShiftWithSticky(comptime Z: type, hi: *Z, lo: *Z, count: u32) void { @@ -285,15 +285,15 @@ fn wideRightShiftWithSticky(comptime Z: type, hi: *Z, lo: *Z, count: u32) void { const typeWidth = @typeInfo(Z).Int.bits; const S = std.math.Log2Int(Z); if (count < typeWidth) { - const sticky = @truncate(u8, lo.* << @intCast(S, typeWidth -% count)); + const sticky = @boolToInt((lo.* << @intCast(S, typeWidth -% count)) != 0); lo.* = (hi.* << @intCast(S, typeWidth -% count)) | (lo.* >> @intCast(S, count)) | sticky; hi.* = hi.* >> @intCast(S, count); } else if (count < 2 * typeWidth) { - const sticky = @truncate(u8, hi.* << @intCast(S, 2 * typeWidth -% count) | lo.*); + const sticky = @boolToInt((hi.* << @intCast(S, 2 * typeWidth -% count) | lo.*) != 0); lo.* = hi.* >> @intCast(S, count -% typeWidth) | sticky; hi.* = 0; } else { - const sticky = @truncate(u8, hi.* | lo.*); + const sticky = @boolToInt((hi.* | lo.*) != 0); lo.* = sticky; hi.* = 0; } diff --git a/lib/std/special/compiler_rt/mulXf3_test.zig b/lib/std/special/compiler_rt/mulXf3_test.zig index b73f03d6c1..d3a61710a1 100644 --- a/lib/std/special/compiler_rt/mulXf3_test.zig +++ b/lib/std/special/compiler_rt/mulXf3_test.zig @@ -88,4 +88,18 @@ test "multf3" { ); try test__multf3(0x1.23456734245345p-10000, 0x1.edcba524498724p-6497, 0x0, 0x0); + + // Denormal operands. + try test__multf3( + 0x0.0000000000000000000000000001p-16382, + 0x1.p16383, + 0x3f90000000000000, + 0x0, + ); + try test__multf3( + 0x1.p16383, + 0x0.0000000000000000000000000001p-16382, + 0x3f90000000000000, + 0x0, + ); }