cmd/w6c/cgen+test: skip dead TRYPROP propret on same-shape ?
Per CLAUDE.md rule 10, align cstage down to wwstage — when every variant in a `?` propagation maps to itself, the remap loop emits zero JMPs and the propret label is dead. Lazy-allocate it so the label-counter ID is only consumed when at least one JMP fires. Smoke test selfhost/test/trypromote.ww exercises same-shape (i64|nomem)→(i64|nomem) propagation; cstage and wwstage now emit byte-identical asm for the TRYPROP region.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,6 +10,7 @@
|
|||||||
/loop
|
/loop
|
||||||
/sym_link
|
/sym_link
|
||||||
/memiotest
|
/memiotest
|
||||||
|
/trypromote
|
||||||
|
|
||||||
# Per-module build artifacts. The .combined.ww files under selfhost/
|
# Per-module build artifacts. The .combined.ww files under selfhost/
|
||||||
# are intentionally tracked — they're frozen bootstrap inputs.
|
# are intentionally tracked — they're frozen bootstrap inputs.
|
||||||
|
|||||||
@@ -5038,7 +5038,11 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
ins2(c, A_CMPQ, aimm(s_tag), areg(D_AX));
|
ins2(c, A_CMPQ, aimm(s_tag), areg(D_AX));
|
||||||
ins1(c, A_JE, abranch(cont));
|
ins1(c, A_JE, abranch(cont));
|
||||||
if (u && r && r->kind == TY_TAGGED && u->params) {
|
if (u && r && r->kind == TY_TAGGED && u->params) {
|
||||||
char *propret = mklabel(c, "tryprop_ret");
|
/* Same-shape unions remap every variant to itself, so
|
||||||
|
* the loop emits no JMPs. Skip propret entirely then —
|
||||||
|
* wwstage doesn't emit a dead label either (CLAUDE.md
|
||||||
|
* rule 10, task #18). */
|
||||||
|
char *propret = NULL;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Tparam *p = u->params; p; p = p->next, i++) {
|
for (Tparam *p = u->params; p; p = p->next, i++) {
|
||||||
if (!cg_variant_is_error(u, i)) continue;
|
if (!cg_variant_is_error(u, i)) continue;
|
||||||
@@ -5049,10 +5053,13 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
ins2(c, A_CMPQ, aimm(i), areg(D_AX));
|
ins2(c, A_CMPQ, aimm(i), areg(D_AX));
|
||||||
ins1(c, A_JNE, abranch(skip));
|
ins1(c, A_JNE, abranch(skip));
|
||||||
ins2(c, A_MOVQ, aimm(j), areg(D_AX));
|
ins2(c, A_MOVQ, aimm(j), areg(D_AX));
|
||||||
|
if (propret == NULL)
|
||||||
|
propret = mklabel(c, "tryprop_ret");
|
||||||
ins1(c, A_JMP, abranch(propret));
|
ins1(c, A_JMP, abranch(propret));
|
||||||
label(c, skip);
|
label(c, skip);
|
||||||
}
|
}
|
||||||
label(c, propret);
|
if (propret != NULL)
|
||||||
|
label(c, propret);
|
||||||
}
|
}
|
||||||
ins2(c, A_MOVQ, areg(D_BP), areg(D_SP));
|
ins2(c, A_MOVQ, areg(D_BP), areg(D_SP));
|
||||||
ins1(c, A_POPQ, areg(D_BP));
|
ins1(c, A_POPQ, areg(D_BP));
|
||||||
|
|||||||
54
selfhost/test/trypromote.ww
Normal file
54
selfhost/test/trypromote.ww
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// selfhost/test/trypromote.ww — smoke for `?` propagation through a
|
||||||
|
// `!void`-shaped alias.
|
||||||
|
//
|
||||||
|
// Task #2 (ww-strings-redesign): proves cgen's TRYPROP tag-remap works
|
||||||
|
// for the exact pattern lib/errors + os.alloc are about to lean on. We
|
||||||
|
// cannot smoke this against lib/ today because there are zero lib-side
|
||||||
|
// `?` users on a `!void` alias yet. Mirrors the shlex.syntaxerr shape
|
||||||
|
// (lib/shlex/shlex.ww:112) for the "nomem" stub.
|
||||||
|
//
|
||||||
|
// Not table-driven on purpose: same-shape `?` is a single cgen emit
|
||||||
|
// pattern, so varying the operand exercises the same asm. The two
|
||||||
|
// match arms below cover both runtime outcomes (success unwrap, error
|
||||||
|
// propagation); asm-level regressions of task #18 are gated by the
|
||||||
|
// byte-identity tests (994_w6c_ww, 995_self_rebuild).
|
||||||
|
|
||||||
|
package test;
|
||||||
|
|
||||||
|
import fmt;
|
||||||
|
|
||||||
|
type nomem = !void;
|
||||||
|
|
||||||
|
fn stub(fail: i64) (i64 | nomem) = {
|
||||||
|
if (fail != 0i64) { let e: nomem; return e; };
|
||||||
|
return 42i64;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn caller(fail: i64) (i64 | nomem) = {
|
||||||
|
let v = stub(fail)?;
|
||||||
|
return v + 1i64;
|
||||||
|
};
|
||||||
|
|
||||||
|
export fn main() i32 = {
|
||||||
|
let rc: i32 = 0;
|
||||||
|
match (caller(0i64)) {
|
||||||
|
case let n: i64 => {
|
||||||
|
fmt.println("ok ", n);
|
||||||
|
if (n != 43i64) { rc = 1; };
|
||||||
|
};
|
||||||
|
case nomem => {
|
||||||
|
fmt.println("unexpected nomem on ok path");
|
||||||
|
rc = 2;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
match (caller(1i64)) {
|
||||||
|
case let n: i64 => {
|
||||||
|
fmt.println("unexpected ", n, " on err path");
|
||||||
|
rc = 3;
|
||||||
|
};
|
||||||
|
case nomem => {
|
||||||
|
fmt.println("nomem as expected");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return rc;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user