w6c+selfhost: float globals — DATAW + LEAQ-indirect MOVSS/MOVSD
f32 → 4B slot, f64 → 8B. C cgen bakes the FLOATLIT bit pattern into DATAW directly; selfhost emits zero-init only (its parser doesn't lex N_FLOATLIT yet). Read/write goes LEAQ name(SB),CX + MOVSS/MOVSD since w6a has no D_EXTERN operand form for SSE moves.
This commit is contained in:
@@ -9147,8 +9147,8 @@ fn internstrlit(c: *cgen, bytes: str) str = {
|
||||
|
||||
// letscalarprim — recognise the bare type-name keywords whose values
|
||||
// fit in an 8-byte .data slot and load back with a plain MOVQ. Float
|
||||
// types deliberately excluded; they need MOVSS/MOVSD. Mirrors C
|
||||
// `let_emit_size`'s 8-byte branch.
|
||||
// types are handled separately by letfloatprim — they need MOVSS/MOVSD
|
||||
// and use 4-byte (f32) or 8-byte (f64) slots.
|
||||
fn letscalarprim(nm: str) bool = {
|
||||
if (streq(nm, "bool")) { return true; };
|
||||
if (streq(nm, "rune")) { return true; };
|
||||
@@ -9166,10 +9166,19 @@ fn letscalarprim(nm: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// letfloatprim — float type-name keywords. f32 → 4B slot, f64 → 8B.
|
||||
// Returns the slot size or 0 if not a float type.
|
||||
fn letfloatprim(nm: str) i32 = {
|
||||
if (streq(nm, "f32")) { return 4; };
|
||||
if (streq(nm, "f64")) { return 8; };
|
||||
return 0;
|
||||
};
|
||||
|
||||
// letemitsize — slot size in bytes for a top-level `let`, or 0 if
|
||||
// the type isn't yet supported as a writable global. Walks type
|
||||
// aliases so byte output matches C cgen, which resolves Type kinds.
|
||||
// 8 → scalar (literal init supported)
|
||||
// 4 → f32 (literal init supported)
|
||||
// 8 → scalar or f64 (literal init supported)
|
||||
// 16 → str (only zero-init / nil / "" supported)
|
||||
// 24 → slice (only zero-init supported)
|
||||
// varies → struct (zero-init only; field reads/scalar-field writes)
|
||||
@@ -9182,6 +9191,8 @@ fn letemitsize(c: *cgen, d: *node) i32 = {
|
||||
if (t.kind != nkind.N_TNAME) { return 0; };
|
||||
let nm: str = t.str;
|
||||
if (letscalarprim(nm)) { return 8; };
|
||||
let fsz: i32 = letfloatprim(nm);
|
||||
if (fsz > 0) { return fsz; };
|
||||
if (streq(nm, "str")) { return 16; };
|
||||
let si: *structinfo = structlookup(c, nm);
|
||||
if (si != nil) { return si.totsize; };
|
||||
@@ -9264,6 +9275,29 @@ fn letvarisslice(c: *cgen, name: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// letvarisfloat — slot size for a named float global, or 0 if not
|
||||
// a float-typed let. Walks aliases so the byte-identity contract
|
||||
// matches C cgen's `let_isfloat` (which resolves Type kinds).
|
||||
fn letvarisfloat(c: *cgen, name: str) i32 = {
|
||||
let lv: *letvar = c.lets;
|
||||
for (lv != nil) {
|
||||
if (streq(lv.name, name)) {
|
||||
let t: *node = lv.tnode;
|
||||
for (t != nil) {
|
||||
if (t.kind != nkind.N_TNAME) { return 0; };
|
||||
let fsz: i32 = letfloatprim(t.str);
|
||||
if (fsz > 0) { return fsz; };
|
||||
let nx: *node = aliaslookup(c, t.str);
|
||||
if (nx == nil) { return 0; };
|
||||
t = nx;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
lv = lv.lvnext;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
// letvarisstruct — is the named top-level let a struct global?
|
||||
// Struct globals use LEAQ name(SB), CX as the field-access base; the
|
||||
// cgdot read and cgassign write paths branch on this to skip the
|
||||
@@ -9393,7 +9427,30 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
if (nm.len > 0) {
|
||||
let sz: i32 = letemitsize(c, d);
|
||||
let issg: bool = letvarisstruct(c, nm);
|
||||
if (sz == 8 && !issg) {
|
||||
let fsz: i32 = letvarisfloat(c, nm);
|
||||
if (fsz > 0) {
|
||||
// Float global: 4B (f32) or 8B (f64).
|
||||
// The selfhost parser doesn't lex
|
||||
// N_FLOATLIT yet, so only zero-init
|
||||
// reaches this path. C cgen emits
|
||||
// identical bytes for the zero-init
|
||||
// case; FLOATLIT-init lives in C cgen
|
||||
// only.
|
||||
let ok: bool = true;
|
||||
if (d.rhs != nil) { ok = false; };
|
||||
if (ok) {
|
||||
emitline("DATAW ");
|
||||
emitsymname(c, nm);
|
||||
emitline("(SB),\"");
|
||||
let i: i32 = 0;
|
||||
for (i < fsz) {
|
||||
emitdatawbyte(0u8);
|
||||
i += 1;
|
||||
};
|
||||
emitline("\"\n");
|
||||
};
|
||||
};
|
||||
if (sz == 8 && !issg && fsz == 0) {
|
||||
let v: u64 = 0u64;
|
||||
let ok: bool = true;
|
||||
if (d.rhs != nil) {
|
||||
|
||||
@@ -562,8 +562,8 @@ fn internstrlit(c: *cgen, bytes: str) str = {
|
||||
|
||||
// letscalarprim — recognise the bare type-name keywords whose values
|
||||
// fit in an 8-byte .data slot and load back with a plain MOVQ. Float
|
||||
// types deliberately excluded; they need MOVSS/MOVSD. Mirrors C
|
||||
// `let_emit_size`'s 8-byte branch.
|
||||
// types are handled separately by letfloatprim — they need MOVSS/MOVSD
|
||||
// and use 4-byte (f32) or 8-byte (f64) slots.
|
||||
fn letscalarprim(nm: str) bool = {
|
||||
if (streq(nm, "bool")) { return true; };
|
||||
if (streq(nm, "rune")) { return true; };
|
||||
@@ -581,10 +581,19 @@ fn letscalarprim(nm: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// letfloatprim — float type-name keywords. f32 → 4B slot, f64 → 8B.
|
||||
// Returns the slot size or 0 if not a float type.
|
||||
fn letfloatprim(nm: str) i32 = {
|
||||
if (streq(nm, "f32")) { return 4; };
|
||||
if (streq(nm, "f64")) { return 8; };
|
||||
return 0;
|
||||
};
|
||||
|
||||
// letemitsize — slot size in bytes for a top-level `let`, or 0 if
|
||||
// the type isn't yet supported as a writable global. Walks type
|
||||
// aliases so byte output matches C cgen, which resolves Type kinds.
|
||||
// 8 → scalar (literal init supported)
|
||||
// 4 → f32 (literal init supported)
|
||||
// 8 → scalar or f64 (literal init supported)
|
||||
// 16 → str (only zero-init / nil / "" supported)
|
||||
// 24 → slice (only zero-init supported)
|
||||
// varies → struct (zero-init only; field reads/scalar-field writes)
|
||||
@@ -597,6 +606,8 @@ fn letemitsize(c: *cgen, d: *node) i32 = {
|
||||
if (t.kind != nkind.N_TNAME) { return 0; };
|
||||
let nm: str = t.str;
|
||||
if (letscalarprim(nm)) { return 8; };
|
||||
let fsz: i32 = letfloatprim(nm);
|
||||
if (fsz > 0) { return fsz; };
|
||||
if (streq(nm, "str")) { return 16; };
|
||||
let si: *structinfo = structlookup(c, nm);
|
||||
if (si != nil) { return si.totsize; };
|
||||
@@ -679,6 +690,29 @@ fn letvarisslice(c: *cgen, name: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// letvarisfloat — slot size for a named float global, or 0 if not
|
||||
// a float-typed let. Walks aliases so the byte-identity contract
|
||||
// matches C cgen's `let_isfloat` (which resolves Type kinds).
|
||||
fn letvarisfloat(c: *cgen, name: str) i32 = {
|
||||
let lv: *letvar = c.lets;
|
||||
for (lv != nil) {
|
||||
if (streq(lv.name, name)) {
|
||||
let t: *node = lv.tnode;
|
||||
for (t != nil) {
|
||||
if (t.kind != nkind.N_TNAME) { return 0; };
|
||||
let fsz: i32 = letfloatprim(t.str);
|
||||
if (fsz > 0) { return fsz; };
|
||||
let nx: *node = aliaslookup(c, t.str);
|
||||
if (nx == nil) { return 0; };
|
||||
t = nx;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
lv = lv.lvnext;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
// letvarisstruct — is the named top-level let a struct global?
|
||||
// Struct globals use LEAQ name(SB), CX as the field-access base; the
|
||||
// cgdot read and cgassign write paths branch on this to skip the
|
||||
@@ -808,7 +842,30 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
if (nm.len > 0) {
|
||||
let sz: i32 = letemitsize(c, d);
|
||||
let issg: bool = letvarisstruct(c, nm);
|
||||
if (sz == 8 && !issg) {
|
||||
let fsz: i32 = letvarisfloat(c, nm);
|
||||
if (fsz > 0) {
|
||||
// Float global: 4B (f32) or 8B (f64).
|
||||
// The selfhost parser doesn't lex
|
||||
// N_FLOATLIT yet, so only zero-init
|
||||
// reaches this path. C cgen emits
|
||||
// identical bytes for the zero-init
|
||||
// case; FLOATLIT-init lives in C cgen
|
||||
// only.
|
||||
let ok: bool = true;
|
||||
if (d.rhs != nil) { ok = false; };
|
||||
if (ok) {
|
||||
emitline("DATAW ");
|
||||
emitsymname(c, nm);
|
||||
emitline("(SB),\"");
|
||||
let i: i32 = 0;
|
||||
for (i < fsz) {
|
||||
emitdatawbyte(0u8);
|
||||
i += 1;
|
||||
};
|
||||
emitline("\"\n");
|
||||
};
|
||||
};
|
||||
if (sz == 8 && !issg && fsz == 0) {
|
||||
let v: u64 = 0u64;
|
||||
let ok: bool = true;
|
||||
if (d.rhs != nil) {
|
||||
|
||||
@@ -9147,8 +9147,8 @@ fn internstrlit(c: *cgen, bytes: str) str = {
|
||||
|
||||
// letscalarprim — recognise the bare type-name keywords whose values
|
||||
// fit in an 8-byte .data slot and load back with a plain MOVQ. Float
|
||||
// types deliberately excluded; they need MOVSS/MOVSD. Mirrors C
|
||||
// `let_emit_size`'s 8-byte branch.
|
||||
// types are handled separately by letfloatprim — they need MOVSS/MOVSD
|
||||
// and use 4-byte (f32) or 8-byte (f64) slots.
|
||||
fn letscalarprim(nm: str) bool = {
|
||||
if (streq(nm, "bool")) { return true; };
|
||||
if (streq(nm, "rune")) { return true; };
|
||||
@@ -9166,10 +9166,19 @@ fn letscalarprim(nm: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// letfloatprim — float type-name keywords. f32 → 4B slot, f64 → 8B.
|
||||
// Returns the slot size or 0 if not a float type.
|
||||
fn letfloatprim(nm: str) i32 = {
|
||||
if (streq(nm, "f32")) { return 4; };
|
||||
if (streq(nm, "f64")) { return 8; };
|
||||
return 0;
|
||||
};
|
||||
|
||||
// letemitsize — slot size in bytes for a top-level `let`, or 0 if
|
||||
// the type isn't yet supported as a writable global. Walks type
|
||||
// aliases so byte output matches C cgen, which resolves Type kinds.
|
||||
// 8 → scalar (literal init supported)
|
||||
// 4 → f32 (literal init supported)
|
||||
// 8 → scalar or f64 (literal init supported)
|
||||
// 16 → str (only zero-init / nil / "" supported)
|
||||
// 24 → slice (only zero-init supported)
|
||||
// varies → struct (zero-init only; field reads/scalar-field writes)
|
||||
@@ -9182,6 +9191,8 @@ fn letemitsize(c: *cgen, d: *node) i32 = {
|
||||
if (t.kind != nkind.N_TNAME) { return 0; };
|
||||
let nm: str = t.str;
|
||||
if (letscalarprim(nm)) { return 8; };
|
||||
let fsz: i32 = letfloatprim(nm);
|
||||
if (fsz > 0) { return fsz; };
|
||||
if (streq(nm, "str")) { return 16; };
|
||||
let si: *structinfo = structlookup(c, nm);
|
||||
if (si != nil) { return si.totsize; };
|
||||
@@ -9264,6 +9275,29 @@ fn letvarisslice(c: *cgen, name: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// letvarisfloat — slot size for a named float global, or 0 if not
|
||||
// a float-typed let. Walks aliases so the byte-identity contract
|
||||
// matches C cgen's `let_isfloat` (which resolves Type kinds).
|
||||
fn letvarisfloat(c: *cgen, name: str) i32 = {
|
||||
let lv: *letvar = c.lets;
|
||||
for (lv != nil) {
|
||||
if (streq(lv.name, name)) {
|
||||
let t: *node = lv.tnode;
|
||||
for (t != nil) {
|
||||
if (t.kind != nkind.N_TNAME) { return 0; };
|
||||
let fsz: i32 = letfloatprim(t.str);
|
||||
if (fsz > 0) { return fsz; };
|
||||
let nx: *node = aliaslookup(c, t.str);
|
||||
if (nx == nil) { return 0; };
|
||||
t = nx;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
lv = lv.lvnext;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
// letvarisstruct — is the named top-level let a struct global?
|
||||
// Struct globals use LEAQ name(SB), CX as the field-access base; the
|
||||
// cgdot read and cgassign write paths branch on this to skip the
|
||||
@@ -9393,7 +9427,30 @@ fn emitletdataw(c: *cgen, file: *node) void = {
|
||||
if (nm.len > 0) {
|
||||
let sz: i32 = letemitsize(c, d);
|
||||
let issg: bool = letvarisstruct(c, nm);
|
||||
if (sz == 8 && !issg) {
|
||||
let fsz: i32 = letvarisfloat(c, nm);
|
||||
if (fsz > 0) {
|
||||
// Float global: 4B (f32) or 8B (f64).
|
||||
// The selfhost parser doesn't lex
|
||||
// N_FLOATLIT yet, so only zero-init
|
||||
// reaches this path. C cgen emits
|
||||
// identical bytes for the zero-init
|
||||
// case; FLOATLIT-init lives in C cgen
|
||||
// only.
|
||||
let ok: bool = true;
|
||||
if (d.rhs != nil) { ok = false; };
|
||||
if (ok) {
|
||||
emitline("DATAW ");
|
||||
emitsymname(c, nm);
|
||||
emitline("(SB),\"");
|
||||
let i: i32 = 0;
|
||||
for (i < fsz) {
|
||||
emitdatawbyte(0u8);
|
||||
i += 1;
|
||||
};
|
||||
emitline("\"\n");
|
||||
};
|
||||
};
|
||||
if (sz == 8 && !issg && fsz == 0) {
|
||||
let v: u64 = 0u64;
|
||||
let ok: bool = true;
|
||||
if (d.rhs != nil) {
|
||||
|
||||
Reference in New Issue
Block a user