From 56253d9e31c0576f024d95929a8fe26428b35176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Sun, 15 Feb 2026 20:41:19 +0000 Subject: [PATCH] x86_64 codegen: fix RoundMode vroundss immediate value Quoting Vol. 2B 4-590 of [Intel SSA manual][1]: > Bit 3 of the immediate byte controls processor behavior for a precision exception <...> The Direction struct is incorrectly sized to 4 bits, which pushes the precision exception bit to the reserved bits, which helpfully crashes under valgrind (but works on real hardware, since CPU ignores it): `` const std = @import("std"); noinline fn ceil(x: f32) f32 { return @ceil(x); } test "ceil" { try std.testing.expectEqual(@as(f32, 2.0), ceil(1.5)); } ``` With Zig 0.15.1: ``` $ zig test -fno-llvm -mcpu x86_64_v3 -fvalgrind ceil_test.zig --test-cmd valgrind --test-cmd --quiet --test-cmd-bin Illegal instruction at address 0x102d14d /home/motiejus/code/ceil_test.zig:4:5: 0x102d14d in ceil (ceil_test.zig) return @ceil(x); ^ /home/motiejus/code/ceil_test.zig:8:52: 0x102d097 in test.ceil (ceil_test.zig) try std.testing.expectEqual(@as(f32, 2.0), ceil(1.5)); ^ /nix/store/n81qdpd96d86ngfv5bqymy26b8kqm654-zig-0.15.1/lib/compiler/test_runner.zig:218:25: 0x1167e80 in mainTerminal (test_runner.zig) if (test_fn.func()) |_| { ^ /nix/store/n81qdpd96d86ngfv5bqymy26b8kqm654-zig-0.15.1/lib/compiler/test_runner.zig:66:28: 0x11610a1 in main (test_runner.zig) return mainTerminal(); ^ /nix/store/n81qdpd96d86ngfv5bqymy26b8kqm654-zig-0.15.1/lib/std/start.zig:618:22: 0x115ae3d in posixCallMainAndExit (std.zig) root.main(); ^ /nix/store/n81qdpd96d86ngfv5bqymy26b8kqm654-zig-0.15.1/lib/std/start.zig:232:5: 0x115a6d1 in _start (std.zig) asm volatile (switch (native_arch) { ^ ???:?:?: 0x0 in ??? (???) error: the following test command crashed: valgrind --quiet /home/motiejus/.cache/zig/o/7cc564b5410fc3facdb6e8768643074e/test ``` Zig 0.15.1 with this patch: ``` zig/zig3 test -fno-llvm -mcpu x86_64_v3 -fvalgrind ceil_test.zig --test-cmd valgrind --test-cmd --quiet --test-cmd-bin All 1 tests passed. ``` Looking through `CodeGen.zig` it _seems_ like the same RoundMode struct is used for vroundss/vroundps/vcvtps2ph, so update the comment while we're at it. But I am only 90% sure it's true. [1]: https://cdrdv2.intel.com/v1/dl/getContent/671200 --- src/codegen/x86_64/bits.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/codegen/x86_64/bits.zig b/src/codegen/x86_64/bits.zig index 05048109335e0256d91c5f350d7fa900ce08e402..452518e14e90c40c14aebc4f0718f89bc31dc338 100644 --- a/src/codegen/x86_64/bits.zig +++ b/src/codegen/x86_64/bits.zig @@ -178,15 +178,15 @@ pub const Condition = enum(u5) { } }; -/// The immediate operand of vcvtps2ph. -pub const RoundMode = packed struct(u5) { +/// The immediate operand of vroundss/vroundps/vcvtps2ph/round??. +pub const RoundMode = packed struct(u4) { direction: Direction = .mxcsr, precision: enum(u1) { normal = 0b0, inexact = 0b1, } = .normal, - pub const Direction = enum(u4) { + pub const Direction = enum(u3) { /// Round to nearest (even) nearest = 0b0_00, /// Round down (toward -∞) -- 2.54.0