diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 8bab1485..64f75874 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -19774,7 +19774,8 @@ fn cgexpr(c: *cgen, n: *node) void = { if (n == nil) { return; }; let k: nkind = n.kind; - if (k == nkind.N_INTLIT) { + switch (k) { + case nkind.N_INTLIT: // A no-decimal `0f64`/`8f64` is an N_INTLIT carrying float // TYPE; it must reach X0 like a true float literal, not the // integer-immediate path (which strands it in AX and an SSE @@ -19802,8 +19803,7 @@ fn cgexpr(c: *cgen, n: *node) void = { emitint(n.uval: i64); emitline(", AX\n"); return; - }; - if (k == nkind.N_FLOATLIT) { + case nkind.N_FLOATLIT: // The bits come from n.uval — the parser populates it from // the lexer's bitcast of t.fval. cgfloatbits(c, n.uval); @@ -19812,71 +19812,55 @@ fn cgexpr(c: *cgen, n: *node) void = { emitline("\tCVTSD2SS\tX0, X0\n"); }; return; - }; - if (k == nkind.N_RUNELIT) { + case nkind.N_RUNELIT: emitline("\tMOVQ\t$"); emitint(n.uval: i64); emitline(", AX\n"); return; - }; - if (k == nkind.N_STRLIT) { cgstrlit(c, n); return; }; - if (k == nkind.N_TRUE) { + case nkind.N_STRLIT: cgstrlit(c, n); return; + case nkind.N_TRUE: emitline("\tMOVQ\t$1, AX\n"); return; - }; - if (k == nkind.N_FALSE) { + case nkind.N_FALSE: emitline("\tMOVQ\t$0, AX\n"); return; - }; - if (k == nkind.N_NIL) { + case nkind.N_NIL: emitline("\tMOVQ\t$0, AX\n"); return; - }; - if (k == nkind.N_VOIDLIT) { + case nkind.N_VOIDLIT: // void value: zero-size, but the consumer's ABI expects a // deterministic AX. Emit 0 like nil/false do. emitline("\tMOVQ\t$0, AX\n"); return; - }; - - if (k == nkind.N_IDENT) { cgident(c, n); return; }; - - if (k == nkind.N_INDEX) { cgindex(c, n); return; }; - - if (k == nkind.N_SLICE) { cgslice(c, n); return; }; - - if (k == nkind.N_MATCH) { cgmatch(c, n); return; }; - - if (k == nkind.N_CAST) { cgcast(c, n); return; }; - - if (k == nkind.N_DOT) { cgdot(c, n); return; }; - - if (k == nkind.N_UN) { cgun(c, n); return; }; - - if (k == nkind.N_BIN) { cgbin(c, n); return; }; - - if (k == nkind.N_CALL) { cgcall(c, n); return; }; - - if (k == nkind.N_ASSIGN) { cgassign(c, n); return; }; - - if (k == nkind.N_TRYPROP) { cgtryprop(c, n); return; }; - if (k == nkind.N_TRYUNW) { cgtryunw(c, n); return; }; - if (k == nkind.N_TYPETEST) { cgtypetest(c, n); return; }; - if (k == nkind.N_TYPEASSERT) { cgtypeassert(c, n); return; }; - if (k == nkind.N_TUPLE) { + case nkind.N_IDENT: cgident(c, n); return; + case nkind.N_INDEX: cgindex(c, n); return; + case nkind.N_SLICE: cgslice(c, n); return; + case nkind.N_MATCH: cgmatch(c, n); return; + case nkind.N_CAST: cgcast(c, n); return; + case nkind.N_DOT: cgdot(c, n); return; + case nkind.N_UN: cgun(c, n); return; + case nkind.N_BIN: cgbin(c, n); return; + case nkind.N_CALL: cgcall(c, n); return; + case nkind.N_ASSIGN: cgassign(c, n); return; + case nkind.N_TRYPROP: cgtryprop(c, n); return; + case nkind.N_TRYUNW: cgtryunw(c, n); return; + case nkind.N_TYPETEST: cgtypetest(c, n); return; + case nkind.N_TYPEASSERT: cgtypeassert(c, n); return; + case nkind.N_TUPLE: // #241: a literal tuple rvalue `(a, b)` is a value — pack its // elements into the register cursor (mirror cgreturn's N_TUPLE // arm) so a let-bind / destructure consumer reads every element, // not just AX = 0 from the default arm below. cgtuplelittocursor(c, n); return; + case: + // Default fallback: produce a deterministic AX = 0. Mirrors + // the C cgen's `default: cgexpr_int(c, 0)` branch, which is + // what `return eof{};` (N_STRUCTLIT with an empty !void + // variant) silently relies on — without this AX carries a + // stale value into the tagged-union return shuffle. + emitline("\tMOVQ\t$0, AX\n"); }; - // Default fallback: produce a deterministic AX = 0. Mirrors - // the C cgen's `default: cgexpr_int(c, 0)` branch, which is - // what `return eof{};` (N_STRUCTLIT with an empty !void - // variant) silently relies on — without this AX carries a - // stale value into the tagged-union return shuffle. - emitline("\tMOVQ\t$0, AX\n"); }; // cgtagvariantidx — find the 0-based variant index of `vt` inside the diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index ddf2e7f3..7bdeedf0 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -38,7 +38,8 @@ fn cgexpr(c: *cgen, n: *node) void = { if (n == nil) { return; }; let k: nkind = n.kind; - if (k == nkind.N_INTLIT) { + switch (k) { + case nkind.N_INTLIT: // A no-decimal `0f64`/`8f64` is an N_INTLIT carrying float // TYPE; it must reach X0 like a true float literal, not the // integer-immediate path (which strands it in AX and an SSE @@ -66,8 +67,7 @@ fn cgexpr(c: *cgen, n: *node) void = { emitint(n.uval: i64); emitline(", AX\n"); return; - }; - if (k == nkind.N_FLOATLIT) { + case nkind.N_FLOATLIT: // The bits come from n.uval — the parser populates it from // the lexer's bitcast of t.fval. cgfloatbits(c, n.uval); @@ -76,71 +76,55 @@ fn cgexpr(c: *cgen, n: *node) void = { emitline("\tCVTSD2SS\tX0, X0\n"); }; return; - }; - if (k == nkind.N_RUNELIT) { + case nkind.N_RUNELIT: emitline("\tMOVQ\t$"); emitint(n.uval: i64); emitline(", AX\n"); return; - }; - if (k == nkind.N_STRLIT) { cgstrlit(c, n); return; }; - if (k == nkind.N_TRUE) { + case nkind.N_STRLIT: cgstrlit(c, n); return; + case nkind.N_TRUE: emitline("\tMOVQ\t$1, AX\n"); return; - }; - if (k == nkind.N_FALSE) { + case nkind.N_FALSE: emitline("\tMOVQ\t$0, AX\n"); return; - }; - if (k == nkind.N_NIL) { + case nkind.N_NIL: emitline("\tMOVQ\t$0, AX\n"); return; - }; - if (k == nkind.N_VOIDLIT) { + case nkind.N_VOIDLIT: // void value: zero-size, but the consumer's ABI expects a // deterministic AX. Emit 0 like nil/false do. emitline("\tMOVQ\t$0, AX\n"); return; - }; - - if (k == nkind.N_IDENT) { cgident(c, n); return; }; - - if (k == nkind.N_INDEX) { cgindex(c, n); return; }; - - if (k == nkind.N_SLICE) { cgslice(c, n); return; }; - - if (k == nkind.N_MATCH) { cgmatch(c, n); return; }; - - if (k == nkind.N_CAST) { cgcast(c, n); return; }; - - if (k == nkind.N_DOT) { cgdot(c, n); return; }; - - if (k == nkind.N_UN) { cgun(c, n); return; }; - - if (k == nkind.N_BIN) { cgbin(c, n); return; }; - - if (k == nkind.N_CALL) { cgcall(c, n); return; }; - - if (k == nkind.N_ASSIGN) { cgassign(c, n); return; }; - - if (k == nkind.N_TRYPROP) { cgtryprop(c, n); return; }; - if (k == nkind.N_TRYUNW) { cgtryunw(c, n); return; }; - if (k == nkind.N_TYPETEST) { cgtypetest(c, n); return; }; - if (k == nkind.N_TYPEASSERT) { cgtypeassert(c, n); return; }; - if (k == nkind.N_TUPLE) { + case nkind.N_IDENT: cgident(c, n); return; + case nkind.N_INDEX: cgindex(c, n); return; + case nkind.N_SLICE: cgslice(c, n); return; + case nkind.N_MATCH: cgmatch(c, n); return; + case nkind.N_CAST: cgcast(c, n); return; + case nkind.N_DOT: cgdot(c, n); return; + case nkind.N_UN: cgun(c, n); return; + case nkind.N_BIN: cgbin(c, n); return; + case nkind.N_CALL: cgcall(c, n); return; + case nkind.N_ASSIGN: cgassign(c, n); return; + case nkind.N_TRYPROP: cgtryprop(c, n); return; + case nkind.N_TRYUNW: cgtryunw(c, n); return; + case nkind.N_TYPETEST: cgtypetest(c, n); return; + case nkind.N_TYPEASSERT: cgtypeassert(c, n); return; + case nkind.N_TUPLE: // #241: a literal tuple rvalue `(a, b)` is a value — pack its // elements into the register cursor (mirror cgreturn's N_TUPLE // arm) so a let-bind / destructure consumer reads every element, // not just AX = 0 from the default arm below. cgtuplelittocursor(c, n); return; + case: + // Default fallback: produce a deterministic AX = 0. Mirrors + // the C cgen's `default: cgexpr_int(c, 0)` branch, which is + // what `return eof{};` (N_STRUCTLIT with an empty !void + // variant) silently relies on — without this AX carries a + // stale value into the tagged-union return shuffle. + emitline("\tMOVQ\t$0, AX\n"); }; - // Default fallback: produce a deterministic AX = 0. Mirrors - // the C cgen's `default: cgexpr_int(c, 0)` branch, which is - // what `return eof{};` (N_STRUCTLIT with an empty !void - // variant) silently relies on — without this AX carries a - // stale value into the tagged-union return shuffle. - emitline("\tMOVQ\t$0, AX\n"); }; // cgtagvariantidx — find the 0-based variant index of `vt` inside the diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index 597d0a5a..ad5e6a3e 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -19774,7 +19774,8 @@ fn cgexpr(c: *cgen, n: *node) void = { if (n == nil) { return; }; let k: nkind = n.kind; - if (k == nkind.N_INTLIT) { + switch (k) { + case nkind.N_INTLIT: // A no-decimal `0f64`/`8f64` is an N_INTLIT carrying float // TYPE; it must reach X0 like a true float literal, not the // integer-immediate path (which strands it in AX and an SSE @@ -19802,8 +19803,7 @@ fn cgexpr(c: *cgen, n: *node) void = { emitint(n.uval: i64); emitline(", AX\n"); return; - }; - if (k == nkind.N_FLOATLIT) { + case nkind.N_FLOATLIT: // The bits come from n.uval — the parser populates it from // the lexer's bitcast of t.fval. cgfloatbits(c, n.uval); @@ -19812,71 +19812,55 @@ fn cgexpr(c: *cgen, n: *node) void = { emitline("\tCVTSD2SS\tX0, X0\n"); }; return; - }; - if (k == nkind.N_RUNELIT) { + case nkind.N_RUNELIT: emitline("\tMOVQ\t$"); emitint(n.uval: i64); emitline(", AX\n"); return; - }; - if (k == nkind.N_STRLIT) { cgstrlit(c, n); return; }; - if (k == nkind.N_TRUE) { + case nkind.N_STRLIT: cgstrlit(c, n); return; + case nkind.N_TRUE: emitline("\tMOVQ\t$1, AX\n"); return; - }; - if (k == nkind.N_FALSE) { + case nkind.N_FALSE: emitline("\tMOVQ\t$0, AX\n"); return; - }; - if (k == nkind.N_NIL) { + case nkind.N_NIL: emitline("\tMOVQ\t$0, AX\n"); return; - }; - if (k == nkind.N_VOIDLIT) { + case nkind.N_VOIDLIT: // void value: zero-size, but the consumer's ABI expects a // deterministic AX. Emit 0 like nil/false do. emitline("\tMOVQ\t$0, AX\n"); return; - }; - - if (k == nkind.N_IDENT) { cgident(c, n); return; }; - - if (k == nkind.N_INDEX) { cgindex(c, n); return; }; - - if (k == nkind.N_SLICE) { cgslice(c, n); return; }; - - if (k == nkind.N_MATCH) { cgmatch(c, n); return; }; - - if (k == nkind.N_CAST) { cgcast(c, n); return; }; - - if (k == nkind.N_DOT) { cgdot(c, n); return; }; - - if (k == nkind.N_UN) { cgun(c, n); return; }; - - if (k == nkind.N_BIN) { cgbin(c, n); return; }; - - if (k == nkind.N_CALL) { cgcall(c, n); return; }; - - if (k == nkind.N_ASSIGN) { cgassign(c, n); return; }; - - if (k == nkind.N_TRYPROP) { cgtryprop(c, n); return; }; - if (k == nkind.N_TRYUNW) { cgtryunw(c, n); return; }; - if (k == nkind.N_TYPETEST) { cgtypetest(c, n); return; }; - if (k == nkind.N_TYPEASSERT) { cgtypeassert(c, n); return; }; - if (k == nkind.N_TUPLE) { + case nkind.N_IDENT: cgident(c, n); return; + case nkind.N_INDEX: cgindex(c, n); return; + case nkind.N_SLICE: cgslice(c, n); return; + case nkind.N_MATCH: cgmatch(c, n); return; + case nkind.N_CAST: cgcast(c, n); return; + case nkind.N_DOT: cgdot(c, n); return; + case nkind.N_UN: cgun(c, n); return; + case nkind.N_BIN: cgbin(c, n); return; + case nkind.N_CALL: cgcall(c, n); return; + case nkind.N_ASSIGN: cgassign(c, n); return; + case nkind.N_TRYPROP: cgtryprop(c, n); return; + case nkind.N_TRYUNW: cgtryunw(c, n); return; + case nkind.N_TYPETEST: cgtypetest(c, n); return; + case nkind.N_TYPEASSERT: cgtypeassert(c, n); return; + case nkind.N_TUPLE: // #241: a literal tuple rvalue `(a, b)` is a value — pack its // elements into the register cursor (mirror cgreturn's N_TUPLE // arm) so a let-bind / destructure consumer reads every element, // not just AX = 0 from the default arm below. cgtuplelittocursor(c, n); return; + case: + // Default fallback: produce a deterministic AX = 0. Mirrors + // the C cgen's `default: cgexpr_int(c, 0)` branch, which is + // what `return eof{};` (N_STRUCTLIT with an empty !void + // variant) silently relies on — without this AX carries a + // stale value into the tagged-union return shuffle. + emitline("\tMOVQ\t$0, AX\n"); }; - // Default fallback: produce a deterministic AX = 0. Mirrors - // the C cgen's `default: cgexpr_int(c, 0)` branch, which is - // what `return eof{};` (N_STRUCTLIT with an empty !void - // variant) silently relies on — without this AX carries a - // stale value into the tagged-union return shuffle. - emitline("\tMOVQ\t$0, AX\n"); }; // cgtagvariantidx — find the 0-based variant index of `vt` inside the