diff --git a/cmd/w6c/cgen.c b/cmd/w6c/cgen.c index e5b628ed..4c6f5217 100644 --- a/cmd/w6c/cgen.c +++ b/cmd/w6c/cgen.c @@ -2341,6 +2341,62 @@ cg_aggcopy(Cg *c, int sz) } } +/* cg_agg_reg_store — the ONE register-cursor aggregate materialise: an + * in-cap (<=24B, GP-class) struct/array/tuple already held in the + * {AX,DX,CX} return cursor is stored into the place base_reg+disp. + * full = sz/8 exact-8B MOVQ words land straight in (safe into any dest); + * the sz%8 tail is one sized MOVB/MOVW/MOVL for {1,2,4} (BOTH branches). + * Extracted from site E (the #10 template) so every narrow-tail + * materialise funnels through one place — close-by-construction (#14). + * + * dest_padded forks ONLY the {3,5,6,7} tail (no GP sub-register exists + * for those widths and w6a has no shift): + * dest_padded == "the dest is a ceil-8/round8 slot (a scratch, or a + * #75 let/local aggregate slot) so an 8B tail over-store stays + * in-bounds." Post-#9: packed struct fields + array elements => 0; + * let/local/scratch slots => 1. It CANNOT be derived — paddedness is + * routing knowledge the caller owns. + * 1 -> a single full MOVQ of the cursor tail eightbyte (= E's #10 + * template; the over-store lands in the slot's pad). + * 0 -> MOVQ the cursor tail eightbyte into the helper's own ceil-8 + * @tagscr pad, then a sized aggcopy of the tail bytes into the + * dest so a packed field / array element is never overrun. + * PRECONDITION (caller-owned, stays per-site): the value is already in + * AX/DX/CX, the dest base is resolved into base_reg+disp, and the + * float-class (#165) / over-cap-sret (#234) loud-stops have already + * fired. Clobbers SI/BX/AX only on the dest_padded==0 detour (the value + * words are in memory by then). */ +static void +cg_agg_reg_store(Cg *c, Local **locals, int base_reg, int disp, int sz, + int dest_padded) +{ + int regs[3] = { D_AX, D_DX, D_CX }; + int full = sz / 8; + int tail = sz % 8; + for (int i = 0; i < full; i++) + ins2(c, A_MOVQ, areg(regs[i]), + amem(base_reg, disp + i * 8)); + if (tail == 0) + return; + if (tail == 1 || tail == 2 || tail == 4) { + int op = (tail == 1) ? A_MOVB + : (tail == 2) ? A_MOVW : A_MOVL; + ins2(c, op, areg(regs[full]), + amem(base_reg, disp + full * 8)); + return; + } + if (dest_padded) { + ins2(c, A_MOVQ, areg(regs[full]), + amem(base_reg, disp + full * 8)); + return; + } + int pad = cg_tagscr_slot(c, locals, 8); + ins2(c, A_MOVQ, areg(regs[full]), amem(D_BP, pad)); + ins2(c, A_LEAQ, amem(D_BP, pad), areg(D_SI)); + ins2(c, A_LEAQ, amem(base_reg, disp + full * 8), areg(D_BX)); + cg_aggcopy(c, tail); +} + /* cgplaceaddr — compute the ADDRESS of an arbitrary place (lvalue) * expression into dst_reg; returns 1 when the shape is wired, 0 * otherwise (the caller loud-stops — rule 7, never a silent drop). @@ -3480,20 +3536,8 @@ cg_structlit_fill(Cg *c, Local **locals_p, Type *lu, Node *lit, ins2(c, A_LEAQ, masym(c, name), areg(D_BX)); else if (mode == DST_PTR_SP) ins2(c, A_MOVQ, amem(D_SP, 0), areg(D_BX)); - int regs[3] = { D_AX, D_DX, D_CX }; - int full = fsz / 8; - int tail = fsz % 8; - for (int i = 0; i < full; i++) - ins2(c, A_MOVQ, areg(regs[i]), - amem(base_reg, - disp + (int)foff + i * 8)); - if (tail > 0) { - int op = (tail == 4) ? A_MOVL - : (tail == 2) ? A_MOVW : A_MOVB; - ins2(c, op, areg(regs[full]), - amem(base_reg, - disp + (int)foff + full * 8)); - } + cg_agg_reg_store(c, locals_p, base_reg, + disp + (int)foff, fsz, 0); continue; } /* str IS []u8: 3-word field (ptr,len,cap). cgexpr leaves @@ -5252,18 +5296,7 @@ cgexpr(Cg *c, Node *n, Local *locals) ins1(c, A_PUSHQ, areg(D_BX)); cgexpr(c, n->rhs, locals); ins1(c, A_POPQ, areg(D_BX)); - int regs[3] = { D_AX, D_DX, D_CX }; - int full = ssz / 8; - int tail = ssz % 8; - for (int i = 0; i < full; i++) - ins2(c, A_MOVQ, areg(regs[i]), - amem(D_BX, i * 8)); - if (tail > 0) { - int op = (tail == 4) ? A_MOVL - : (tail == 2) ? A_MOVW : A_MOVB; - ins2(c, op, areg(regs[full]), - amem(D_BX, full * 8)); - } + cg_agg_reg_store(c, &locals, D_BX, 0, ssz, 0); break; } } @@ -5495,9 +5528,6 @@ cgexpr(Cg *c, Node *n, Local *locals) || str_fu->size % 8 == 4)) { int ssz = (int)str_fu->size; cgexpr(c, n->rhs, locals); - int regs[3] = { D_AX, D_DX, D_CX }; - int full = ssz / 8; - int tail = ssz % 8; int base_reg, base_disp; if (via_ptr || is_global) { if (via_ptr) @@ -5514,18 +5544,8 @@ cgexpr(Cg *c, Node *n, Local *locals) base_reg = D_BP; base_disp = boff + foff; } - for (int i = 0; i < full; i++) - ins2(c, A_MOVQ, areg(regs[i]), - amem(base_reg, - base_disp + i * 8)); - if (tail > 0) { - int op = (tail == 4) ? A_MOVL - : (tail == 2) ? A_MOVW - : A_MOVB; - ins2(c, op, areg(regs[full]), - amem(base_reg, - base_disp + full * 8)); - } + cg_agg_reg_store(c, &locals, base_reg, + base_disp, ssz, 0); break; } if (n->op == TK_ASSIGN && str_fu @@ -6723,9 +6743,6 @@ cgexpr(Cg *c, Node *n, Local *locals) && (fsz % 8 == 0 || fsz % 8 == 1 || fsz % 8 == 2 || fsz % 8 == 4)) { cgexpr(c, n->rhs, locals); - int regs[3] = { D_AX, D_DX, D_CX }; - int full = fsz / 8; - int tail = fsz % 8; int base_reg, base_off; if (via_cx) { if (ptr_root) @@ -6742,18 +6759,8 @@ cgexpr(Cg *c, Node *n, Local *locals) base_reg = D_BP; base_off = base_disp + total_off; } - for (int i = 0; i < full; i++) - ins2(c, A_MOVQ, areg(regs[i]), - amem(base_reg, - base_off + i * 8)); - if (tail > 0) { - int op = (tail == 4) ? A_MOVL - : (tail == 2) ? A_MOVW - : A_MOVB; - ins2(c, op, areg(regs[full]), - amem(base_reg, - base_off + full * 8)); - } + cg_agg_reg_store(c, &locals, + base_reg, base_off, fsz, 0); break; } if (fu && fu->kind == TY_STRUCT @@ -7119,19 +7126,7 @@ cgexpr(Cg *c, Node *n, Local *locals) int scr = cg_tagscr_slot(c, &locals, esz); cgexpr(c, n->rhs, locals); /* call → AX/DX/CX */ /* AX/DX/CX → scratch (mirror cgen.c:3434 receive). */ - int regs[3] = { D_AX, D_DX, D_CX }; - int full = esz / 8; - int tail = esz % 8; - for (int i = 0; i < full; i++) - ins2(c, A_MOVQ, areg(regs[i]), - amem(D_BP, scr + i * 8)); - if (tail > 0) { - int op = (tail == 1) ? A_MOVB - : (tail == 2) ? A_MOVW - : (tail == 4) ? A_MOVL : A_MOVQ; - ins2(c, op, areg(regs[full]), - amem(D_BP, scr + full * 8)); - } + cg_agg_reg_store(c, &locals, D_BP, scr, esz, 1); /* dest &a[i] → BX (mirror #121 / #270-1b resolve) */ cgexpr(c, n->lhs->rhs, locals); /* idx → AX */ if (esz > 1) { @@ -7954,19 +7949,7 @@ cgexpr(Cg *c, Node *n, Local *locals) || sz % 8 == 2 || sz % 8 == 4)) { cgexpr(c, n->rhs, locals); - int regs[3] = { D_AX, D_DX, D_CX }; - int full = sz / 8; - int tail = sz % 8; - for (int i = 0; i < full; i++) - ins2(c, A_MOVQ, areg(regs[i]), - amem(D_BP, off + i * 8)); - if (tail > 0) { - int op = (tail == 4) ? A_MOVL - : (tail == 2) ? A_MOVW - : A_MOVB; - ins2(c, op, areg(regs[full]), - amem(D_BP, off + full * 8)); - } + cg_agg_reg_store(c, &locals, D_BP, off, sz, 0); break; } if (isglob && au->kind == TY_ARRAY @@ -13623,18 +13606,7 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame) && (sz % 8 == 0 || sz % 8 == 1 || sz % 8 == 2 || sz % 8 == 4)) { cgexpr(c, n->rhs, *locals); - int regs[3] = { D_AX, D_DX, D_CX }; - int full = sz / 8; - int tail = sz % 8; - for (int i = 0; i < full; i++) - ins2(c, A_MOVQ, areg(regs[i]), - amem(D_BP, off + i * 8)); - if (tail > 0) { - int op = (tail == 4) ? A_MOVL - : (tail == 2) ? A_MOVW : A_MOVB; - ins2(c, op, areg(regs[full]), - amem(D_BP, off + full * 8)); - } + cg_agg_reg_store(c, locals, D_BP, off, sz, 1); goto letlink; } /* array literal initialiser: `let xs: [N]T = [a, b, c];`. diff --git a/selfhost/cmd/wcc/cgenexpr.ww b/selfhost/cmd/wcc/cgenexpr.ww index da0ac5f2..881433ff 100644 --- a/selfhost/cmd/wcc/cgenexpr.ww +++ b/selfhost/cmd/wcc/cgenexpr.ww @@ -1721,6 +1721,88 @@ fn aggcopy(c: *cgen, sz: i32) void = { }; }; +// cgaggregstore — ww twin of cstage cgen.c cg_agg_reg_store. The ONE +// register-cursor aggregate materialise: an in-cap (<=24B, GP-class) +// struct/array/tuple already held in the {AX,DX,CX} return cursor is +// stored into basereg+disp. full=sz/8 exact-8B MOVQ words land straight +// in; the sz%8 tail is one sized MOVB/MOVW/MOVL for {1,2,4} (BOTH +// branches). Extracted from the cstage site-E #10 template so every +// narrow-tail materialise funnels through one place — close-by- +// construction (task #14). +// +// dest_padded forks ONLY the {3,5,6,7} tail (no GP sub-register exists +// for those widths and w6a has no shift): +// dest_padded == "the dest is a ceil-8/round8 slot (a scratch, or a +// #75 let/local aggregate slot) so an 8B tail over-store stays +// in-bounds." Post-#9: packed struct fields + array elements => false; +// let/local/scratch slots => true. It CANNOT be derived — paddedness +// is routing knowledge the caller owns. +// true -> a single full MOVQ of the cursor tail eightbyte (= the +// #10 template; the over-store lands in the slot's pad). +// false -> MOVQ the cursor tail eightbyte into the helper's own +// ceil-8 @tagscr pad, then a sized aggcopy of the tail bytes +// into the dest so a packed field / array element is never +// overrun. +// PRECONDITION (caller-owned, stays per-site): the value is already in +// AX/DX/CX, the dest base is resolved into basereg+disp, and the +// float-class (#165) / over-cap-sret (#234) loud-stops have already +// fired. Clobbers SI/BX/AX only on the dest_padded==false detour (the +// value words are in memory by then). +fn cgaggregstore(c: *cgen, basereg: str, disp: i32, sz: i32, dest_padded: bool) void = { + let full: i32 = sz / 8; + let tail: i32 = sz - full * 8; + let i: i32 = 0; + for (i < full) { + let reg: str = "AX"; + if (i == 1) { reg = "DX"; }; + if (i == 2) { reg = "CX"; }; + emitline("\tMOVQ\t"); + emitline(reg); + emitline(", "); + emitdispreg((disp + i * 8): i64, basereg); + emitline("\n"); + i += 1; + }; + if (tail == 0) { return; }; + let treg: str = "AX"; + if (full == 1) { treg = "DX"; }; + if (full == 2) { treg = "CX"; }; + if (tail == 1 || tail == 2 || tail == 4) { + let top: str = "MOVB"; + if (tail == 4) { top = "MOVL"; }; + if (tail == 2) { top = "MOVW"; }; + emitline("\t"); + emitline(top); + emitline("\t"); + emitline(treg); + emitline(", "); + emitdispreg((disp + full * 8): i64, basereg); + emitline("\n"); + return; + }; + if (dest_padded) { + emitline("\tMOVQ\t"); + emitline(treg); + emitline(", "); + emitdispreg((disp + full * 8): i64, basereg); + emitline("\n"); + return; + }; + let pad: i32 = tagscradd(c, 8); + emitline("\tMOVQ\t"); + emitline(treg); + emitline(", "); + emitdispreg(pad: i64, "BP"); + emitline("\n"); + emitline("\tLEAQ\t"); + emitdispreg(pad: i64, "BP"); + emitline(", SI\n"); + emitline("\tLEAQ\t"); + emitdispreg((disp + full * 8): i64, basereg); + emitline(", BX\n"); + aggcopy(c, tail); +}; + // copysrcnatsize — natural byte width of a whole-struct copy's SOURCE // operand, read from the source node's stamped tinfo (tichase peels // NAMED). #71: the four whole-struct field-copy sites must move this many @@ -8399,34 +8481,7 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { emitline("\tPUSHQ\tBX\n"); cgexpr(c, n.rhs); emitline("\tPOPQ\tBX\n"); - let full: i32 = ssz / 8; - let i: i32 = 0; - for (i < full) { - let reg: str = "AX"; - if (i == 1) { reg = "DX"; }; - if (i == 2) { reg = "CX"; }; - emitline("\tMOVQ\t"); - emitline(reg); - emitline(", "); - emitdispreg((i * 8): i64, "BX"); - emitline("\n"); - i += 1; - }; - if (tlm > 0) { - let top: str = "MOVB"; - if (tlm == 4) { top = "MOVL"; }; - if (tlm == 2) { top = "MOVW"; }; - let treg: str = "AX"; - if (full == 1) { treg = "DX"; }; - if (full == 2) { treg = "CX"; }; - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitdispreg((full * 8): i64, "BX"); - emitline("\n"); - }; + cgaggregstore(c, "BX", 0, ssz, false); return; }; }; @@ -9217,36 +9272,7 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { let scrc2: i32 = tagscradd(c, esz); cgexpr(c, n.rhs); // call -> AX/DX/CX // AX/DX/CX -> scratch (mirror cstage cgen.c:3434). - let full: i32 = esz / 8; - let tail: i32 = esz % 8; - let wi: i32 = 0; - for (wi < full) { - let rn: str = "AX"; - if (wi == 1) { rn = "DX"; } - else { if (wi == 2) { rn = "CX"; }; }; - emitline("\tMOVQ\t"); - emitline(rn); - emitline(", "); - emitoff((scrc2 + wi * 8): i64); - emitline("(BP)\n"); - wi += 1; - }; - if (tail > 0) { - let top: str = "MOVQ"; - if (tail == 1) { top = "MOVB"; } - else { if (tail == 2) { top = "MOVW"; } - else { if (tail == 4) { top = "MOVL"; }; }; }; - let treg: str = "AX"; - if (full == 1) { treg = "DX"; } - else { if (full == 2) { treg = "CX"; }; }; - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitoff((scrc2 + full * 8): i64); - emitline("(BP)\n"); - }; + cgaggregstore(c, "BP", scrc2, esz, true); // dest &a[i] -> BX (#121 / #270-1b base resolve) cgexpr(c, idx); if (esz > 1) { @@ -10601,34 +10627,7 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { emitline("\tMOVQ\t"); emitoff(lc.off: i64); emitline("(BP), BX\n"); - let full: i32 = ssz / 8; - let i: i32 = 0; - for (i < full) { - let reg: str = "AX"; - if (i == 1) { reg = "DX"; }; - if (i == 2) { reg = "CX"; }; - emitline("\tMOVQ\t"); - emitline(reg); - emitline(", "); - emitdispreg((fi.foff + i * 8): i64, "BX"); - emitline("\n"); - i += 1; - }; - if (tlm > 0) { - let top: str = "MOVB"; - if (tlm == 4) { top = "MOVL"; }; - if (tlm == 2) { top = "MOVW"; }; - let treg: str = "AX"; - if (full == 1) { treg = "DX"; }; - if (full == 2) { treg = "CX"; }; - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitdispreg((fi.foff + full * 8): i64, "BX"); - emitline("\n"); - }; + cgaggregstore(c, "BX", fi.foff, ssz, false); return; }; }; @@ -10847,34 +10846,7 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { if (tlm == 0 || tlm == 1 || tlm == 2 || tlm == 4) { cgexpr(c, n.rhs); - let full: i32 = ssz / 8; - let i: i32 = 0; - for (i < full) { - let reg: str = "AX"; - if (i == 1) { reg = "DX"; }; - if (i == 2) { reg = "CX"; }; - emitline("\tMOVQ\t"); - emitline(reg); - emitline(", "); - emitoff((lc.off + fi.foff + i * 8): i64); - emitline("(BP)\n"); - i += 1; - }; - if (tlm > 0) { - let top: str = "MOVB"; - if (tlm == 4) { top = "MOVL"; }; - if (tlm == 2) { top = "MOVW"; }; - let treg: str = "AX"; - if (full == 1) { treg = "DX"; }; - if (full == 2) { treg = "CX"; }; - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitoff((lc.off + fi.foff + full * 8): i64); - emitline("(BP)\n"); - }; + cgaggregstore(c, "BP", lc.off + fi.foff, ssz, false); return; }; }; @@ -11141,34 +11113,7 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { emitline("\tLEAQ\t"); emitsymname(c, bn); emitline("(SB), BX\n"); - let full: i32 = ssz / 8; - let i: i32 = 0; - for (i < full) { - let reg: str = "AX"; - if (i == 1) { reg = "DX"; }; - if (i == 2) { reg = "CX"; }; - emitline("\tMOVQ\t"); - emitline(reg); - emitline(", "); - emitdispreg((fi.foff + i * 8): i64, "BX"); - emitline("\n"); - i += 1; - }; - if (tlm > 0) { - let top: str = "MOVB"; - if (tlm == 4) { top = "MOVL"; }; - if (tlm == 2) { top = "MOVW"; }; - let treg: str = "AX"; - if (full == 1) { treg = "DX"; }; - if (full == 2) { treg = "CX"; }; - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitdispreg((fi.foff + full * 8): i64, "BX"); - emitline("\n"); - }; + cgaggregstore(c, "BX", fi.foff, ssz, false); return; }; }; @@ -11848,52 +11793,7 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { emitline("(SB), BX\n"); }; }; - let full: i32 = lsz / 8; - let i: i32 = 0; - for (i < full) { - let reg: str = "AX"; - if (i == 1) { reg = "DX"; }; - if (i == 2) { reg = "CX"; }; - if (viacx) { - emitline("\tMOVQ\t"); - emitline(reg); - emitline(", "); - emitdispreg((totaloff + i * 8): i64, "BX"); - emitline("\n"); - } else { - emitline("\tMOVQ\t"); - emitline(reg); - emitline(", "); - emitoff((rootoff + totaloff + i * 8): i64); - emitline("(BP)\n"); - }; - i += 1; - }; - if (tlm > 0) { - let top: str = "MOVB"; - if (tlm == 4) { top = "MOVL"; }; - if (tlm == 2) { top = "MOVW"; }; - let treg: str = "AX"; - if (full == 1) { treg = "DX"; }; - if (full == 2) { treg = "CX"; }; - if (viacx) { - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitdispreg((totaloff + full * 8): i64, "BX"); - emitline("\n"); - } else { - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitoff((rootoff + totaloff + full * 8): i64); - emitline("(BP)\n"); - }; - }; + if (viacx) { cgaggregstore(c, "BX", totaloff, lsz, false); } else { cgaggregstore(c, "BP", rootoff + totaloff, lsz, false); }; return; }; }; @@ -12638,34 +12538,7 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { if (tlm == 0 || tlm == 1 || tlm == 2 || tlm == 4) { cgexpr(c, n.rhs); - let full: i32 = lcsz / 8; - let i: i32 = 0; - for (i < full) { - let reg: str = "AX"; - if (i == 1) { reg = "DX"; }; - if (i == 2) { reg = "CX"; }; - emitline("\tMOVQ\t"); - emitline(reg); - emitline(", "); - emitoff((off + i * 8): i64); - emitline("(BP)\n"); - i += 1; - }; - if (tlm > 0) { - let top: str = "MOVB"; - if (tlm == 4) { top = "MOVL"; }; - if (tlm == 2) { top = "MOVW"; }; - let treg: str = "AX"; - if (full == 1) { treg = "DX"; }; - if (full == 2) { treg = "CX"; }; - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitoff((off + full * 8): i64); - emitline("(BP)\n"); - }; + cgaggregstore(c, "BP", off, lcsz, false); return; }; }; @@ -12702,34 +12575,7 @@ fn cgassign(c: *cgen, n: *syntax.node) void = { if (tlm == 0 || tlm == 1 || tlm == 2 || tlm == 4) { cgexpr(c, n.rhs); - let full: i32 = lcsz / 8; - let i: i32 = 0; - for (i < full) { - let reg: str = "AX"; - if (i == 1) { reg = "DX"; }; - if (i == 2) { reg = "CX"; }; - emitline("\tMOVQ\t"); - emitline(reg); - emitline(", "); - emitoff((off + i * 8): i64); - emitline("(BP)\n"); - i += 1; - }; - if (tlm > 0) { - let top: str = "MOVB"; - if (tlm == 4) { top = "MOVL"; }; - if (tlm == 2) { top = "MOVW"; }; - let treg: str = "AX"; - if (full == 1) { treg = "DX"; }; - if (full == 2) { treg = "CX"; }; - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitoff((off + full * 8): i64); - emitline("(BP)\n"); - }; + cgaggregstore(c, "BP", off, lcsz, false); return; }; }; diff --git a/selfhost/cmd/wcc/cgenstmt.ww b/selfhost/cmd/wcc/cgenstmt.ww index 979b72d2..d293eb7a 100644 --- a/selfhost/cmd/wcc/cgenstmt.ww +++ b/selfhost/cmd/wcc/cgenstmt.ww @@ -2603,34 +2603,7 @@ fn cgletbody(c: *cgen, n: *syntax.node, off: i32) void = { if (tlm == 0 || tlm == 1 || tlm == 2 || tlm == 4) { cgexpr(c, rhs); - let full: i32 = lsz / 8; - let i: i32 = 0; - for (i < full) { - let reg: str = "AX"; - if (i == 1) { reg = "DX"; }; - if (i == 2) { reg = "CX"; }; - emitline("\tMOVQ\t"); - emitline(reg); - emitline(", "); - emitoff((off + i * 8): i64); - emitline("(BP)\n"); - i += 1; - }; - if (tlm > 0) { - let top: str = "MOVB"; - if (tlm == 4) { top = "MOVL"; }; - if (tlm == 2) { top = "MOVW"; }; - let treg: str = "AX"; - if (full == 1) { treg = "DX"; }; - if (full == 2) { treg = "CX"; }; - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitoff((off + full * 8): i64); - emitline("(BP)\n"); - }; + cgaggregstore(c, "BP", off, lsz, true); c.lastwasreturn = 0; return; }; @@ -2655,34 +2628,7 @@ fn cgletbody(c: *cgen, n: *syntax.node, off: i32) void = { if (tlm == 0 || tlm == 1 || tlm == 2 || tlm == 4) { cgexpr(c, rhs); - let full: i32 = lsz / 8; - let i: i32 = 0; - for (i < full) { - let reg: str = "AX"; - if (i == 1) { reg = "DX"; }; - if (i == 2) { reg = "CX"; }; - emitline("\tMOVQ\t"); - emitline(reg); - emitline(", "); - emitoff((off + i * 8): i64); - emitline("(BP)\n"); - i += 1; - }; - if (tlm > 0) { - let top: str = "MOVB"; - if (tlm == 4) { top = "MOVL"; }; - if (tlm == 2) { top = "MOVW"; }; - let treg: str = "AX"; - if (full == 1) { treg = "DX"; }; - if (full == 2) { treg = "CX"; }; - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(treg); - emitline(", "); - emitoff((off + full * 8): i64); - emitline("(BP)\n"); - }; + cgaggregstore(c, "BP", off, lsz, true); c.lastwasreturn = 0; return; }; diff --git a/selfhost/cmd/wcc/cgenutil.ww b/selfhost/cmd/wcc/cgenutil.ww index c9fd3e3d..2748ea57 100644 --- a/selfhost/cmd/wcc/cgenutil.ww +++ b/selfhost/cmd/wcc/cgenutil.ww @@ -5387,44 +5387,7 @@ fn cgstructlitfill(c: *cgen, si: *structinfo, lit: *syntax.node, if (mode == 3) { emitline("\tMOVQ\t(SP), BX\n"); }; - let full: i32 = cfsz / 8; - let ci: i32 = 0; - for (ci < full) { - let r: str = "AX"; - if (ci == 1) { r = "DX"; }; - if (ci == 2) { r = "CX"; }; - emitline("\tMOVQ\t"); - emitline(r); - emitline(", "); - if (mode == 0) { - emitoff((disp + fi.foff + ci * 8): i64); - emitline("(BP)\n"); - } else { - emitdispreg((disp + fi.foff + ci * 8): i64, basereg); - emitline("\n"); - }; - ci += 1; - }; - if (crem > 0) { - let top: str = "MOVB"; - if (crem == 4) { top = "MOVL"; }; - if (crem == 2) { top = "MOVW"; }; - let tr: str = "AX"; - if (full == 1) { tr = "DX"; }; - if (full == 2) { tr = "CX"; }; - emitline("\t"); - emitline(top); - emitline("\t"); - emitline(tr); - emitline(", "); - if (mode == 0) { - emitoff((disp + fi.foff + full * 8): i64); - emitline("(BP)\n"); - } else { - emitdispreg((disp + fi.foff + full * 8): i64, basereg); - emitline("\n"); - }; - }; + cgaggregstore(c, basereg, disp + fi.foff, cfsz, false); callwhole = true; }; };