| author | |
| committer | |
| log | e0fb4c29cb618fe912c82fed06bb305db14606d8 |
| tree | 8443bb64aaf65db00dc760c659c93754031fd824 |
| parent | b89158d6fd7ce0960b3f8085368ae102b48747d0 |
@bitCast from integer NaN representation to float NaN resulted in
changed bits in float. This only happened with signaled NaN.
- added test for signaled NaN
- added tests for quiet NaN (for completeness)
closes #141983 files changed, 32 insertions(+), 4 deletions(-)
src/codegen/llvm.zig+13-4| ... | ... | @@ -3287,15 +3287,24 @@ pub const DeclGen = struct { |
| 3287 | 3287 | .Float => { |
| 3288 | 3288 | const llvm_ty = try dg.lowerType(tv.ty); |
| 3289 | 3289 | switch (tv.ty.floatBits(target)) { |
| 3290 | 16 => if (intrinsicsAllowed(tv.ty, target)) { | |
| 3291 | return llvm_ty.constReal(tv.val.toFloat(f16)); | |
| 3292 | } else { | |
| 3290 | 16 => { | |
| 3293 | 3291 | const repr = @bitCast(u16, tv.val.toFloat(f16)); |
| 3294 | 3292 | const llvm_i16 = dg.context.intType(16); |
| 3295 | 3293 | const int = llvm_i16.constInt(repr, .False); |
| 3296 | 3294 | return int.constBitCast(llvm_ty); |
| 3297 | 3295 | }, |
| 3298 | 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)), | |
| 3296 | 32 => { | |
| 3297 | const repr = @bitCast(u32, tv.val.toFloat(f32)); | |
| 3298 | const llvm_i32 = dg.context.intType(32); | |
| 3299 | const int = llvm_i32.constInt(repr, .False); | |
| 3300 | return int.constBitCast(llvm_ty); | |
| 3301 | }, | |
| 3302 | 64 => { | |
| 3303 | const repr = @bitCast(u64, tv.val.toFloat(f64)); | |
| 3304 | const llvm_i64 = dg.context.intType(64); | |
| 3305 | const int = llvm_i64.constInt(repr, .False); | |
| 3306 | return int.constBitCast(llvm_ty); | |
| 3307 | }, | |
| 3299 | 3308 | 80 => { |
| 3300 | 3309 | const float = tv.val.toFloat(f80); |
| 3301 | 3310 | const repr = std.math.break_f80(float); |
test/behavior.zig+1| ... | ... | @@ -241,6 +241,7 @@ test { |
| 241 | 241 | { |
| 242 | 242 | _ = @import("behavior/bugs/13063.zig"); |
| 243 | 243 | _ = @import("behavior/bugs/11227.zig"); |
| 244 | _ = @import("behavior/bugs/14198.zig"); | |
| 244 | 245 | _ = @import("behavior/export.zig"); |
| 245 | 246 | } |
| 246 | 247 |
test/behavior/bugs/14198.zig created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | const std = @import("std"); | |
| 2 | const math = std.math; | |
| 3 | const mem = std.mem; | |
| 4 | const testing = std.testing; | |
| 5 | ||
| 6 | test "nan memory equality" { | |
| 7 | // signaled | |
| 8 | try testing.expect(mem.eql(u8, mem.asBytes(&math.nan_u16), mem.asBytes(&math.nan_f16))); | |
| 9 | try testing.expect(mem.eql(u8, mem.asBytes(&math.nan_u32), mem.asBytes(&math.nan_f32))); | |
| 10 | try testing.expect(mem.eql(u8, mem.asBytes(&math.nan_u64), mem.asBytes(&math.nan_f64))); | |
| 11 | try testing.expect(mem.eql(u8, mem.asBytes(&math.nan_u128), mem.asBytes(&math.nan_f128))); | |
| 12 | ||
| 13 | // quiet | |
| 14 | try testing.expect(mem.eql(u8, mem.asBytes(&math.qnan_u16), mem.asBytes(&math.qnan_f16))); | |
| 15 | try testing.expect(mem.eql(u8, mem.asBytes(&math.qnan_u32), mem.asBytes(&math.qnan_f32))); | |
| 16 | try testing.expect(mem.eql(u8, mem.asBytes(&math.qnan_u64), mem.asBytes(&math.qnan_f64))); | |
| 17 | try testing.expect(mem.eql(u8, mem.asBytes(&math.qnan_u128), mem.asBytes(&math.qnan_f128))); | |
| 18 | } |