w6c: key tagged natural-push call args on type equality, not slot size
pushargsrev's five aistagged gates (N_IDENT #55, N_CALL #21, N_INDEX #12, N_DOT #22a, deref #35) treated a tagged arg as already-tagged when its SLOT SIZE matched the param's. A same-slot subset union ((bool|void) into (i64|bool|void), both 16B) then natural-pushed the narrower box's words carrying SOURCE tags — no re-layout, no cg_widen_tag_remap twin — so the callee matched the wrong arm (silent: probes exited 10/90 where cstage exits 30/27). cstage keys widen detection on type equality (cgen.c:10000 same = (pu == au) || type_eq) and routes every non-same tagged source through the zeroed scratch + tag remap; the slot-DIFFER wwstage path already mirrored that byte-identically, so the fix computes cstage's same check once (wsame) and replaces each slot-size test with it. This also erases the last known cs!=ww shape divergence (the 16B-local staging vs direct-push frame delta on prefix subsets). 8 subsetwiden_* fixtures own the class: call-result/ident/str-payload /mid-arg remap (the wrong-arm shapes), prefix (the shape-divergence repro), and bigslot/return-pos/struct-24-to-32 sibling guards. Corpus pin 1740/343/22/209/1166/3480.
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
package wwfixture;
|
||||
|
||||
def protocolversion: i32 = 1;
|
||||
def corpuscount: i32 = 1732;
|
||||
def corpuscount: i32 = 1740;
|
||||
def errorcount: i32 = 343;
|
||||
def compilecount: i32 = 22;
|
||||
def runcount: i32 = 209;
|
||||
def runexitcount: i32 = 1158;
|
||||
def nativecount: i32 = 3464;
|
||||
def corpushash: str = "df3862c647aae744b549089ab4a180b36371fe898f5996c13099f52da203265e";
|
||||
def runexitcount: i32 = 1166;
|
||||
def nativecount: i32 = 3480;
|
||||
def corpushash: str = "a2f2514f07ca4e20457331e30f051394da3e59fcfa8f5f6ec3b33d9c14490354";
|
||||
|
||||
type directive = enum i32 {
|
||||
ERROR = 0,
|
||||
|
||||
@@ -493,39 +493,51 @@ fn pushargsrev(c: *cgen, arg: *syntax.node, param: *syntax.node, memphase: bool,
|
||||
let ptype: *syntax.node = param.lhs;
|
||||
if (istaggedtype(c, ptype)) {
|
||||
let aistagged: bool = false;
|
||||
// "Already tagged, natural push" is TYPE equality
|
||||
// with the param, never slot-size equality: a
|
||||
// same-slot SUBSET ((bool|void) → (i64|bool|void),
|
||||
// both 16B) still needs the scratch re-layout +
|
||||
// tag remap below — the old slot-keyed gates
|
||||
// natural-pushed the narrower box's words with
|
||||
// SOURCE tags, so the callee matched the wrong
|
||||
// arm. Mirrors cstage's widen detection
|
||||
// (cmd/w6c/cgen.c:10000 `same = (pu == au) ||
|
||||
// type_eq(p->type, at)`).
|
||||
let wsame: bool = false;
|
||||
let wpt: *syntax.tinfo = ptype.type_: *syntax.tinfo;
|
||||
let wat: *syntax.tinfo = arg.type_: *syntax.tinfo;
|
||||
let wpu: *syntax.tinfo = tichase(wpt);
|
||||
let wau: *syntax.tinfo = tichase(wat);
|
||||
if (wpu != nil && wpu == wau) { wsame = true; };
|
||||
if (!wsame && wpt != nil && wat != nil) {
|
||||
if (syntax.typeeq(wpt, wat)) { wsame = true; };
|
||||
};
|
||||
if (arg.kind == syntax.nkind.N_IDENT) {
|
||||
let lc: *local = localfindnode(c, arg.str);
|
||||
if (lc != nil) {
|
||||
// #55: only treat a tagged ident as
|
||||
// "already tagged" (natural push, no remap)
|
||||
// when its slot MATCHES the param. On slot-
|
||||
// DIFFER the source is a NARROWER union widened
|
||||
// into a wider one — fall to the widen scratch
|
||||
// + tag-remap below (the slot-gated INDEX/DOT/
|
||||
// STAR arms' twin). Pre-#55 the ungated TRUE
|
||||
// natural-pushed the narrower box's words with
|
||||
// no remap (aligned-tag LUCK, misaligned-tag
|
||||
// wrong). cstage routes every tagged source
|
||||
// #55: any non-same tagged local — slot-
|
||||
// differ or same-slot subset — falls to the
|
||||
// widen scratch + tag-remap below. cstage
|
||||
// routes every non-same tagged source
|
||||
// through cg_widen_tagged_store (cmd/w6c/
|
||||
// cgen.c:2982 src_is_tagged).
|
||||
if (istaggedtype(c, lc.tnode)) {
|
||||
if (slotsize(c, lc.tnode) == slotsize(c, ptype)) {
|
||||
if (wsame) {
|
||||
aistagged = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
// #21: a CALL returning a tagged-union must
|
||||
// skip widening — cgexpr leaves AX=tag,
|
||||
// DX=word0, CX=word1, R8=word2 per the
|
||||
// tagged-return ABI; the widening branch would
|
||||
// treat AX as a concrete payload and silently
|
||||
// drop DX/CX/R8. Restrict to the matching-slot
|
||||
// case (mirrors cstage type_eq at
|
||||
// cmd/w6c/cgen.c:4216-4221); tagged-source
|
||||
// widening into a wider slot is out of scope.
|
||||
if (taggedcallslot(c, arg) == slotsize(c, ptype)) {
|
||||
aistagged = true;
|
||||
// #21: an exact-type CALL result skips widening —
|
||||
// cgexpr leaves AX=tag, DX=word0, CX=word1,
|
||||
// R8=word2 per the tagged-return ABI and the
|
||||
// natural push keeps that cursor. A non-same
|
||||
// (subset) call result routes through the widen
|
||||
// scratch, whose cursor arm spills + tag-remaps.
|
||||
if (taggedcallslot(c, arg) > 0) {
|
||||
if (wsame) {
|
||||
aistagged = true;
|
||||
};
|
||||
};
|
||||
// #12: N_INDEX of a sum-typed slice element —
|
||||
// cgindex emits the same AX/DX/CX/R8 tagged ABI.
|
||||
@@ -533,13 +545,13 @@ fn pushargsrev(c: *cgen, arg: *syntax.node, param: *syntax.node, memphase: bool,
|
||||
// hardcodes the param's first-variant tag and
|
||||
// the callee reads a fixed arm on garbage.
|
||||
// #60: arg.type_ is the checker-stamped element
|
||||
// tinfo (check.ww indexresult); istaggedtype/
|
||||
// slotsize read .type_, so feed the N_INDEX node
|
||||
// tinfo (check.ww indexresult); istaggedtype
|
||||
// reads .type_, so feed the N_INDEX node
|
||||
// directly. cstage reads the element via
|
||||
// base->type->sub (cmd/w6c/cgen.c:3518).
|
||||
if (arg.kind == syntax.nkind.N_INDEX) {
|
||||
if (istaggedtype(c, arg)) {
|
||||
if (slotsize(c, arg) == slotsize(c, ptype)) {
|
||||
if (wsame) {
|
||||
aistagged = true;
|
||||
};
|
||||
};
|
||||
@@ -555,7 +567,7 @@ fn pushargsrev(c: *cgen, arg: *syntax.node, param: *syntax.node, memphase: bool,
|
||||
// check is type-keyed on args[i]->type).
|
||||
if (arg.kind == syntax.nkind.N_DOT) {
|
||||
if (istaggedtype(c, arg)) {
|
||||
if (slotsize(c, arg) == slotsize(c, ptype)) {
|
||||
if (wsame) {
|
||||
aistagged = true;
|
||||
};
|
||||
};
|
||||
@@ -564,11 +576,11 @@ fn pushargsrev(c: *cgen, arg: *syntax.node, param: *syntax.node, memphase: bool,
|
||||
// tagged box too (mem-based, any size)
|
||||
// — without this gate the widening
|
||||
// scalar branch boxed the box. Same
|
||||
// slotsize key as the N_INDEX/N_DOT
|
||||
// type key as the N_INDEX/N_DOT
|
||||
// stamped-carrier arms above.
|
||||
if (arg.kind == syntax.nkind.N_UN && arg.op == syntax.tkind.TK_STAR) {
|
||||
if (istaggedtype(c, arg)) {
|
||||
if (slotsize(c, arg) == slotsize(c, ptype)) {
|
||||
if (wsame) {
|
||||
aistagged = true;
|
||||
};
|
||||
};
|
||||
|
||||
11
test/wcc/data/subsetwiden_bigslot/case.ww
Normal file
11
test/wcc/data/subsetwiden_bigslot/case.ww
Normal file
@@ -0,0 +1,11 @@
|
||||
//ww:run-exit 30
|
||||
package main;
|
||||
fn mk(v: bool) (i64 | bool) = { return v; };
|
||||
fn pick(r: (i64 | bool | str)) i32 = {
|
||||
match (r) {
|
||||
case let n: i64 => return 10;
|
||||
case let b: bool => return 30;
|
||||
case let s: str => return 40;
|
||||
};
|
||||
};
|
||||
export fn main() i32 = { return pick(mk(true)); };
|
||||
11
test/wcc/data/subsetwiden_callarg_prefix/case.ww
Normal file
11
test/wcc/data/subsetwiden_callarg_prefix/case.ww
Normal file
@@ -0,0 +1,11 @@
|
||||
//ww:run-exit 30
|
||||
package main;
|
||||
fn mk(v: bool) (i64 | bool) = { return v; };
|
||||
fn pick(r: (i64 | bool | void)) i32 = {
|
||||
match (r) {
|
||||
case let n: i64 => return 10;
|
||||
case let b: bool => return 30;
|
||||
case void => return 20;
|
||||
};
|
||||
};
|
||||
export fn main() i32 = { return pick(mk(true)); };
|
||||
11
test/wcc/data/subsetwiden_callarg_remap/case.ww
Normal file
11
test/wcc/data/subsetwiden_callarg_remap/case.ww
Normal file
@@ -0,0 +1,11 @@
|
||||
//ww:run-exit 30
|
||||
package main;
|
||||
fn mk(v: bool) (bool | void) = { return v; };
|
||||
fn pick(r: (i64 | bool | void)) i32 = {
|
||||
match (r) {
|
||||
case let n: i64 => return 10;
|
||||
case let b: bool => return 30;
|
||||
case void => return 20;
|
||||
};
|
||||
};
|
||||
export fn main() i32 = { return pick(mk(true)); };
|
||||
13
test/wcc/data/subsetwiden_identarg_remap/case.ww
Normal file
13
test/wcc/data/subsetwiden_identarg_remap/case.ww
Normal file
@@ -0,0 +1,13 @@
|
||||
//ww:run-exit 30
|
||||
package main;
|
||||
fn pick(r: (i64 | bool | void)) i32 = {
|
||||
match (r) {
|
||||
case let n: i64 => return 10;
|
||||
case let b: bool => return 30;
|
||||
case void => return 20;
|
||||
};
|
||||
};
|
||||
export fn main() i32 = {
|
||||
let v: (bool | void) = true;
|
||||
return pick(v);
|
||||
};
|
||||
11
test/wcc/data/subsetwiden_midarg_remap/case.ww
Normal file
11
test/wcc/data/subsetwiden_midarg_remap/case.ww
Normal file
@@ -0,0 +1,11 @@
|
||||
//ww:run-exit 27
|
||||
package main;
|
||||
fn mk(v: bool) (bool | void) = { return v; };
|
||||
fn pick3(a: i32, r: (i64 | bool | void), b: i32) i32 = {
|
||||
match (r) {
|
||||
case let n: i64 => return 90;
|
||||
case let b2: bool => return a*10 + b;
|
||||
case void => return 91;
|
||||
};
|
||||
};
|
||||
export fn main() i32 = { return pick3(2, mk(true), 7); };
|
||||
12
test/wcc/data/subsetwiden_return_pos/case.ww
Normal file
12
test/wcc/data/subsetwiden_return_pos/case.ww
Normal file
@@ -0,0 +1,12 @@
|
||||
//ww:run-exit 30
|
||||
package main;
|
||||
fn mk(v: bool) (bool | void) = { return v; };
|
||||
fn wide(v: bool) (i64 | bool | void) = { return mk(v); };
|
||||
fn pick(r: (i64 | bool | void)) i32 = {
|
||||
match (r) {
|
||||
case let n: i64 => return 10;
|
||||
case let b: bool => return 30;
|
||||
case void => return 20;
|
||||
};
|
||||
};
|
||||
export fn main() i32 = { return pick(wide(true)); };
|
||||
11
test/wcc/data/subsetwiden_strpayload_remap/case.ww
Normal file
11
test/wcc/data/subsetwiden_strpayload_remap/case.ww
Normal file
@@ -0,0 +1,11 @@
|
||||
//ww:run-exit 30
|
||||
package main;
|
||||
fn mk(s: str) (str | void) = { return s; };
|
||||
fn pick(r: (i64 | str | void)) i32 = {
|
||||
match (r) {
|
||||
case let n: i64 => return 10;
|
||||
case let s: str => { if (len(s) != 5) { return 4; }; return 30; };
|
||||
case void => return 20;
|
||||
};
|
||||
};
|
||||
export fn main() i32 = { return pick(mk("hello")); };
|
||||
15
test/wcc/data/subsetwiden_struct2432_remap/case.ww
Normal file
15
test/wcc/data/subsetwiden_struct2432_remap/case.ww
Normal file
@@ -0,0 +1,15 @@
|
||||
//ww:run-exit 30
|
||||
package main;
|
||||
type pair = struct { a: i64, b: i64 };
|
||||
fn mk(x: i64) (pair | void) = {
|
||||
let p: pair; p.a = x; p.b = x + 1;
|
||||
return p;
|
||||
};
|
||||
fn pick(r: (str | pair | void)) i32 = {
|
||||
match (r) {
|
||||
case let s: str => return 10;
|
||||
case let p: pair => { if (p.a != 5) { return 4; }; if (p.b != 6) { return 5; }; return 30; };
|
||||
case void => return 20;
|
||||
};
|
||||
};
|
||||
export fn main() i32 = { return pick(mk(5)); };
|
||||
Reference in New Issue
Block a user