selfhost/cmd/wcc/cgenutil: collapse N_DOT arms onto n.type_ (#55, A.6.3g)
nodeisunsigned + exprfloatkind each manually walked base->struct->field on N_DOT, gated on `base.kind == nkind.N_IDENT` -- duplicating cstage's behaviour at the AST level while silently dropping the nested-N_DOT case (`a.b.c` returned the conservative default). After A.6.2 the checker stamps n.type_ on every N_DOT expression (check.ww:1973 struct-field arm of exprtype), and A.6.3a/b landed the tinfo helpers (typeisunsigned, isfloattype/isf32type) that the inner reads already use. Both arms collapse to one tinfo read. Polarity DOWN per rule 10: cstage was already aligned. cmd/w6c/cgen.c: 2330-2331 reads type_isunsigned(n->lhs->type) directly; cgen.c:152-156 node_isfloat = cg_isfloat(n->type); cgen.c:195-199 node_isf32 = type_isf32(n->type). No exprfloatkind-equivalent walker exists in cstage -- it is pre-A.6.2 wwstage scaffolding. Wwstage now reads the same shape as cstage on N_DOT. Nested N_DOT (a.b.c) now resolves to the field type instead of returning the conservative default. Byte-identity (994/995) confirms the codegen matches cstage on the test set -- cstage was already getting nested-dot right via checker-stamped n->type, wwstage was the laggard. make test 133/133 ok. Net cgenutil.ww -41 / +3.
This commit is contained in:
@@ -11587,10 +11587,10 @@ fn indexvaluetnode(c: *cgen, n: *node) *node = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// nodeisunsigned — best-effort cgen-time inference from the AST. We
|
// nodeisunsigned — best-effort cgen-time inference from the AST. We
|
||||||
// don't have a typed AST yet, so we walk surface nodes:
|
// walk surface nodes (N_DOT now reads n.type_ — #55 A.6.3g):
|
||||||
// nkind.N_INTLIT — never marked unsigned (no tsuffix plumbing yet)
|
// nkind.N_INTLIT — never marked unsigned (no tsuffix plumbing yet)
|
||||||
// nkind.N_IDENT — look up the local's declared type
|
// nkind.N_IDENT — look up the local's declared type
|
||||||
// nkind.N_DOT — look up the field's declared type via struct reg
|
// nkind.N_DOT — read the checker-stamped n.type_ (#55 A.6.3g)
|
||||||
// nkind.N_BIN / nkind.N_UN — recurse: unsigned if either operand is unsigned
|
// nkind.N_BIN / nkind.N_UN — recurse: unsigned if either operand is unsigned
|
||||||
// nkind.N_CAST — use the cast target type
|
// nkind.N_CAST — use the cast target type
|
||||||
//
|
//
|
||||||
@@ -11609,43 +11609,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if (k == nkind.N_DOT) {
|
if (k == nkind.N_DOT) {
|
||||||
let base: *node = n.lhs;
|
return typeisunsigned(n.type_: *tinfo);
|
||||||
let fld: str = n.str;
|
|
||||||
if (base != nil) {
|
|
||||||
if (base.kind == nkind.N_IDENT) {
|
|
||||||
let bn: str = base.str;
|
|
||||||
let lc: *local = localfindnode(c, bn);
|
|
||||||
if (lc != nil) {
|
|
||||||
let tn: *node = lc.tnode;
|
|
||||||
let lkind: nkind = nkind.N_NONE;
|
|
||||||
if (tn != nil) { lkind = tn.kind; };
|
|
||||||
let sname: str;
|
|
||||||
sname.ptr = nil; sname.len = 0;
|
|
||||||
if (lkind == nkind.N_TPTR) {
|
|
||||||
let inner: *node = tn.lhs;
|
|
||||||
if (inner != nil) {
|
|
||||||
if (inner.kind == nkind.N_TNAME) { sname = inner.str; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (lkind == nkind.N_TNAME) { sname = tn.str; };
|
|
||||||
if (sname.len > 0) {
|
|
||||||
let si: *structinfo = structlookup(c, sname);
|
|
||||||
if (si != nil) {
|
|
||||||
let fi: *fieldinfo = si.fields;
|
|
||||||
for (fi != nil) {
|
|
||||||
let fn_: str = fi.fname;
|
|
||||||
if (streq(fn_, fld)) {
|
|
||||||
if (fi.tnode == nil) { return false; };
|
|
||||||
return typeisunsigned(fi.tnode.type_: *tinfo);
|
|
||||||
};
|
|
||||||
fi = fi.finext;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
if (k == nkind.N_CAST) {
|
if (k == nkind.N_CAST) {
|
||||||
if (n.rhs == nil) { return false; };
|
if (n.rhs == nil) { return false; };
|
||||||
@@ -12537,42 +12501,12 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
|
|||||||
// `p.field` where the struct field is f64/f32. Without this,
|
// `p.field` where the struct field is f64/f32. Without this,
|
||||||
// `v.fval: i64` lowers to CVTSI on an integer-load value
|
// `v.fval: i64` lowers to CVTSI on an integer-load value
|
||||||
// instead of CVTTSD2SI on the X0 the cgdot path actually
|
// instead of CVTTSD2SI on the X0 the cgdot path actually
|
||||||
// emits for an f64 field.
|
// emits for an f64 field. Read the checker-stamped tinfo on
|
||||||
let base: *node = n.lhs;
|
// the N_DOT itself (check.ww:1973 stamps the field type);
|
||||||
let fld: str = n.str;
|
// cstage cgen.c:2128 reads node_isfloat(n) the same way.
|
||||||
if (base != nil) {
|
// Collapsed per A.6.3g (#55).
|
||||||
let sname: str;
|
if (isf32type(c, n)) { return 1; };
|
||||||
sname.ptr = nil; sname.len = 0;
|
if (isfloattype(c, n)) { return 2; };
|
||||||
if (base.kind == nkind.N_IDENT) {
|
|
||||||
let lc: *local = localfindnode(c, base.str);
|
|
||||||
if (lc != nil) {
|
|
||||||
let tn: *node = lc.tnode;
|
|
||||||
if (tn != nil) {
|
|
||||||
if (tn.kind == nkind.N_TNAME) { sname = tn.str; };
|
|
||||||
if (tn.kind == nkind.N_TPTR) {
|
|
||||||
let pe: *node = tn.lhs;
|
|
||||||
if (pe != nil) {
|
|
||||||
if (pe.kind == nkind.N_TNAME) { sname = pe.str; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (sname.len > 0) {
|
|
||||||
let si: *structinfo = structlookup(c, sname);
|
|
||||||
if (si != nil) {
|
|
||||||
let fi: *fieldinfo = si.fields;
|
|
||||||
for (fi != nil) {
|
|
||||||
if (streq(fi.fname, fld)) {
|
|
||||||
if (isf32type(c, fi.tnode)) { return 1; };
|
|
||||||
if (isfloattype(c, fi.tnode)) { return 2; };
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
fi = fi.finext;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1203,10 +1203,10 @@ fn indexvaluetnode(c: *cgen, n: *node) *node = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// nodeisunsigned — best-effort cgen-time inference from the AST. We
|
// nodeisunsigned — best-effort cgen-time inference from the AST. We
|
||||||
// don't have a typed AST yet, so we walk surface nodes:
|
// walk surface nodes (N_DOT now reads n.type_ — #55 A.6.3g):
|
||||||
// nkind.N_INTLIT — never marked unsigned (no tsuffix plumbing yet)
|
// nkind.N_INTLIT — never marked unsigned (no tsuffix plumbing yet)
|
||||||
// nkind.N_IDENT — look up the local's declared type
|
// nkind.N_IDENT — look up the local's declared type
|
||||||
// nkind.N_DOT — look up the field's declared type via struct reg
|
// nkind.N_DOT — read the checker-stamped n.type_ (#55 A.6.3g)
|
||||||
// nkind.N_BIN / nkind.N_UN — recurse: unsigned if either operand is unsigned
|
// nkind.N_BIN / nkind.N_UN — recurse: unsigned if either operand is unsigned
|
||||||
// nkind.N_CAST — use the cast target type
|
// nkind.N_CAST — use the cast target type
|
||||||
//
|
//
|
||||||
@@ -1225,43 +1225,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if (k == nkind.N_DOT) {
|
if (k == nkind.N_DOT) {
|
||||||
let base: *node = n.lhs;
|
return typeisunsigned(n.type_: *tinfo);
|
||||||
let fld: str = n.str;
|
|
||||||
if (base != nil) {
|
|
||||||
if (base.kind == nkind.N_IDENT) {
|
|
||||||
let bn: str = base.str;
|
|
||||||
let lc: *local = localfindnode(c, bn);
|
|
||||||
if (lc != nil) {
|
|
||||||
let tn: *node = lc.tnode;
|
|
||||||
let lkind: nkind = nkind.N_NONE;
|
|
||||||
if (tn != nil) { lkind = tn.kind; };
|
|
||||||
let sname: str;
|
|
||||||
sname.ptr = nil; sname.len = 0;
|
|
||||||
if (lkind == nkind.N_TPTR) {
|
|
||||||
let inner: *node = tn.lhs;
|
|
||||||
if (inner != nil) {
|
|
||||||
if (inner.kind == nkind.N_TNAME) { sname = inner.str; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (lkind == nkind.N_TNAME) { sname = tn.str; };
|
|
||||||
if (sname.len > 0) {
|
|
||||||
let si: *structinfo = structlookup(c, sname);
|
|
||||||
if (si != nil) {
|
|
||||||
let fi: *fieldinfo = si.fields;
|
|
||||||
for (fi != nil) {
|
|
||||||
let fn_: str = fi.fname;
|
|
||||||
if (streq(fn_, fld)) {
|
|
||||||
if (fi.tnode == nil) { return false; };
|
|
||||||
return typeisunsigned(fi.tnode.type_: *tinfo);
|
|
||||||
};
|
|
||||||
fi = fi.finext;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
if (k == nkind.N_CAST) {
|
if (k == nkind.N_CAST) {
|
||||||
if (n.rhs == nil) { return false; };
|
if (n.rhs == nil) { return false; };
|
||||||
@@ -2153,42 +2117,12 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
|
|||||||
// `p.field` where the struct field is f64/f32. Without this,
|
// `p.field` where the struct field is f64/f32. Without this,
|
||||||
// `v.fval: i64` lowers to CVTSI on an integer-load value
|
// `v.fval: i64` lowers to CVTSI on an integer-load value
|
||||||
// instead of CVTTSD2SI on the X0 the cgdot path actually
|
// instead of CVTTSD2SI on the X0 the cgdot path actually
|
||||||
// emits for an f64 field.
|
// emits for an f64 field. Read the checker-stamped tinfo on
|
||||||
let base: *node = n.lhs;
|
// the N_DOT itself (check.ww:1973 stamps the field type);
|
||||||
let fld: str = n.str;
|
// cstage cgen.c:2128 reads node_isfloat(n) the same way.
|
||||||
if (base != nil) {
|
// Collapsed per A.6.3g (#55).
|
||||||
let sname: str;
|
if (isf32type(c, n)) { return 1; };
|
||||||
sname.ptr = nil; sname.len = 0;
|
if (isfloattype(c, n)) { return 2; };
|
||||||
if (base.kind == nkind.N_IDENT) {
|
|
||||||
let lc: *local = localfindnode(c, base.str);
|
|
||||||
if (lc != nil) {
|
|
||||||
let tn: *node = lc.tnode;
|
|
||||||
if (tn != nil) {
|
|
||||||
if (tn.kind == nkind.N_TNAME) { sname = tn.str; };
|
|
||||||
if (tn.kind == nkind.N_TPTR) {
|
|
||||||
let pe: *node = tn.lhs;
|
|
||||||
if (pe != nil) {
|
|
||||||
if (pe.kind == nkind.N_TNAME) { sname = pe.str; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (sname.len > 0) {
|
|
||||||
let si: *structinfo = structlookup(c, sname);
|
|
||||||
if (si != nil) {
|
|
||||||
let fi: *fieldinfo = si.fields;
|
|
||||||
for (fi != nil) {
|
|
||||||
if (streq(fi.fname, fld)) {
|
|
||||||
if (isf32type(c, fi.tnode)) { return 1; };
|
|
||||||
if (isfloattype(c, fi.tnode)) { return 2; };
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
fi = fi.finext;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -11587,10 +11587,10 @@ fn indexvaluetnode(c: *cgen, n: *node) *node = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// nodeisunsigned — best-effort cgen-time inference from the AST. We
|
// nodeisunsigned — best-effort cgen-time inference from the AST. We
|
||||||
// don't have a typed AST yet, so we walk surface nodes:
|
// walk surface nodes (N_DOT now reads n.type_ — #55 A.6.3g):
|
||||||
// nkind.N_INTLIT — never marked unsigned (no tsuffix plumbing yet)
|
// nkind.N_INTLIT — never marked unsigned (no tsuffix plumbing yet)
|
||||||
// nkind.N_IDENT — look up the local's declared type
|
// nkind.N_IDENT — look up the local's declared type
|
||||||
// nkind.N_DOT — look up the field's declared type via struct reg
|
// nkind.N_DOT — read the checker-stamped n.type_ (#55 A.6.3g)
|
||||||
// nkind.N_BIN / nkind.N_UN — recurse: unsigned if either operand is unsigned
|
// nkind.N_BIN / nkind.N_UN — recurse: unsigned if either operand is unsigned
|
||||||
// nkind.N_CAST — use the cast target type
|
// nkind.N_CAST — use the cast target type
|
||||||
//
|
//
|
||||||
@@ -11609,43 +11609,7 @@ fn nodeisunsigned(c: *cgen, n: *node) bool = {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if (k == nkind.N_DOT) {
|
if (k == nkind.N_DOT) {
|
||||||
let base: *node = n.lhs;
|
return typeisunsigned(n.type_: *tinfo);
|
||||||
let fld: str = n.str;
|
|
||||||
if (base != nil) {
|
|
||||||
if (base.kind == nkind.N_IDENT) {
|
|
||||||
let bn: str = base.str;
|
|
||||||
let lc: *local = localfindnode(c, bn);
|
|
||||||
if (lc != nil) {
|
|
||||||
let tn: *node = lc.tnode;
|
|
||||||
let lkind: nkind = nkind.N_NONE;
|
|
||||||
if (tn != nil) { lkind = tn.kind; };
|
|
||||||
let sname: str;
|
|
||||||
sname.ptr = nil; sname.len = 0;
|
|
||||||
if (lkind == nkind.N_TPTR) {
|
|
||||||
let inner: *node = tn.lhs;
|
|
||||||
if (inner != nil) {
|
|
||||||
if (inner.kind == nkind.N_TNAME) { sname = inner.str; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (lkind == nkind.N_TNAME) { sname = tn.str; };
|
|
||||||
if (sname.len > 0) {
|
|
||||||
let si: *structinfo = structlookup(c, sname);
|
|
||||||
if (si != nil) {
|
|
||||||
let fi: *fieldinfo = si.fields;
|
|
||||||
for (fi != nil) {
|
|
||||||
let fn_: str = fi.fname;
|
|
||||||
if (streq(fn_, fld)) {
|
|
||||||
if (fi.tnode == nil) { return false; };
|
|
||||||
return typeisunsigned(fi.tnode.type_: *tinfo);
|
|
||||||
};
|
|
||||||
fi = fi.finext;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
if (k == nkind.N_CAST) {
|
if (k == nkind.N_CAST) {
|
||||||
if (n.rhs == nil) { return false; };
|
if (n.rhs == nil) { return false; };
|
||||||
@@ -12537,42 +12501,12 @@ export fn exprfloatkind(c: *cgen, n: *node) i32 = {
|
|||||||
// `p.field` where the struct field is f64/f32. Without this,
|
// `p.field` where the struct field is f64/f32. Without this,
|
||||||
// `v.fval: i64` lowers to CVTSI on an integer-load value
|
// `v.fval: i64` lowers to CVTSI on an integer-load value
|
||||||
// instead of CVTTSD2SI on the X0 the cgdot path actually
|
// instead of CVTTSD2SI on the X0 the cgdot path actually
|
||||||
// emits for an f64 field.
|
// emits for an f64 field. Read the checker-stamped tinfo on
|
||||||
let base: *node = n.lhs;
|
// the N_DOT itself (check.ww:1973 stamps the field type);
|
||||||
let fld: str = n.str;
|
// cstage cgen.c:2128 reads node_isfloat(n) the same way.
|
||||||
if (base != nil) {
|
// Collapsed per A.6.3g (#55).
|
||||||
let sname: str;
|
if (isf32type(c, n)) { return 1; };
|
||||||
sname.ptr = nil; sname.len = 0;
|
if (isfloattype(c, n)) { return 2; };
|
||||||
if (base.kind == nkind.N_IDENT) {
|
|
||||||
let lc: *local = localfindnode(c, base.str);
|
|
||||||
if (lc != nil) {
|
|
||||||
let tn: *node = lc.tnode;
|
|
||||||
if (tn != nil) {
|
|
||||||
if (tn.kind == nkind.N_TNAME) { sname = tn.str; };
|
|
||||||
if (tn.kind == nkind.N_TPTR) {
|
|
||||||
let pe: *node = tn.lhs;
|
|
||||||
if (pe != nil) {
|
|
||||||
if (pe.kind == nkind.N_TNAME) { sname = pe.str; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
if (sname.len > 0) {
|
|
||||||
let si: *structinfo = structlookup(c, sname);
|
|
||||||
if (si != nil) {
|
|
||||||
let fi: *fieldinfo = si.fields;
|
|
||||||
for (fi != nil) {
|
|
||||||
if (streq(fi.fname, fld)) {
|
|
||||||
if (isf32type(c, fi.tnode)) { return 1; };
|
|
||||||
if (isfloattype(c, fi.tnode)) { return 2; };
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
fi = fi.finext;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user