code wiki / (root) / nx_f64_gate.nx

nx_f64_gate.nx

buildroot/runtime/nx_f64_gate.nx

45837 B801 linesdepth 4pulls 7 transitivereach 0 importersview sourcekind gate/prooftopic f64
docsdependenciesstructsconstsfunctions

about

nx_f64_gate.nx -- LN16 "WORKING f64 ARITHMETIC": the x86_64 backend's IEEE-754 binary64 arithmetic AND ordering, measured BIT FOR BIT against independent software implementations of the same standard. WHAT THIS MEASURES THAT THE INCUMBENT CANNOT. nx_f64_adversary (T12, shipped 2026-07-16) is a DECIMAL instrument: every check truncates a scaled product to six or nine digits and compares a hand-typed integer. That shape cannot see a one-ulp error, cannot say WHICH bit moved, and asks the reader to take six magic constants on trust. It also compares only NON-NEGATIVE values, which is why it never found the ordering defect this gate reports. Every expectation here is DERIVED at run time from nx_f64_oracle_sov (orc_add/orc_sub/orc_mul/ orc_div) and nx_f64 (nx_f64_lt/gt/eq) -- pure-integer implementations whose anchor proof is the 1217 hardware-IEEE KAT values in _f64_soak_gate_authored. There is not one hand-typed floating-point constant in this file, and operand bit patterns come from nx_i64_to_f64, a THIRD path, so an operand and its expectation are never produced by the same code. WHY BITS AND NOT PRINTED DECIMALS. Two doubles one ulp apart print identically at nine significant digits. The defect this rung exists to remove -- f64 arithmetic silently executed at single precision -- is a low-mantissa error, so a decimal comparison is precisely the instrument that cannot see the end of it. WHY ORDERING IS IN SCOPE. A double rides in an i64 register, and x86ctx_emit_cmp lowers EVERY compare to a signed integer cmpq on those bits. Among two negative doubles the signed-integer order is the REVERSE of the numeric order, so `-1.0 < -2.0` evaluates TRUE. The rung's own done-rule program compares two f64 values, so ordering is already inside the capability the row claims; flipping the row while `<` is inverted would publish a capability that is not there. Tooth `neg-control-chosen-negative-pair-is-exactly-where-integer-compare-fails` proves the operands chosen are the discriminating ones and not a lucky pair. HOW A FIXTURE REPORTS. A wait status carries eight bits of exit code. A value fixture returns 0 when the bits matched and F6_EXITBASE + k when the HIGHEST differing bit is k (2..65, inside 255), so a failure NAMES the field that moved: 63 sign, 52..62 exponent, 0..51 significand. A predicate fixture returns F6_EXITBASE + the boolean the compiler actually produced, so a failure says which way it went. A pass/fail bit would have said only "wrong". HOW THE BITS ARE READ. NishiLang carries an f64 in an i64 register and `as` is a BIT-REINTERPRET, never a value conversion -- only the __f64_to_i64 intrinsic

dependencies 6 imports · 0 importers

nx_syscalls.nx nx_gate_verdict.nx nx_ccbuild_lib.nx nx_f64.nx nx_f64_cvt.nx nx_f64_oracle_sov.nx nx_f64_gate.nx

imports: nx_syscalls.nxnx_gate_verdict.nxnx_ccbuild_lib.nxnx_f64.nxnx_f64_cvt.nxnx_f64_oracle_sov.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main sys_ignore_sigpipe sys_mmap nxa_die sys_write sys_exit nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ gv_puts sys_write ↻ sys_exit ↻ cb_anchor_root sys_openat_rd sys_close sys_chdir sys_mmap ↻ sys_mkdir sys_mmap ↻ sys_openat_wr gv_head gv_puts ↻ gv_num sys_mmap ↻ sys_write ↻ sys_munmap cb_fsize sys_openat_rd ↻ sys_lseek sys_close ↻ nx_i64_to_f64 _f64_round_pack

structs

none

consts

80const F6_EXIT_USAGE: i64 = 2
81const F6_EXIT_NOTREE: i64 = 4
82const F6_MODE_0644: i64 = 0x1a4
83const F6_MODE_0755: i64 = 0x1ed
86const F6_BITS: i64 = 64
90const F6_EXITBASE: i64 = 2
92const F6_WAIT_SHIFT: i64 = 8
93const F6_WAIT_MASK: i64 = 255
95const F6_DIGITS_MAX: i64 = 20
96const F6_PATH_CAP: i64 = 4096 // Linux PATH_MAX
99const F6_INT_N: i64 = 100
100const F6_INT_MUL: i64 = 3
101const F6_INT_SUB: i64 = 1
105const F6_ACASES: i64 = 12
106const F6_PSLOT: i64 = 20
107const F6_PCASES: i64 = 6
108const F6_SLOT_NAN: i64 = 30 // LN38: the IEEE-unordered fixture program
109const F6_SLOT_LIT: i64 = 31 // LN36/LN40: exponent and long-literal packing fixture
110const F6_SLOT_CONST: i64 = 32 // LN39: f64 const-expression fixture
111const F6_SLOT_IOVER: i64 = 33 // LN40: integer literal that exceeds i64 must be REFUSED
112const F6_SLOT_EXP: i64 = 34 // LN36: a malformed exponent must be REFUSED
113const F6_SLOT_IMAX: i64 = 35 // neg-control: the largest i64 literal still compiles
114const F6_SLOT_U64: i64 = 36 // positive control: a u64-range decimal keeps its bit pattern (FNV constants)
118const F6_CCLOG_READ_CAP: i64 = 65536
119const F6_SLOT_PROBE: i64 = 80
120const F6_SLOT_INT_A: i64 = 90
121const F6_SLOT_INT_B: i64 = 91
122const F6_SLOTS: i64 = 92

