wcc/cgenexpr: cgexpr node-kind if-ladder -> switch (Wave-2 structural)
23-arm top-level if (k == nkind.N_X) dispatch ladder becomes one switch (k) with an empty-label default case for the AX=0 fallback. N_RUNELIT stays a separate arm (no float check, unlike cstage's INTLIT grouping). Not byte-id-neutral (if-chain -> switch); 990-997 cstage==wwstage byte-id is the functional-equivalence gate. w6c + wwdump combined.ww regenerated.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user