summary_m2comp_step5.2.md 1.9 KB

m2comp step 5.2 — real-comparison codegen fix (tag: m2comp-step5.2)

The step-4 "VM-domain D5 quirk" (negative-vs-zero real comparisons) re-checked: the VM was innocent. Real < > <= >= never emitted D5 (0D5H) — only = / # did. The ordered comparisons emitted bare stack juggling, leaving a raw operand bit-pattern as the boolean (nonzero reads back TRUE). Fixed in both compilers' MGens; D5 itself needed no change (mcint and all images untouched). Suite 56/56 (new r_rcmp regression).

Reproduction

13-case probe (tests/r_rcmp.mod, powers-of-two encoding): -1.0</>/= 0.0, 0.0</>/= -1.0, -1.0</>/= -1.0, 0.0 = 0.0, -0.0</>/= 0.0 (via -1.0 * 0.0). Before: five </> results wrong (every < behaved per the wrong operand, every > likewise; = correct throughout, including -0.0 = 0.0). After: 31 (all 13 correct).

Root cause

EmitExpr lowered real </>/<=/>= to swap/drop/not sequences that are exactly right for D5 outputs on the stack — but never emitted the D5. So < yielded (right-operand ≠ 0), > yielded (left-operand ≠ 0), etc. It hid because most tests compare nonzero values. v1's MGen even documented the broken contract (RealLt: [gt lt] -> lt — inputs no caller provides); V2 had copied the recipe inline. Both compilers emitted identical bytes, hence the "reproduces under m2c" misdirection.

Fix

One OPrCmp prepended per sequence (contracts now [r1 r2]): < = cmp,swap,drop (keep lt); <= = cmp,drop,not; > = cmp,drop (keep gt); >= = cmp,swap,drop,not. Same four lines in m2compiler-v1/src/MGen.mod (RealLt/Le/Gt/Ge, comments corrected); r_real/t_real expectations needed no change (they were written for correct semantics and now pass genuinely).

Note corrections

Step-4's "Non-bugs established by bisection" entry and the steps 1–4 wrap-up's "Hard-won facts" entry blamed the VM; both now carry a [Correction (step 5.2)] annotation pointing here.