cgen: B6-c4 cast/is/try family single peels fold into type_chase_named — 10 lines
The exact B6-c4 set (rob b6 spec §2, numbering at4cac1cb): :9422 (N_MATCH Family-C identity-cast peel su), :9598 (match-bind base bu), :9674 (tryprop non-call source u), :9718 (cg_ret_type peel r at the cgexpr try region — same rt-route kinship as B5-c3's cgreturn chase: the nullable/tagged propagate keys the chased enclosing return type exactly as the return arms do), :9819 (tryunw twin u — LOUD-PRESERVING ONLY, the #38b sret bound is alias-INDEPENDENT), :9986/:9991 (N_TYPEASSERT u + enum vu), :10103/:10105 (str→[]u8 cap-synth tu/fu), :10131 (narrowing-cast tu). Raw `->under` in cgen.c 27→17 — remaining = whitelist 5 (:731 :813/:814 :834/:835) + B7 emitters 4 + the c5 set 8, grep-verified exact. FLIP: kb6_strcast (str→[]u8 over 2-level alias, was both-correct divergent NO(2)) → 0/0 BYTE-ID; cs converged onto ww's UNCHANGED asm (#263 polarity, cmp-proven) and the alias shape now equals the plain shape (kb6_strcast_p, same hash — ken's c4 pre-test confirmed ww's dedicated gate DOES fire on alias here, unlike the c3 sites). kb6_try loud held both stages with the pinned #38b text (try_loud_38b row); idcast/is/succ byte-id held; zero other movers. TRAIN INVARIANT: cs-only; w6c_ww/ww_ww bit-identical to the4cac1cbbaselines (b6bddc8e…/4e9ca874…). cs movers c3→c4 bounded to exactly {kb6_strcast}; rest of corpus + five mains byte-NEUTRAL; detectors unmoved; 989 ratchet zero flips. 944_alias_cgen_b6_run grows 14→18 rows, 38→49 checks: strcast_2lvl flip + idcast_2lvl/is_2lvl controls + try_loud_38b both-loud pin. All 944-family suites green; sizelint 0.
This commit is contained in:
@@ -9399,7 +9399,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
/* Family C (#35): identity-cast peel — see the `is` twin. */
|
/* Family C (#35): identity-cast peel — see the `is` twin. */
|
||||||
Node *s = cg_tagged_idcastpeel(n->lhs);
|
Node *s = cg_tagged_idcastpeel(n->lhs);
|
||||||
Type *st = s ? s->type : NULL;
|
Type *st = s ? s->type : NULL;
|
||||||
Type *su = (st && st->kind == TY_NAMED) ? st->under : st;
|
Type *su = type_chase_named(st);
|
||||||
int is_nullable = type_isnullable(st);
|
int is_nullable = type_isnullable(st);
|
||||||
int slot_size = (su && su->kind == TY_TAGGED) ? (int)su->size : 16;
|
int slot_size = (su && su->kind == TY_TAGGED) ? (int)su->size : 16;
|
||||||
int sl_off;
|
int sl_off;
|
||||||
@@ -9574,8 +9574,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
}
|
}
|
||||||
if (cs->str && cs->str[0] && cs->type) {
|
if (cs->str && cs->str[0] && cs->type) {
|
||||||
Type *bt = cs->type;
|
Type *bt = cs->type;
|
||||||
Type *bu = (bt && bt->kind == TY_NAMED)
|
Type *bu = type_chase_named(bt);
|
||||||
? bt->under : bt;
|
|
||||||
if (is_nullable) {
|
if (is_nullable) {
|
||||||
/* Bind *T or void to a local. The
|
/* Bind *T or void to a local. The
|
||||||
* value IS the slot's pointer word; no
|
* value IS the slot's pointer word; no
|
||||||
@@ -9651,7 +9650,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
"return unwired (sret error-propagate is a "
|
"return unwired (sret error-propagate is a "
|
||||||
"#40-family follow-up)");
|
"#40-family follow-up)");
|
||||||
Type *u = n->lhs ? n->lhs->type : NULL;
|
Type *u = n->lhs ? n->lhs->type : NULL;
|
||||||
if (u && u->kind == TY_NAMED) u = u->under;
|
u = type_chase_named(u);
|
||||||
/* Family C (#35/#46): non-call sources don't fill the
|
/* Family C (#35/#46): non-call sources don't fill the
|
||||||
* AX/DX/CX/R8 cursor the unwrap below reads — an IDENT
|
* AX/DX/CX/R8 cursor the unwrap below reads — an IDENT
|
||||||
* loads it from its slot, a mem-based read (deref at any
|
* loads it from its slot, a mem-based read (deref at any
|
||||||
@@ -9695,7 +9694,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
} else
|
} else
|
||||||
cgexpr(c, n->lhs, locals);
|
cgexpr(c, n->lhs, locals);
|
||||||
Type *r = cg_ret_type;
|
Type *r = cg_ret_type;
|
||||||
if (r && r->kind == TY_NAMED) r = r->under;
|
r = type_chase_named(r);
|
||||||
if (u && u->kind == TY_TAGGED && u->nullable) {
|
if (u && u->kind == TY_TAGGED && u->nullable) {
|
||||||
char *cont = mklabel(c, "tryprop_ok");
|
char *cont = mklabel(c, "tryprop_ok");
|
||||||
ins2(c, A_CMPQ, aimm(0), areg(D_AX));
|
ins2(c, A_CMPQ, aimm(0), areg(D_AX));
|
||||||
@@ -9796,7 +9795,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
"unwired (mem-based unwrap is a #40-family "
|
"unwired (mem-based unwrap is a #40-family "
|
||||||
"follow-up)");
|
"follow-up)");
|
||||||
Type *u = n->lhs ? n->lhs->type : NULL;
|
Type *u = n->lhs ? n->lhs->type : NULL;
|
||||||
if (u && u->kind == TY_NAMED) u = u->under;
|
u = type_chase_named(u);
|
||||||
/* Family C (#35/#46): see the N_TRYPROP twin — ident loads
|
/* Family C (#35/#46): see the N_TRYPROP twin — ident loads
|
||||||
* the cursor from its slot, a mem-based read from the box
|
* the cursor from its slot, a mem-based read from the box
|
||||||
* address; >32B non-call stays loud (#40 family). */
|
* address; >32B non-call stays loud (#40 family). */
|
||||||
@@ -9963,12 +9962,12 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
/* Family C (#35): identity-cast peel — see the `is` twin. */
|
/* Family C (#35): identity-cast peel — see the `is` twin. */
|
||||||
Node *s = cg_tagged_idcastpeel(n->lhs);
|
Node *s = cg_tagged_idcastpeel(n->lhs);
|
||||||
Type *st = s ? s->type : NULL;
|
Type *st = s ? s->type : NULL;
|
||||||
Type *u = (st && st->kind == TY_NAMED) ? st->under : st;
|
Type *u = type_chase_named(st);
|
||||||
Type *vt = n->type;
|
Type *vt = n->type;
|
||||||
/* Enum ↔ integer: reinterpret-only. The value already lives
|
/* Enum ↔ integer: reinterpret-only. The value already lives
|
||||||
* in AX after evaluating the LHS; no tag/unwrap needed. */
|
* in AX after evaluating the LHS; no tag/unwrap needed. */
|
||||||
{
|
{
|
||||||
Type *vu = (vt && vt->kind == TY_NAMED) ? vt->under : vt;
|
Type *vu = type_chase_named(vt);
|
||||||
if ((u && u->kind == TY_ENUM) ||
|
if ((u && u->kind == TY_ENUM) ||
|
||||||
(vu && vu->kind == TY_ENUM)) {
|
(vu && vu->kind == TY_ENUM)) {
|
||||||
cgexpr(c, s, locals);
|
cgexpr(c, s, locals);
|
||||||
@@ -10080,9 +10079,9 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
* and the receiver reads a stale value. */
|
* and the receiver reads a stale value. */
|
||||||
{
|
{
|
||||||
Type *tt = n->type;
|
Type *tt = n->type;
|
||||||
Type *tu = (tt && tt->kind == TY_NAMED) ? tt->under : tt;
|
Type *tu = type_chase_named(tt);
|
||||||
Type *ft = n->lhs ? n->lhs->type : NULL;
|
Type *ft = n->lhs ? n->lhs->type : NULL;
|
||||||
Type *fu = (ft && ft->kind == TY_NAMED) ? ft->under : ft;
|
Type *fu = type_chase_named(ft);
|
||||||
if (tu && tu->kind == TY_SLICE
|
if (tu && tu->kind == TY_SLICE
|
||||||
&& fu && fu->kind == TY_STR) {
|
&& fu && fu->kind == TY_STR) {
|
||||||
ins2(c, A_MOVQ, areg(D_BX), areg(D_CX));
|
ins2(c, A_MOVQ, areg(D_BX), areg(D_CX));
|
||||||
@@ -10108,7 +10107,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
* unsigned (Unicode scalar) and lands on the MOVL path. */
|
* unsigned (Unicode scalar) and lands on the MOVL path. */
|
||||||
if (!from_f && !to_f && n->type) {
|
if (!from_f && !to_f && n->type) {
|
||||||
Type *tt = n->type;
|
Type *tt = n->type;
|
||||||
Type *tu = (tt && tt->kind == TY_NAMED) ? tt->under : tt;
|
Type *tu = type_chase_named(tt);
|
||||||
/* Identity-width identity-sign cast is a no-op at the
|
/* Identity-width identity-sign cast is a no-op at the
|
||||||
* machine-int level: src and dst share both width and
|
* machine-int level: src and dst share both width and
|
||||||
* signedness, so the natural slot/load already carries
|
* signedness, so the natural slot/load already carries
|
||||||
|
|||||||
@@ -84,6 +84,22 @@
|
|||||||
* esub_2lvl | kb6_esub: [3]my32b narrow-elem index |
|
* esub_2lvl | kb6_esub: [3]my32b narrow-elem index |
|
||||||
* | (#61/#101-kin at the INDEX sites) — |
|
* | (#61/#101-kin at the INDEX sites) — |
|
||||||
* | latent control | 0/0
|
* | latent control | 0/0
|
||||||
|
* ---- c4 (cast/is/try: :9422 :9598 :9674 :9718 :9819 ----------
|
||||||
|
* :9986/:9991 :10103/:10105 :10131, numbering at 4cac1cb) -
|
||||||
|
* strcast_2lvl | kb6_strcast: str→[]u8 over 2-lvl |
|
||||||
|
* | alias — was both-correct divergent; |
|
||||||
|
* | the :10103/:10105 tu/fu chase FLIPS |
|
||||||
|
* | it (cs → ww's unchanged asm, #263 |
|
||||||
|
* | polarity; alias == plain shape) | 0/0
|
||||||
|
* idcast_2lvl | kb6_idcast: identity cast over alias |
|
||||||
|
* | union (Family-C peel) — latent | 0/0
|
||||||
|
* is_2lvl | kb6_is: `is` over alias union — |
|
||||||
|
* | latent control | 0/0
|
||||||
|
* try_loud_38b | kb6_try: `?` on a >48B sret-class |
|
||||||
|
* | call result — the #38b loud is |
|
||||||
|
* | ALIAS-INDEPENDENT (documented bound);|
|
||||||
|
* | :9819's chase is loud-preserving |
|
||||||
|
* | ONLY — twin texts, shared experr | err/err
|
||||||
*
|
*
|
||||||
* K_RUN rows build+run BOTH drivers (cs exit==cswant, ww exit==wwwant)
|
* K_RUN rows build+run BOTH drivers (cs exit==cswant, ww exit==wwwant)
|
||||||
* and assert cstage/wwstage asm byte-id. K_BUILDERR rows must FAIL
|
* and assert cstage/wwstage asm byte-id. K_BUILDERR rows must FAIL
|
||||||
@@ -338,6 +354,67 @@ static const struct row rows[] = {
|
|||||||
" if (xs[0]: i64 + xs[1]: i64 + xs[2]: i64 != 18) { return 1; };\n"
|
" if (xs[0]: i64 + xs[1]: i64 + xs[2]: i64 != 18) { return 1; };\n"
|
||||||
" return 0;\n"
|
" return 0;\n"
|
||||||
"};\n", 0, 0, K_RUN, NULL, NULL },
|
"};\n", 0, 0, K_RUN, NULL, NULL },
|
||||||
|
/* ---- c4: cast/is/try family */
|
||||||
|
{ "strcast_2lvl",
|
||||||
|
"package main;\n"
|
||||||
|
"type ms0 = str;\n"
|
||||||
|
"type ms = ms0;\n"
|
||||||
|
"export fn main() i32 = {\n"
|
||||||
|
" let a: ms = \"hey\";\n"
|
||||||
|
" let b: []u8 = a: []u8;\n"
|
||||||
|
" if (len(b) != 3) { return 1; };\n"
|
||||||
|
" if (b[0] != 'h') { return 2; };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n", 0, 0, K_RUN, NULL, NULL },
|
||||||
|
{ "idcast_2lvl",
|
||||||
|
"package main;\n"
|
||||||
|
"type u0 = (void | i64);\n"
|
||||||
|
"type u = u0;\n"
|
||||||
|
"export fn main() i32 = {\n"
|
||||||
|
" let v: u = 42i64;\n"
|
||||||
|
" let w: u = (v: u);\n"
|
||||||
|
" match (w) {\n"
|
||||||
|
" case let n: i64 => { if (n != 42) { return 1; }; };\n"
|
||||||
|
" case void => { return 2; };\n"
|
||||||
|
" };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n", 0, 0, K_RUN, NULL, NULL },
|
||||||
|
{ "is_2lvl",
|
||||||
|
"package main;\n"
|
||||||
|
"type u0 = (void | i64);\n"
|
||||||
|
"type u = u0;\n"
|
||||||
|
"export fn main() i32 = {\n"
|
||||||
|
" let v: u = 42i64;\n"
|
||||||
|
" if (!(v is i64)) { return 1; };\n"
|
||||||
|
" if (v is void) { return 2; };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n", 0, 0, K_RUN, NULL, NULL },
|
||||||
|
/* ALIAS-INDEPENDENT #38b bound (ken's row is >48B sret-class):
|
||||||
|
* the :9819 chase must stay loud-preserving — this pins the
|
||||||
|
* fatal so a future chase can't silently green it. */
|
||||||
|
{ "try_loud_38b",
|
||||||
|
"package main;\n"
|
||||||
|
"type e0 = !i64;\n"
|
||||||
|
"type big = struct { a: i64, b: i64, c: i64, d: i64, e: i64, f: i64, g: i64 };\n"
|
||||||
|
"type r0 = (big | e0);\n"
|
||||||
|
"type r = r0;\n"
|
||||||
|
"fn w() r = {\n"
|
||||||
|
" let s: big;\n"
|
||||||
|
" s.a = 1; s.b = 2; s.c = 3; s.d = 4; s.e = 5; s.f = 6; s.g = 77;\n"
|
||||||
|
" return s;\n"
|
||||||
|
"};\n"
|
||||||
|
"fn outer() (i64 | e0) = {\n"
|
||||||
|
" let v = w()?;\n"
|
||||||
|
" return v.g;\n"
|
||||||
|
"};\n"
|
||||||
|
"export fn main() i32 = {\n"
|
||||||
|
" match (outer()) {\n"
|
||||||
|
" case let n: i64 => { if (n != 77) { return 1; }; };\n"
|
||||||
|
" case e0 => { return 2; };\n"
|
||||||
|
" };\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"};\n", 0, 0, K_BUILDERR,
|
||||||
|
"#38b: `?`/`!` on an sret-class call result unwired", NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|||||||
Reference in New Issue
Block a user