diff --git a/FIX.org b/FIX.org index b8802dc..da2a620 100644 --- a/FIX.org +++ b/FIX.org @@ -675,9 +675,11 @@ the dev loop's default backend, which is what turned a backend gap into a thing the author hit while writing ordinary code. Fixed by calling the same function LLVM calls. There is no SSE remainder -instruction and LLVM does not invent one: at -O0 it lowers frem to fmod or -fmodf, which objdump shows as a call to the PLT stub in any build of a program -with a typed float % in it. x86.ml now loads the two operands into xmm0 and +instruction and LLVM does not invent one: a frem that reaches the code +generator becomes a call to fmod or fmodf, which objdump shows as a call to +the PLT stub — fourteen of them in a build of the probe whose operands come +through globals, and none at all in one written with float literals, where the +pair is folded to its answer before any call exists. x86.ml now loads the two operands into xmm0 and xmm1 — already the SysV argument registers — and calls fmod or fmodf by width. Agreement is then by construction rather than by a second hand-written identity that would have to get every rounding, every signed zero and every @@ -702,13 +704,14 @@ build. So a corpus program that exercises a construct is already a test that the two backends agree about it, and the float % cases added to math3.flan are in that set by being in test/programs. -What @x86 does not do is fix the LLVM side at -O0. It builds both sides with -whatever the default optimisation is, so a construct LLVM folds at compile -time — a % over two float literals is one; the operator never survives to the -IR — is compared as a constant against the x86 backend's actual lowering. The -float % block in math3.flan goes through globals for that reason, the same -reason arith.flan gives for its own. Two things would close the rest of the -gap: a SURVEY_FLAGS=-O0 pass, so the LLVM side emits the calls and branches -rather than the answers, and something that walks the two prim match arms -mechanically rather than relying on somebody reading them side by side, which -is how this gap survived. Neither is queued. +What @x86 does not do is pin the LLVM side at -O0. It builds both sides at the +default -O2, so a construct LLVM folds at compile time — a % over two float +literals is one: that build contains no fmod call — is compared as a constant +against the x86 backend's actual lowering. The float % block in math3.flan +goes through globals for that reason, the same reason arith.flan gives for its +own. Two things would close the rest of the gap: an -O0 pass of the sweep, so +the LLVM side emits the calls and branches rather than the answers — the +script already has SURVEY_FLAGS, which hands the same extra flags to both +sides, and both sides do accept -O0 — and something that walks the two prim +match arms mechanically rather than relying on somebody reading them side by +side, which is how this gap survived. Neither is queued. diff --git a/lib/x86.ml b/lib/x86.ml index 528f0bf..97cd423 100644 --- a/lib/x86.ml +++ b/lib/x86.ml @@ -2762,10 +2762,15 @@ and prim f (e : Tast.expr) (p : Tast.prim) (args : Tast.expr list) dst = fload f.b ~dst:1 ~mm:(lmem f lb ~scratch:r11) ~f64; (match p with (* There is no SSE remainder instruction, and LLVM does not pretend - otherwise: at -O0 it lowers [frem] to a call to C's [fmod] or - [fmodf], which `objdump -d` on any build of a program containing a - typed float [%] shows as a [call fmod@plt]. Calling the same - function is what makes the two backends agree by construction + otherwise: it lowers a [frem] that reaches the code generator to a + call to C's [fmod] or [fmodf], which is what `objdump -d` shows as a + [call fmod@plt] in a build whose operands come through globals. A + [%] over two float literals is folded on the way and contains no + call at all, which is why the corpus block that covers this uses + globals — a folded answer is evidence about the folder. + + Calling the same function is what makes the two backends agree by + construction rather than by a hand-written identity that would have to get every rounding, every sign of zero and every infinity right on its own. The prelude already declares both symbols ([fmod-f32],