# 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.