wcc+w6c_ww: >48B tagged args from place-resolved sources (#38b cont.)
Task #40 (FB3): the #38b MEMORY-class staging only accepted ident / aggarg_srcaddr-enumerated sources, loud-stopping on a slice-element arg — the regex run_thread loop-condition shape is_consuming_inst(re.insts[threads[i].pc]) (regex.ha:602) and B4's (*p)[i] spelling. The staging now falls back to cgplaceaddr (the F6 resolver) for the slot's source address; the existing word-push machinery is unchanged. Placed AFTER aggarg_srcaddr so every pre-#40 shape keeps its asm byte-exact (verified vs a master w6c). Boundaries kept loud (rule 7): exact-type rvalue (no place to resolve), sret-class call source (#40-family follow-up), global tagged let (task #25), variadic element, register-overflow mixing. Diagnostic re-worded to match: slice-element is wired, rvalue and unresolvable-place sources are not. test/929 grows 6 run rows (element source with literal+computed index, deref-spine, nested re.insts[threads[i].pc] spelling, element mixed with register args both orders, fn-call index with two mem args per call — the inner CALL runs inside the mem pre-pass with the other slot already staged — and global-slice element, the storage-backed twin of the loud fail_global_src boundary — all build-fail loud at master) and 1 reject row pinning the new boundary text on both stages.
This commit is contained in:
@@ -7391,8 +7391,23 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
memslots += msz / 8;
|
||||
continue;
|
||||
}
|
||||
/* #40/FB3: a place the enumerated arms miss —
|
||||
* slice element, deref-spine element — resolves
|
||||
* through the F6 resolver. AFTER aggarg_srcaddr
|
||||
* so every pre-#40 shape keeps its asm; the
|
||||
* resolver balances its own pushes, so the words
|
||||
* already staged below stay put. */
|
||||
if (cgplaceaddr(c, args[i], D_SI, locals)) {
|
||||
for (int k = msz/8 - 1; k >= 0; k--) {
|
||||
ins2(c, A_MOVQ, amem(D_SI, k*8),
|
||||
areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
}
|
||||
memslots += msz / 8;
|
||||
continue;
|
||||
}
|
||||
fatal("#38b: >48B tagged arg from unsupported source "
|
||||
"kind %d (slice-element and rvalue sources "
|
||||
"kind %d (rvalue and unresolvable-place sources "
|
||||
"unwired)", args[i]->kind);
|
||||
}
|
||||
/* eval right-to-left, push to stack. Each N_IDENT fast-path
|
||||
|
||||
@@ -16000,7 +16000,23 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node, memphase: bool) i32 = {
|
||||
};
|
||||
return rest + memsz / 8;
|
||||
};
|
||||
let mu: str = "#38b: >48B tagged arg from unsupported source kind (slice-element and rvalue sources unwired)\n";
|
||||
// #40/FB3: a place the enumerated arms miss — slice
|
||||
// element, deref-spine element — resolves through the F6
|
||||
// resolver. AFTER aggargsrcaddr so every pre-#40 shape
|
||||
// keeps its asm; the resolver balances its own pushes, so
|
||||
// the words already staged below stay put.
|
||||
if (cgplaceaddr(c, arg, "SI")) {
|
||||
let w: i32 = memsz / 8 - 1;
|
||||
for (w >= 0) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((w*8): i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
w -= 1;
|
||||
};
|
||||
return rest + memsz / 8;
|
||||
};
|
||||
let mu: str = "#38b: >48B tagged arg from unsupported source kind (rvalue and unresolvable-place sources unwired)\n";
|
||||
os.write(2, mu.ptr, mu.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
|
||||
@@ -214,7 +214,23 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node, memphase: bool) i32 = {
|
||||
};
|
||||
return rest + memsz / 8;
|
||||
};
|
||||
let mu: str = "#38b: >48B tagged arg from unsupported source kind (slice-element and rvalue sources unwired)\n";
|
||||
// #40/FB3: a place the enumerated arms miss — slice
|
||||
// element, deref-spine element — resolves through the F6
|
||||
// resolver. AFTER aggargsrcaddr so every pre-#40 shape
|
||||
// keeps its asm; the resolver balances its own pushes, so
|
||||
// the words already staged below stay put.
|
||||
if (cgplaceaddr(c, arg, "SI")) {
|
||||
let w: i32 = memsz / 8 - 1;
|
||||
for (w >= 0) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((w*8): i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
w -= 1;
|
||||
};
|
||||
return rest + memsz / 8;
|
||||
};
|
||||
let mu: str = "#38b: >48B tagged arg from unsupported source kind (rvalue and unresolvable-place sources unwired)\n";
|
||||
os.write(2, mu.ptr, mu.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
|
||||
@@ -16000,7 +16000,23 @@ fn pushargsrev(c: *cgen, arg: *node, param: *node, memphase: bool) i32 = {
|
||||
};
|
||||
return rest + memsz / 8;
|
||||
};
|
||||
let mu: str = "#38b: >48B tagged arg from unsupported source kind (slice-element and rvalue sources unwired)\n";
|
||||
// #40/FB3: a place the enumerated arms miss — slice
|
||||
// element, deref-spine element — resolves through the F6
|
||||
// resolver. AFTER aggargsrcaddr so every pre-#40 shape
|
||||
// keeps its asm; the resolver balances its own pushes, so
|
||||
// the words already staged below stay put.
|
||||
if (cgplaceaddr(c, arg, "SI")) {
|
||||
let w: i32 = memsz / 8 - 1;
|
||||
for (w >= 0) {
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff((w*8): i64);
|
||||
emitline("(SI), AX\n");
|
||||
emitline("\tPUSHQ\tAX\n");
|
||||
w -= 1;
|
||||
};
|
||||
return rest + memsz / 8;
|
||||
};
|
||||
let mu: str = "#38b: >48B tagged arg from unsupported source kind (rvalue and unresolvable-place sources unwired)\n";
|
||||
os.write(2, mu.ptr, mu.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
|
||||
@@ -29,8 +29,10 @@
|
||||
* Rows flagged `buildfail` must be rejected by BOTH stages with that
|
||||
* row's EXACT #38b diagnostic — pinning WHICH guard fired (the
|
||||
* remaining unwired sub-shapes: sret-class call source, global-let
|
||||
* source, variadic element, register-overflow mixing caller- and
|
||||
* callee-side).
|
||||
* source, exact-type rvalue, variadic element, register-overflow
|
||||
* mixing caller- and callee-side). #40/FB3 wired the place-resolved
|
||||
* sources (slice element, deref-spine, nested index) via the
|
||||
* cgplaceaddr fallback — those are run rows now.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -309,6 +311,140 @@ static const struct row rows[] = {
|
||||
" return 0;\n"
|
||||
"};\n",
|
||||
0, "\tADDQ\t$56, SP\n", NULL, 0, NULL },
|
||||
/* #40/FB3: exact-type SLICE-ELEMENT source — `f(xs[i])`, the
|
||||
* regex run_thread loop-condition shape
|
||||
* (is_consuming_inst(re.insts[threads[i].pc]), regex.ha:602).
|
||||
* Staged from a cgplaceaddr-resolved address; literal and
|
||||
* computed indices, every variant, late payload word per arm. */
|
||||
{ "mem56_elem_source",
|
||||
MEM56_TYPES
|
||||
MEM56_PROBE
|
||||
"export fn main() i32 = {\n"
|
||||
" let xs: []t_u = [];\n"
|
||||
" let a: t_u = ('x': t_lit);\n"
|
||||
" append(xs, a);\n"
|
||||
" let r: t_rep = " MEM56_REP_LIT ";\n"
|
||||
" let b: t_u = r;\n"
|
||||
" append(xs, b);\n"
|
||||
" if (probe(xs[0]) != 1) { return 1; };\n"
|
||||
" if (probe(xs[1]) != 3) { return 2; };\n"
|
||||
" let i: size = 1;\n"
|
||||
" if (probe(xs[i]) != 3) { return 3; };\n"
|
||||
" return 0;\n"
|
||||
"};\n",
|
||||
0, "\tADDQ\t$56, SP\n", NULL, 0, NULL },
|
||||
/* #40/FB3: deref-spine element source — `f((*p)[i])`, B4's
|
||||
* actual spelling (slice reached through a pointer). */
|
||||
{ "mem56_elem_deref_spine",
|
||||
MEM56_TYPES
|
||||
MEM56_PROBE
|
||||
"export fn main() i32 = {\n"
|
||||
" let xs: []t_u = [];\n"
|
||||
" let r: t_rep = " MEM56_REP_LIT ";\n"
|
||||
" let b: t_u = r;\n"
|
||||
" append(xs, b);\n"
|
||||
" let p: *[]t_u = &xs;\n"
|
||||
" if (probe((*p)[0]) != 3) { return 1; };\n"
|
||||
" return 0;\n"
|
||||
"};\n",
|
||||
0, "\tADDQ\t$56, SP\n", NULL, 0, NULL },
|
||||
/* #40/FB3: the full nested spelling — dot-base slice indexed
|
||||
* by a field of another indexed element
|
||||
* (re.insts[threads[i].pc]). */
|
||||
{ "mem56_elem_nested_spine",
|
||||
MEM56_TYPES
|
||||
"type re_t = struct { flag: i64, insts: []t_u };\n"
|
||||
"type thr = struct { pc: size, gen: i64 };\n"
|
||||
MEM56_PROBE
|
||||
"export fn main() i32 = {\n"
|
||||
" let xs: []t_u = [];\n"
|
||||
" let a: t_u = ('x': t_lit);\n"
|
||||
" append(xs, a);\n"
|
||||
" let r: t_rep = " MEM56_REP_LIT ";\n"
|
||||
" let b: t_u = r;\n"
|
||||
" append(xs, b);\n"
|
||||
" let re: re_t = re_t { flag = 4, insts = xs };\n"
|
||||
" let threads: []thr = [];\n"
|
||||
" append(threads, thr { pc = 1, gen = 5 });\n"
|
||||
" if (probe(re.insts[threads[0].pc]) != 3) { return 1; };\n"
|
||||
" return 0;\n"
|
||||
"};\n",
|
||||
0, "\tADDQ\t$56, SP\n", NULL, 0, NULL },
|
||||
/* #40/FB3: element source mixed with register-class args, both
|
||||
* orders — the resolver's transient AX/CX clobbers must not
|
||||
* disturb the staged words or the register cursors. */
|
||||
{ "mem56_elem_mixed_regs",
|
||||
MEM56_TYPES
|
||||
"fn before(k: i64, s: str, a: t_u) i64 = {\n"
|
||||
" if (k != 5) { return 91; };\n"
|
||||
" if (s.len != 3) { return 92; };\n"
|
||||
" match (a) {\n"
|
||||
" case let r: t_rep => { return k + (r.m3: i64); };\n"
|
||||
" case => { return 93; };\n"
|
||||
" };\n"
|
||||
" return 99;\n"
|
||||
"};\n"
|
||||
"fn after(a: t_u, k: i64, s: str) i64 = {\n"
|
||||
" if (k != 6) { return 91; };\n"
|
||||
" if (s.len != 3) { return 92; };\n"
|
||||
" match (a) {\n"
|
||||
" case let r: t_rep => { return k + (r.m3: i64); };\n"
|
||||
" case => { return 93; };\n"
|
||||
" };\n"
|
||||
" return 99;\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let xs: []t_u = [];\n"
|
||||
" let r: t_rep = " MEM56_REP_LIT ";\n"
|
||||
" let b: t_u = r;\n"
|
||||
" append(xs, b);\n"
|
||||
" if (before(5, \"abc\", xs[0]) != 1239) { return 1; };\n"
|
||||
" if (after(xs[0], 6, \"abc\") != 1240) { return 2; };\n"
|
||||
" return 0;\n"
|
||||
"};\n",
|
||||
0, "\tADDQ\t$56, SP\n", NULL, 0, NULL },
|
||||
/* #40/FB3: fn-CALL index (the 2c computed-pc shape) + TWO mem
|
||||
* args per call, both orders. The inner CALL runs inside the
|
||||
* mem pre-pass with the other arg's 7 words already staged —
|
||||
* pins the resolver's push-balance claim; $112 = both slots. */
|
||||
{ "mem56_elem_callidx_twomem",
|
||||
MEM56_TYPES
|
||||
MEM56_PROBE
|
||||
"fn pick() size = {\n"
|
||||
" return 1;\n"
|
||||
"};\n"
|
||||
"fn two(a: t_u, b: t_u) i32 = {\n"
|
||||
" return probe(a) * 10 + probe(b);\n"
|
||||
"};\n"
|
||||
"export fn main() i32 = {\n"
|
||||
" let xs: []t_u = [];\n"
|
||||
" let a: t_u = ('x': t_lit);\n"
|
||||
" append(xs, a);\n"
|
||||
" let r: t_rep = " MEM56_REP_LIT ";\n"
|
||||
" let b: t_u = r;\n"
|
||||
" append(xs, b);\n"
|
||||
" if (two(xs[0], xs[pick()]) != 13) { return 1; };\n"
|
||||
" if (two(xs[pick()], xs[0]) != 31) { return 2; };\n"
|
||||
" return 0;\n"
|
||||
"};\n",
|
||||
0, "\tADDQ\t$112, SP\n", NULL, 0, NULL },
|
||||
/* #40/FB3: element of a GLOBAL slice let — the resolver's
|
||||
* let_islet arm, sound because slice globals have DATA storage
|
||||
* (the element lives behind .ptr). The storage-LESS twin (a
|
||||
* global tagged VALUE, let_emit_size=0, task #25) must stay
|
||||
* loud — fail_global_src pins that side of the boundary. */
|
||||
{ "mem56_elem_global_slice",
|
||||
MEM56_TYPES
|
||||
"let gxs: []t_u;\n"
|
||||
MEM56_PROBE
|
||||
"export fn main() i32 = {\n"
|
||||
" let r: t_rep = " MEM56_REP_LIT ";\n"
|
||||
" let b: t_u = r;\n"
|
||||
" append(gxs, b);\n"
|
||||
" if (probe(gxs[0]) != 3) { return 1; };\n"
|
||||
" return 0;\n"
|
||||
"};\n",
|
||||
0, "\tADDQ\t$56, SP\n", NULL, 0, NULL },
|
||||
/* BOUNDARY: 40B payload = EXACTLY 48B slot — must stay on the
|
||||
* register convention (no mem cleanup ADDQ). An off-by-one in
|
||||
* tagged_memarg_size flips every 48B-slot call in the tree. */
|
||||
@@ -435,6 +571,21 @@ static const struct row rows[] = {
|
||||
0, NULL, NULL, 1,
|
||||
"#38b: >48B tagged arg mixed with register-overflow stack "
|
||||
"args unwired" },
|
||||
/* LOUD-STOP: exact-type RVALUE source (same-type cast) — no
|
||||
* place to resolve; stays loud post-#40. Marker is the
|
||||
* parenthetical tail shared verbatim by both stages (cstage
|
||||
* interposes the numeric node kind), complementing
|
||||
* fail_global_src's prefix pin of the same guard. */
|
||||
{ "fail_rvalue_cast",
|
||||
MEM56_TYPES
|
||||
MEM56_PROBE
|
||||
"export fn main() i32 = {\n"
|
||||
" let a: t_u = ('x': t_lit);\n"
|
||||
" if (probe((a: t_u)) != 1) { return 1; };\n"
|
||||
" return 0;\n"
|
||||
"};\n",
|
||||
0, NULL, NULL, 1,
|
||||
"(rvalue and unresolvable-place sources unwired)" },
|
||||
};
|
||||
|
||||
static const char *g_bin;
|
||||
|
||||
Reference in New Issue
Block a user