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;
+ }
}
/*
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)
{
void
noops(void)
{
- Prog *p, *q, *q1;
+ Prog *p, *q, *q1, *q2;
int o;
Prog *pmorestack;
Sym *symmorestack;
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;
}
}
// 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:
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;
+ }
}
/*
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)
{
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'])
// the cleanup.
p->spadj = +autoffset;
}
+ if(p->to.sym) // retjmp
+ p->as = AJMP;
}
}
}
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;
+ }
}
/*
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)
{
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)) */
// the cleanup.
p->spadj = +autoffset;
}
+ if(p->to.sym) // retjmp
+ p->as = AJMP;
}
}
}
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;
break;
case ORETURN:
+ case ORETJMP:
cgen_ret(n);
break;
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,
};
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*);
case ODEFER:
case ODCLTYPE: // can't print yet
case ODCLCONST: // can't print yet
+ case ORETJMP:
return 1;
break;
case_OFALL:
case OGOTO:
case OLABEL:
+ case ORETJMP:
// Special: n->left is not an expression; save as is.
*out = list(*out, n);
break;
ordercallargs(&n->list, out);
*out = list(*out, n);
break;
-
+
case OSELECT:
for(l=n->list; l; l=l->next) {
if(l->n->op != OXCASE)
case OIF:
case OCALLMETH:
case ORETURN:
+ case ORETJMP:
case OSWITCH:
case OSELECT:
case OEMPTY:
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;
}
}
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;
}
}
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);
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());
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;
- }
- fn->nbody = list(fn->nbody, call);
+ 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);
+ }
if(0 && debug['r'])
dumplist("genwrapper body", fn->nbody);
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;
case OGOTO:
case ORETURN:
+ case ORETJMP:
case OPANIC:
case OXFALL:
return 1;
n->list = ll;
break;
+ case ORETJMP:
+ break;
+
case OSELECT:
walkselect(n);
break;