ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
33.84k stars 2.48k forks source link

failing behavior test: coerce between pointers of compatible differently-named floats #12396

Open andrewrk opened 2 years ago

andrewrk commented 2 years ago

This problem has been ongoing but masked by #12380.

2022-08-09T08:15:17.7124009Z 431/1344 behavior.cast.test "behavior-native-Debug-bare-multi-default coerce between pointers of compatible differently-named floats"... FAIL (TestUnexpectedResult)
2022-08-09T08:15:17.7128834Z D:\a\1\s\test\behavior\bugs\11159.zig:11:41: 0x7ff7c426d424 in ehavior.bugs.11159.test "behavior-native-Debug-bare-multi-default " (test.obj)
2022-08-09T08:15:17.7132484Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest; // TODO
2022-08-09T08:15:17.7136271Z                                         ^
2022-08-09T08:15:17.7141631Z D:\a\1\s\test\behavior\bugs\11162.zig:6:41: 0x7ff7c426d444 in ehavior.bugs.11162.test "behavior-native-Debug-bare-multi-default aggregate initializers should allow initializing comptime fields, verifying equality (stage2 only)" (test.obj)
2022-08-09T08:15:17.7144925Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest; // TODO
2022-08-09T08:15:17.7148539Z                                         ^
2022-08-09T08:15:17.7153581Z D:\a\1\s\test\behavior\cast.zig:116:41: 0x7ff7c426e3e4 in ehavior.cast.test "behavior-native-Debug-bare-multi-default @intToFloat(f80)" (test.obj)
2022-08-09T08:15:17.7161623Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7163138Z                                         ^
2022-08-09T08:15:17.7170669Z D:\a\1\s\test\behavior\cast.zig:715:9: 0x7ff7c426fa74 in ehavior.cast.test "behavior-native-Debug-bare-multi-default peer type resolution: disjoint error sets" (test.obj)
2022-08-09T08:15:17.7172574Z         return error.SkipZigTest;
2022-08-09T08:15:17.7177930Z         ^
2022-08-09T08:15:17.7183200Z D:\a\1\s\test\behavior\cast.zig:749:9: 0x7ff7c426fa94 in ehavior.cast.test "behavior-native-Debug-bare-multi-default peer type resolution: error union and error set" (test.obj)
2022-08-09T08:15:17.7185739Z         return error.SkipZigTest;
2022-08-09T08:15:17.7191044Z         ^
2022-08-09T08:15:17.7195426Z D:\a\1\s\test\behavior\cast.zig:1114:41: 0x7ff7c4270a44 in ehavior.cast.test "behavior-native-Debug-bare-multi-default compile time int to ptr of function" (test.obj)
2022-08-09T08:15:17.7198873Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7203198Z                                         ^
2022-08-09T08:15:17.7210321Z D:\a\1\s\lib\std\testing.zig:351:14: 0x7ff7c429836b in td.testing.expect (test.obj)
2022-08-09T08:15:17.7214715Z     if (!ok) return error.TestUnexpectedResult;
2022-08-09T08:15:17.7218310Z              ^
2022-08-09T08:15:17.7223475Z D:\a\1\s\test\behavior\cast.zig:1445:5: 0x7ff7c42717f5 in ehavior.cast.test "behavior-native-Debug-bare-multi-default coerce between pointers of compatible differently-named floats" (test.obj)
2022-08-09T08:15:17.7228679Z     try expect(f1 == @as(F, 12.34) + 1);
2022-08-09T08:15:17.7231594Z     ^
2022-08-09T08:15:17.7236942Z D:\a\1\s\test\behavior\basic.zig:203:9: 0x7ff7c42685c4 in ehavior.basic.test "behavior-native-Debug-bare-multi-default opaque types" (test.obj)
2022-08-09T08:15:17.7241091Z         return error.SkipZigTest;
2022-08-09T08:15:17.7244767Z         ^
2022-08-09T08:15:17.7250714Z D:\a\1\s\test\behavior\basic.zig:293:41: 0x7ff7c4268814 in ehavior.basic.test "behavior-native-Debug-bare-multi-default call function pointer in struct" (test.obj)
2022-08-09T08:15:17.7254692Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7258393Z                                         ^
2022-08-09T08:15:17.7263345Z D:\a\1\s\test\behavior\basic.zig:332:41: 0x7ff7c4268974 in ehavior.basic.test "behavior-native-Debug-bare-multi-default call result of if else expression" (test.obj)
2022-08-09T08:15:17.7268185Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 has different function pointers
2022-08-09T08:15:17.7272622Z                                         ^
2022-08-09T08:15:17.7278872Z D:\a\1\s\test\behavior\basic.zig:583:41: 0x7ff7c4268fc4 in ehavior.basic.test "behavior-native-Debug-bare-multi-default comptime cast fn to ptr" (test.obj)
2022-08-09T08:15:17.7284748Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7288347Z                                         ^
2022-08-09T08:15:17.7293599Z D:\a\1\s\test\behavior\basic.zig:590:41: 0x7ff7c4268fe4 in ehavior.basic.test "behavior-native-Debug-bare-multi-default equality compare fn ptrs" (test.obj)
2022-08-09T08:15:17.7296123Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7302992Z                                         ^
2022-08-09T08:15:17.7304828Z D:\a\1\s\test\behavior\basic.zig:597:41: 0x7ff7c4269004 in ehavior.basic.test "behavior-native-Debug-bare-multi-default self reference through fn ptr field" (test.obj)
2022-08-09T08:15:17.7309815Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7314316Z                                         ^
2022-08-09T08:15:17.7318624Z D:\a\1\s\test\behavior\basic.zig:801:9: 0x7ff7c4269b04 in ehavior.basic.test "behavior-native-Debug-bare-multi-default extern variable with non-pointer opaque type" (test.obj)
2022-08-09T08:15:17.7323193Z         return error.SkipZigTest;
2022-08-09T08:15:17.7325142Z         ^
2022-08-09T08:15:17.7330661Z D:\a\1\s\test\behavior\basic.zig:956:15: 0x7ff7c4269e88 in ehavior.basic.test "behavior-native-Debug-bare-multi-default weird array and tuple initializations" (test.obj)
2022-08-09T08:15:17.7333464Z     if (true) return error.SkipZigTest;
2022-08-09T08:15:17.7337859Z               ^
2022-08-09T08:15:17.7343244Z D:\a\1\s\test\behavior\basic.zig:1086:41: 0x7ff7c426a044 in ehavior.basic.test "behavior-native-Debug-bare-multi-default namespace lookup ignores decl causing the lookup" (test.obj)
2022-08-09T08:15:17.7345586Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7349623Z                                         ^
2022-08-09T08:15:17.7355016Z D:\a\1\s\test\behavior\bitcast.zig:108:9: 0x7ff7c426a644 in ehavior.bitcast.test "behavior-native-Debug-bare-multi-default @bitCast packed structs at runtime and comptime" (test.obj)
2022-08-09T08:15:17.7358711Z         return error.SkipZigTest;
2022-08-09T08:15:17.7363581Z         ^
2022-08-09T08:15:17.7368901Z D:\a\1\s\test\behavior\bitreverse.zig:9:41: 0x7ff7c426a8e4 in ehavior.bitreverse.test "behavior-native-Debug-bare-multi-default @bitReverse large exotic integer" (test.obj)
2022-08-09T08:15:17.7372489Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7377202Z                                         ^
2022-08-09T08:15:17.7381636Z D:\a\1\s\test\behavior\bitreverse.zig:99:41: 0x7ff7c426a954 in ehavior.bitreverse.test "behavior-native-Debug-bare-multi-default bitReverse vectors u8" (test.obj)
2022-08-09T08:15:17.7383730Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7391180Z                                         ^
2022-08-09T08:15:17.7392526Z D:\a\1\s\test\behavior\bitreverse.zig:118:41: 0x7ff7c426a974 in ehavior.bitreverse.test "behavior-native-Debug-bare-multi-default bitReverse vectors u16" (test.obj)
2022-08-09T08:15:17.7401304Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7406457Z                                         ^
2022-08-09T08:15:17.7412477Z D:\a\1\s\test\behavior\bitreverse.zig:137:41: 0x7ff7c426a994 in ehavior.bitreverse.test "behavior-native-Debug-bare-multi-default bitReverse vectors u24" (test.obj)
2022-08-09T08:15:17.7416886Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7421554Z                                         ^
2022-08-09T08:15:17.7427595Z D:\a\1\s\test\behavior\bitreverse.zig:156:41: 0x7ff7c426a9b4 in ehavior.bitreverse.test "behavior-native-Debug-bare-multi-default bitReverse vectors u0" (test.obj)
2022-08-09T08:15:17.7431268Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7434913Z                                         ^
2022-08-09T08:15:17.7439720Z D:\a\1\s\test\behavior\bugs\1277.zig:15:41: 0x7ff7c426b374 in ehavior.bugs.1277.test "behavior-native-Debug-bare-multi-default don't emit an LLVM global for a const function when it's in an optional in a struct" (test.obj)
2022-08-09T08:15:17.7442812Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 has different function pointers
2022-08-09T08:15:17.7447561Z                                         ^
2022-08-09T08:15:17.7452872Z D:\a\1\s\test\behavior\bugs\1310.zig:26:41: 0x7ff7c426b394 in ehavior.bugs.1310.test "behavior-native-Debug-bare-multi-default fixed" (test.obj)
2022-08-09T08:15:17.7457890Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7463046Z                                         ^
2022-08-09T08:15:17.7467606Z D:\a\1\s\test\behavior\bugs\3112.zig:16:41: 0x7ff7c426c2a4 in ehavior.bugs.3112.test "behavior-native-Debug-bare-multi-default zig test crash" (test.obj)
2022-08-09T08:15:17.7471999Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
2022-08-09T08:15:17.7475889Z                                         ^
2022-08-09T08:15:17.7480145Z D:\a\1\s\test\behavior\bugs\3779.zig:9:41: 0x7ff7c426c4b4 in ehavior.bugs.3779.test "behavior-native-Debug-bare-multi-default @tagName() returns a string literal" (test.obj)
2022-08-09T08:15:17.7485082Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
2022-08-09T08:15:17.7489548Z                                         ^
2022-08-09T08:15:17.7496000Z D:\a\1\s\test\behavior\bugs\3779.zig:22:41: 0x7ff7c426c4d4 in ehavior.bugs.3779.test "behavior-native-Debug-bare-multi-default @errorName() returns a string literal" (test.obj)
2022-08-09T08:15:17.7500802Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
2022-08-09T08:15:17.7507297Z                                         ^
2022-08-09T08:15:17.7511878Z D:\a\1\s\test\behavior\bugs\3779.zig:35:41: 0x7ff7c426c4f4 in ehavior.bugs.3779.test "behavior-native-Debug-bare-multi-default @typeName() returns a string literal" (test.obj)
2022-08-09T08:15:17.7515270Z     if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
2022-08-09T08:15:17.7518547Z                                         ^
2022-08-09T08:15:17.7522559Z D:\a\1\s\test\behavior\bugs\10138.zig:7:66: 0x7ff7c426d0e4 in ehavior.bugs.10138.test "behavior-native-Debug-bare-multi-default registers get overwritten when ignoring return" (test.obj)
2022-08-09T08:15:17.7526031Z     if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .linux) return error.SkipZigTest;
2022-08-09T08:15:17.7530455Z                                                                  ^
2022-08-09T08:15:17.7535251Z D:\a\1\s\test\behavior\bugs\11046.zig:5:12: 0x7ff7c43413a8 in ehavior.bugs.11046.foo (test.obj)
2022-08-09T08:15:17.7541368Z     if (a) return error.Foo;
2022-08-09T08:15:17.7575075Z            ^
2022-08-09T08:15:17.7580011Z D:\a\1\s\test\behavior\bugs\11046.zig:9:5: 0x7ff7c4305251 in ehavior.bugs.11046.bar (test.obj)
2022-08-09T08:15:17.7583161Z     try foo();
2022-08-09T08:15:17.7588034Z     ^
2022-08-09T08:15:18.2436119Z 1207 passed; 136 skipped; 1 failed.
2022-08-09T08:15:18.2440410Z error: the following test command failed with exit code 1:
2022-08-09T08:15:18.2451413Z D:\a\1\s\zig-cache\o\4e84a459ebc02fbcf6c66fe97cbdb871\test.exe D:\a\1\s\build\dist\bin\zig.exe
2022-08-09T08:15:18.2456990Z error: test...
2022-08-09T08:15:18.2460498Z error: The following command exited with error code 1:
2022-08-09T08:15:18.2465973Z D:\a\1\s\build\dist\bin\zig.exe test D:\a\1\s\test\behavior.zig --test-name-prefix behavior-native-Debug-bare-multi-default  --cache-dir D:\a\1\s\zig-cache --global-cache-dir C:\Users\VssAdministrator\AppData\Local\zig --name test -fno-single-threaded -I D:\a\1\s\test --zig-lib-dir D:\a\1\s\lib --enable-cache 
hdorio commented 2 years ago

