wcc/check+w6c+w6c_ww: materialize array-literal slice-borrow base into per-fn scratch (fix #25 + #31)
A one-step `let xs: []T = [e0,e1,..]` had two faults. #31 (silent, cs!=ww): the #258 array→slice borrow wrapped the un-addressable N_ARRLIT directly as the N_SLICE base and cgen never spilled it to a stack slot, so .ptr dangled (`let xs:[]i32=[10,20,30]; xs[1]` returned the un-stored header 1; []u8/[]str segfaulted). #25 (over-strict): a slice target fell through to the exact- element type_eq borrow gate, rejecting bare-int-width ([]u8=[1,2,3]) and str elements the array-init path coerces. Fix (re-stamp + per-borrow scratch; both stages byte-identical asm): - Checker re-stamps the slice arrlit as [count]T, reusing the array-init per-element coercion + range-check (#25): in-range accepts, out-of-range loud-rejects. cstage arrlit_init_fits gains a TY_SLICE arm; wwstage checkletassign mirrors it and stashes the synthesized [count]T tnode on arrlit.lhs (free for N_ARRLIT) so cgen can size the backing NODE-wise (elemsizeofc) and count from the tnode's .rhs intlit — the arrlit's own value tinfo carries the literal's untyped element (unsized), so node-first sizing is required (a cstage/wwstage representation divergence; cstage's Type IS sized and reads base->type). - cgen materialises the N_ARRLIT borrow base into a FRESH per-borrow @slicescr stack slot (distinct slot per borrow: a borrow's backing must outlive the lowering, so it can't share a cached @aggargscr/@tagscr-style slot — two live borrows would alias one backing; localalloc/local_alloc is always-fresh), filled by REUSING the array-init element fill extracted from the N_LET path (cstage cg_arrlit_fill_bp, wwstage cgarrlitfillbp — same store sequence the byte-id-green `let a:[N]T=[..]` uses, the frame-order + store-op guarantee), then LEAQ'd as the base. Supported ONLY at a `let` init. In call-arg / return / assign position there is no addressable backing, so both stages LOUD-REJECT ("bind it to a `let` first") — aligning cstage DOWN to wwstage (which already refused the untyped arrlit element) per rule-10; this closes #31's silent call-arg segfault as a compile error. Full non-let support is deferred (#33). Escape (rule-8 WHY): a `let xs:[]T=[..]; return xs;` returns a slice into a freed frame slot = dangling, IDENTICAL to the pre-existing named-array borrow and Hare-consistent (no escape analysis / GC / heap promotion). Test 953_arrlit_slice_run: 8 accept rows (cstage runtime readback + cs==ww byte-id, frame-size canary incl.) covering the #31 i32 pin, bare-int→u8 coercion, str readback, the multi-live soundness pin (xs[0]+ys[0]=5, not 8 — proves fresh-per-borrow), and a mutate-through-borrow proof; 4 reject rows (out-of-range element + the three non-let contexts, loud in both stages). Tuple-element slices stay blocked by the pre-existing #30 array-init FATAL.
This commit is contained in:
@@ -1471,6 +1471,238 @@ fn cgexprstmt(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
|
||||
// cgarrlitfillbp — #31: fill the [count]T destination at BP-relative
|
||||
// `off` from an N_ARRLIT, extracted from the cglet array-init path so
|
||||
// the slice-borrow base materialisation (cgslice N_ARRLIT-base arm)
|
||||
// reuses the IDENTICAL element-store sequence — the frame-order /
|
||||
// store-op guarantee for rule-10 byte-id (ken). `arrtn` is the [count]T
|
||||
// type NODE (cglet n.lhs; cgslice the re-stamped tnode on arrlit.lhs,
|
||||
// #25); `rhs` the literal. Twin of cstage cg_arrlit_fill_bp.
|
||||
fn cgarrlitfillbp(c: *cgen, arrtn: *node, rhs: *node, off: i32) void = {
|
||||
let elemn: *node = arrtn.lhs;
|
||||
let esz: i32 = 8;
|
||||
let isstrel: bool = false;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
if (streq(elemn.str, "str")) {
|
||||
esz = primtypesize("str"): i32;
|
||||
isstrel = true;
|
||||
} else {
|
||||
let ps: i32 = primsize(elemn.str);
|
||||
if (ps > 0) { esz = ps; };
|
||||
};
|
||||
};
|
||||
};
|
||||
// #270-1c: an AGGREGATE (struct/array/tuple) element of
|
||||
// an array literal — the scalar per-element store below
|
||||
// writes only the first 8 bytes (unpopulated tail). Fill
|
||||
// each element slot from its literal (cgstructlitfillbp)
|
||||
// or source ident (word-copy). esz is the element's
|
||||
// natural size (cstage esub->size).
|
||||
let esubti: *tinfo = nil;
|
||||
if (elemn != nil) { esubti = elemn.type_: *tinfo; };
|
||||
for (esubti != nil && esubti.kind == tykind.TY_NAMED) {
|
||||
esubti = esubti.under;
|
||||
};
|
||||
let isagg: bool = esubti != nil
|
||||
&& (esubti.kind == tykind.TY_STRUCT
|
||||
|| esubti.kind == tykind.TY_ARRAY
|
||||
|| esubti.kind == tykind.TY_TUPLE);
|
||||
if (isagg) { esz = esubti.size: i32; };
|
||||
// #20/#270 str-slice arm: a slice element (N_TSLICE) is
|
||||
// a 24B {ptr,len,cap} header — it matches no prim/str/agg
|
||||
// branch above, so esz stayed the 8 sentinel (wrong stride,
|
||||
// the -96-vs-80 cs!=ww frame divergence) and the scalar
|
||||
// store dropped .len/.cap. Size it from the stamped tinfo
|
||||
// and route it through the 3-word header store below.
|
||||
let isslicel: bool = esubti != nil
|
||||
&& esubti.kind == tykind.TY_SLICE;
|
||||
if (isslicel) { esz = esubti.size: i32; };
|
||||
// #12: a tagged-union element. NOT folded into isagg —
|
||||
// isagg's body word-copies/fatals and never boxes the
|
||||
// tag+payload; route through the cgwidentaggedstore
|
||||
// choke-point the N_LET tagged path (cgenstmt.ww:1627)
|
||||
// uses. esz must come from the stamped slot size (#8-class
|
||||
// trap, rule-13): the narrow override below only rescues
|
||||
// 1/2/4, so a tagged 16/24B element keeps the wrong 8
|
||||
// sentinel stride without this.
|
||||
let istaggedel: bool = esubti != nil
|
||||
&& esubti.kind == tykind.TY_TAGGED;
|
||||
if (istaggedel) { esz = esubti.size: i32; };
|
||||
// #8: a named-narrow element (`[N]tk`, tk = enum i32) is
|
||||
// neither a builtin prim (primsize=0 above, so esz stayed
|
||||
// the 8 sentinel) nor an aggregate, so the scalar store kept
|
||||
// an 8B stride/MOVQ and overran the stride-4 frame slot —
|
||||
// smashing the saved BP / return addr (SEGFAULT). Mirror
|
||||
// cstage's uniform lu->sub->size (cgen.c:6387) and the
|
||||
// elemsizeofc read-side fix: take the stamped element tinfo's
|
||||
// size for a narrow scalar (1/2/4). Wider non-prim elements
|
||||
// (tagged/slice/str two-half) stay the documented follow-up
|
||||
// at :1742-1744 — the single-MOVx store below is scalar-only.
|
||||
if (!isstrel && !isagg && esz == 8 && esubti != nil) {
|
||||
let es: i32 = esubti.size: i32;
|
||||
if (es == 1 || es == 2 || es == 4) { esz = es; };
|
||||
};
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
// float element → store FROM X0 (MOVSS/MOVSD): cgexpr
|
||||
// leaves a float in X0 and for f32 the #104 CVTSD2SS
|
||||
// narrowing only touches X0; the AX store (mop) would
|
||||
// write the raw double low-bits, garbage for f32 (#122,
|
||||
// mirrors cstage cgen.c:6889 arr-lit float store).
|
||||
let isfloatel: bool = isfloattype(c, elemn);
|
||||
let fmov: str = "MOVSD";
|
||||
if (isf32type(c, elemn)) { fmov = "MOVSS"; };
|
||||
let idx: i32 = 0;
|
||||
let repeat: bool = false;
|
||||
let e: *node = rhs.list;
|
||||
for (e != nil) {
|
||||
let isellip: bool = false;
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
isellip = true;
|
||||
};
|
||||
};
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
if (isagg) {
|
||||
if (e.kind == nkind.N_STRUCTLIT) {
|
||||
let esi: *structinfo = structlookupchain(c, elemn);
|
||||
cgstructlitfillbp(c, esi, e, off + idx * esz);
|
||||
} else { if (e.kind == nkind.N_IDENT) {
|
||||
let sl: *local = localfindnode(c, e.str);
|
||||
let soff: i32 = 0;
|
||||
if (sl != nil) { soff = sl.off; };
|
||||
let kc: i32 = 0;
|
||||
for (kc + 8 <= esz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 8;
|
||||
};
|
||||
if (kc + 4 <= esz) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 4;
|
||||
};
|
||||
if (kc + 2 <= esz) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 2;
|
||||
};
|
||||
if (kc + 1 <= esz) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 1;
|
||||
};
|
||||
} else {
|
||||
let m1c: str = "#270-1c: array-literal aggregate element shape unsupported (rule-7)\n";
|
||||
os.write(2, m1c.ptr, m1c.len: u64);
|
||||
os.exit(1);
|
||||
}; };
|
||||
} else { if (istaggedel) {
|
||||
cgwidentaggedstore(c, esubti, e, "BP", off + idx * esz, esz);
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (isstrel || isslicel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + idx * esz + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitoff((off + idx * esz + 16): i64);
|
||||
emitline("(BP)\n");
|
||||
} else { if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
}; };
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat && isagg) {
|
||||
let m1cr: str = "#270-1c: `...` repeat of an aggregate array-literal element not wired (rule-7)\n";
|
||||
os.write(2, m1cr.ptr, m1cr.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// #12: `...` re-stores from AX, but cgwidentaggedstore consumed
|
||||
// the node and trashed AX — the repeat-fill would write garbage.
|
||||
// No consumer needs `[N]tagged=[x,...]`.
|
||||
if (repeat && istaggedel) {
|
||||
let m12r: str = "#12: `...` repeat of a tagged-union array-literal element not wired (rule-7)\n";
|
||||
os.write(2, m12r.ptr, m12r.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// AX (and BX for str) still holds the last stored value;
|
||||
// fill remaining slots up to the declared length with it.
|
||||
if (repeat) {
|
||||
let total: i32 = idx;
|
||||
if (arrtn != nil) {
|
||||
if (arrtn.kind == nkind.N_TARRAY) {
|
||||
if (arrtn.rhs != nil) {
|
||||
if (arrtn.rhs.kind == nkind.N_INTLIT) {
|
||||
total = arrtn.rhs.uval: i32;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
for (idx < total) {
|
||||
if (isstrel || isslicel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + idx * esz + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitoff((off + idx * esz + 16): i64);
|
||||
emitline("(BP)\n");
|
||||
} else { if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
idx += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fn cglet(c: *cgen, n: *node) void = {
|
||||
let nm: str = n.str;
|
||||
let sz: i32 = letslotsize(c, n);
|
||||
@@ -1744,228 +1976,7 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
// composites generally. The str/slice element now stores all 3
|
||||
// words; [N]tagged element arrays still hit the gap, task #12.)
|
||||
if (rhs.kind == nkind.N_ARRLIT) {
|
||||
let elemn: *node = n.lhs.lhs;
|
||||
let esz: i32 = 8;
|
||||
let isstrel: bool = false;
|
||||
if (elemn != nil) {
|
||||
if (elemn.kind == nkind.N_TNAME) {
|
||||
if (streq(elemn.str, "str")) {
|
||||
esz = primtypesize("str"): i32;
|
||||
isstrel = true;
|
||||
} else {
|
||||
let ps: i32 = primsize(elemn.str);
|
||||
if (ps > 0) { esz = ps; };
|
||||
};
|
||||
};
|
||||
};
|
||||
// #270-1c: an AGGREGATE (struct/array/tuple) element of
|
||||
// an array literal — the scalar per-element store below
|
||||
// writes only the first 8 bytes (unpopulated tail). Fill
|
||||
// each element slot from its literal (cgstructlitfillbp)
|
||||
// or source ident (word-copy). esz is the element's
|
||||
// natural size (cstage esub->size).
|
||||
let esubti: *tinfo = nil;
|
||||
if (elemn != nil) { esubti = elemn.type_: *tinfo; };
|
||||
for (esubti != nil && esubti.kind == tykind.TY_NAMED) {
|
||||
esubti = esubti.under;
|
||||
};
|
||||
let isagg: bool = esubti != nil
|
||||
&& (esubti.kind == tykind.TY_STRUCT
|
||||
|| esubti.kind == tykind.TY_ARRAY
|
||||
|| esubti.kind == tykind.TY_TUPLE);
|
||||
if (isagg) { esz = esubti.size: i32; };
|
||||
// #20/#270 str-slice arm: a slice element (N_TSLICE) is
|
||||
// a 24B {ptr,len,cap} header — it matches no prim/str/agg
|
||||
// branch above, so esz stayed the 8 sentinel (wrong stride,
|
||||
// the -96-vs-80 cs!=ww frame divergence) and the scalar
|
||||
// store dropped .len/.cap. Size it from the stamped tinfo
|
||||
// and route it through the 3-word header store below.
|
||||
let isslicel: bool = esubti != nil
|
||||
&& esubti.kind == tykind.TY_SLICE;
|
||||
if (isslicel) { esz = esubti.size: i32; };
|
||||
// #12: a tagged-union element. NOT folded into isagg —
|
||||
// isagg's body word-copies/fatals and never boxes the
|
||||
// tag+payload; route through the cgwidentaggedstore
|
||||
// choke-point the N_LET tagged path (cgenstmt.ww:1627)
|
||||
// uses. esz must come from the stamped slot size (#8-class
|
||||
// trap, rule-13): the narrow override below only rescues
|
||||
// 1/2/4, so a tagged 16/24B element keeps the wrong 8
|
||||
// sentinel stride without this.
|
||||
let istaggedel: bool = esubti != nil
|
||||
&& esubti.kind == tykind.TY_TAGGED;
|
||||
if (istaggedel) { esz = esubti.size: i32; };
|
||||
// #8: a named-narrow element (`[N]tk`, tk = enum i32) is
|
||||
// neither a builtin prim (primsize=0 above, so esz stayed
|
||||
// the 8 sentinel) nor an aggregate, so the scalar store kept
|
||||
// an 8B stride/MOVQ and overran the stride-4 frame slot —
|
||||
// smashing the saved BP / return addr (SEGFAULT). Mirror
|
||||
// cstage's uniform lu->sub->size (cgen.c:6387) and the
|
||||
// elemsizeofc read-side fix: take the stamped element tinfo's
|
||||
// size for a narrow scalar (1/2/4). Wider non-prim elements
|
||||
// (tagged/slice/str two-half) stay the documented follow-up
|
||||
// at :1742-1744 — the single-MOVx store below is scalar-only.
|
||||
if (!isstrel && !isagg && esz == 8 && esubti != nil) {
|
||||
let es: i32 = esubti.size: i32;
|
||||
if (es == 1 || es == 2 || es == 4) { esz = es; };
|
||||
};
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
// float element → store FROM X0 (MOVSS/MOVSD): cgexpr
|
||||
// leaves a float in X0 and for f32 the #104 CVTSD2SS
|
||||
// narrowing only touches X0; the AX store (mop) would
|
||||
// write the raw double low-bits, garbage for f32 (#122,
|
||||
// mirrors cstage cgen.c:6889 arr-lit float store).
|
||||
let isfloatel: bool = isfloattype(c, elemn);
|
||||
let fmov: str = "MOVSD";
|
||||
if (isf32type(c, elemn)) { fmov = "MOVSS"; };
|
||||
let idx: i32 = 0;
|
||||
let repeat: bool = false;
|
||||
let e: *node = rhs.list;
|
||||
for (e != nil) {
|
||||
let isellip: bool = false;
|
||||
if (e.kind == nkind.N_FIELD) {
|
||||
if (streq(e.str, "...")) {
|
||||
repeat = true;
|
||||
isellip = true;
|
||||
};
|
||||
};
|
||||
if (isellip) {
|
||||
e = nil;
|
||||
} else {
|
||||
if (isagg) {
|
||||
if (e.kind == nkind.N_STRUCTLIT) {
|
||||
let esi: *structinfo = structlookupchain(c, elemn);
|
||||
cgstructlitfillbp(c, esi, e, off + idx * esz);
|
||||
} else { if (e.kind == nkind.N_IDENT) {
|
||||
let sl: *local = localfindnode(c, e.str);
|
||||
let soff: i32 = 0;
|
||||
if (sl != nil) { soff = sl.off; };
|
||||
let kc: i32 = 0;
|
||||
for (kc + 8 <= esz) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 8;
|
||||
};
|
||||
if (kc + 4 <= esz) {
|
||||
emitline("\tMOVL\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVL\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 4;
|
||||
};
|
||||
if (kc + 2 <= esz) {
|
||||
emitline("\tMOVW\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVW\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 2;
|
||||
};
|
||||
if (kc + 1 <= esz) {
|
||||
emitline("\tMOVB\t");
|
||||
emitoff((soff + kc): i64);
|
||||
emitline("(BP), AX\n");
|
||||
emitline("\tMOVB\tAX, ");
|
||||
emitoff((off + idx * esz + kc): i64);
|
||||
emitline("(BP)\n");
|
||||
kc += 1;
|
||||
};
|
||||
} else {
|
||||
let m1c: str = "#270-1c: array-literal aggregate element shape unsupported (rule-7)\n";
|
||||
os.write(2, m1c.ptr, m1c.len: u64);
|
||||
os.exit(1);
|
||||
}; };
|
||||
} else { if (istaggedel) {
|
||||
cgwidentaggedstore(c, esubti, e, "BP", off + idx * esz, esz);
|
||||
} else {
|
||||
cgexpr(c, e);
|
||||
if (isstrel || isslicel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + idx * esz + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitoff((off + idx * esz + 16): i64);
|
||||
emitline("(BP)\n");
|
||||
} else { if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
}; };
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
if (repeat && isagg) {
|
||||
let m1cr: str = "#270-1c: `...` repeat of an aggregate array-literal element not wired (rule-7)\n";
|
||||
os.write(2, m1cr.ptr, m1cr.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// #12: `...` re-stores from AX, but cgwidentaggedstore consumed
|
||||
// the node and trashed AX — the repeat-fill would write garbage.
|
||||
// No consumer needs `[N]tagged=[x,...]`.
|
||||
if (repeat && istaggedel) {
|
||||
let m12r: str = "#12: `...` repeat of a tagged-union array-literal element not wired (rule-7)\n";
|
||||
os.write(2, m12r.ptr, m12r.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
// AX (and BX for str) still holds the last stored value;
|
||||
// fill remaining slots up to the declared length with it.
|
||||
if (repeat) {
|
||||
let total: i32 = idx;
|
||||
if (n.lhs != nil) {
|
||||
if (n.lhs.kind == nkind.N_TARRAY) {
|
||||
if (n.lhs.rhs != nil) {
|
||||
if (n.lhs.rhs.kind == nkind.N_INTLIT) {
|
||||
total = n.lhs.rhs.uval: i32;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
for (idx < total) {
|
||||
if (isstrel || isslicel) {
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, ");
|
||||
emitoff((off + idx * esz + 8): i64);
|
||||
emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tCX, ");
|
||||
emitoff((off + idx * esz + 16): i64);
|
||||
emitline("(BP)\n");
|
||||
} else { if (isfloatel) {
|
||||
emitline("\t");
|
||||
emitline(fmov);
|
||||
emitline("\tX0, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
} else {
|
||||
emitline("\t");
|
||||
emitline(mop);
|
||||
emitline("\tAX, ");
|
||||
emitoff((off + idx * esz): i64);
|
||||
emitline("(BP)\n");
|
||||
}; };
|
||||
idx += 1;
|
||||
};
|
||||
};
|
||||
cgarrlitfillbp(c, n.lhs, rhs, off);
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user