wcc: widen-push spills the float payload from X0, both stages
Widening a runtime f64 into a tagged slot pushed a stale AX as the payload while the value sat in X0 — both stages shared the push bug (float literals dodged it because TK_FLOAT loads AX too); the divergent pop sides then produced different garbage. Spill the payload from X0 (MOVSD) with the variant tag. Review item #49. Both stages move in one commit: one emission contract; splitting would leave the byte-id gates red between the halves.
This commit is contained in:
@@ -97,6 +97,32 @@ static const struct row rows[] = {
|
||||
" let d: f64 = 3.5;\n"
|
||||
" return g(d);\n"
|
||||
"};\n", 2, K_RUN, NULL },
|
||||
/* #49 (#263 both-stages): a RUNTIME f64 producer (mk) feeds a value
|
||||
* widened into (f64|void), and the f64 arm READS the payload
|
||||
* (d == 2.5). Pre-fix the widen-PUSH did `PUSHQ AX` for the payload
|
||||
* while the f64 sat in X0, so d read stale bits → 1 (cs) / 3 (ww,
|
||||
* the #48 pop divergence compounding). #48's arm dodged this by not
|
||||
* reading the payload; this one catches the stale-AX push. Both
|
||||
* stages now spill X0 → 0. (After the c4 drain fix the two stages
|
||||
* already agree on the pop; this push fix closes the shared bug.) */
|
||||
{ "runtime_float_widen_payload",
|
||||
"package main;\n"
|
||||
"type fv = (f64 | void);\n"
|
||||
"fn mk(x: f64) f64 = { return x + 1.5; };\n"
|
||||
"fn take(v: fv) i32 = {\n"
|
||||
" match (v) {\n"
|
||||
" case let d: f64 => {\n"
|
||||
" if (d == 2.5) { return 0; };\n"
|
||||
" return 1;\n"
|
||||
" };\n"
|
||||
" case void => { return 2; };\n"
|
||||
" };\n"
|
||||
" return 3;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let d: f64 = mk(1.0);\n"
|
||||
" return take(d);\n"
|
||||
"};\n", 0, K_RUN, NULL },
|
||||
};
|
||||
|
||||
static int
|
||||
|
||||
Reference in New Issue
Block a user