w6c+selfhost: principled sub-word signedness (closes #5/#10)
type_isunsigned recurses TY_ENUM and includes TY_RUNE on both stages. 13 LOAD + 6 STORE ladder sites (cstage) plus 4 more wwstage stragglers in cgindex/cgforrange collapsed to fldloadop/fldstoreop helpers. N_CAST narrow gate symmetrised; task #1's literal-kind workaround retired. bool kept out of type_isunsigned, special-cased in field helpers. Retroactively fixes a u32 mis-sign-extend in deref-compound (sz=4 hardcoded MOVSXD), pinned by new 660_field_signed row.
This commit is contained in:
@@ -373,9 +373,7 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
if (ps > 0) { esz = ps; };
|
||||
};
|
||||
};
|
||||
let mop: str = "MOVQ";
|
||||
if (esz == 1) { mop = "MOVB"; }
|
||||
else { if (esz == 4) { mop = "MOVL"; }; };
|
||||
let mop: str = tnodestoreop(c, elemn, esz);
|
||||
let idx: i32 = 0;
|
||||
let repeat: bool = false;
|
||||
let e: *node = rhs.list;
|
||||
@@ -491,7 +489,7 @@ fn cglet(c: *cgen, n: *node) void = {
|
||||
emitline("(BP)\n");
|
||||
fi = nil;
|
||||
} else {
|
||||
let sop: str = fieldstoreop(fi);
|
||||
let sop: str = fieldstoreop(c, fi);
|
||||
emitline("\t");
|
||||
emitline(sop);
|
||||
emitline("\tAX, ");
|
||||
@@ -806,16 +804,11 @@ fn paramfieldsize(t: *node) i32 = {
|
||||
return 8;
|
||||
};
|
||||
|
||||
// paramissigned — does this primitive type need sign-extending on a
|
||||
// narrow (4B) load? Mirrors C cgen's `binds[b].signed_field` flag.
|
||||
fn paramissigned(t: *node) bool = {
|
||||
if (t == nil) { return false; };
|
||||
if (t.kind != nkind.N_TNAME) { return false; };
|
||||
let nm: str = t.str;
|
||||
if (streq(nm, "i8")) { return true; };
|
||||
if (streq(nm, "i16")) { return true; };
|
||||
if (streq(nm, "i32")) { return true; };
|
||||
return false;
|
||||
// paramissigned — does this type need sign-extending on a sub-word
|
||||
// (1/2/4B) load? Mirrors cstage's signed_field check via
|
||||
// fieldissignedc (resolves TBANG / TENUM / alias chains).
|
||||
fn paramissigned(c: *cgen, t: *node) bool = {
|
||||
return fieldissignedc(c, t);
|
||||
};
|
||||
|
||||
// cgforrange — lower `for (let x .. slice) body` (and the tuple-
|
||||
@@ -889,7 +882,7 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
let signf: bool = false;
|
||||
if (tp != nil) {
|
||||
fsz = paramfieldsize(tp);
|
||||
signf = paramissigned(tp);
|
||||
signf = paramissigned(c, tp);
|
||||
};
|
||||
let slot_sz: i32 = fsz;
|
||||
if (slot_sz < 8) { slot_sz = 8; };
|
||||
@@ -917,7 +910,7 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
// reads `u->sub->kind` for the elem type.
|
||||
bind_signed[0] = false;
|
||||
if (elemt != nil) {
|
||||
bind_signed[0] = paramissigned(elemt);
|
||||
bind_signed[0] = paramissigned(c, elemt);
|
||||
};
|
||||
if (n.str.len > 0) {
|
||||
// Register with elem tnode so x.field on a loop
|
||||
@@ -1015,15 +1008,12 @@ fn cgforrange(c: *cgen, n: *node) void = {
|
||||
};
|
||||
emitline("\tADDQ\tAX, BX\n");
|
||||
|
||||
// Per-binding load from BX+foff.
|
||||
// Per-binding load from BX+foff. Signedness comes from bind_signed
|
||||
// (set via paramissigned → fieldissignedc), so enum-aliased narrows
|
||||
// pick the right MOVS*Q without a literal-name gate.
|
||||
let b: i32 = 0;
|
||||
for (b < nbinds) {
|
||||
let op: str = "MOVQ";
|
||||
if (bind_sz[b] == 1) { op = "MOVZBQ"; }
|
||||
else { if (bind_sz[b] == 4) {
|
||||
if (bind_signed[b]) { op = "MOVSXD"; }
|
||||
else { op = "MOVL"; };
|
||||
};};
|
||||
let op: str = loadopsz(bind_signed[b], bind_sz[b]);
|
||||
emitline("\t");
|
||||
emitline(op);
|
||||
emitline("\t");
|
||||
|
||||
Reference in New Issue
Block a user