w6c+wwstage: array return-by-value via the struct-return ABI (#267 fold-2)
Wire TY_ARRAY into the existing struct-return gates so arrays ride the same reg-class (<=24B in AX:DX:CX) / sret-class (>24B) path the struct return ABI already emits byte-identically. No new ABI machinery. Both stages, uniform gate-widen: - cg_sret_retsize / sretretsize: +TY_ARRAY (natural size sub.size*len, the type table) -> auto-enables sret send/recv + the >24B sret N_IDENT word-copy + return-forward, all keyed on the shared sret SSoT. - cgreturn <=24B reg-send: +TY_ARRAY (N_IDENT scratch word-copy -> AX/DX/CX). reg-class return-forward rides the default cgexpr passthrough. - let-init / assign <=24B recv: +TY_ARRAY (AX/DX/CX sized stores). struct_float_class stays struct-only: pure-int element arrays only; no pure-float-array-return consumer exists today. 949 +11 rows: reg-class 8/16/24B + sret-class 32B, [N]u32 and [N]u8, at let-init/assign/return-forward, full-member readback, + a struct- return regression control. All cstage-run + cs==ww byte-id.
This commit is contained in:
@@ -311,6 +311,11 @@ cg_sret_retsize(Type *rt)
|
|||||||
if (rt == NULL) return 0;
|
if (rt == NULL) return 0;
|
||||||
if (rt->kind == TY_STRUCT)
|
if (rt->kind == TY_STRUCT)
|
||||||
return (int)rt->size <= 24 ? 0 : (int)rt->size;
|
return (int)rt->size <= 24 ? 0 : (int)rt->size;
|
||||||
|
/* #267: arrays ride the struct-return ABI — same ≤24 reg / >24 sret
|
||||||
|
* split. Pure-int element arrays only; no float-array-return
|
||||||
|
* consumer exists, so struct_float_class stays struct-only. */
|
||||||
|
if (rt->kind == TY_ARRAY)
|
||||||
|
return (int)rt->size <= 24 ? 0 : (int)rt->size;
|
||||||
if (rt->kind == TY_TUPLE) {
|
if (rt->kind == TY_TUPLE) {
|
||||||
int gptotal = 0, ssecount = 0, f32;
|
int gptotal = 0, ssecount = 0, f32;
|
||||||
for (Tparam *p = rt->params; p; p = p->next) {
|
for (Tparam *p = rt->params; p; p = p->next) {
|
||||||
@@ -5453,7 +5458,7 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
* the receive side of #4's cgreturn (calls + literals).
|
* the receive side of #4's cgreturn (calls + literals).
|
||||||
* Sizes >24B and non-{0,1,2,4}-byte tails fall through
|
* Sizes >24B and non-{0,1,2,4}-byte tails fall through
|
||||||
* to the existing scalar path. */
|
* to the existing scalar path. */
|
||||||
if (lu && lu->kind == TY_STRUCT
|
if (lu && (lu->kind == TY_STRUCT || lu->kind == TY_ARRAY)
|
||||||
&& (int)lu->size <= 24) {
|
&& (int)lu->size <= 24) {
|
||||||
int off = localfind(locals, n->lhs->str);
|
int off = localfind(locals, n->lhs->str);
|
||||||
if (off != 0) {
|
if (off != 0) {
|
||||||
@@ -8620,7 +8625,8 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (n->rhs && n->rhs->kind == N_CALL && lu
|
if (n->rhs && n->rhs->kind == N_CALL && lu
|
||||||
&& lu->kind == TY_STRUCT && sz <= 24
|
&& (lu->kind == TY_STRUCT || lu->kind == TY_ARRAY)
|
||||||
|
&& sz <= 24
|
||||||
&& (sz % 8 == 0 || sz % 8 == 1
|
&& (sz % 8 == 0 || sz % 8 == 1
|
||||||
|| sz % 8 == 2 || sz % 8 == 4)) {
|
|| sz % 8 == 2 || sz % 8 == 4)) {
|
||||||
cgexpr(c, n->rhs, *locals);
|
cgexpr(c, n->rhs, *locals);
|
||||||
@@ -9171,7 +9177,7 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
|||||||
ins0(c, A_RET);
|
ins0(c, A_RET);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (rt && rt->kind == TY_STRUCT
|
if (rt && (rt->kind == TY_STRUCT || rt->kind == TY_ARRAY)
|
||||||
&& (int)rt->size > 24
|
&& (int)rt->size > 24
|
||||||
&& (n->lhs->kind == N_IDENT
|
&& (n->lhs->kind == N_IDENT
|
||||||
|| n->lhs->kind == N_STRUCTLIT)) {
|
|| n->lhs->kind == N_STRUCTLIT)) {
|
||||||
@@ -9182,9 +9188,12 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
|||||||
* narrow field (e.g. bool@32 in a 33B struct
|
* narrow field (e.g. bool@32 in a 33B struct
|
||||||
* padded to 40B) widened to an 8B MOVQ at the
|
* padded to 40B) widened to an 8B MOVQ at the
|
||||||
* loop tail — diverged from wwstage's MOVB
|
* loop tail — diverged from wwstage's MOVB
|
||||||
* tail. Task #33, Class A. */
|
* tail. Task #33, Class A. An array (#267) has no
|
||||||
|
* fields; its natural size IS rt->size. */
|
||||||
int sz = 0;
|
int sz = 0;
|
||||||
for (Tfield *fl = rt->fields; fl; fl = fl->next) {
|
if (rt->kind == TY_ARRAY) {
|
||||||
|
sz = (int)rt->size;
|
||||||
|
} else for (Tfield *fl = rt->fields; fl; fl = fl->next) {
|
||||||
int end = (int)fl->offset + (int)(fl->type
|
int end = (int)fl->offset + (int)(fl->type
|
||||||
? fl->type->size : 8);
|
? fl->type->size : 8);
|
||||||
if (end > sz) sz = end;
|
if (end > sz) sz = end;
|
||||||
@@ -9260,7 +9269,8 @@ cgstmt(Cg *c, Node *n, Local **locals, int *frame)
|
|||||||
* for the same rationale. The ≤24B register-return
|
* for the same rationale. The ≤24B register-return
|
||||||
* ABI uses the same TY_STRUCT gate. */
|
* ABI uses the same TY_STRUCT gate. */
|
||||||
Type *rt = type_chase_named(cg_ret_type);
|
Type *rt = type_chase_named(cg_ret_type);
|
||||||
if (rt && rt->kind == TY_STRUCT && rt->size <= 24
|
if (rt && (rt->kind == TY_STRUCT || rt->kind == TY_ARRAY)
|
||||||
|
&& rt->size <= 24
|
||||||
&& (n->lhs->kind == N_IDENT
|
&& (n->lhs->kind == N_IDENT
|
||||||
|| n->lhs->kind == N_STRUCTLIT)) {
|
|| n->lhs->kind == N_STRUCTLIT)) {
|
||||||
int sz = (int)rt->size;
|
int sz = (int)rt->size;
|
||||||
|
|||||||
@@ -16814,6 +16814,18 @@ export fn sretretsize(c: *cgen, t: *node) i32 = {
|
|||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
// #267: arrays ride the struct-return ABI — natural size
|
||||||
|
// (sub.size*len, the type table) gates ≤24 reg / >24 sret, mirroring
|
||||||
|
// cstage cg_sret_retsize TY_ARRAY arm. Pure-int element arrays only;
|
||||||
|
// no float-array-return consumer (structfloatclass stays struct-only).
|
||||||
|
if (r.kind == nkind.N_TARRAY) {
|
||||||
|
let ati: *tinfo = r.type_: *tinfo;
|
||||||
|
for (ati != nil && ati.kind == tykind.TY_NAMED) { ati = ati.under; };
|
||||||
|
if (ati == nil) { return 0; };
|
||||||
|
let asz: i32 = ati.size: i32;
|
||||||
|
if (asz <= 24) { return 0; };
|
||||||
|
return asz;
|
||||||
|
};
|
||||||
if (r.kind != nkind.N_TNAME) { return 0; };
|
if (r.kind != nkind.N_TNAME) { return 0; };
|
||||||
// Primitives / aliased-to-primitives are never sret.
|
// Primitives / aliased-to-primitives are never sret.
|
||||||
if (primsize(r.str) > 0) { return 0; };
|
if (primsize(r.str) > 0) { return 0; };
|
||||||
@@ -26968,6 +26980,69 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #267: array return-by-value RECV — `c = mk()` where c is
|
||||||
|
// an array local. Arrays ride the struct reg/sret recv path.
|
||||||
|
// >24B sret keys on callsretsize (the shared SSoT, c's slot
|
||||||
|
// IS the prealloc dest); ≤24B arrives in AX/DX/CX, sized
|
||||||
|
// stores. Array natural size (tinfo.size = sub.size*len)
|
||||||
|
// mirrors cstage lu->size. No structfloatclass (pure-int
|
||||||
|
// element arrays).
|
||||||
|
if (lcn != nil && n.op == tkind.TK_ASSIGN
|
||||||
|
&& n.rhs != nil && n.rhs.kind == nkind.N_CALL) {
|
||||||
|
let acati: *tinfo = nil;
|
||||||
|
if (lcn.tnode != nil) { acati = lcn.tnode.type_: *tinfo; };
|
||||||
|
for (acati != nil && acati.kind == tykind.TY_NAMED) {
|
||||||
|
acati = acati.under;
|
||||||
|
};
|
||||||
|
if (acati != nil && acati.kind == tykind.TY_ARRAY) {
|
||||||
|
let lcsz: i32 = acati.size: i32;
|
||||||
|
if (lcsz > 24) {
|
||||||
|
let rscs: i32 = callsretsize(c, n.rhs);
|
||||||
|
if (rscs > 0) {
|
||||||
|
c.sretdestoff = off;
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
c.sretdestoff = 0;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (lcsz <= 24) {
|
||||||
|
let tlm: i32 = lcsz - (lcsz / 8) * 8;
|
||||||
|
if (tlm == 0 || tlm == 1
|
||||||
|
|| tlm == 2 || tlm == 4) {
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
let full: i32 = lcsz / 8;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < full) {
|
||||||
|
let reg: str = "AX";
|
||||||
|
if (i == 1) { reg = "DX"; };
|
||||||
|
if (i == 2) { reg = "CX"; };
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(reg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + i * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
if (tlm > 0) {
|
||||||
|
let top: str = "MOVB";
|
||||||
|
if (tlm == 4) { top = "MOVL"; };
|
||||||
|
if (tlm == 2) { top = "MOVW"; };
|
||||||
|
let treg: str = "AX";
|
||||||
|
if (full == 1) { treg = "DX"; };
|
||||||
|
if (full == 2) { treg = "CX"; };
|
||||||
|
emitline("\t");
|
||||||
|
emitline(top);
|
||||||
|
emitline("\t");
|
||||||
|
emitline(treg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + full * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
// Float-typed local: rhs lands in X0; store via MOVSD/
|
// Float-typed local: rhs lands in X0; store via MOVSD/
|
||||||
// MOVSS, no AX shuffle. Compound (+= -= *= /=) loads
|
// MOVSS, no AX shuffle. Compound (+= -= *= /=) loads
|
||||||
// slot into X1, combines into X1, stores X1 back —
|
// slot into X1, combines into X1, stores X1 back —
|
||||||
@@ -28229,6 +28304,80 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #267: array return-by-value SEND. >24B sret rides the sret
|
||||||
|
// block above (scs = sretretsize keys it, N_IDENT word-copy /
|
||||||
|
// N_CALL forward generic). ≤24B reg-class `return a;` (N_IDENT)
|
||||||
|
// mirrors the struct ≤24B path: zero-pad a 24B scratch, word-
|
||||||
|
// copy the array slot in, ship AX/DX/CX. Array natural size
|
||||||
|
// (tinfo.size = sub.size*len) mirrors cstage rt->size. No
|
||||||
|
// structfloatclass (pure-int arrays); N_CALL forward at reg-
|
||||||
|
// class falls to the default cgexpr passthrough below.
|
||||||
|
if (c.fnret != nil && c.fnret.kind == nkind.N_TARRAY
|
||||||
|
&& rhs.kind == nkind.N_IDENT) {
|
||||||
|
let ati: *tinfo = c.fnret.type_: *tinfo;
|
||||||
|
for (ati != nil && ati.kind == tykind.TY_NAMED) { ati = ati.under; };
|
||||||
|
if (ati != nil) {
|
||||||
|
let rsz: i32 = ati.size: i32;
|
||||||
|
if (rsz <= 24) {
|
||||||
|
let rl: *local = localfindnode(c, rhs.str);
|
||||||
|
if (rl != nil) {
|
||||||
|
let scroff: i32 = localadd(c, "@retscr", 24, nil);
|
||||||
|
emitline("\tXORQ\tAX, AX\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff(scroff: i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((scroff + 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((scroff + 16): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
let k: i32 = 0;
|
||||||
|
for (k + 8 <= rsz) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((rl.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((scroff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 8;
|
||||||
|
};
|
||||||
|
for (k + 4 <= rsz) {
|
||||||
|
emitline("\tMOVL\t");
|
||||||
|
emitoff((rl.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVL\tAX, ");
|
||||||
|
emitoff((scroff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
for (k < rsz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((rl.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitoff((scroff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 1;
|
||||||
|
};
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff(scroff: i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((scroff + 8): i64);
|
||||||
|
emitline("(BP), DX\n");
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((scroff + 16): i64);
|
||||||
|
emitline("(BP), CX\n");
|
||||||
|
emitline("\tMOVQ\tBP, SP\n");
|
||||||
|
emitline("\tPOPQ\tBP\n");
|
||||||
|
emitline("\tRET\n");
|
||||||
|
c.lastwasreturn = 1;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
cgexpr(c, rhs);
|
cgexpr(c, rhs);
|
||||||
} else {
|
} else {
|
||||||
// Bare `return;` from a tagged-union-returning fn is
|
// Bare `return;` from a tagged-union-returning fn is
|
||||||
@@ -28796,6 +28945,57 @@ fn cglet(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #267: array return-by-value RECV ≤24B — `let c = mk()`
|
||||||
|
// where mk returns an array. Arrays ride the struct reg-recv
|
||||||
|
// path (AX/DX/CX, sized tail). >24B sret rides the sret recv
|
||||||
|
// above (callsretsize keyed). Array natural size (tinfo.size
|
||||||
|
// = sub.size*len) mirrors cstage lu->size. No structfloatclass
|
||||||
|
// (pure-int element arrays).
|
||||||
|
if (rhs.kind == nkind.N_CALL && tn != nil
|
||||||
|
&& tn.kind == nkind.N_TARRAY) {
|
||||||
|
let ati: *tinfo = tn.type_: *tinfo;
|
||||||
|
for (ati != nil && ati.kind == tykind.TY_NAMED) { ati = ati.under; };
|
||||||
|
if (ati != nil) {
|
||||||
|
let lsz: i32 = ati.size: i32;
|
||||||
|
let tlm: i32 = lsz - (lsz / 8) * 8;
|
||||||
|
if (lsz <= 24) {
|
||||||
|
if (tlm == 0 || tlm == 1
|
||||||
|
|| tlm == 2 || tlm == 4) {
|
||||||
|
cgexpr(c, rhs);
|
||||||
|
let full: i32 = lsz / 8;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < full) {
|
||||||
|
let reg: str = "AX";
|
||||||
|
if (i == 1) { reg = "DX"; };
|
||||||
|
if (i == 2) { reg = "CX"; };
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(reg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + i * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
if (tlm > 0) {
|
||||||
|
let top: str = "MOVB";
|
||||||
|
if (tlm == 4) { top = "MOVL"; };
|
||||||
|
if (tlm == 2) { top = "MOVW"; };
|
||||||
|
let treg: str = "AX";
|
||||||
|
if (full == 1) { treg = "DX"; };
|
||||||
|
if (full == 2) { treg = "CX"; };
|
||||||
|
emitline("\t");
|
||||||
|
emitline(top);
|
||||||
|
emitline("\t");
|
||||||
|
emitline(treg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + full * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
c.lastwasreturn = 0;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
// Struct ident copy: `let p2: T = p1;` where T is a struct
|
// Struct ident copy: `let p2: T = p1;` where T is a struct
|
||||||
// >8B and rhs is a local ident. Per-qword MOVQ from src
|
// >8B and rhs is a local ident. Per-qword MOVQ from src
|
||||||
// slot to dst slot, with a sized tail (MOVL/MOVB) for
|
// slot to dst slot, with a sized tail (MOVL/MOVB) for
|
||||||
|
|||||||
@@ -7500,6 +7500,69 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #267: array return-by-value RECV — `c = mk()` where c is
|
||||||
|
// an array local. Arrays ride the struct reg/sret recv path.
|
||||||
|
// >24B sret keys on callsretsize (the shared SSoT, c's slot
|
||||||
|
// IS the prealloc dest); ≤24B arrives in AX/DX/CX, sized
|
||||||
|
// stores. Array natural size (tinfo.size = sub.size*len)
|
||||||
|
// mirrors cstage lu->size. No structfloatclass (pure-int
|
||||||
|
// element arrays).
|
||||||
|
if (lcn != nil && n.op == tkind.TK_ASSIGN
|
||||||
|
&& n.rhs != nil && n.rhs.kind == nkind.N_CALL) {
|
||||||
|
let acati: *tinfo = nil;
|
||||||
|
if (lcn.tnode != nil) { acati = lcn.tnode.type_: *tinfo; };
|
||||||
|
for (acati != nil && acati.kind == tykind.TY_NAMED) {
|
||||||
|
acati = acati.under;
|
||||||
|
};
|
||||||
|
if (acati != nil && acati.kind == tykind.TY_ARRAY) {
|
||||||
|
let lcsz: i32 = acati.size: i32;
|
||||||
|
if (lcsz > 24) {
|
||||||
|
let rscs: i32 = callsretsize(c, n.rhs);
|
||||||
|
if (rscs > 0) {
|
||||||
|
c.sretdestoff = off;
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
c.sretdestoff = 0;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (lcsz <= 24) {
|
||||||
|
let tlm: i32 = lcsz - (lcsz / 8) * 8;
|
||||||
|
if (tlm == 0 || tlm == 1
|
||||||
|
|| tlm == 2 || tlm == 4) {
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
let full: i32 = lcsz / 8;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < full) {
|
||||||
|
let reg: str = "AX";
|
||||||
|
if (i == 1) { reg = "DX"; };
|
||||||
|
if (i == 2) { reg = "CX"; };
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(reg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + i * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
if (tlm > 0) {
|
||||||
|
let top: str = "MOVB";
|
||||||
|
if (tlm == 4) { top = "MOVL"; };
|
||||||
|
if (tlm == 2) { top = "MOVW"; };
|
||||||
|
let treg: str = "AX";
|
||||||
|
if (full == 1) { treg = "DX"; };
|
||||||
|
if (full == 2) { treg = "CX"; };
|
||||||
|
emitline("\t");
|
||||||
|
emitline(top);
|
||||||
|
emitline("\t");
|
||||||
|
emitline(treg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + full * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
// Float-typed local: rhs lands in X0; store via MOVSD/
|
// Float-typed local: rhs lands in X0; store via MOVSD/
|
||||||
// MOVSS, no AX shuffle. Compound (+= -= *= /=) loads
|
// MOVSS, no AX shuffle. Compound (+= -= *= /=) loads
|
||||||
// slot into X1, combines into X1, stores X1 back —
|
// slot into X1, combines into X1, stores X1 back —
|
||||||
|
|||||||
@@ -1089,6 +1089,80 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #267: array return-by-value SEND. >24B sret rides the sret
|
||||||
|
// block above (scs = sretretsize keys it, N_IDENT word-copy /
|
||||||
|
// N_CALL forward generic). ≤24B reg-class `return a;` (N_IDENT)
|
||||||
|
// mirrors the struct ≤24B path: zero-pad a 24B scratch, word-
|
||||||
|
// copy the array slot in, ship AX/DX/CX. Array natural size
|
||||||
|
// (tinfo.size = sub.size*len) mirrors cstage rt->size. No
|
||||||
|
// structfloatclass (pure-int arrays); N_CALL forward at reg-
|
||||||
|
// class falls to the default cgexpr passthrough below.
|
||||||
|
if (c.fnret != nil && c.fnret.kind == nkind.N_TARRAY
|
||||||
|
&& rhs.kind == nkind.N_IDENT) {
|
||||||
|
let ati: *tinfo = c.fnret.type_: *tinfo;
|
||||||
|
for (ati != nil && ati.kind == tykind.TY_NAMED) { ati = ati.under; };
|
||||||
|
if (ati != nil) {
|
||||||
|
let rsz: i32 = ati.size: i32;
|
||||||
|
if (rsz <= 24) {
|
||||||
|
let rl: *local = localfindnode(c, rhs.str);
|
||||||
|
if (rl != nil) {
|
||||||
|
let scroff: i32 = localadd(c, "@retscr", 24, nil);
|
||||||
|
emitline("\tXORQ\tAX, AX\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff(scroff: i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((scroff + 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((scroff + 16): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
let k: i32 = 0;
|
||||||
|
for (k + 8 <= rsz) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((rl.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((scroff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 8;
|
||||||
|
};
|
||||||
|
for (k + 4 <= rsz) {
|
||||||
|
emitline("\tMOVL\t");
|
||||||
|
emitoff((rl.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVL\tAX, ");
|
||||||
|
emitoff((scroff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
for (k < rsz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((rl.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitoff((scroff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 1;
|
||||||
|
};
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff(scroff: i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((scroff + 8): i64);
|
||||||
|
emitline("(BP), DX\n");
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((scroff + 16): i64);
|
||||||
|
emitline("(BP), CX\n");
|
||||||
|
emitline("\tMOVQ\tBP, SP\n");
|
||||||
|
emitline("\tPOPQ\tBP\n");
|
||||||
|
emitline("\tRET\n");
|
||||||
|
c.lastwasreturn = 1;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
cgexpr(c, rhs);
|
cgexpr(c, rhs);
|
||||||
} else {
|
} else {
|
||||||
// Bare `return;` from a tagged-union-returning fn is
|
// Bare `return;` from a tagged-union-returning fn is
|
||||||
@@ -1656,6 +1730,57 @@ fn cglet(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #267: array return-by-value RECV ≤24B — `let c = mk()`
|
||||||
|
// where mk returns an array. Arrays ride the struct reg-recv
|
||||||
|
// path (AX/DX/CX, sized tail). >24B sret rides the sret recv
|
||||||
|
// above (callsretsize keyed). Array natural size (tinfo.size
|
||||||
|
// = sub.size*len) mirrors cstage lu->size. No structfloatclass
|
||||||
|
// (pure-int element arrays).
|
||||||
|
if (rhs.kind == nkind.N_CALL && tn != nil
|
||||||
|
&& tn.kind == nkind.N_TARRAY) {
|
||||||
|
let ati: *tinfo = tn.type_: *tinfo;
|
||||||
|
for (ati != nil && ati.kind == tykind.TY_NAMED) { ati = ati.under; };
|
||||||
|
if (ati != nil) {
|
||||||
|
let lsz: i32 = ati.size: i32;
|
||||||
|
let tlm: i32 = lsz - (lsz / 8) * 8;
|
||||||
|
if (lsz <= 24) {
|
||||||
|
if (tlm == 0 || tlm == 1
|
||||||
|
|| tlm == 2 || tlm == 4) {
|
||||||
|
cgexpr(c, rhs);
|
||||||
|
let full: i32 = lsz / 8;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < full) {
|
||||||
|
let reg: str = "AX";
|
||||||
|
if (i == 1) { reg = "DX"; };
|
||||||
|
if (i == 2) { reg = "CX"; };
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(reg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + i * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
if (tlm > 0) {
|
||||||
|
let top: str = "MOVB";
|
||||||
|
if (tlm == 4) { top = "MOVL"; };
|
||||||
|
if (tlm == 2) { top = "MOVW"; };
|
||||||
|
let treg: str = "AX";
|
||||||
|
if (full == 1) { treg = "DX"; };
|
||||||
|
if (full == 2) { treg = "CX"; };
|
||||||
|
emitline("\t");
|
||||||
|
emitline(top);
|
||||||
|
emitline("\t");
|
||||||
|
emitline(treg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + full * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
c.lastwasreturn = 0;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
// Struct ident copy: `let p2: T = p1;` where T is a struct
|
// Struct ident copy: `let p2: T = p1;` where T is a struct
|
||||||
// >8B and rhs is a local ident. Per-qword MOVQ from src
|
// >8B and rhs is a local ident. Per-qword MOVQ from src
|
||||||
// slot to dst slot, with a sized tail (MOVL/MOVB) for
|
// slot to dst slot, with a sized tail (MOVL/MOVB) for
|
||||||
|
|||||||
@@ -1304,6 +1304,18 @@ export fn sretretsize(c: *cgen, t: *node) i32 = {
|
|||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
// #267: arrays ride the struct-return ABI — natural size
|
||||||
|
// (sub.size*len, the type table) gates ≤24 reg / >24 sret, mirroring
|
||||||
|
// cstage cg_sret_retsize TY_ARRAY arm. Pure-int element arrays only;
|
||||||
|
// no float-array-return consumer (structfloatclass stays struct-only).
|
||||||
|
if (r.kind == nkind.N_TARRAY) {
|
||||||
|
let ati: *tinfo = r.type_: *tinfo;
|
||||||
|
for (ati != nil && ati.kind == tykind.TY_NAMED) { ati = ati.under; };
|
||||||
|
if (ati == nil) { return 0; };
|
||||||
|
let asz: i32 = ati.size: i32;
|
||||||
|
if (asz <= 24) { return 0; };
|
||||||
|
return asz;
|
||||||
|
};
|
||||||
if (r.kind != nkind.N_TNAME) { return 0; };
|
if (r.kind != nkind.N_TNAME) { return 0; };
|
||||||
// Primitives / aliased-to-primitives are never sret.
|
// Primitives / aliased-to-primitives are never sret.
|
||||||
if (primsize(r.str) > 0) { return 0; };
|
if (primsize(r.str) > 0) { return 0; };
|
||||||
|
|||||||
@@ -16814,6 +16814,18 @@ export fn sretretsize(c: *cgen, t: *node) i32 = {
|
|||||||
};
|
};
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
// #267: arrays ride the struct-return ABI — natural size
|
||||||
|
// (sub.size*len, the type table) gates ≤24 reg / >24 sret, mirroring
|
||||||
|
// cstage cg_sret_retsize TY_ARRAY arm. Pure-int element arrays only;
|
||||||
|
// no float-array-return consumer (structfloatclass stays struct-only).
|
||||||
|
if (r.kind == nkind.N_TARRAY) {
|
||||||
|
let ati: *tinfo = r.type_: *tinfo;
|
||||||
|
for (ati != nil && ati.kind == tykind.TY_NAMED) { ati = ati.under; };
|
||||||
|
if (ati == nil) { return 0; };
|
||||||
|
let asz: i32 = ati.size: i32;
|
||||||
|
if (asz <= 24) { return 0; };
|
||||||
|
return asz;
|
||||||
|
};
|
||||||
if (r.kind != nkind.N_TNAME) { return 0; };
|
if (r.kind != nkind.N_TNAME) { return 0; };
|
||||||
// Primitives / aliased-to-primitives are never sret.
|
// Primitives / aliased-to-primitives are never sret.
|
||||||
if (primsize(r.str) > 0) { return 0; };
|
if (primsize(r.str) > 0) { return 0; };
|
||||||
@@ -26968,6 +26980,69 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #267: array return-by-value RECV — `c = mk()` where c is
|
||||||
|
// an array local. Arrays ride the struct reg/sret recv path.
|
||||||
|
// >24B sret keys on callsretsize (the shared SSoT, c's slot
|
||||||
|
// IS the prealloc dest); ≤24B arrives in AX/DX/CX, sized
|
||||||
|
// stores. Array natural size (tinfo.size = sub.size*len)
|
||||||
|
// mirrors cstage lu->size. No structfloatclass (pure-int
|
||||||
|
// element arrays).
|
||||||
|
if (lcn != nil && n.op == tkind.TK_ASSIGN
|
||||||
|
&& n.rhs != nil && n.rhs.kind == nkind.N_CALL) {
|
||||||
|
let acati: *tinfo = nil;
|
||||||
|
if (lcn.tnode != nil) { acati = lcn.tnode.type_: *tinfo; };
|
||||||
|
for (acati != nil && acati.kind == tykind.TY_NAMED) {
|
||||||
|
acati = acati.under;
|
||||||
|
};
|
||||||
|
if (acati != nil && acati.kind == tykind.TY_ARRAY) {
|
||||||
|
let lcsz: i32 = acati.size: i32;
|
||||||
|
if (lcsz > 24) {
|
||||||
|
let rscs: i32 = callsretsize(c, n.rhs);
|
||||||
|
if (rscs > 0) {
|
||||||
|
c.sretdestoff = off;
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
c.sretdestoff = 0;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (lcsz <= 24) {
|
||||||
|
let tlm: i32 = lcsz - (lcsz / 8) * 8;
|
||||||
|
if (tlm == 0 || tlm == 1
|
||||||
|
|| tlm == 2 || tlm == 4) {
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
let full: i32 = lcsz / 8;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < full) {
|
||||||
|
let reg: str = "AX";
|
||||||
|
if (i == 1) { reg = "DX"; };
|
||||||
|
if (i == 2) { reg = "CX"; };
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(reg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + i * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
if (tlm > 0) {
|
||||||
|
let top: str = "MOVB";
|
||||||
|
if (tlm == 4) { top = "MOVL"; };
|
||||||
|
if (tlm == 2) { top = "MOVW"; };
|
||||||
|
let treg: str = "AX";
|
||||||
|
if (full == 1) { treg = "DX"; };
|
||||||
|
if (full == 2) { treg = "CX"; };
|
||||||
|
emitline("\t");
|
||||||
|
emitline(top);
|
||||||
|
emitline("\t");
|
||||||
|
emitline(treg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + full * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
// Float-typed local: rhs lands in X0; store via MOVSD/
|
// Float-typed local: rhs lands in X0; store via MOVSD/
|
||||||
// MOVSS, no AX shuffle. Compound (+= -= *= /=) loads
|
// MOVSS, no AX shuffle. Compound (+= -= *= /=) loads
|
||||||
// slot into X1, combines into X1, stores X1 back —
|
// slot into X1, combines into X1, stores X1 back —
|
||||||
@@ -28229,6 +28304,80 @@ fn cgreturn(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #267: array return-by-value SEND. >24B sret rides the sret
|
||||||
|
// block above (scs = sretretsize keys it, N_IDENT word-copy /
|
||||||
|
// N_CALL forward generic). ≤24B reg-class `return a;` (N_IDENT)
|
||||||
|
// mirrors the struct ≤24B path: zero-pad a 24B scratch, word-
|
||||||
|
// copy the array slot in, ship AX/DX/CX. Array natural size
|
||||||
|
// (tinfo.size = sub.size*len) mirrors cstage rt->size. No
|
||||||
|
// structfloatclass (pure-int arrays); N_CALL forward at reg-
|
||||||
|
// class falls to the default cgexpr passthrough below.
|
||||||
|
if (c.fnret != nil && c.fnret.kind == nkind.N_TARRAY
|
||||||
|
&& rhs.kind == nkind.N_IDENT) {
|
||||||
|
let ati: *tinfo = c.fnret.type_: *tinfo;
|
||||||
|
for (ati != nil && ati.kind == tykind.TY_NAMED) { ati = ati.under; };
|
||||||
|
if (ati != nil) {
|
||||||
|
let rsz: i32 = ati.size: i32;
|
||||||
|
if (rsz <= 24) {
|
||||||
|
let rl: *local = localfindnode(c, rhs.str);
|
||||||
|
if (rl != nil) {
|
||||||
|
let scroff: i32 = localadd(c, "@retscr", 24, nil);
|
||||||
|
emitline("\tXORQ\tAX, AX\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff(scroff: i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((scroff + 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((scroff + 16): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
let k: i32 = 0;
|
||||||
|
for (k + 8 <= rsz) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((rl.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVQ\tAX, ");
|
||||||
|
emitoff((scroff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 8;
|
||||||
|
};
|
||||||
|
for (k + 4 <= rsz) {
|
||||||
|
emitline("\tMOVL\t");
|
||||||
|
emitoff((rl.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVL\tAX, ");
|
||||||
|
emitoff((scroff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 4;
|
||||||
|
};
|
||||||
|
for (k < rsz) {
|
||||||
|
emitline("\tMOVB\t");
|
||||||
|
emitoff((rl.off + k): i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVB\tAX, ");
|
||||||
|
emitoff((scroff + k): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
k += 1;
|
||||||
|
};
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff(scroff: i64);
|
||||||
|
emitline("(BP), AX\n");
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((scroff + 8): i64);
|
||||||
|
emitline("(BP), DX\n");
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitoff((scroff + 16): i64);
|
||||||
|
emitline("(BP), CX\n");
|
||||||
|
emitline("\tMOVQ\tBP, SP\n");
|
||||||
|
emitline("\tPOPQ\tBP\n");
|
||||||
|
emitline("\tRET\n");
|
||||||
|
c.lastwasreturn = 1;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
cgexpr(c, rhs);
|
cgexpr(c, rhs);
|
||||||
} else {
|
} else {
|
||||||
// Bare `return;` from a tagged-union-returning fn is
|
// Bare `return;` from a tagged-union-returning fn is
|
||||||
@@ -28796,6 +28945,57 @@ fn cglet(c: *cgen, n: *node) void = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #267: array return-by-value RECV ≤24B — `let c = mk()`
|
||||||
|
// where mk returns an array. Arrays ride the struct reg-recv
|
||||||
|
// path (AX/DX/CX, sized tail). >24B sret rides the sret recv
|
||||||
|
// above (callsretsize keyed). Array natural size (tinfo.size
|
||||||
|
// = sub.size*len) mirrors cstage lu->size. No structfloatclass
|
||||||
|
// (pure-int element arrays).
|
||||||
|
if (rhs.kind == nkind.N_CALL && tn != nil
|
||||||
|
&& tn.kind == nkind.N_TARRAY) {
|
||||||
|
let ati: *tinfo = tn.type_: *tinfo;
|
||||||
|
for (ati != nil && ati.kind == tykind.TY_NAMED) { ati = ati.under; };
|
||||||
|
if (ati != nil) {
|
||||||
|
let lsz: i32 = ati.size: i32;
|
||||||
|
let tlm: i32 = lsz - (lsz / 8) * 8;
|
||||||
|
if (lsz <= 24) {
|
||||||
|
if (tlm == 0 || tlm == 1
|
||||||
|
|| tlm == 2 || tlm == 4) {
|
||||||
|
cgexpr(c, rhs);
|
||||||
|
let full: i32 = lsz / 8;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < full) {
|
||||||
|
let reg: str = "AX";
|
||||||
|
if (i == 1) { reg = "DX"; };
|
||||||
|
if (i == 2) { reg = "CX"; };
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(reg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + i * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
if (tlm > 0) {
|
||||||
|
let top: str = "MOVB";
|
||||||
|
if (tlm == 4) { top = "MOVL"; };
|
||||||
|
if (tlm == 2) { top = "MOVW"; };
|
||||||
|
let treg: str = "AX";
|
||||||
|
if (full == 1) { treg = "DX"; };
|
||||||
|
if (full == 2) { treg = "CX"; };
|
||||||
|
emitline("\t");
|
||||||
|
emitline(top);
|
||||||
|
emitline("\t");
|
||||||
|
emitline(treg);
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((off + full * 8): i64);
|
||||||
|
emitline("(BP)\n");
|
||||||
|
};
|
||||||
|
c.lastwasreturn = 0;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
// Struct ident copy: `let p2: T = p1;` where T is a struct
|
// Struct ident copy: `let p2: T = p1;` where T is a struct
|
||||||
// >8B and rhs is a local ident. Per-qword MOVQ from src
|
// >8B and rhs is a local ident. Per-qword MOVQ from src
|
||||||
// slot to dst slot, with a sized tail (MOVL/MOVB) for
|
// slot to dst slot, with a sized tail (MOVL/MOVB) for
|
||||||
|
|||||||
@@ -954,6 +954,72 @@ static const struct row rows[] = {
|
|||||||
" let c: T = G;\n"
|
" let c: T = G;\n"
|
||||||
" return (c.a+c.b+c.c+c.d): i32;\n"
|
" return (c.a+c.b+c.c+c.d): i32;\n"
|
||||||
"};\n", 100, 1 },
|
"};\n", 100, 1 },
|
||||||
|
/* #267 fold-2: array return-by-value ABI. Arrays ride the existing
|
||||||
|
* struct-return path (≤24B in AX:DX:CX, >24B via sret) — these rows
|
||||||
|
* pin the runtime value AND cs==ww byte-id across reg-class (8/16/
|
||||||
|
* 24B) and sret-class (32B), [N]u32 and [N]u8, at the let-init /
|
||||||
|
* assign / return-forward receive contexts. ctrl_struct_ret is the
|
||||||
|
* regression control: a struct return still byte-id (the struct path
|
||||||
|
* the arrays were wired into didn't change). FULL readback (sum every
|
||||||
|
* member) so a dropped eightbyte surfaces. */
|
||||||
|
{ "ret_arr_u32_8",
|
||||||
|
"package main;\n"
|
||||||
|
"fn mk() [2]u32 = { let a: [2]u32; a[0]=3u32; a[1]=4u32; return a; };\n"
|
||||||
|
"export fn main() i32 = { let c = mk(); return (c[0]+c[1]): i32; };\n",
|
||||||
|
7, 1 },
|
||||||
|
{ "ret_arr_u32_16",
|
||||||
|
"package main;\n"
|
||||||
|
"fn mk() [4]u32 = { let a: [4]u32; a[0]=1u32;a[1]=2u32;a[2]=3u32;a[3]=4u32; return a; };\n"
|
||||||
|
"export fn main() i32 = { let c = mk(); return (c[0]+c[1]+c[2]+c[3]): i32; };\n",
|
||||||
|
10, 1 },
|
||||||
|
{ "ret_arr_u32_24",
|
||||||
|
"package main;\n"
|
||||||
|
"fn mk() [6]u32 = { let a: [6]u32; a[0]=1u32;a[1]=2u32;a[2]=3u32;a[3]=4u32;a[4]=5u32;a[5]=6u32; return a; };\n"
|
||||||
|
"export fn main() i32 = { let c = mk(); return (c[0]+c[1]+c[2]+c[3]+c[4]+c[5]): i32; };\n",
|
||||||
|
21, 1 },
|
||||||
|
{ "ret_arr_u32_32_sret",
|
||||||
|
"package main;\n"
|
||||||
|
"fn mk() [8]u32 = { let a: [8]u32; a[0]=1u32;a[1]=2u32;a[2]=3u32;a[3]=4u32;a[4]=5u32;a[5]=6u32;a[6]=7u32;a[7]=8u32; return a; };\n"
|
||||||
|
"export fn main() i32 = { let c = mk(); return (c[0]+c[1]+c[2]+c[3]+c[4]+c[5]+c[6]+c[7]): i32; };\n",
|
||||||
|
36, 1 },
|
||||||
|
{ "ret_arr_u8_4",
|
||||||
|
"package main;\n"
|
||||||
|
"fn mk() [4]u8 = { let a: [4]u8; a[0]=10u8;a[1]=20u8;a[2]=30u8;a[3]=40u8; return a; };\n"
|
||||||
|
"export fn main() i32 = { let c = mk(); return (c[0]+c[1]+c[2]+c[3]): i32; };\n",
|
||||||
|
100, 1 },
|
||||||
|
{ "ret_arr_u8_32_sret",
|
||||||
|
"package main;\n"
|
||||||
|
"fn mk() [32]u8 = { let a: [32]u8; a[0]=50u8;a[15]=30u8;a[31]=40u8; return a; };\n"
|
||||||
|
"export fn main() i32 = { let c = mk(); return (c[0]+c[15]+c[31]): i32; };\n",
|
||||||
|
120, 1 },
|
||||||
|
{ "ret_arr_assign_16",
|
||||||
|
"package main;\n"
|
||||||
|
"fn mk() [4]u32 = { let a: [4]u32; a[0]=1u32;a[1]=2u32;a[2]=3u32;a[3]=4u32; return a; };\n"
|
||||||
|
"export fn main() i32 = { let c: [4]u32; c = mk(); return (c[0]+c[1]+c[2]+c[3]): i32; };\n",
|
||||||
|
10, 1 },
|
||||||
|
{ "ret_arr_assign_32_sret",
|
||||||
|
"package main;\n"
|
||||||
|
"fn mk() [8]u32 = { let a: [8]u32; a[0]=1u32;a[7]=8u32; return a; };\n"
|
||||||
|
"export fn main() i32 = { let c: [8]u32; c = mk(); return (c[0]+c[7]): i32; };\n",
|
||||||
|
9, 1 },
|
||||||
|
{ "ret_arr_fwd_16",
|
||||||
|
"package main;\n"
|
||||||
|
"fn mk() [4]u32 = { let a: [4]u32; a[0]=1u32;a[1]=2u32;a[2]=3u32;a[3]=4u32; return a; };\n"
|
||||||
|
"fn fwd() [4]u32 = { return mk(); };\n"
|
||||||
|
"export fn main() i32 = { let c = fwd(); return (c[0]+c[1]+c[2]+c[3]): i32; };\n",
|
||||||
|
10, 1 },
|
||||||
|
{ "ret_arr_fwd_32_sret",
|
||||||
|
"package main;\n"
|
||||||
|
"fn mk() [8]u32 = { let a: [8]u32; a[0]=1u32;a[7]=8u32; return a; };\n"
|
||||||
|
"fn fwd() [8]u32 = { return mk(); };\n"
|
||||||
|
"export fn main() i32 = { let c = fwd(); return (c[0]+c[7]): i32; };\n",
|
||||||
|
9, 1 },
|
||||||
|
{ "ctrl_struct_ret",
|
||||||
|
"package main;\n"
|
||||||
|
"type T = struct { a: u32, b: u32, c: u32 };\n"
|
||||||
|
"fn mk() T = { let s: T; s.a=1u32;s.b=2u32;s.c=3u32; return s; };\n"
|
||||||
|
"export fn main() i32 = { let v = mk(); return (v.a+v.b+v.c): i32; };\n",
|
||||||
|
6, 1 },
|
||||||
{ NULL, NULL, 0, 0 }
|
{ NULL, NULL, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user