selfhost: resync w6c/wwdump combined.ww to current wcc source (#109)
Catch-up regen only; no source change. w6c and wwdump embed the wcc cgen, whose post-#97 edits landed without regenerating these two tools' combined.ww -- the byte-id gates are freshness-blind, so master stayed green while shipping a stale artifact. Permanent freshness gate filed as #110.
This commit is contained in:
@@ -12572,6 +12572,18 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
|
||||
if (n == nil) { return 0; };
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_FLOATLIT) { return 2; };
|
||||
if (k == nkind.N_INTLIT) {
|
||||
// A float-typed integer literal (`8f64`/`0f32`) now
|
||||
// materialises in X0 (#103 FACE X), so the cast / spill /
|
||||
// arith-recursion sides must classify it as float — else
|
||||
// `(8f64 * 10.0): i32` recurses to this N_INTLIT lhs and
|
||||
// falls through to integer, emitting MOVSXD not CVTTSD2SI
|
||||
// (the #101 structural-vs-stamped asymmetry). cstage reads
|
||||
// the checker-stamped type via node_isfloat directly.
|
||||
if (isf32type(c, n)) { return 1; };
|
||||
if (isfloattype(c, n)) { return 2; };
|
||||
return 0;
|
||||
};
|
||||
if (k == nkind.N_CAST) {
|
||||
if (isf32type(c, n.rhs)) { return 1; };
|
||||
if (isfloattype(c, n.rhs)) { return 2; };
|
||||
@@ -12614,18 +12626,35 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
|
||||
return 0;
|
||||
};
|
||||
if (k == nkind.N_CALL) {
|
||||
// Look up the callee's declared return type — fnretlookup
|
||||
// Look up the callee's declared return type — fnretlookupmod
|
||||
// returns the type-AST. Routes float-returning fns through
|
||||
// the X0 ABI so cglet / cgassign know to spill from X0.
|
||||
let nm: str;
|
||||
nm.ptr = nil; nm.len = 0;
|
||||
if (n.lhs != nil) {
|
||||
if (n.lhs.kind == nkind.N_IDENT) { nm = n.lhs.str; };
|
||||
};
|
||||
if (nm.len > 0) {
|
||||
let rtyp: *node = fnretlookup(c, nm);
|
||||
if (isf32type(c, rtyp)) { return 1; };
|
||||
if (isfloattype(c, rtyp)) { return 2; };
|
||||
// N_DOT (cross-module callee, #98/#101): without the explicit
|
||||
// arm a module-qualified `myf.g()` callee never reaches any
|
||||
// lookup, so an imported f64-returning fn fell through to
|
||||
// integer (0) — cgcast then emitted MOVSXD not CVTTSD2SI
|
||||
// (#101) and pushargsrev spilled the result as a GPR not
|
||||
// MOVSD (#98). Mirror nodeisslice / nodeisstr's #34 N_DOT arm
|
||||
// so cross-module resolves to kind 2 like same-module does.
|
||||
let callee: *node = n.lhs;
|
||||
if (callee != nil) {
|
||||
if (callee.kind == nkind.N_IDENT) {
|
||||
let rtyp: *node = fnretlookupmod(c, callee.str, c.curmod);
|
||||
if (isf32type(c, rtyp)) { return 1; };
|
||||
if (isfloattype(c, rtyp)) { return 2; };
|
||||
};
|
||||
if (callee.kind == nkind.N_DOT) {
|
||||
let cmod: str;
|
||||
cmod.ptr = nil; cmod.len = 0;
|
||||
if (callee.lhs != nil) {
|
||||
if (callee.lhs.kind == nkind.N_IDENT) {
|
||||
cmod = callee.lhs.str;
|
||||
};
|
||||
};
|
||||
let rtyp: *node = fnretlookupmod(c, callee.str, cmod);
|
||||
if (isf32type(c, rtyp)) { return 1; };
|
||||
if (isfloattype(c, rtyp)) { return 2; };
|
||||
};
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
@@ -14044,11 +14073,37 @@ import typ;
|
||||
import sym;
|
||||
import strconv;
|
||||
|
||||
// cgfloatbits — materialise a float constant in X0: MOVQ the IEEE bits
|
||||
// into AX, PUSH, MOVSD off the stack into X0. Shared by N_FLOATLIT (bits
|
||||
// already in n.uval from the lexer's bitcast) and the f64/f32-typed
|
||||
// N_INTLIT arm (#103 FACE X).
|
||||
fn cgfloatbits(c: *cgen, bits: u64) void = {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(bits: i64);
|
||||
emitline(", AX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
emitline("\tMOVSD\t(SP), X0\n");
|
||||
emitline("\tADDQ\t$8, SP\n");
|
||||
};
|
||||
|
||||
fn cgexpr(c: *cgen, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
let k: nkind = n.kind;
|
||||
|
||||
if (k == 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
|
||||
// compare/mul reads a stale X0 — #103 FACE X). The bits are
|
||||
// the IEEE pattern of the integer value, mirroring cstage's
|
||||
// `(double)(long long)n->uval`; the (&fv):*u64 bitcast is the
|
||||
// lex.ww idiom (lib/ww/lex/lex.ww).
|
||||
if (isfloattype(c, n)) {
|
||||
let fv: f64 = (n.uval: i64): f64;
|
||||
let pu: *u64 = (&fv): *u64;
|
||||
cgfloatbits(c, *pu);
|
||||
return;
|
||||
};
|
||||
// Print signed (i64), not unsigned (u64). C cgen uses
|
||||
// `$%lld` so 64-bit constants with bit 63 set show up as
|
||||
// negative — e.g. FNV-1a's offset basis prints as
|
||||
@@ -14059,19 +14114,11 @@ fn cgexpr(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
if (k == nkind.N_FLOATLIT) {
|
||||
// Materialise the f64 bit pattern in AX, push, then MOVSD it
|
||||
// into X0. The bits come from n.uval — the parser populates
|
||||
// it from the lexer's bitcast of t.fval, so this path stays
|
||||
// integer-only (no SSE in the cgen source). The f32
|
||||
// narrowing is handled at the consumer site, not here — the
|
||||
// literal always carries the full double precision until
|
||||
// typed by context.
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(n.uval: i64);
|
||||
emitline(", AX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
emitline("\tMOVSD\t(SP), X0\n");
|
||||
emitline("\tADDQ\t$8, SP\n");
|
||||
// The bits come from n.uval — the parser populates it from
|
||||
// the lexer's bitcast of t.fval. The f32 narrowing is handled
|
||||
// at the consumer site, not here — the literal always carries
|
||||
// the full double precision until typed by context.
|
||||
cgfloatbits(c, n.uval);
|
||||
return;
|
||||
};
|
||||
if (k == nkind.N_RUNELIT) {
|
||||
@@ -15675,6 +15722,21 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
emitline("(BP), CX\n");
|
||||
return;
|
||||
};
|
||||
// f64/f32 tuple field must ride X0 via
|
||||
// MOVSD/MOVSS; the integer load op left it
|
||||
// in AX (#103 FACE Z). Mirrors the float
|
||||
// local load above and cstage cgen.c:1462,
|
||||
// 1838 (the #96 pattern).
|
||||
if (isfloattype(c, tpt)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, tpt)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
emitoff((lc.off + foff): i64);
|
||||
emitline("(BP), X0\n");
|
||||
return;
|
||||
};
|
||||
let sz: i32 = slotsize(c, tpt);
|
||||
let op: str = tnodeloadop(c, tpt, sz);
|
||||
emitline("\t");
|
||||
@@ -20336,7 +20398,7 @@ fn rettupleof(c: *cgen, rhs: *node) *node = {
|
||||
// header (ref/hare/rt/ensure.ha:4-8) at off/+8/+16 from consecutive
|
||||
// cursor registers; a scalar stores 1 word. Byte-identical to the cstage
|
||||
// N_MLET/N_MASSIGN store (cmd/w6c/cgen.c).
|
||||
fn tupstore(cur: i32, off: i32, wide: bool) void = {
|
||||
fn tupstore(c: *cgen, cur: i32, off: i32, wide: bool, tn: *node) void = {
|
||||
if (wide) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitline(tupreg(cur + 0));
|
||||
@@ -20355,6 +20417,20 @@ fn tupstore(cur: i32, off: i32, wide: bool) void = {
|
||||
emitline("(BP)\n");
|
||||
return;
|
||||
};
|
||||
// #105: an f64/f32 element rides X0 (the SSE return reg), not its
|
||||
// integer cursor reg — MOVSD/MOVSS it, else the slot gets garbage and
|
||||
// the FACE-Z field read sees it. X0 survives the reg->mem stores.
|
||||
// Single-float scope; multi-float collides on X0 at RETURN (#107).
|
||||
if (isfloattype(c, tn)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, tn)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
emitoff(off: i64);
|
||||
emitline("(BP)\n");
|
||||
return;
|
||||
};
|
||||
emitline("\tMOVQ\t");
|
||||
emitline(tupreg(cur));
|
||||
emitline(", ");
|
||||
@@ -21037,6 +21113,58 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// 16B tuple init from a function call. An integer word rides
|
||||
// its integer cursor reg (AX, DX); a single f64/f32 word rides
|
||||
// X0, the SSE return reg — the RETURN leaves the float in X0
|
||||
// and pushes garbage through that word's integer slot, so a
|
||||
// blanket MOVQ-from-integer spill stores garbage and the #103-
|
||||
// FACE-Z field read (MOVSD-from-slot) reads it (#105). Spill
|
||||
// each word from its real class. Multi-float tuples collide on
|
||||
// X0 at the RETURN (#107), out of scope. Mirror of cstage
|
||||
// cgen.c. Without this branch a 16B tuple receive (any element
|
||||
// mix) fell to the generic single-word store below and dropped
|
||||
// word1 — silent loss of t.1 (#102).
|
||||
let rt16: *node = rettupleof(c, rhs);
|
||||
if (rt16 != nil && sz == 16) {
|
||||
let q0: *node = rt16.list;
|
||||
let q1: *node = nil;
|
||||
if (q0 != nil) { q1 = q0.next; };
|
||||
let q0t: *node = nil;
|
||||
let q1t: *node = nil;
|
||||
if (q0 != nil) { q0t = q0.lhs; };
|
||||
if (q1 != nil) { q1t = q1.lhs; };
|
||||
let e0f: bool = isfloattype(c, q0t);
|
||||
let e1f: bool = isfloattype(c, q1t);
|
||||
cgexpr(c, rhs);
|
||||
if (e0f) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, q0t)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
emitoff(off: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(off: i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
if (e1f) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, q1t)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\tDX, ");
|
||||
emitoff((off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
// Array literal init: `let xs: [N]T = [a, b, c];` (or [_]T).
|
||||
// Walk elements in declaration order, store each at off + i*esz
|
||||
// using the right width for the element type. Trailing `...`
|
||||
@@ -21504,7 +21632,7 @@ fn cgmassign(c: *cgen, n: *node) void = {
|
||||
let off: i32 = 0;
|
||||
if (l.kind == nkind.N_IDENT) { off = localfind(c, l.str); };
|
||||
if (off != 0) {
|
||||
tupstore(cur, off, wide);
|
||||
tupstore(c, cur, off, wide, tn);
|
||||
};
|
||||
cur = cur + tupebytes(wide);
|
||||
l = l.next;
|
||||
@@ -21576,7 +21704,7 @@ fn cgmlet(c: *cgen, n: *node) void = {
|
||||
let sz: i32 = 8;
|
||||
if (wide) { sz = tyslicesize(): i32; };
|
||||
let off: i32 = localadd(c, l.str, sz, tn);
|
||||
tupstore(cur, off, wide);
|
||||
tupstore(c, cur, off, wide, tn);
|
||||
cur = cur + tupebytes(wide);
|
||||
l = l.next;
|
||||
if (pt != nil) { pt = pt.next; };
|
||||
|
||||
@@ -12572,6 +12572,18 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
|
||||
if (n == nil) { return 0; };
|
||||
let k: nkind = n.kind;
|
||||
if (k == nkind.N_FLOATLIT) { return 2; };
|
||||
if (k == nkind.N_INTLIT) {
|
||||
// A float-typed integer literal (`8f64`/`0f32`) now
|
||||
// materialises in X0 (#103 FACE X), so the cast / spill /
|
||||
// arith-recursion sides must classify it as float — else
|
||||
// `(8f64 * 10.0): i32` recurses to this N_INTLIT lhs and
|
||||
// falls through to integer, emitting MOVSXD not CVTTSD2SI
|
||||
// (the #101 structural-vs-stamped asymmetry). cstage reads
|
||||
// the checker-stamped type via node_isfloat directly.
|
||||
if (isf32type(c, n)) { return 1; };
|
||||
if (isfloattype(c, n)) { return 2; };
|
||||
return 0;
|
||||
};
|
||||
if (k == nkind.N_CAST) {
|
||||
if (isf32type(c, n.rhs)) { return 1; };
|
||||
if (isfloattype(c, n.rhs)) { return 2; };
|
||||
@@ -12614,18 +12626,35 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
|
||||
return 0;
|
||||
};
|
||||
if (k == nkind.N_CALL) {
|
||||
// Look up the callee's declared return type — fnretlookup
|
||||
// Look up the callee's declared return type — fnretlookupmod
|
||||
// returns the type-AST. Routes float-returning fns through
|
||||
// the X0 ABI so cglet / cgassign know to spill from X0.
|
||||
let nm: str;
|
||||
nm.ptr = nil; nm.len = 0;
|
||||
if (n.lhs != nil) {
|
||||
if (n.lhs.kind == nkind.N_IDENT) { nm = n.lhs.str; };
|
||||
};
|
||||
if (nm.len > 0) {
|
||||
let rtyp: *node = fnretlookup(c, nm);
|
||||
if (isf32type(c, rtyp)) { return 1; };
|
||||
if (isfloattype(c, rtyp)) { return 2; };
|
||||
// N_DOT (cross-module callee, #98/#101): without the explicit
|
||||
// arm a module-qualified `myf.g()` callee never reaches any
|
||||
// lookup, so an imported f64-returning fn fell through to
|
||||
// integer (0) — cgcast then emitted MOVSXD not CVTTSD2SI
|
||||
// (#101) and pushargsrev spilled the result as a GPR not
|
||||
// MOVSD (#98). Mirror nodeisslice / nodeisstr's #34 N_DOT arm
|
||||
// so cross-module resolves to kind 2 like same-module does.
|
||||
let callee: *node = n.lhs;
|
||||
if (callee != nil) {
|
||||
if (callee.kind == nkind.N_IDENT) {
|
||||
let rtyp: *node = fnretlookupmod(c, callee.str, c.curmod);
|
||||
if (isf32type(c, rtyp)) { return 1; };
|
||||
if (isfloattype(c, rtyp)) { return 2; };
|
||||
};
|
||||
if (callee.kind == nkind.N_DOT) {
|
||||
let cmod: str;
|
||||
cmod.ptr = nil; cmod.len = 0;
|
||||
if (callee.lhs != nil) {
|
||||
if (callee.lhs.kind == nkind.N_IDENT) {
|
||||
cmod = callee.lhs.str;
|
||||
};
|
||||
};
|
||||
let rtyp: *node = fnretlookupmod(c, callee.str, cmod);
|
||||
if (isf32type(c, rtyp)) { return 1; };
|
||||
if (isfloattype(c, rtyp)) { return 2; };
|
||||
};
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
@@ -14044,11 +14073,37 @@ import typ;
|
||||
import sym;
|
||||
import strconv;
|
||||
|
||||
// cgfloatbits — materialise a float constant in X0: MOVQ the IEEE bits
|
||||
// into AX, PUSH, MOVSD off the stack into X0. Shared by N_FLOATLIT (bits
|
||||
// already in n.uval from the lexer's bitcast) and the f64/f32-typed
|
||||
// N_INTLIT arm (#103 FACE X).
|
||||
fn cgfloatbits(c: *cgen, bits: u64) void = {
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(bits: i64);
|
||||
emitline(", AX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
emitline("\tMOVSD\t(SP), X0\n");
|
||||
emitline("\tADDQ\t$8, SP\n");
|
||||
};
|
||||
|
||||
fn cgexpr(c: *cgen, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
let k: nkind = n.kind;
|
||||
|
||||
if (k == 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
|
||||
// compare/mul reads a stale X0 — #103 FACE X). The bits are
|
||||
// the IEEE pattern of the integer value, mirroring cstage's
|
||||
// `(double)(long long)n->uval`; the (&fv):*u64 bitcast is the
|
||||
// lex.ww idiom (lib/ww/lex/lex.ww).
|
||||
if (isfloattype(c, n)) {
|
||||
let fv: f64 = (n.uval: i64): f64;
|
||||
let pu: *u64 = (&fv): *u64;
|
||||
cgfloatbits(c, *pu);
|
||||
return;
|
||||
};
|
||||
// Print signed (i64), not unsigned (u64). C cgen uses
|
||||
// `$%lld` so 64-bit constants with bit 63 set show up as
|
||||
// negative — e.g. FNV-1a's offset basis prints as
|
||||
@@ -14059,19 +14114,11 @@ fn cgexpr(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
if (k == nkind.N_FLOATLIT) {
|
||||
// Materialise the f64 bit pattern in AX, push, then MOVSD it
|
||||
// into X0. The bits come from n.uval — the parser populates
|
||||
// it from the lexer's bitcast of t.fval, so this path stays
|
||||
// integer-only (no SSE in the cgen source). The f32
|
||||
// narrowing is handled at the consumer site, not here — the
|
||||
// literal always carries the full double precision until
|
||||
// typed by context.
|
||||
emitline("\tMOVQ\t$");
|
||||
emitint(n.uval: i64);
|
||||
emitline(", AX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
emitline("\tMOVSD\t(SP), X0\n");
|
||||
emitline("\tADDQ\t$8, SP\n");
|
||||
// The bits come from n.uval — the parser populates it from
|
||||
// the lexer's bitcast of t.fval. The f32 narrowing is handled
|
||||
// at the consumer site, not here — the literal always carries
|
||||
// the full double precision until typed by context.
|
||||
cgfloatbits(c, n.uval);
|
||||
return;
|
||||
};
|
||||
if (k == nkind.N_RUNELIT) {
|
||||
@@ -15675,6 +15722,21 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
emitline("(BP), CX\n");
|
||||
return;
|
||||
};
|
||||
// f64/f32 tuple field must ride X0 via
|
||||
// MOVSD/MOVSS; the integer load op left it
|
||||
// in AX (#103 FACE Z). Mirrors the float
|
||||
// local load above and cstage cgen.c:1462,
|
||||
// 1838 (the #96 pattern).
|
||||
if (isfloattype(c, tpt)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, tpt)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\t");
|
||||
emitoff((lc.off + foff): i64);
|
||||
emitline("(BP), X0\n");
|
||||
return;
|
||||
};
|
||||
let sz: i32 = slotsize(c, tpt);
|
||||
let op: str = tnodeloadop(c, tpt, sz);
|
||||
emitline("\t");
|
||||
@@ -20336,7 +20398,7 @@ fn rettupleof(c: *cgen, rhs: *node) *node = {
|
||||
// header (ref/hare/rt/ensure.ha:4-8) at off/+8/+16 from consecutive
|
||||
// cursor registers; a scalar stores 1 word. Byte-identical to the cstage
|
||||
// N_MLET/N_MASSIGN store (cmd/w6c/cgen.c).
|
||||
fn tupstore(cur: i32, off: i32, wide: bool) void = {
|
||||
fn tupstore(c: *cgen, cur: i32, off: i32, wide: bool, tn: *node) void = {
|
||||
if (wide) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitline(tupreg(cur + 0));
|
||||
@@ -20355,6 +20417,20 @@ fn tupstore(cur: i32, off: i32, wide: bool) void = {
|
||||
emitline("(BP)\n");
|
||||
return;
|
||||
};
|
||||
// #105: an f64/f32 element rides X0 (the SSE return reg), not its
|
||||
// integer cursor reg — MOVSD/MOVSS it, else the slot gets garbage and
|
||||
// the FACE-Z field read sees it. X0 survives the reg->mem stores.
|
||||
// Single-float scope; multi-float collides on X0 at RETURN (#107).
|
||||
if (isfloattype(c, tn)) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, tn)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
emitoff(off: i64);
|
||||
emitline("(BP)\n");
|
||||
return;
|
||||
};
|
||||
emitline("\tMOVQ\t");
|
||||
emitline(tupreg(cur));
|
||||
emitline(", ");
|
||||
@@ -21037,6 +21113,58 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
};
|
||||
// 16B tuple init from a function call. An integer word rides
|
||||
// its integer cursor reg (AX, DX); a single f64/f32 word rides
|
||||
// X0, the SSE return reg — the RETURN leaves the float in X0
|
||||
// and pushes garbage through that word's integer slot, so a
|
||||
// blanket MOVQ-from-integer spill stores garbage and the #103-
|
||||
// FACE-Z field read (MOVSD-from-slot) reads it (#105). Spill
|
||||
// each word from its real class. Multi-float tuples collide on
|
||||
// X0 at the RETURN (#107), out of scope. Mirror of cstage
|
||||
// cgen.c. Without this branch a 16B tuple receive (any element
|
||||
// mix) fell to the generic single-word store below and dropped
|
||||
// word1 — silent loss of t.1 (#102).
|
||||
let rt16: *node = rettupleof(c, rhs);
|
||||
if (rt16 != nil && sz == 16) {
|
||||
let q0: *node = rt16.list;
|
||||
let q1: *node = nil;
|
||||
if (q0 != nil) { q1 = q0.next; };
|
||||
let q0t: *node = nil;
|
||||
let q1t: *node = nil;
|
||||
if (q0 != nil) { q0t = q0.lhs; };
|
||||
if (q1 != nil) { q1t = q1.lhs; };
|
||||
let e0f: bool = isfloattype(c, q0t);
|
||||
let e1f: bool = isfloattype(c, q1t);
|
||||
cgexpr(c, rhs);
|
||||
if (e0f) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, q0t)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
emitoff(off: i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(off: i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
if (e1f) {
|
||||
let mov: str = "MOVSD";
|
||||
if (isf32type(c, q1t)) { mov = "MOVSS"; };
|
||||
emitline("\t");
|
||||
emitline(mov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\tMOVQ\tDX, ");
|
||||
emitoff((off + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
// Array literal init: `let xs: [N]T = [a, b, c];` (or [_]T).
|
||||
// Walk elements in declaration order, store each at off + i*esz
|
||||
// using the right width for the element type. Trailing `...`
|
||||
@@ -21504,7 +21632,7 @@ fn cgmassign(c: *cgen, n: *node) void = {
|
||||
let off: i32 = 0;
|
||||
if (l.kind == nkind.N_IDENT) { off = localfind(c, l.str); };
|
||||
if (off != 0) {
|
||||
tupstore(cur, off, wide);
|
||||
tupstore(c, cur, off, wide, tn);
|
||||
};
|
||||
cur = cur + tupebytes(wide);
|
||||
l = l.next;
|
||||
@@ -21576,7 +21704,7 @@ fn cgmlet(c: *cgen, n: *node) void = {
|
||||
let sz: i32 = 8;
|
||||
if (wide) { sz = tyslicesize(): i32; };
|
||||
let off: i32 = localadd(c, l.str, sz, tn);
|
||||
tupstore(cur, off, wide);
|
||||
tupstore(c, cur, off, wide, tn);
|
||||
cur = cur + tupebytes(wide);
|
||||
l = l.next;
|
||||
if (pt != nil) { pt = pt.next; };
|
||||
|
||||
Reference in New Issue
Block a user