selfhost: cgfn pre-scan SysV-class accounting (closes #7)
Mirrors cgen.c §5130-5223 / cgfnparams: reg-spill, tagged-partial-fit, pure-stack. Pure-stack does not bump cursor (cstage semantics). Fixes 16B over-allocation on 7+ arg functions; bootstrap stays byte-identical. Slice/str at reg/stack straddle is deferred to task #11 (cgfnparams doesn't stitch them either); pre-scan stays symmetric until then.
This commit is contained in:
@@ -13680,22 +13680,65 @@ fn cgfn(c: *cgen, fn_: *node) void = {
|
||||
os.write(1, nm.ptr, nm.len: u64);
|
||||
emitline(",$");
|
||||
|
||||
// Pre-scan total frame: 24 bytes per slice param, 16 per str
|
||||
// param, 8 per other param, plus per-let from scanlocals.
|
||||
// Seed c.locals with param-name stubs so scanlocals dedups a
|
||||
// re-declared `let <name>` in the body against the param's
|
||||
// slot (matches C cgen). Stubs get cleared before emission.
|
||||
// Pre-scan total frame: only count params that land in a local
|
||||
// slot. SysV-class accounting; mirrors runtime walk in cstage
|
||||
// cgen.c §5130-5223 and cgfnparams below. A stack-spilled param
|
||||
// is addressed at a positive BP offset by cgfnparams (via
|
||||
// localaddstack) and consumes no frame, so adding its size here
|
||||
// would over-allocate. Seed c.locals with param-name stubs so
|
||||
// scanlocals dedups a re-declared `let <name>` in the body
|
||||
// against the param's slot (matches C cgen). Stubs get cleared
|
||||
// before emission.
|
||||
let scanp: *node = fn_.list;
|
||||
let frame: i32 = 0;
|
||||
let argi: i32 = 0;
|
||||
let fargi: i32 = 0;
|
||||
for (scanp != nil) {
|
||||
if (scanp.kind == nkind.N_PARAM) {
|
||||
// Hare-style variadic `T...`: param is []T inside
|
||||
// the callee, so it occupies a 24B slice slot.
|
||||
if (scanp.op == tkind.TK_ELLIPSIS) { frame += 24; }
|
||||
else { if (istaggedtype(c, scanp.lhs)) { frame += slotsize(c, scanp.lhs); }
|
||||
else { if (isslicetype(c, scanp.lhs)) { frame += 24; }
|
||||
else { if (isstrtype(c, scanp.lhs)) { frame += 16; }
|
||||
else { frame += 8; }; }; }; };
|
||||
let isvar: bool = scanp.op == tkind.TK_ELLIPSIS;
|
||||
let isf: bool = false;
|
||||
let istg: bool = false;
|
||||
let issl: bool = false;
|
||||
let isst: bool = false;
|
||||
if (!isvar) {
|
||||
isf = isfloattype(c, scanp.lhs);
|
||||
istg = istaggedtype(c, scanp.lhs);
|
||||
if (!isf && !istg) {
|
||||
issl = isslicetype(c, scanp.lhs);
|
||||
if (!issl) { isst = isstrtype(c, scanp.lhs); };
|
||||
};
|
||||
};
|
||||
let eb: i32 = 1;
|
||||
let sz: i32 = 8;
|
||||
if (isvar) { eb = 3; sz = 24; }
|
||||
else { if (istg) { sz = slotsize(c, scanp.lhs); eb = sz / 8; }
|
||||
else { if (issl) { eb = 3; sz = 24; }
|
||||
else { if (isst) { eb = 2; sz = 16; }
|
||||
else { if (isf) {
|
||||
eb = 1;
|
||||
sz = 8;
|
||||
if (isf32type(c, scanp.lhs)) { sz = 4; };
|
||||
}; }; }; }; };
|
||||
let regs_left: i32 = 6 - argi;
|
||||
if (isf) { regs_left = 8 - fargi; };
|
||||
if (regs_left >= eb) {
|
||||
frame += sz;
|
||||
if (isf) { fargi += 1; }
|
||||
else { argi += eb; };
|
||||
} else { if (eb > 1 && regs_left > 0 && istg) {
|
||||
// Tagged param straddles the reg/stack boundary;
|
||||
// cgfnparams stitches the tail from positive BP
|
||||
// offsets into a single local slot, so we still
|
||||
// reserve the full size. Slice/str at the same
|
||||
// straddle are *not* stitched by cgfnparams today
|
||||
// (task #11) — once that's fixed the predicate
|
||||
// here must widen symmetrically.
|
||||
frame += sz;
|
||||
argi = 6;
|
||||
} else {
|
||||
// Pure stack: lives at +BP(16+stkcursor*8); no
|
||||
// local slot consumed. The reg cursor stays put.
|
||||
}; };
|
||||
scanseenmark(c, scanp.str);
|
||||
};
|
||||
scanp = scanp.next;
|
||||
|
||||
@@ -562,22 +562,65 @@ fn cgfn(c: *cgen, fn_: *node) void = {
|
||||
os.write(1, nm.ptr, nm.len: u64);
|
||||
emitline(",$");
|
||||
|
||||
// Pre-scan total frame: 24 bytes per slice param, 16 per str
|
||||
// param, 8 per other param, plus per-let from scanlocals.
|
||||
// Seed c.locals with param-name stubs so scanlocals dedups a
|
||||
// re-declared `let <name>` in the body against the param's
|
||||
// slot (matches C cgen). Stubs get cleared before emission.
|
||||
// Pre-scan total frame: only count params that land in a local
|
||||
// slot. SysV-class accounting; mirrors runtime walk in cstage
|
||||
// cgen.c §5130-5223 and cgfnparams below. A stack-spilled param
|
||||
// is addressed at a positive BP offset by cgfnparams (via
|
||||
// localaddstack) and consumes no frame, so adding its size here
|
||||
// would over-allocate. Seed c.locals with param-name stubs so
|
||||
// scanlocals dedups a re-declared `let <name>` in the body
|
||||
// against the param's slot (matches C cgen). Stubs get cleared
|
||||
// before emission.
|
||||
let scanp: *node = fn_.list;
|
||||
let frame: i32 = 0;
|
||||
let argi: i32 = 0;
|
||||
let fargi: i32 = 0;
|
||||
for (scanp != nil) {
|
||||
if (scanp.kind == nkind.N_PARAM) {
|
||||
// Hare-style variadic `T...`: param is []T inside
|
||||
// the callee, so it occupies a 24B slice slot.
|
||||
if (scanp.op == tkind.TK_ELLIPSIS) { frame += 24; }
|
||||
else { if (istaggedtype(c, scanp.lhs)) { frame += slotsize(c, scanp.lhs); }
|
||||
else { if (isslicetype(c, scanp.lhs)) { frame += 24; }
|
||||
else { if (isstrtype(c, scanp.lhs)) { frame += 16; }
|
||||
else { frame += 8; }; }; }; };
|
||||
let isvar: bool = scanp.op == tkind.TK_ELLIPSIS;
|
||||
let isf: bool = false;
|
||||
let istg: bool = false;
|
||||
let issl: bool = false;
|
||||
let isst: bool = false;
|
||||
if (!isvar) {
|
||||
isf = isfloattype(c, scanp.lhs);
|
||||
istg = istaggedtype(c, scanp.lhs);
|
||||
if (!isf && !istg) {
|
||||
issl = isslicetype(c, scanp.lhs);
|
||||
if (!issl) { isst = isstrtype(c, scanp.lhs); };
|
||||
};
|
||||
};
|
||||
let eb: i32 = 1;
|
||||
let sz: i32 = 8;
|
||||
if (isvar) { eb = 3; sz = 24; }
|
||||
else { if (istg) { sz = slotsize(c, scanp.lhs); eb = sz / 8; }
|
||||
else { if (issl) { eb = 3; sz = 24; }
|
||||
else { if (isst) { eb = 2; sz = 16; }
|
||||
else { if (isf) {
|
||||
eb = 1;
|
||||
sz = 8;
|
||||
if (isf32type(c, scanp.lhs)) { sz = 4; };
|
||||
}; }; }; }; };
|
||||
let regs_left: i32 = 6 - argi;
|
||||
if (isf) { regs_left = 8 - fargi; };
|
||||
if (regs_left >= eb) {
|
||||
frame += sz;
|
||||
if (isf) { fargi += 1; }
|
||||
else { argi += eb; };
|
||||
} else { if (eb > 1 && regs_left > 0 && istg) {
|
||||
// Tagged param straddles the reg/stack boundary;
|
||||
// cgfnparams stitches the tail from positive BP
|
||||
// offsets into a single local slot, so we still
|
||||
// reserve the full size. Slice/str at the same
|
||||
// straddle are *not* stitched by cgfnparams today
|
||||
// (task #11) — once that's fixed the predicate
|
||||
// here must widen symmetrically.
|
||||
frame += sz;
|
||||
argi = 6;
|
||||
} else {
|
||||
// Pure stack: lives at +BP(16+stkcursor*8); no
|
||||
// local slot consumed. The reg cursor stays put.
|
||||
}; };
|
||||
scanseenmark(c, scanp.str);
|
||||
};
|
||||
scanp = scanp.next;
|
||||
|
||||
@@ -13680,22 +13680,65 @@ fn cgfn(c: *cgen, fn_: *node) void = {
|
||||
os.write(1, nm.ptr, nm.len: u64);
|
||||
emitline(",$");
|
||||
|
||||
// Pre-scan total frame: 24 bytes per slice param, 16 per str
|
||||
// param, 8 per other param, plus per-let from scanlocals.
|
||||
// Seed c.locals with param-name stubs so scanlocals dedups a
|
||||
// re-declared `let <name>` in the body against the param's
|
||||
// slot (matches C cgen). Stubs get cleared before emission.
|
||||
// Pre-scan total frame: only count params that land in a local
|
||||
// slot. SysV-class accounting; mirrors runtime walk in cstage
|
||||
// cgen.c §5130-5223 and cgfnparams below. A stack-spilled param
|
||||
// is addressed at a positive BP offset by cgfnparams (via
|
||||
// localaddstack) and consumes no frame, so adding its size here
|
||||
// would over-allocate. Seed c.locals with param-name stubs so
|
||||
// scanlocals dedups a re-declared `let <name>` in the body
|
||||
// against the param's slot (matches C cgen). Stubs get cleared
|
||||
// before emission.
|
||||
let scanp: *node = fn_.list;
|
||||
let frame: i32 = 0;
|
||||
let argi: i32 = 0;
|
||||
let fargi: i32 = 0;
|
||||
for (scanp != nil) {
|
||||
if (scanp.kind == nkind.N_PARAM) {
|
||||
// Hare-style variadic `T...`: param is []T inside
|
||||
// the callee, so it occupies a 24B slice slot.
|
||||
if (scanp.op == tkind.TK_ELLIPSIS) { frame += 24; }
|
||||
else { if (istaggedtype(c, scanp.lhs)) { frame += slotsize(c, scanp.lhs); }
|
||||
else { if (isslicetype(c, scanp.lhs)) { frame += 24; }
|
||||
else { if (isstrtype(c, scanp.lhs)) { frame += 16; }
|
||||
else { frame += 8; }; }; }; };
|
||||
let isvar: bool = scanp.op == tkind.TK_ELLIPSIS;
|
||||
let isf: bool = false;
|
||||
let istg: bool = false;
|
||||
let issl: bool = false;
|
||||
let isst: bool = false;
|
||||
if (!isvar) {
|
||||
isf = isfloattype(c, scanp.lhs);
|
||||
istg = istaggedtype(c, scanp.lhs);
|
||||
if (!isf && !istg) {
|
||||
issl = isslicetype(c, scanp.lhs);
|
||||
if (!issl) { isst = isstrtype(c, scanp.lhs); };
|
||||
};
|
||||
};
|
||||
let eb: i32 = 1;
|
||||
let sz: i32 = 8;
|
||||
if (isvar) { eb = 3; sz = 24; }
|
||||
else { if (istg) { sz = slotsize(c, scanp.lhs); eb = sz / 8; }
|
||||
else { if (issl) { eb = 3; sz = 24; }
|
||||
else { if (isst) { eb = 2; sz = 16; }
|
||||
else { if (isf) {
|
||||
eb = 1;
|
||||
sz = 8;
|
||||
if (isf32type(c, scanp.lhs)) { sz = 4; };
|
||||
}; }; }; }; };
|
||||
let regs_left: i32 = 6 - argi;
|
||||
if (isf) { regs_left = 8 - fargi; };
|
||||
if (regs_left >= eb) {
|
||||
frame += sz;
|
||||
if (isf) { fargi += 1; }
|
||||
else { argi += eb; };
|
||||
} else { if (eb > 1 && regs_left > 0 && istg) {
|
||||
// Tagged param straddles the reg/stack boundary;
|
||||
// cgfnparams stitches the tail from positive BP
|
||||
// offsets into a single local slot, so we still
|
||||
// reserve the full size. Slice/str at the same
|
||||
// straddle are *not* stitched by cgfnparams today
|
||||
// (task #11) — once that's fixed the predicate
|
||||
// here must widen symmetrically.
|
||||
frame += sz;
|
||||
argi = 6;
|
||||
} else {
|
||||
// Pure stack: lives at +BP(16+stkcursor*8); no
|
||||
// local slot consumed. The reg cursor stays put.
|
||||
}; };
|
||||
scanseenmark(c, scanp.str);
|
||||
};
|
||||
scanp = scanp.next;
|
||||
|
||||
Reference in New Issue
Block a user