functions

124func f6_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
130func f6_t0() -> *u8 { return "func main(argc: i64, argv: *i64) -> i64 {\n\x00" as *u8 }
called by 1: f6_build_src
131func f6_t1() -> *u8 { return " let r: f64 = \x00" as *u8 }
called by 1: f6_build_src
132func f6_t2() -> *u8 { return "\n let got: i64 = r as i64\n let want: i64 = \x00" as *u8 }
called by 1: f6_build_src
133func f6_t3() -> *u8 { return "\n if got == want { return 0 }\n var k: i64 = \x00" as *u8 }
called by 1: f6_build_src
134func f6_t4() -> *u8 { return "\n while k >= 0 {\n let gb: i64 = (got >> k) & 1\n let wb: i64 = (want >> k) & 1\n if gb > wb { return \x00" as *u8 }
called by 1: f6_build_src
135func f6_t5() -> *u8 { return " + k }\n if wb > gb { return \x00" as *u8 }
called by 1: f6_build_src
136func f6_t6() -> *u8 { return " + k }\n k = k - 1\n }\n return 1\n}\n\x00" as *u8 }
called by 1: f6_build_src
139func f6_q0() -> *u8 { return "func main(argc: i64, argv: *i64) -> i64 {\n let a: f64 = \x00" as *u8 }
called by 1: f6_pred_src
140func f6_q1() -> *u8 { return "\n let b: f64 = \x00" as *u8 }
called by 1: f6_pred_src
141func f6_q2() -> *u8 { return "\n var got: i64 = 0\n if a \x00" as *u8 }
called by 1: f6_pred_src
142func f6_q3() -> *u8 { return " b { got = 1 }\n let want: i64 = \x00" as *u8 }
called by 1: f6_pred_src
143func f6_q4() -> *u8 { return "\n if got == want { return 0 }\n return \x00" as *u8 }
called by 1: f6_pred_src
144func f6_q5() -> *u8 { return " + got\n}\n\x00" as *u8 }
called by 1: f6_pred_src
146func f6_d0() -> *u8 { return " let a: f64 = \x00" as *u8 }
called by 1: f6_decls2
147func f6_d1() -> *u8 { return "\n let b: f64 = \x00" as *u8 }
called by 1: f6_decls2
148func f6_d2() -> *u8 { return "\n\x00" as *u8 }
called by 1: f6_decls2
149func f6_c0() -> *u8 { return "__f64_from_i64(\x00" as *u8 }
called by 1: f6_fromi
150func f6_c1() -> *u8 { return ")\x00" as *u8 }
called by 1: f6_fromi
151func f6_n0() -> *u8 { return "0 - \x00" as *u8 }
called by 1: f6_catwant
156func f6_catwant(b: *u8, o: i64, v: i64) -> i64
called by 1: f6_build_src calls 3: gv_catngv_catf6_n0
162func f6_build_src(decls: *u8, expr: *u8, want: i64, outlen: *i64) -> *u8
called by 1: f6_case calls 12: f6_slenf6_t0f6_t1f6_t2f6_t3f6_t4+6
185func f6_pred_src(aexpr: *u8, bexpr: *u8, op: *u8, want: i64, outlen: *i64) -> *u8
206func f6_decls2(a: *u8, b: *u8) -> *u8
222func f6_fromi(n: i64) -> *u8
232func f6_path(pre: *u8, idx: i64, suf: *u8) -> *u8
called by 2: f6_tmpf6_bld calls 3: sys_mmapgv_catgv_catn
240func f6_tmp(idx: i64, suf: *u8) -> *u8 { return f6_path("/tmp/nx_f64_gate/c\x00" as *u8, idx, suf) }
called by 3: f6_build_runf6_run_srcmain calls 1: f6_path
241func f6_bld(idx: i64, suf: *u8) -> *u8 { return f6_path("_build/nx_f64_gate_c\x00" as *u8, idx, suf) }
called by 3: f6_build_runf6_reportmain calls 1: f6_path
243func f6_write(path: *u8, s: *u8, n: i64) -> i64
253func f6_build_run(cc: *u8, idx: i64, p_nx: *u8, envp: *i64, devnull: i64, out: *i64) -> i64
273func f6_run_src(cc: *u8, idx: i64, src: *u8, srclen: i64, envp: *i64, devnull: i64, out: *i64) -> i64
279func f6_report(idx: i64, label: *u8, want: i64, kindbits: i64, out: *i64) -> i64
299func f6_case(cc: *u8, idx: i64, label: *u8, decls: *u8, expr: *u8, want: i64,
310func f6_pcase(cc: *u8, idx: i64, label: *u8, aexpr: *u8, bexpr: *u8, op: *u8, want: i64,
323func f6_nan_src() -> *u8
called by 1: main
325func fx_id(x: f64) -> f64 { return x }
326func main() -> i64
353func f6_lit_src() -> *u8 { return "func fx_id(x: f64) -> f64 { return x }\nfunc main() -> i64 {\n var bad: i64 = 0\n let ten9: f64 = fx_id(1000000000.0)\n let e21: f64 = fx_id(1000000000000000000000.0)\n let e20: f64 = fx_id(100000000000000000000.0)\n if 1e9 != ten9 { bad = bad + 1 }\n if 2.5e-3 != fx_id(2.5) / fx_id(1000.0) { bad = bad + 2 }\n if 1e-9 != fx_id(1.0) / ten9 { bad = bad + 4 }\n if 6.02e23 != fx_id(602.0) * e21 { bad = bad + 8 }\n if 1e-20 != fx_id(1.0) / e20 { bad = bad + 16 }\n if 1E+2 != fx_id(100.0) { bad = bad + 32 }\n if 123.456e2 != fx_id(12345.6) { bad = bad + 64 }\n if 9007199254740993.0 != fx_id(9007199254740992.0) { bad = bad + 128 }\n if 9007199254740995.0 != fx_id(9007199254740996.0) { bad = bad + 256 }\n if 0.1 + 0.2 == 0.3 { bad = bad + 512 }\n if 1e400 <= 1e308 { bad = bad + 1024 }\n if 12345678901234567890.5 != fx_id(12345678901234567890.0) + fx_id(0.5) { bad = bad + 2048 }\n if 1e0 != fx_id(1.0) { bad = bad + 4096 }\n return bad\n}\n\x00" as *u8 }
354func f6_const_src() -> *u8 { return "const PI: f64 = 3.141592653589793\nconst HALF_PI: f64 = PI / 2.0\nconst TWO_PI: f64 = 2.0 * PI\nconst NEG_1P5: f64 = -1.5\nconst K: i64 = 3\nconst KF: f64 = K * 2.0\nconst E9: f64 = 1e9\nconst MIX: f64 = (PI - 1.0) / (K + 1)\nfunc fx_id(x: f64) -> f64 { return x }\nfunc main() -> i64 {\n var bad: i64 = 0\n let pi: f64 = fx_id(3.141592653589793)\n if HALF_PI != pi / fx_id(2.0) { bad = bad + 1 }\n if TWO_PI != fx_id(2.0) * pi { bad = bad + 2 }\n if NEG_1P5 != fx_id(0.0) - fx_id(1.5) { bad = bad + 4 }\n if KF != fx_id(6.0) { bad = bad + 8 }\n if E9 != fx_id(1000000000.0) { bad = bad + 16 }\n if MIX != (pi - fx_id(1.0)) / fx_id(4.0) { bad = bad + 32 }\n if PI != pi { bad = bad + 64 }\n return bad\n}\n\x00" as *u8 }
355func f6_iover_src() -> *u8 { return "func main() -> i64 {\n let x: i64 = 99999999999999999999\n if x == 0 { return 1 }\n return 0\n}\n\x00" as *u8 }
356func f6_badexp_src() -> *u8 { return "func main() -> i64 {\n let y: f64 = 1e-\n if y == 0.0 { return 1 }\n return 0\n}\n\x00" as *u8 }
357func f6_imax_src() -> *u8 { return "func main() -> i64 {\n let x: i64 = 9223372036854775807\n if x == 9223372036854775807 { return 0 }\n return 1\n}\n\x00" as *u8 }
359func f6_u64_src() -> *u8 { return "func main() -> i64 {\n let x: i64 = 18446744073709551615\n let y: i64 = 14695981039346656037\n if x != 0 - 1 { return 1 }\n if y == 0 { return 2 }\n return 0\n}\n\x00" as *u8 }
363func f6_file_has(path: *u8, needle: *u8) -> i64
386func f6_int_sum() -> i64
392func f6_i0() -> *u8 { return "func main(argc: i64, argv: *i64) -> i64 {\n var s: i64 = 0\n var i: i64 = 0\n while i < \x00" as *u8 }
393func f6_i1() -> *u8 { return " {\n s = s + i * \x00" as *u8 }
394func f6_i2() -> *u8 { return " - \x00" as *u8 }
395func f6_i3() -> *u8 { return "\n i = i + 1\n }\n if s == \x00" as *u8 }
396func f6_i4() -> *u8 { return " { return 0 }\n return 1\n}\n\x00" as *u8 }
398func f6_int_src(outlen: *i64) -> *u8
416func main(argc: i64, argv: *i64) -> i64