Sorry if this is noise but I think this issue comes from += for type f80. When doing f1 -= 0 nothing changes but doing f1 += 0 breaks f1 when f1 is of type f80 on Windows.

f64 and f128 work fine.

const builtin = @import("builtin");
const std = @import("std");

test "coerce between pointers of compatible differently-named floats" {
    std.debug.print("\n", .{});

    std.debug.print("stage:      {d}\n", .{builtin.zig_backend});
    std.debug.print("12.34:      {d}\n", .{@bitCast(u80, @as(f80, 12.34))});
    std.debug.print("12.34 +0:   {d}\n", .{@bitCast(u80, @as(f80, 12.34) + 0)});
    std.debug.print("12.34 -0:   {d}\n", .{@bitCast(u80, @as(f80, 12.34) - 0)});
    std.debug.print("\n", .{});

    var f1: f80 = 12.34;
    std.debug.print("f1 (12.34):    {d}\n", .{@bitCast(u80, f1)});
    f1 -= 0;
    std.debug.print("f1 (12.34 -0): {d}\n", .{@bitCast(u80, f1)});
    f1 += 0; // gives         302282575443171561271296
             // but should be 302282575443171561271460
    std.debug.print("f1 (12.34 +0): {d}\n", .{@bitCast(u80, f1)});
}

