cgen: default the hi bound of a slice/str-field slice, both stages
x.slicefield[:] / x.strfield[2:] emitted MOVQ $0 for the omitted hi
bound on BOTH stages (N_IDENT-gated dispatch; symmetric, so byte
identity never caught it) in all four sites: cgexpr N_SLICE + pushargs
(cstage), cgslice + pushargsrev (wwstage). The new arm re-evaluates
the pure field read for its {ptr,len,cap} header and takes .len,
covering local, viaptr, dot-chain, (*p), arr[i], and global inners.
Call inners still loud-reject upstream. Sibling of the #252/#257
array-field arms.
This commit is contained in:
@@ -10112,6 +10112,14 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
} else {
|
} else {
|
||||||
ins2(c, A_MOVQ, amem(D_BP, boff + 8), areg(D_AX));
|
ins2(c, A_MOVQ, amem(D_BP, boff + 8), areg(D_AX));
|
||||||
}
|
}
|
||||||
|
} else if (base->kind == N_DOT && bu &&
|
||||||
|
(bu->kind == TY_SLICE || bu->kind == TY_STR)) {
|
||||||
|
/* slice/str FIELD base — the arg twin
|
||||||
|
* of the cgexpr N_SLICE default-hi
|
||||||
|
* arm above; same re-eval-for-header
|
||||||
|
* rationale. */
|
||||||
|
cgexpr(c, base, locals);
|
||||||
|
ins2(c, A_MOVQ, areg(D_BX), areg(D_AX));
|
||||||
} else {
|
} else {
|
||||||
cgexpr_int(c, 0);
|
cgexpr_int(c, 0);
|
||||||
}
|
}
|
||||||
@@ -13242,6 +13250,18 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
ins2(c, A_MOVQ, amem(D_BP, boff + 8),
|
ins2(c, A_MOVQ, amem(D_BP, boff + 8),
|
||||||
areg(D_AX));
|
areg(D_AX));
|
||||||
}
|
}
|
||||||
|
} else if (base && base->kind == N_DOT && bu &&
|
||||||
|
(bu->kind == TY_SLICE || bu->kind == TY_STR)) {
|
||||||
|
/* slice/str FIELD base (#252's slice twin): the old
|
||||||
|
* fall-through emitted $0 — a silent 0/negative len on
|
||||||
|
* BOTH stages, byteid-blind. Re-evaluate the field
|
||||||
|
* read for its header (a pure place: call inners
|
||||||
|
* loud-reject upstream; cgexpr's N_DOT slice/str arms
|
||||||
|
* leave AX=ptr, BX=len, CX=cap for every supported
|
||||||
|
* inner — ident, chain, (*p), arr[i]) and take .len.
|
||||||
|
* All scratch regs are dead at the hi step. */
|
||||||
|
cgexpr(c, base, locals);
|
||||||
|
ins2(c, A_MOVQ, areg(D_BX), areg(D_AX));
|
||||||
} else {
|
} else {
|
||||||
cgexpr_int(c, 0);
|
cgexpr_int(c, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package wwfixture;
|
package wwfixture;
|
||||||
|
|
||||||
def protocolversion: i32 = 1;
|
def protocolversion: i32 = 1;
|
||||||
def corpuscount: i32 = 1230;
|
def corpuscount: i32 = 1233;
|
||||||
def errorcount: i32 = 314;
|
def errorcount: i32 = 314;
|
||||||
def compilecount: i32 = 12;
|
def compilecount: i32 = 12;
|
||||||
def runcount: i32 = 138;
|
def runcount: i32 = 141;
|
||||||
def runexitcount: i32 = 766;
|
def runexitcount: i32 = 766;
|
||||||
def nativecount: i32 = 2460;
|
def nativecount: i32 = 2466;
|
||||||
def corpushash: str = "fd04059b05a19ae63f1bec3edaefedf1d8ce9a505302a153434457d0fb9b9eca";
|
def corpushash: str = "65d3642dfb77b486f5aed23044a979bbce37c36fbbcb7a7aedae20d87c7b0e4f";
|
||||||
|
|
||||||
type directive = enum i32 {
|
type directive = enum i32 {
|
||||||
ERROR = 0,
|
ERROR = 0,
|
||||||
|
|||||||
@@ -3000,6 +3000,17 @@ fn cgslice(c: *cgen, n: *syntax.node) void = {
|
|||||||
emitline("\tMOVQ\t$");
|
emitline("\tMOVQ\t$");
|
||||||
emitint(dotbu.alen: i64);
|
emitint(dotbu.alen: i64);
|
||||||
emitline(", AX\n");
|
emitline(", AX\n");
|
||||||
|
} else { if (dotbu != nil && (dotbu.kind == syntax.tykind.TY_SLICE
|
||||||
|
|| dotbu.kind == syntax.tykind.TY_STR)) {
|
||||||
|
// slice/str FIELD base (#252's slice twin): the old
|
||||||
|
// fall-through emitted $0 — silent 0/negative len on BOTH
|
||||||
|
// stages, byteid-blind. Re-evaluate the field read for its
|
||||||
|
// header (pure place: call inners loud-reject upstream;
|
||||||
|
// cgdot's slice/str arms leave AX=ptr, BX=len, CX=cap for
|
||||||
|
// every supported inner) and take .len. Scratch regs are
|
||||||
|
// dead at the hi step. Cstage twin: cgen.c N_SLICE.
|
||||||
|
cgexpr(c, base);
|
||||||
|
emitline("\tMOVQ\tBX, AX\n");
|
||||||
} else { if (arrlittn != nil) {
|
} else { if (arrlittn != nil) {
|
||||||
// #31: default-hi for the arrlit base = its element count (the
|
// #31: default-hi for the arrlit base = its element count (the
|
||||||
// stashed [count]T tnode's .rhs intlit).
|
// stashed [count]T tnode's .rhs intlit).
|
||||||
@@ -3014,7 +3025,7 @@ fn cgslice(c: *cgen, n: *syntax.node) void = {
|
|||||||
emitline(", AX\n");
|
emitline(", AX\n");
|
||||||
} else {
|
} else {
|
||||||
emitline("\tMOVQ\t$0, AX\n");
|
emitline("\tMOVQ\t$0, AX\n");
|
||||||
};};};};};
|
};};};};};};
|
||||||
emitline("\tMOVQ\tAX, BX\n");
|
emitline("\tMOVQ\tAX, BX\n");
|
||||||
emitline("\tPOPQ\tCX\n");
|
emitline("\tPOPQ\tCX\n");
|
||||||
emitline("\tPOPQ\tAX\n");
|
emitline("\tPOPQ\tAX\n");
|
||||||
|
|||||||
@@ -782,9 +782,16 @@ fn pushargsrev(c: *cgen, arg: *syntax.node, param: *syntax.node, memphase: bool,
|
|||||||
emitline("\tMOVQ\t$");
|
emitline("\tMOVQ\t$");
|
||||||
emitint(dotbu.alen: i64);
|
emitint(dotbu.alen: i64);
|
||||||
emitline(", AX\n");
|
emitline(", AX\n");
|
||||||
|
} else { if (dotbu != nil && (dotbu.kind == syntax.tykind.TY_SLICE
|
||||||
|
|| dotbu.kind == syntax.tykind.TY_STR)) {
|
||||||
|
// slice/str FIELD base — the arg twin of the cgslice
|
||||||
|
// default-hi arm; same re-eval-for-header rationale.
|
||||||
|
// Cstage twin: cgen.c pushargs N_SLICE.
|
||||||
|
cgexpr(c, base);
|
||||||
|
emitline("\tMOVQ\tBX, AX\n");
|
||||||
} else {
|
} else {
|
||||||
emitline("\tMOVQ\t$0, AX\n");
|
emitline("\tMOVQ\t$0, AX\n");
|
||||||
};};};};
|
};};};};};
|
||||||
emitline("\tPUSHQ\tAX\n");
|
emitline("\tPUSHQ\tAX\n");
|
||||||
// lo (default 0) → AX
|
// lo (default 0) → AX
|
||||||
if (lo != nil) { cgexpr(c, lo); }
|
if (lo != nil) { cgexpr(c, lo); }
|
||||||
|
|||||||
49
test/wcc/data/dotfield_slice_defhi/case.ww
Normal file
49
test/wcc/data/dotfield_slice_defhi/case.ww
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//ww:run
|
||||||
|
// Default-hi slice of a slice/str FIELD (`x.f[:]`, `x.f[2:]`) —
|
||||||
|
// expression position. The pre-fix default-hi dispatch was
|
||||||
|
// N_IDENT-gated on BOTH stages, so an N_DOT base fell to MOVQ $0
|
||||||
|
// (len 0 / negative, byteid-blind). Covers local, viaptr, dot-chain,
|
||||||
|
// (*p) spelling, and struct-array-element inners.
|
||||||
|
package main;
|
||||||
|
|
||||||
|
type inner = struct {
|
||||||
|
buf: []i32,
|
||||||
|
name: str,
|
||||||
|
};
|
||||||
|
|
||||||
|
type outer = struct {
|
||||||
|
pad: i64,
|
||||||
|
in: inner,
|
||||||
|
};
|
||||||
|
|
||||||
|
export fn main() int = {
|
||||||
|
let arr: [4]i32 = [10, 20, 30, 40];
|
||||||
|
let v: inner = inner{ buf = arr[:], name = "hello" };
|
||||||
|
let b1: []i32 = v.buf[:];
|
||||||
|
if (len(b1) != 4) { return 1; };
|
||||||
|
let b2: []i32 = v.buf[1:];
|
||||||
|
if (len(b2) != 3) { return 2; };
|
||||||
|
if (b2[0] != 20) { return 3; };
|
||||||
|
let s1: str = v.name[2:];
|
||||||
|
if (len(s1) != 3) { return 4; };
|
||||||
|
let p: *inner = &v;
|
||||||
|
let b3: []i32 = p.buf[:];
|
||||||
|
if (len(b3) != 4) { return 5; };
|
||||||
|
let s2: str = p.name[1:];
|
||||||
|
if (len(s2) != 4) { return 6; };
|
||||||
|
let o: outer = outer{ pad = 7, in = inner{ buf = arr[:], name = "world" } };
|
||||||
|
let b4: []i32 = o.in.buf[:];
|
||||||
|
if (len(b4) != 4) { return 7; };
|
||||||
|
let b5: []i32 = o.in.buf[2:];
|
||||||
|
if (len(b5) != 2) { return 8; };
|
||||||
|
if (b5[1] != 40) { return 9; };
|
||||||
|
let s3: str = o.in.name[3:];
|
||||||
|
if (len(s3) != 2) { return 10; };
|
||||||
|
let b6: []i32 = (*p).buf[:];
|
||||||
|
if (len(b6) != 4) { return 11; };
|
||||||
|
let xs: [2]inner = [v, v];
|
||||||
|
let b7: []i32 = xs[1].buf[:];
|
||||||
|
if (len(b7) != 4) { return 12; };
|
||||||
|
if (b7[3] != 40) { return 13; };
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
46
test/wcc/data/dotfield_slice_defhi_arg/case.ww
Normal file
46
test/wcc/data/dotfield_slice_defhi_arg/case.ww
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
//ww:run
|
||||||
|
// Default-hi slice of a slice/str FIELD in call-ARG position — the
|
||||||
|
// pushargs twin of dotfield_slice_defhi. Pre-fix the pushargs
|
||||||
|
// N_SLICE default-hi arm was N_IDENT-gated on BOTH stages, so
|
||||||
|
// callees received a 0-length slice.
|
||||||
|
package main;
|
||||||
|
|
||||||
|
type inner = struct {
|
||||||
|
buf: []i32,
|
||||||
|
name: str,
|
||||||
|
};
|
||||||
|
|
||||||
|
type outer = struct {
|
||||||
|
pad: i64,
|
||||||
|
in: inner,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn sum(xs: []i32) i32 = {
|
||||||
|
let t: i32 = 0;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < len(xs)) {
|
||||||
|
t += xs[i];
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn slen(s: str) i32 = {
|
||||||
|
return len(s);
|
||||||
|
};
|
||||||
|
|
||||||
|
export fn main() int = {
|
||||||
|
let arr: [4]i32 = [10, 20, 30, 40];
|
||||||
|
let v: inner = inner{ buf = arr[:], name = "hello" };
|
||||||
|
if (sum(v.buf[:]) != 100) { return 1; };
|
||||||
|
if (sum(v.buf[2:]) != 70) { return 2; };
|
||||||
|
if (slen(v.name[1:]) != 4) { return 3; };
|
||||||
|
let p: *inner = &v;
|
||||||
|
if (sum(p.buf[:]) != 100) { return 4; };
|
||||||
|
if (slen(p.name[2:]) != 3) { return 5; };
|
||||||
|
let o: outer = outer{ pad = 7, in = inner{ buf = arr[:], name = "world" } };
|
||||||
|
if (sum(o.in.buf[:]) != 100) { return 6; };
|
||||||
|
if (sum(o.in.buf[1:]) != 90) { return 7; };
|
||||||
|
if (slen(o.in.name[4:]) != 1) { return 8; };
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
51
test/wcc/data/dotfield_slice_defhi_global/case.ww
Normal file
51
test/wcc/data/dotfield_slice_defhi_global/case.ww
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//ww:run
|
||||||
|
// Default-hi slice of a slice/str FIELD on module-GLOBAL struct
|
||||||
|
// bases (single dot and chain), expression + arg positions — the
|
||||||
|
// global leg of dotfield_slice_defhi.
|
||||||
|
package main;
|
||||||
|
|
||||||
|
type inner = struct {
|
||||||
|
buf: []i32,
|
||||||
|
name: str,
|
||||||
|
};
|
||||||
|
|
||||||
|
type outer = struct {
|
||||||
|
pad: i64,
|
||||||
|
in: inner,
|
||||||
|
};
|
||||||
|
|
||||||
|
let g: inner = inner{};
|
||||||
|
let go: outer = outer{};
|
||||||
|
|
||||||
|
fn sum(xs: []i32) i32 = {
|
||||||
|
let t: i32 = 0;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < len(xs)) {
|
||||||
|
t += xs[i];
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
|
||||||
|
export fn main() int = {
|
||||||
|
let arr: [4]i32 = [10, 20, 30, 40];
|
||||||
|
g.buf = arr[:];
|
||||||
|
g.name = "globals";
|
||||||
|
let b1: []i32 = g.buf[:];
|
||||||
|
if (len(b1) != 4) { return 1; };
|
||||||
|
let b2: []i32 = g.buf[2:];
|
||||||
|
if (len(b2) != 2) { return 2; };
|
||||||
|
if (b2[0] != 30) { return 3; };
|
||||||
|
let s1: str = g.name[3:];
|
||||||
|
if (len(s1) != 4) { return 4; };
|
||||||
|
if (sum(g.buf[:]) != 100) { return 5; };
|
||||||
|
if (sum(g.buf[1:]) != 90) { return 6; };
|
||||||
|
go.in.buf = arr[:];
|
||||||
|
go.in.name = "chain";
|
||||||
|
let b3: []i32 = go.in.buf[:];
|
||||||
|
if (len(b3) != 4) { return 7; };
|
||||||
|
if (sum(go.in.buf[2:]) != 70) { return 8; };
|
||||||
|
let s2: str = go.in.name[1:];
|
||||||
|
if (len(s2) != 4) { return 9; };
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user