w6c+wwstage: array global-aggregate-receive g = f() (#272 commit-2)
The caller-half of the global case: `g = mk()` into a GLOBAL array stored only the first word — a ≤24B reg-return landed `MOVQ AX, g(SB)` (8 of 24 bytes); a >24B sret-return hit the #220 sret-to-symbol gate which was TY_STRUCT-only and fell through to the same truncation. ≤24B: the local aggregate-receive arm was `off != 0`-only, so a global array fell to the scalar IDENT store. Add a global ARRAY arm — LEAQ name(SB), DI then store the full+tail words from AX/DX/CX (an array is never float-class, so AX/DX/CX is always the transport; no `g+8(SB)` operand form exists). Mirrors the str/slice global arm. >24B: add TY_ARRAY to the #220 sret-to-symbol gate (cg_sret_dest_sym / sretdestnode) — the callee writes the whole array through RDI. A ≤24B STRUCT global receive can be float-class (X0/X1, not AX/DX/CX), so it is left at its pre-existing symmetric behaviour — no consumer. 949_aggret_source_run gains global_recv (c → 15) and global_recv_sret (>24B → 22), both with per-row byte-id.
This commit is contained in:
@@ -5625,11 +5625,12 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
* global arm above (let_islet + LEAQ masym). The
|
* global arm above (let_islet + LEAQ masym). The
|
||||||
* scalar fall-through below would emit a truncated
|
* scalar fall-through below would emit a truncated
|
||||||
* 8-byte `MOVQ AX, g(SB)` and drop the struct body.
|
* 8-byte `MOVQ AX, g(SB)` and drop the struct body.
|
||||||
* Kept TY_STRUCT-only: a tuple-typed global reassign
|
* Kept aggregate-only (struct + #272 array): a
|
||||||
* has no sret-to-symbol path in wwstage either, so
|
* tuple-typed global reassign has no sret-to-symbol
|
||||||
* leaving it to fall through keeps the stages aligned
|
* path in wwstage either, so leaving it to fall
|
||||||
* (rule-10). */
|
* through keeps the stages aligned (rule-10). */
|
||||||
if (lu && lu->kind == TY_STRUCT
|
if (lu && (lu->kind == TY_STRUCT
|
||||||
|
|| lu->kind == TY_ARRAY)
|
||||||
&& let_islet(n->lhs->str)) {
|
&& let_islet(n->lhs->str)) {
|
||||||
cg_sret_dest_sym = n->lhs->str;
|
cg_sret_dest_sym = n->lhs->str;
|
||||||
cgexpr(c, n->rhs, locals);
|
cgexpr(c, n->rhs, locals);
|
||||||
@@ -5687,6 +5688,35 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (lu->kind == TY_ARRAY
|
||||||
|
&& let_islet(n->lhs->str)
|
||||||
|
&& n->rhs && n->rhs->kind == N_CALL
|
||||||
|
&& n->op == TK_ASSIGN) {
|
||||||
|
/* #272: `g = f();` where g is a GLOBAL
|
||||||
|
* aggregate â¤24B. The callee leaves the result
|
||||||
|
* in AX/DX/CX (#272 reg-return); the scalar IDENT
|
||||||
|
* fall-through below would store only MOVQ AX,
|
||||||
|
* g(SB) = the first word. The asm has no `g+8(SB)`
|
||||||
|
* operand form, so LEAQ the symbol into DI and
|
||||||
|
* store the full+tail words. Mirrors the str/slice
|
||||||
|
* global arm above and the #220 sret-to-symbol path. */
|
||||||
|
int sz = (int)lu->size;
|
||||||
|
cgexpr(c, n->rhs, locals);
|
||||||
|
ins2(c, A_LEAQ, masym(c, n->lhs->str), areg(D_DI));
|
||||||
|
int regs[3] = { D_AX, D_DX, D_CX };
|
||||||
|
int full = sz / 8;
|
||||||
|
int tail = sz % 8;
|
||||||
|
for (int i = 0; i < full; i++)
|
||||||
|
ins2(c, A_MOVQ, areg(regs[i]),
|
||||||
|
amem(D_DI, i * 8));
|
||||||
|
if (tail > 0) {
|
||||||
|
int op = (tail == 4) ? A_MOVL
|
||||||
|
: (tail == 2) ? A_MOVW
|
||||||
|
: A_MOVB;
|
||||||
|
ins2(c, op, areg(regs[full]),
|
||||||
|
amem(D_DI, full * 8));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27067,30 +27067,81 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\tX1, (CX)\n");
|
emitline("\tX1, (CX)\n");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
// #220: `g = f();` where g is a GLOBAL struct >24B.
|
// #220: `g = f();` where g is a GLOBAL aggregate >24B
|
||||||
// No BP slot for the sret dest, so route RDI to g's
|
// (struct or #272 array). No BP slot for the sret dest,
|
||||||
// symbol; the callee writes the struct straight into
|
// so route RDI to g's symbol; the callee writes straight
|
||||||
// g's storage. The scalar store below would emit a
|
// into g's storage. The scalar store below would emit a
|
||||||
// truncated `MOVQ AX, g(SB)` and drop the body. Mirror
|
// truncated `MOVQ AX, g(SB)` and drop the body. Mirror
|
||||||
// of the C cgen N_ASSIGN global arm (cmd/w6c/cgen.c).
|
// of the C cgen N_ASSIGN global arm (cmd/w6c/cgen.c).
|
||||||
if (n.op == tkind.TK_ASSIGN && n.rhs != nil
|
if (n.op == tkind.TK_ASSIGN && n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_CALL && lvftn != nil) {
|
&& n.rhs.kind == nkind.N_CALL && lvftn != nil) {
|
||||||
|
let gsz: i32 = 0;
|
||||||
if (lvftn.kind == nkind.N_TNAME) {
|
if (lvftn.kind == nkind.N_TNAME) {
|
||||||
let gsi: *structinfo = structlookup(c, lvftn.str);
|
let gsi: *structinfo = structlookup(c, lvftn.str);
|
||||||
if (gsi != nil) {
|
if (gsi != nil) { gsz = structabisize(gsi); };
|
||||||
let gsz: i32 = structabisize(gsi);
|
};
|
||||||
if (gsz > 24) {
|
if (lvftn.kind == nkind.N_TARRAY) {
|
||||||
let rscs: i32 = callsretsize(c, n.rhs);
|
let gat: *tinfo = lvftn.type_: *tinfo;
|
||||||
if (rscs > 0) {
|
for (gat != nil && gat.kind == tykind.TY_NAMED) { gat = gat.under; };
|
||||||
c.sretdestnode = lhs;
|
if (gat != nil) { gsz = gat.size: i32; };
|
||||||
cgexpr(c, n.rhs);
|
};
|
||||||
c.sretdestnode = nil;
|
if (gsz > 24) {
|
||||||
return;
|
let rscs: i32 = callsretsize(c, n.rhs);
|
||||||
};
|
if (rscs > 0) {
|
||||||
};
|
c.sretdestnode = lhs;
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
c.sretdestnode = nil;
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #272: `g = f();` where g is a GLOBAL ARRAY ≤24B.
|
||||||
|
// The callee leaves AX/DX/CX (#272 reg-return; an array
|
||||||
|
// is never float-class, so AX/DX/CX is always the
|
||||||
|
// transport); the scalar store below would truncate to
|
||||||
|
// MOVQ AX, g(SB). LEAQ the symbol into DI, store the
|
||||||
|
// full+tail words. Mirror of cstage cgen.c ≤24B global
|
||||||
|
// arm. A ≤24B STRUCT global receive can be float-class
|
||||||
|
// (X0/X1) so it stays at its pre-existing behaviour — no
|
||||||
|
// consumer (rule-10 aligned with cstage).
|
||||||
|
if (n.op == tkind.TK_ASSIGN && n.rhs != nil
|
||||||
|
&& n.rhs.kind == nkind.N_CALL && lvftn != nil
|
||||||
|
&& lvftn.kind == nkind.N_TARRAY) {
|
||||||
|
let aggsz: i32 = 0;
|
||||||
|
let aat: *tinfo = lvftn.type_: *tinfo;
|
||||||
|
for (aat != nil && aat.kind == tykind.TY_NAMED) { aat = aat.under; };
|
||||||
|
if (aat != nil) { aggsz = aat.size: i32; };
|
||||||
|
if (aggsz > 0 && aggsz <= 24) {
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
emitline("\tLEAQ\t");
|
||||||
|
emitsymname(c, nm);
|
||||||
|
emitline("(SB), DI\n");
|
||||||
|
let full: i32 = aggsz / 8;
|
||||||
|
let tail: i32 = aggsz - full * 8;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < full) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(tupreg(i));
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((i * 8): i64);
|
||||||
|
emitline("(DI)\n");
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
if (tail > 0) {
|
||||||
|
let top: str = "MOVB";
|
||||||
|
if (tail == 4) { top = "MOVL"; };
|
||||||
|
if (tail == 2) { top = "MOVW"; };
|
||||||
|
emitline("\t");
|
||||||
|
emitline(top);
|
||||||
|
emitline("\t");
|
||||||
|
emitline(tupreg(full));
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((full * 8): i64);
|
||||||
|
emitline("(DI)\n");
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (n.op == tkind.TK_ASSIGN) {
|
if (n.op == tkind.TK_ASSIGN) {
|
||||||
// str/slice top-level let: str IS []u8, so both store the
|
// str/slice top-level let: str IS []u8, so both store the
|
||||||
|
|||||||
@@ -7441,30 +7441,81 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\tX1, (CX)\n");
|
emitline("\tX1, (CX)\n");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
// #220: `g = f();` where g is a GLOBAL struct >24B.
|
// #220: `g = f();` where g is a GLOBAL aggregate >24B
|
||||||
// No BP slot for the sret dest, so route RDI to g's
|
// (struct or #272 array). No BP slot for the sret dest,
|
||||||
// symbol; the callee writes the struct straight into
|
// so route RDI to g's symbol; the callee writes straight
|
||||||
// g's storage. The scalar store below would emit a
|
// into g's storage. The scalar store below would emit a
|
||||||
// truncated `MOVQ AX, g(SB)` and drop the body. Mirror
|
// truncated `MOVQ AX, g(SB)` and drop the body. Mirror
|
||||||
// of the C cgen N_ASSIGN global arm (cmd/w6c/cgen.c).
|
// of the C cgen N_ASSIGN global arm (cmd/w6c/cgen.c).
|
||||||
if (n.op == tkind.TK_ASSIGN && n.rhs != nil
|
if (n.op == tkind.TK_ASSIGN && n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_CALL && lvftn != nil) {
|
&& n.rhs.kind == nkind.N_CALL && lvftn != nil) {
|
||||||
|
let gsz: i32 = 0;
|
||||||
if (lvftn.kind == nkind.N_TNAME) {
|
if (lvftn.kind == nkind.N_TNAME) {
|
||||||
let gsi: *structinfo = structlookup(c, lvftn.str);
|
let gsi: *structinfo = structlookup(c, lvftn.str);
|
||||||
if (gsi != nil) {
|
if (gsi != nil) { gsz = structabisize(gsi); };
|
||||||
let gsz: i32 = structabisize(gsi);
|
};
|
||||||
if (gsz > 24) {
|
if (lvftn.kind == nkind.N_TARRAY) {
|
||||||
let rscs: i32 = callsretsize(c, n.rhs);
|
let gat: *tinfo = lvftn.type_: *tinfo;
|
||||||
if (rscs > 0) {
|
for (gat != nil && gat.kind == tykind.TY_NAMED) { gat = gat.under; };
|
||||||
c.sretdestnode = lhs;
|
if (gat != nil) { gsz = gat.size: i32; };
|
||||||
cgexpr(c, n.rhs);
|
};
|
||||||
c.sretdestnode = nil;
|
if (gsz > 24) {
|
||||||
return;
|
let rscs: i32 = callsretsize(c, n.rhs);
|
||||||
};
|
if (rscs > 0) {
|
||||||
};
|
c.sretdestnode = lhs;
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
c.sretdestnode = nil;
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #272: `g = f();` where g is a GLOBAL ARRAY ≤24B.
|
||||||
|
// The callee leaves AX/DX/CX (#272 reg-return; an array
|
||||||
|
// is never float-class, so AX/DX/CX is always the
|
||||||
|
// transport); the scalar store below would truncate to
|
||||||
|
// MOVQ AX, g(SB). LEAQ the symbol into DI, store the
|
||||||
|
// full+tail words. Mirror of cstage cgen.c ≤24B global
|
||||||
|
// arm. A ≤24B STRUCT global receive can be float-class
|
||||||
|
// (X0/X1) so it stays at its pre-existing behaviour — no
|
||||||
|
// consumer (rule-10 aligned with cstage).
|
||||||
|
if (n.op == tkind.TK_ASSIGN && n.rhs != nil
|
||||||
|
&& n.rhs.kind == nkind.N_CALL && lvftn != nil
|
||||||
|
&& lvftn.kind == nkind.N_TARRAY) {
|
||||||
|
let aggsz: i32 = 0;
|
||||||
|
let aat: *tinfo = lvftn.type_: *tinfo;
|
||||||
|
for (aat != nil && aat.kind == tykind.TY_NAMED) { aat = aat.under; };
|
||||||
|
if (aat != nil) { aggsz = aat.size: i32; };
|
||||||
|
if (aggsz > 0 && aggsz <= 24) {
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
emitline("\tLEAQ\t");
|
||||||
|
emitsymname(c, nm);
|
||||||
|
emitline("(SB), DI\n");
|
||||||
|
let full: i32 = aggsz / 8;
|
||||||
|
let tail: i32 = aggsz - full * 8;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < full) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(tupreg(i));
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((i * 8): i64);
|
||||||
|
emitline("(DI)\n");
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
if (tail > 0) {
|
||||||
|
let top: str = "MOVB";
|
||||||
|
if (tail == 4) { top = "MOVL"; };
|
||||||
|
if (tail == 2) { top = "MOVW"; };
|
||||||
|
emitline("\t");
|
||||||
|
emitline(top);
|
||||||
|
emitline("\t");
|
||||||
|
emitline(tupreg(full));
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((full * 8): i64);
|
||||||
|
emitline("(DI)\n");
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (n.op == tkind.TK_ASSIGN) {
|
if (n.op == tkind.TK_ASSIGN) {
|
||||||
// str/slice top-level let: str IS []u8, so both store the
|
// str/slice top-level let: str IS []u8, so both store the
|
||||||
|
|||||||
@@ -27067,30 +27067,81 @@ fn cgassign(c: *cgen, n: *node) void = {
|
|||||||
emitline("\tX1, (CX)\n");
|
emitline("\tX1, (CX)\n");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
// #220: `g = f();` where g is a GLOBAL struct >24B.
|
// #220: `g = f();` where g is a GLOBAL aggregate >24B
|
||||||
// No BP slot for the sret dest, so route RDI to g's
|
// (struct or #272 array). No BP slot for the sret dest,
|
||||||
// symbol; the callee writes the struct straight into
|
// so route RDI to g's symbol; the callee writes straight
|
||||||
// g's storage. The scalar store below would emit a
|
// into g's storage. The scalar store below would emit a
|
||||||
// truncated `MOVQ AX, g(SB)` and drop the body. Mirror
|
// truncated `MOVQ AX, g(SB)` and drop the body. Mirror
|
||||||
// of the C cgen N_ASSIGN global arm (cmd/w6c/cgen.c).
|
// of the C cgen N_ASSIGN global arm (cmd/w6c/cgen.c).
|
||||||
if (n.op == tkind.TK_ASSIGN && n.rhs != nil
|
if (n.op == tkind.TK_ASSIGN && n.rhs != nil
|
||||||
&& n.rhs.kind == nkind.N_CALL && lvftn != nil) {
|
&& n.rhs.kind == nkind.N_CALL && lvftn != nil) {
|
||||||
|
let gsz: i32 = 0;
|
||||||
if (lvftn.kind == nkind.N_TNAME) {
|
if (lvftn.kind == nkind.N_TNAME) {
|
||||||
let gsi: *structinfo = structlookup(c, lvftn.str);
|
let gsi: *structinfo = structlookup(c, lvftn.str);
|
||||||
if (gsi != nil) {
|
if (gsi != nil) { gsz = structabisize(gsi); };
|
||||||
let gsz: i32 = structabisize(gsi);
|
};
|
||||||
if (gsz > 24) {
|
if (lvftn.kind == nkind.N_TARRAY) {
|
||||||
let rscs: i32 = callsretsize(c, n.rhs);
|
let gat: *tinfo = lvftn.type_: *tinfo;
|
||||||
if (rscs > 0) {
|
for (gat != nil && gat.kind == tykind.TY_NAMED) { gat = gat.under; };
|
||||||
c.sretdestnode = lhs;
|
if (gat != nil) { gsz = gat.size: i32; };
|
||||||
cgexpr(c, n.rhs);
|
};
|
||||||
c.sretdestnode = nil;
|
if (gsz > 24) {
|
||||||
return;
|
let rscs: i32 = callsretsize(c, n.rhs);
|
||||||
};
|
if (rscs > 0) {
|
||||||
};
|
c.sretdestnode = lhs;
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
c.sretdestnode = nil;
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
// #272: `g = f();` where g is a GLOBAL ARRAY ≤24B.
|
||||||
|
// The callee leaves AX/DX/CX (#272 reg-return; an array
|
||||||
|
// is never float-class, so AX/DX/CX is always the
|
||||||
|
// transport); the scalar store below would truncate to
|
||||||
|
// MOVQ AX, g(SB). LEAQ the symbol into DI, store the
|
||||||
|
// full+tail words. Mirror of cstage cgen.c ≤24B global
|
||||||
|
// arm. A ≤24B STRUCT global receive can be float-class
|
||||||
|
// (X0/X1) so it stays at its pre-existing behaviour — no
|
||||||
|
// consumer (rule-10 aligned with cstage).
|
||||||
|
if (n.op == tkind.TK_ASSIGN && n.rhs != nil
|
||||||
|
&& n.rhs.kind == nkind.N_CALL && lvftn != nil
|
||||||
|
&& lvftn.kind == nkind.N_TARRAY) {
|
||||||
|
let aggsz: i32 = 0;
|
||||||
|
let aat: *tinfo = lvftn.type_: *tinfo;
|
||||||
|
for (aat != nil && aat.kind == tykind.TY_NAMED) { aat = aat.under; };
|
||||||
|
if (aat != nil) { aggsz = aat.size: i32; };
|
||||||
|
if (aggsz > 0 && aggsz <= 24) {
|
||||||
|
cgexpr(c, n.rhs);
|
||||||
|
emitline("\tLEAQ\t");
|
||||||
|
emitsymname(c, nm);
|
||||||
|
emitline("(SB), DI\n");
|
||||||
|
let full: i32 = aggsz / 8;
|
||||||
|
let tail: i32 = aggsz - full * 8;
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < full) {
|
||||||
|
emitline("\tMOVQ\t");
|
||||||
|
emitline(tupreg(i));
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((i * 8): i64);
|
||||||
|
emitline("(DI)\n");
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
if (tail > 0) {
|
||||||
|
let top: str = "MOVB";
|
||||||
|
if (tail == 4) { top = "MOVL"; };
|
||||||
|
if (tail == 2) { top = "MOVW"; };
|
||||||
|
emitline("\t");
|
||||||
|
emitline(top);
|
||||||
|
emitline("\t");
|
||||||
|
emitline(tupreg(full));
|
||||||
|
emitline(", ");
|
||||||
|
emitoff((full * 8): i64);
|
||||||
|
emitline("(DI)\n");
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
};
|
||||||
cgexpr(c, n.rhs);
|
cgexpr(c, n.rhs);
|
||||||
if (n.op == tkind.TK_ASSIGN) {
|
if (n.op == tkind.TK_ASSIGN) {
|
||||||
// str/slice top-level let: str IS []u8, so both store the
|
// str/slice top-level let: str IS []u8, so both store the
|
||||||
|
|||||||
@@ -103,6 +103,22 @@ static const struct row rows[] = {
|
|||||||
"fn mk(p: *pair) pair = { return *p; };\n"
|
"fn mk(p: *pair) pair = { return *p; };\n"
|
||||||
"export fn main() i32 = { let x: pair = pair { a = 5i64, b = 9i64 };\n"
|
"export fn main() i32 = { let x: pair = pair { a = 5i64, b = 9i64 };\n"
|
||||||
" let r: pair = mk(&x); return (r.a + r.b): i32; };\n", 14 },
|
" let r: pair = mk(&x); return (r.a + r.b): i32; };\n", 14 },
|
||||||
|
/* #272 commit-2 caller-half: `g = mk()` into a GLOBAL array ≤24B.
|
||||||
|
* The receive must store the full AX/DX/CX, not the 8-byte AX
|
||||||
|
* truncation (g[1]/g[2] would read 0). */
|
||||||
|
{ "global_recv",
|
||||||
|
"package main;\n"
|
||||||
|
"let g: [3]i64 = [0i64, 0i64, 0i64];\n"
|
||||||
|
"fn mk() [3]i64 = { return [4i64, 5i64, 6i64]; };\n"
|
||||||
|
"export fn main() i32 = { g = mk();\n"
|
||||||
|
" return (g[0]+g[1]+g[2]): i32; };\n", 15 },
|
||||||
|
/* global receive into a >24B array — the sret-to-symbol path. */
|
||||||
|
{ "global_recv_sret",
|
||||||
|
"package main;\n"
|
||||||
|
"let g: [4]i64 = [0i64,0i64,0i64,0i64];\n"
|
||||||
|
"fn mk(p: *[4]i64) [4]i64 = { return *p; };\n"
|
||||||
|
"export fn main() i32 = { let a: [4]i64 = [4i64,5i64,6i64,7i64];\n"
|
||||||
|
" g = mk(&a); return (g[0]+g[1]+g[2]+g[3]): i32; };\n", 22 },
|
||||||
{ NULL, NULL, 0 }
|
{ NULL, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user