// # Windows (zig 0.10.0-dev.3475+b3d463c9e)
//PS C:\Users\user> C:\Users\user\zig\zig.exe test  .\src\test\behavior\cast.zig
//Test [1/1] test "coerce between pointers of compatible differently-named floats"...
//stage:      std.builtin.CompilerBackend.stage1
//12.34:      302282575443171561271460
//12.34 +0:   302282575443171561271460
//12.34 -0:   302282575443171561271460
//
//f1 (12.34):    302282575443171561271460
//f1 (12.34 -0): 302282575443171561271460
//f1 (12.34 +0): 302282575443171561271296 <--- diff
//All 1 tests passed.

// # Linux (zig 0.10.0-dev.1740+971ef7b9c)
//Test [1/1] test "coerce between pointers of compatible differently-named floats"... 
//stage:      std.builtin.CompilerBackend.stage1
//12.34:      302282575443171561271460
//12.34 +0:   302282575443171561271460
//12.34 -0:   302282575443171561271460
//
//f1 (12.34):    302282575443171561271460
//f1 (12.34 -0): 302282575443171561271460
//f1 (12.34 +0): 302282575443171561271460
//All 1 tests passed.
hdorio commented 2 years ago

This problem has been ongoing but masked by #12380.

While 12380 did mask the issue of the "+= on f80" highlighted by the test 6fde2fc coerce between pointers of compatible differently-named floats (2022-05-08) the issue predates 02902cc (2022-02-17).

