mirror of
https://github.com/golang/go
synced 2024-11-12 03:50:21 -07:00
cmd/gc: move genembedtramp into portable code
Requires adding new linker instruction RET f(SB) meaning return but then immediately call f. This is what you'd use to implement a tail call after fiddling with the arguments, but the compiler only uses it in genwrapper. This CL eliminates the copy-and-paste genembedtramp functions from 5g/8g/6g and makes the code run on ARM for the first time. It removes a small special case for function generation, which should help Carl a bit, but at the same time it does not bother to implement general tail call optimization, which we do not want anyway. Fixes #5627. R=ken2 CC=golang-dev https://golang.org/cl/10057044
This commit is contained in:
parent
9b2561ef16
commit
1f51d27922
@ -365,11 +365,19 @@ cgen_aret(Node *n, Node *res)
|
||||
void
|
||||
cgen_ret(Node *n)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
genlist(n->list); // copy out args
|
||||
if(hasdefer || curfn->exit)
|
||||
if(hasdefer || curfn->exit) {
|
||||
gjmp(retpc);
|
||||
else
|
||||
gins(ARET, N, N);
|
||||
return;
|
||||
}
|
||||
p = gins(ARET, N, N);
|
||||
if(n->op == ORETJMP) {
|
||||
p->to.name = D_EXTERN;
|
||||
p->to.type = D_CONST;
|
||||
p->to.sym = n->left->sym;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -518,88 +518,6 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
|
||||
return off;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
|
||||
{
|
||||
// TODO(kaib): re-implement genembedtramp
|
||||
genwrapper(rcvr, method, newnam, iface);
|
||||
/*
|
||||
Sym *e;
|
||||
int c, d, o;
|
||||
Prog *p;
|
||||
Type *f;
|
||||
|
||||
e = method->sym;
|
||||
for(d=0; d<nelem(dotlist); d++) {
|
||||
c = adddot1(e, rcvr, d, nil, 0);
|
||||
if(c == 1)
|
||||
goto out;
|
||||
}
|
||||
fatal("genembedtramp %T.%S", rcvr, method->sym);
|
||||
|
||||
out:
|
||||
newplist()->name = newname(newnam);
|
||||
|
||||
//TEXT main·S_test2(SB),7,$0
|
||||
p = pc;
|
||||
gins(ATEXT, N, N);
|
||||
p->from.type = D_OREG;
|
||||
p->from.name = D_EXTERN;
|
||||
p->from.sym = newnam;
|
||||
p->to.type = D_CONST2;
|
||||
p->to.offset = 0; // stack size
|
||||
p->to.offset2 = rnd(method->type->argwid, widthptr); // argument size
|
||||
p->reg = 7; // textflag
|
||||
p->to.reg = NREG;
|
||||
//print("1. %P\n", p);
|
||||
|
||||
o = 0;
|
||||
for(c=d-1; c>=0; c--) {
|
||||
f = dotlist[c].field;
|
||||
o += f->width;
|
||||
if(!isptr[f->type->etype])
|
||||
continue;
|
||||
|
||||
//MOVW o(R0), R0
|
||||
p = pc;
|
||||
gins(AMOVW, N, N);
|
||||
p->from.type = D_OREG;
|
||||
p->from.reg = REGARG;
|
||||
p->from.offset = o;
|
||||
p->to.type = D_REG;
|
||||
p->to.reg = REGARG;
|
||||
//print("2. %P\n", p);
|
||||
o = 0;
|
||||
}
|
||||
if(o != 0) {
|
||||
//MOVW $XX(R0), R0
|
||||
p = pc;
|
||||
gins(AMOVW, N, N);
|
||||
p->from.type = D_CONST;
|
||||
p->from.reg = REGARG;
|
||||
p->from.offset = o;
|
||||
p->to.type = D_REG;
|
||||
p->to.reg = REGARG;
|
||||
//print("3. %P\n", p);
|
||||
}
|
||||
|
||||
f = dotlist[0].field;
|
||||
//B main·*Sub_test2(SB)
|
||||
if(isptr[f->type->etype])
|
||||
f = f->type;
|
||||
p = pc;
|
||||
gins(AB, N, N);
|
||||
p->to.type = D_OREG;
|
||||
p->to.reg = NREG;
|
||||
p->to.name = D_EXTERN;
|
||||
p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
|
||||
//print("4. %P\n", p);
|
||||
|
||||
pc->as = ARET; // overwrite AEND
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
nopout(Prog *p)
|
||||
{
|
||||
|
@ -62,7 +62,7 @@ linkcase(Prog *casep)
|
||||
void
|
||||
noops(void)
|
||||
{
|
||||
Prog *p, *q, *q1;
|
||||
Prog *p, *q, *q1, *q2;
|
||||
int o;
|
||||
Prog *pmorestack;
|
||||
Sym *symmorestack;
|
||||
@ -343,9 +343,14 @@ noops(void)
|
||||
if(!autosize) {
|
||||
p->as = AB;
|
||||
p->from = zprg.from;
|
||||
p->to.type = D_OREG;
|
||||
p->to.offset = 0;
|
||||
p->to.reg = REGLINK;
|
||||
if(p->to.sym) { // retjmp
|
||||
p->to.type = D_BRANCH;
|
||||
p->cond = p->to.sym->text;
|
||||
} else {
|
||||
p->to.type = D_OREG;
|
||||
p->to.offset = 0;
|
||||
p->to.reg = REGLINK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -359,6 +364,17 @@ noops(void)
|
||||
// If there are instructions following
|
||||
// this ARET, they come from a branch
|
||||
// with the same stackframe, so no spadj.
|
||||
|
||||
if(p->to.sym) { // retjmp
|
||||
p->to.reg = REGLINK;
|
||||
q2 = appendp(p);
|
||||
q2->as = AB;
|
||||
q2->to.type = D_BRANCH;
|
||||
q2->to.sym = p->to.sym;
|
||||
q2->cond = p->to.sym->text;
|
||||
p->to.sym = nil;
|
||||
p = q2;
|
||||
}
|
||||
break;
|
||||
|
||||
case AADD:
|
||||
|
@ -325,11 +325,18 @@ cgen_aret(Node *n, Node *res)
|
||||
void
|
||||
cgen_ret(Node *n)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
genlist(n->list); // copy out args
|
||||
if(hasdefer || curfn->exit)
|
||||
if(hasdefer || curfn->exit) {
|
||||
gjmp(retpc);
|
||||
else
|
||||
gins(ARET, N, N);
|
||||
return;
|
||||
}
|
||||
p = gins(ARET, N, N);
|
||||
if(n->op == ORETJMP) {
|
||||
p->to.type = D_EXTERN;
|
||||
p->to.sym = n->left->sym;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -497,115 +497,6 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
|
||||
return off;
|
||||
}
|
||||
|
||||
void
|
||||
genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
|
||||
{
|
||||
Sym *e;
|
||||
int c, d, mov, add, loaded;
|
||||
int64 o;
|
||||
Prog *p;
|
||||
Type *f;
|
||||
|
||||
USED(iface);
|
||||
|
||||
if(0 && debug['r'])
|
||||
print("genembedtramp %T %T %S\n", rcvr, method, newnam);
|
||||
|
||||
e = method->sym;
|
||||
for(d=0; d<nelem(dotlist); d++) {
|
||||
c = adddot1(e, rcvr, d, nil, 0);
|
||||
if(c == 1)
|
||||
goto out;
|
||||
}
|
||||
fatal("genembedtramp %T.%S", rcvr, method->sym);
|
||||
|
||||
out:
|
||||
newplist()->name = newname(newnam);
|
||||
|
||||
//TEXT main·S_test2(SB),7,$0
|
||||
p = pc;
|
||||
gins(ATEXT, N, N);
|
||||
p->from.type = D_EXTERN;
|
||||
p->from.sym = newnam;
|
||||
p->to.type = D_CONST;
|
||||
p->to.offset = 0; // stack size
|
||||
p->to.offset |= rnd(method->type->argwid, widthptr) << 32; // argument size
|
||||
p->from.scale = 7; // textflag
|
||||
//print("1. %P\n", p);
|
||||
|
||||
mov = AMOVQ;
|
||||
add = AADDQ;
|
||||
loaded = 0;
|
||||
o = 0;
|
||||
for(c=d-1; c>=0; c--) {
|
||||
f = dotlist[c].field;
|
||||
o += f->width;
|
||||
if(!isptr[f->type->etype])
|
||||
continue;
|
||||
if(!loaded) {
|
||||
loaded = 1;
|
||||
//MOVQ 8(SP), AX
|
||||
p = pc;
|
||||
gins(mov, N, N);
|
||||
p->from.type = D_INDIR+D_SP;
|
||||
p->from.offset = widthptr;
|
||||
p->to.type = D_AX;
|
||||
//print("2. %P\n", p);
|
||||
}
|
||||
|
||||
//MOVQ o(AX), AX
|
||||
p = pc;
|
||||
gins(mov, N, N);
|
||||
p->from.type = D_INDIR+D_AX;
|
||||
p->from.offset = o;
|
||||
p->to.type = D_AX;
|
||||
//print("3. %P\n", p);
|
||||
o = 0;
|
||||
}
|
||||
if(o != 0) {
|
||||
//ADDQ $XX, AX
|
||||
p = pc;
|
||||
gins(add, N, N);
|
||||
p->from.type = D_CONST;
|
||||
p->from.offset = o;
|
||||
if(loaded)
|
||||
p->to.type = D_AX;
|
||||
else {
|
||||
p->to.type = D_INDIR+D_SP;
|
||||
p->to.offset = widthptr;
|
||||
}
|
||||
//print("4. %P\n", p);
|
||||
}
|
||||
|
||||
//MOVQ AX, 8(SP)
|
||||
if(loaded) {
|
||||
p = pc;
|
||||
gins(mov, N, N);
|
||||
p->from.type = D_AX;
|
||||
p->to.type = D_INDIR+D_SP;
|
||||
p->to.offset = widthptr;
|
||||
//print("5. %P\n", p);
|
||||
} else {
|
||||
// TODO(rsc): obviously this is unnecessary,
|
||||
// but 6l has a bug, and it can't handle
|
||||
// JMP instructions too close to the top of
|
||||
// a new function.
|
||||
gins(ANOP, N, N);
|
||||
}
|
||||
|
||||
f = dotlist[0].field;
|
||||
//JMP main·*Sub_test2(SB)
|
||||
if(isptr[f->type->etype])
|
||||
f = f->type;
|
||||
p = pc;
|
||||
gins(AJMP, N, N);
|
||||
p->to.type = D_EXTERN;
|
||||
p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
|
||||
//print("6. %P\n", p);
|
||||
|
||||
pc->as = ARET; // overwrite AEND
|
||||
}
|
||||
|
||||
void
|
||||
nopout(Prog *p)
|
||||
{
|
||||
|
@ -318,7 +318,7 @@ patch(void)
|
||||
if(p->to.type == D_INDIR+D_GS)
|
||||
p->to.type = D_INDIR+D_FS;
|
||||
}
|
||||
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
|
||||
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
|
||||
s = p->to.sym;
|
||||
if(s) {
|
||||
if(debug['c'])
|
||||
@ -747,6 +747,8 @@ dostkoff(void)
|
||||
// the cleanup.
|
||||
p->spadj = +autoffset;
|
||||
}
|
||||
if(p->to.sym) // retjmp
|
||||
p->as = AJMP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -360,11 +360,18 @@ cgen_aret(Node *n, Node *res)
|
||||
void
|
||||
cgen_ret(Node *n)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
genlist(n->list); // copy out args
|
||||
if(retpc)
|
||||
if(retpc) {
|
||||
gjmp(retpc);
|
||||
else
|
||||
gins(ARET, N, N);
|
||||
return;
|
||||
}
|
||||
p = gins(ARET, N, N);
|
||||
if(n->op == ORETJMP) {
|
||||
p->to.type = D_EXTERN;
|
||||
p->to.sym = n->left->sym;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -507,112 +507,6 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
|
||||
return off;
|
||||
}
|
||||
|
||||
void
|
||||
genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
|
||||
{
|
||||
Sym *e;
|
||||
int c, d, o, mov, add, loaded;
|
||||
Prog *p;
|
||||
Type *f;
|
||||
|
||||
USED(iface);
|
||||
|
||||
e = method->sym;
|
||||
for(d=0; d<nelem(dotlist); d++) {
|
||||
c = adddot1(e, rcvr, d, nil, 0);
|
||||
if(c == 1)
|
||||
goto out;
|
||||
}
|
||||
fatal("genembedtramp %T.%S", rcvr, method->sym);
|
||||
|
||||
out:
|
||||
newplist()->name = newname(newnam);
|
||||
|
||||
//TEXT main·S_test2(SB),7,$0
|
||||
p = pc;
|
||||
gins(ATEXT, N, N);
|
||||
p->from.type = D_EXTERN;
|
||||
p->from.sym = newnam;
|
||||
p->to.type = D_CONST;
|
||||
p->to.offset = 0; // stack skize
|
||||
p->to.offset2 = rnd(method->type->argwid, widthptr); // argument size
|
||||
p->from.scale = 7; // textflag
|
||||
//print("1. %P\n", p);
|
||||
|
||||
mov = AMOVL;
|
||||
add = AADDL;
|
||||
|
||||
loaded = 0;
|
||||
o = 0;
|
||||
for(c=d-1; c>=0; c--) {
|
||||
f = dotlist[c].field;
|
||||
o += f->width;
|
||||
if(!isptr[f->type->etype])
|
||||
continue;
|
||||
if(!loaded) {
|
||||
loaded = 1;
|
||||
//MOVL 4(SP), AX
|
||||
p = pc;
|
||||
gins(mov, N, N);
|
||||
p->from.type = D_INDIR+D_SP;
|
||||
p->from.offset = widthptr;
|
||||
p->to.type = D_AX;
|
||||
//print("2. %P\n", p);
|
||||
}
|
||||
|
||||
//MOVL o(AX), AX
|
||||
p = pc;
|
||||
gins(mov, N, N);
|
||||
p->from.type = D_INDIR+D_AX;
|
||||
p->from.offset = o;
|
||||
p->to.type = D_AX;
|
||||
//print("3. %P\n", p);
|
||||
o = 0;
|
||||
}
|
||||
if(o != 0) {
|
||||
//ADDL $XX, AX
|
||||
p = pc;
|
||||
gins(add, N, N);
|
||||
p->from.type = D_CONST;
|
||||
p->from.offset = o;
|
||||
if(loaded)
|
||||
p->to.type = D_AX;
|
||||
else {
|
||||
p->to.type = D_INDIR+D_SP;
|
||||
p->to.offset = widthptr;
|
||||
}
|
||||
//print("4. %P\n", p);
|
||||
}
|
||||
|
||||
//MOVL AX, 4(SP)
|
||||
if(loaded) {
|
||||
p = pc;
|
||||
gins(mov, N, N);
|
||||
p->from.type = D_AX;
|
||||
p->to.type = D_INDIR+D_SP;
|
||||
p->to.offset = widthptr;
|
||||
//print("5. %P\n", p);
|
||||
} else {
|
||||
// TODO(rsc): obviously this is unnecessary,
|
||||
// but 6l has a bug, and it can't handle
|
||||
// JMP instructions too close to the top of
|
||||
// a new function.
|
||||
gins(ANOP, N, N);
|
||||
}
|
||||
|
||||
f = dotlist[0].field;
|
||||
//JMP main·*Sub_test2(SB)
|
||||
if(isptr[f->type->etype])
|
||||
f = f->type;
|
||||
p = pc;
|
||||
gins(AJMP, N, N);
|
||||
p->to.type = D_EXTERN;
|
||||
p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
|
||||
//print("6. %P\n", p);
|
||||
|
||||
pc->as = ARET; // overwrite AEND
|
||||
}
|
||||
|
||||
void
|
||||
nopout(Prog *p)
|
||||
{
|
||||
|
@ -329,7 +329,7 @@ patch(void)
|
||||
p->from.offset = 0;
|
||||
}
|
||||
}
|
||||
if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH)) {
|
||||
if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
|
||||
s = p->to.sym;
|
||||
if(p->to.type == D_INDIR+D_ADDR) {
|
||||
/* skip check if this is an indirect call (CALL *symbol(SB)) */
|
||||
@ -692,6 +692,8 @@ dostkoff(void)
|
||||
// the cleanup.
|
||||
p->spadj = +autoffset;
|
||||
}
|
||||
if(p->to.sym) // retjmp
|
||||
p->as = AJMP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -870,6 +870,10 @@ stmtfmt(Fmt *f, Node *n)
|
||||
fmtprint(f, "return %,H", n->list);
|
||||
break;
|
||||
|
||||
case ORETJMP:
|
||||
fmtprint(f, "retjmp %S", n->sym);
|
||||
break;
|
||||
|
||||
case OPROC:
|
||||
fmtprint(f, "go %N", n->left);
|
||||
break;
|
||||
|
@ -489,6 +489,7 @@ gen(Node *n)
|
||||
break;
|
||||
|
||||
case ORETURN:
|
||||
case ORETJMP:
|
||||
cgen_ret(n);
|
||||
break;
|
||||
|
||||
|
@ -581,6 +581,7 @@ enum
|
||||
OHMUL, // high mul: AMUL/AIMUL for unsigned/signed (OMUL uses AIMUL for both).
|
||||
OLROT, // left rotate: AROL.
|
||||
ORROTC, // right rotate-carry: ARCR.
|
||||
ORETJMP, // return to other function
|
||||
|
||||
OEND,
|
||||
};
|
||||
@ -1461,7 +1462,6 @@ void fixautoused(Prog*);
|
||||
void gdata(Node*, Node*, int);
|
||||
void gdatacomplex(Node*, Mpcplx*);
|
||||
void gdatastring(Node*, Strlit*);
|
||||
void genembedtramp(Type*, Type*, Sym*, int iface);
|
||||
void ggloblnod(Node *nam);
|
||||
void ggloblsym(Sym *s, int32 width, int dupok, int rodata);
|
||||
Prog* gjmp(Prog*);
|
||||
|
@ -197,6 +197,7 @@ ishairy(Node *n, int *budget)
|
||||
case ODEFER:
|
||||
case ODCLTYPE: // can't print yet
|
||||
case ODCLCONST: // can't print yet
|
||||
case ORETJMP:
|
||||
return 1;
|
||||
|
||||
break;
|
||||
|
@ -218,6 +218,7 @@ orderstmt(Node *n, NodeList **out)
|
||||
case_OFALL:
|
||||
case OGOTO:
|
||||
case OLABEL:
|
||||
case ORETJMP:
|
||||
// Special: n->left is not an expression; save as is.
|
||||
*out = list(*out, n);
|
||||
break;
|
||||
@ -263,7 +264,7 @@ orderstmt(Node *n, NodeList **out)
|
||||
ordercallargs(&n->list, out);
|
||||
*out = list(*out, n);
|
||||
break;
|
||||
|
||||
|
||||
case OSELECT:
|
||||
for(l=n->list; l; l=l->next) {
|
||||
if(l->n->op != OXCASE)
|
||||
|
@ -364,6 +364,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
|
||||
case OIF:
|
||||
case OCALLMETH:
|
||||
case ORETURN:
|
||||
case ORETJMP:
|
||||
case OSWITCH:
|
||||
case OSELECT:
|
||||
case OEMPTY:
|
||||
|
@ -208,16 +208,8 @@ methods(Type *t)
|
||||
if(!(a->isym->flags & SymSiggen)) {
|
||||
a->isym->flags |= SymSiggen;
|
||||
if(!eqtype(this, it) || this->width < types[tptr]->width) {
|
||||
// Is okay to call genwrapper here always,
|
||||
// but we can generate more efficient code
|
||||
// using genembedtramp if all that is necessary
|
||||
// is a pointer adjustment and a JMP.
|
||||
compiling_wrappers = 1;
|
||||
if(isptr[it->etype] && isptr[this->etype]
|
||||
&& f->embedded && !isifacemethod(f->type))
|
||||
genembedtramp(it, f, a->isym, 1);
|
||||
else
|
||||
genwrapper(it, f, a->isym, 1);
|
||||
genwrapper(it, f, a->isym, 1);
|
||||
compiling_wrappers = 0;
|
||||
}
|
||||
}
|
||||
@ -226,11 +218,7 @@ methods(Type *t)
|
||||
a->tsym->flags |= SymSiggen;
|
||||
if(!eqtype(this, t)) {
|
||||
compiling_wrappers = 1;
|
||||
if(isptr[t->etype] && isptr[this->etype]
|
||||
&& f->embedded && !isifacemethod(f->type))
|
||||
genembedtramp(t, f, a->tsym, 0);
|
||||
else
|
||||
genwrapper(t, f, a->tsym, 0);
|
||||
genwrapper(t, f, a->tsym, 0);
|
||||
compiling_wrappers = 0;
|
||||
}
|
||||
}
|
||||
|
@ -2495,13 +2495,13 @@ structargs(Type **tl, int mustname)
|
||||
void
|
||||
genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
|
||||
{
|
||||
Node *this, *fn, *call, *n, *t, *pad;
|
||||
Node *this, *fn, *call, *n, *t, *pad, *dot, *as;
|
||||
NodeList *l, *args, *in, *out;
|
||||
Type *tpad;
|
||||
Type *tpad, *methodrcvr;
|
||||
int isddd;
|
||||
Val v;
|
||||
|
||||
if(debug['r'])
|
||||
if(0 && debug['r'])
|
||||
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
|
||||
rcvr, method, newnam);
|
||||
|
||||
@ -2547,8 +2547,10 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
|
||||
isddd = l->n->left->isddd;
|
||||
}
|
||||
|
||||
methodrcvr = getthisx(method->type)->type->type;
|
||||
|
||||
// generate nil pointer check for better error
|
||||
if(isptr[rcvr->etype] && rcvr->type == getthisx(method->type)->type->type) {
|
||||
if(isptr[rcvr->etype] && rcvr->type == methodrcvr) {
|
||||
// generating wrapper from *T to T.
|
||||
n = nod(OIF, N, N);
|
||||
n->ntest = nod(OEQ, this->left, nodnil());
|
||||
@ -2567,17 +2569,32 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
|
||||
n->nbody = list1(call);
|
||||
fn->nbody = list(fn->nbody, n);
|
||||
}
|
||||
|
||||
|
||||
dot = adddot(nod(OXDOT, this->left, newname(method->sym)));
|
||||
|
||||
// generate call
|
||||
call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N);
|
||||
call->list = args;
|
||||
call->isddd = isddd;
|
||||
if(method->type->outtuple > 0) {
|
||||
n = nod(ORETURN, N, N);
|
||||
n->list = list1(call);
|
||||
call = n;
|
||||
if(isptr[rcvr->etype] && isptr[methodrcvr->etype] && method->embedded && !isifacemethod(method->type)) {
|
||||
// skip final .M
|
||||
dot = dot->left;
|
||||
if(!isptr[dotlist[0].field->type->etype])
|
||||
dot = nod(OADDR, dot, N);
|
||||
as = nod(OAS, this->left, nod(OCONVNOP, dot, N));
|
||||
as->right->type = rcvr;
|
||||
fn->nbody = list(fn->nbody, as);
|
||||
n = nod(ORETJMP, N, N);
|
||||
n->left = newname(methodsym(method->sym, methodrcvr, 0));
|
||||
fn->nbody = list(fn->nbody, n);
|
||||
} else {
|
||||
call = nod(OCALL, dot, N);
|
||||
call->list = args;
|
||||
call->isddd = isddd;
|
||||
if(method->type->outtuple > 0) {
|
||||
n = nod(ORETURN, N, N);
|
||||
n->list = list1(call);
|
||||
call = n;
|
||||
}
|
||||
fn->nbody = list(fn->nbody, call);
|
||||
}
|
||||
fn->nbody = list(fn->nbody, call);
|
||||
|
||||
if(0 && debug['r'])
|
||||
dumplist("genwrapper body", fn->nbody);
|
||||
|
@ -1651,6 +1651,10 @@ reswitch:
|
||||
goto ret;
|
||||
typecheckaste(ORETURN, nil, 0, getoutargx(curfn->type), n->list, "return argument");
|
||||
goto ret;
|
||||
|
||||
case ORETJMP:
|
||||
ok |= Etop;
|
||||
goto ret;
|
||||
|
||||
case OSELECT:
|
||||
ok |= Etop;
|
||||
@ -3282,6 +3286,7 @@ isterminating(NodeList *l, int top)
|
||||
|
||||
case OGOTO:
|
||||
case ORETURN:
|
||||
case ORETJMP:
|
||||
case OPANIC:
|
||||
case OXFALL:
|
||||
return 1;
|
||||
|
@ -282,6 +282,9 @@ walkstmt(Node **np)
|
||||
n->list = ll;
|
||||
break;
|
||||
|
||||
case ORETJMP:
|
||||
break;
|
||||
|
||||
case OSELECT:
|
||||
walkselect(n);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user