Repository navigation
t27b: @intFromFloat of a NaN gives 0, the x86_64 reference gives a target value #7445
Description
Refs #6063.
Problem
t27b passes three probe files that the reference fails. Each one converts a NaN with @intFromFloat.
- The reference:
t27c test-reportrunszig teston the x86_64 lab host.@intFromFloatof a NaN does not trap there: Zig's out-of-range safety check is two ordered comparisons, and both are false for a NaN. The value that comes out is whatever the x86_64 instruction gives, and it is not 0. For example,cvttsd2sigives0x80000000for an i32. In Zig this is illegal behaviour, and the value depends on the target. - t27b: its codegen (
cli/t27b/src/codegen.rs,ExprKind::FloatToInt) and evaluator (eval.rs) turn a NaN into 0. That is what FCVTZ* does on AArch64. The comment in codegen calls this "what Zig 0.16 Debug does". That is true on AArch64, but the reference runs on x86_64.
Evidence (lab, t27b built at 6dc75fe)
Each probe is a module P with fn to_usize(x: f64) -> usize { const i: usize = @intFromFloat(x); return i; }, the same for i32, and pick(x) = T[@intFromFloat(x)] over const T: [2]f64. The NaN comes from inf - inf at run time.
| probe | reference | t27b |
|---|---|---|
to_usize(nan) == 0 |
FAIL | PASS |
const i = to_usize(nan); i == i |
pass | PASS |
to_i32(nan) == 0 |
FAIL | PASS |
pick(nan) == 5.0 (index 0) |
FAIL | PASS |
control to_usize(3.7) == 3, pick(1.2) == 6.0 |
pass | PASS |
The same thing showed up as a mutation survivor in specs/tri/t27b/libm.t27. Removing the port's NaN guard sends a NaN into the table index. The reference then fails the NaN test, but t27b still returns NaN through index 0 and passes.
No corpus file reaches this today: corpus mismatch is 0. Still, it is a place where t27b can report a pass that the reference does not give.
Options
- Trap on a NaN operand with a kind that reports the test as not reproducible (the reference's value is target-defined illegal behaviour), not as a pass or a plain fail.
- Copy the x86_64 values (
0x8000...patterns). This ties t27b to the reference host's ISA. - Keep 0 and document the gap in the ledger and the docs.
Option 1 is the honest default. It never reports a pass the reference does not give.
Boundary
specs/tri/t27b/libm.t27cli/t27b/src/codegen.rs
User Scenarios
- Given a t27b probe that converts a runtime NaN to an integer via
@intFromFloat, when the probe runs under t27b, then t27b reports the test as not reproducible rather than passing with value 0. - Given the reference x86_64 behavior where
@intFromFloatof NaN produces a target-defined illegal value (e.g.,0x80000000for i32), when t27b encounters the same operation, then it must not report a pass that the reference does not give.
Requirements
FR-001: t27b MUST trap on NaN operand in @intFromFloat and report the test as not reproducible.
FR-002: The not-reproducible result MUST be distinct from pass and plain fail in the test report.
FR-003: The change MUST apply to both codegen (cli/t27b/src/codegen.rs) and evaluator paths.
FR-004: Existing non-NaN float-to-int conversions MUST continue to produce correct results.
Success Criteria
t27c test-reporton the three NaN probe files reports "not reproducible" for each NaN case (exit 0)- The mutation survivor in
specs/tri/t27b/libm.t27no longer passes spuriously; the NaN index test reports not reproducible (exit 0) - Control probes (e.g.,
to_usize(3.7) == 3) continue to pass (5 tests pass,exit 0)
Activity
t27b ledger: @log moves gen_cross_entropy to pass, 823 -> 827 with @exp…
gHashTag commentedon Oct 7, 2026
Reopened 2026-10-07: the bulk close of issues without a
## Boundarysection was reverted by the owner. Nothing to do here; this comment replaces the earlier close notice.