// zig v0.10.0-dev.765+02902cc09
// zig run test.zig
const std = @import("std");

pub fn main() void {
  var f1: f80 = 12.34;
  std.debug.print("{d}\n", .{@bitCast(u80, f1)}); //              302282575443171561271460
  f1 += 0;
  std.debug.print("{d}\n", .{@bitCast(u80, f1)}); //              302282575443171561271296
  std.debug.print("{d}\n", .{@bitCast(u80, @as(f80, 12.34))}); // 302282575443171561271460
}
hdorio commented 1 year ago

+= 0 on type f80 is now fixed in version 0.11.0-dev.1025+aadd1b252, but += 1 is still broken.

For what it's worth, the problem only appears in Debug mode with no Link Time Optimization (LTO).

// zig version 0.11.0-dev.1025+aadd1b252
// test.zig
const std = @import("std");

pub fn main() void {
    var f1: f80 = 12.34;
    std.debug.print("{d}\n", .{@bitCast(u80, f1)});
    f1 += 1;
    std.debug.print("{d}\n", .{@bitCast(u80, f1)});
    std.debug.print("{d}\n", .{@bitCast(u80, @as(f80, 12.34) + 1)});
}

// $ zig2.exe run -ODebug -flto test.zig
// 302282575443171561271460
// 302283728364676168118436
// 302283728364676168118436
//
// $ zig2.exe run -ODebug -fno-lto test.zig
// 302282575443171561271460
// 302283728364676168118272 <--- this is wrong (last bits of f80 seem truncated)
// 302283728364676168118436
//
// -OReleaseFast and -OReleaseSmall work with or without LTO

When launching the failing test with LTO, the test "coerce between pointers of compatible differently-named floats" passed on Windows. .\build\zig2.exe test .\test\behavior.zig -flto --test-name-prefix behavior-native-Debug-bare-multi-default --name test

hdorio commented 1 year ago

I think I found the issue.

On Windows, the FPU Control Word (fctrl) register is set to double precision (0x027f) by default instead of double extended-precision (0x037f).

Changing the precision to double extended-precision or using finit at the beginning of the program should fix the problem.

As a side note, linking to libc -lc also fixes the problem; my guess is that libc initializes fctrl correctly at the start.

``` const std = @import("std"); pub fn main() !void { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const env_map = try arena.allocator().create(std.process.EnvMap); env_map.* = try std.process.getEnvMap(arena.allocator()); defer env_map.deinit(); const num = env_map.get("NUM") orelse ""; _ = asm volatile ("finit"); // set fctrl to 0x037f var f1: f80 = 12.34; std.debug.print("value f1 : {d}\n", .{@bitCast(u80, f1)}); // 302282575443171561271460 f1 += @intToFloat(f80, num.len); std.debug.print("value f1 +num: {d}\n", .{@bitCast(u80, f1)}); // `NUM=1 wine ./zig.exe run test.zig` #=> 302283728364676168118436 } ```