]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: move genembedtramp into portable code
authorRuss Cox <rsc@golang.org>
Tue, 11 Jun 2013 13:41:49 +0000 (09:41 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 11 Jun 2013 13:41:49 +0000 (09:41 -0400)
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

19 files changed:
src/cmd/5g/ggen.c
src/cmd/5g/gobj.c
src/cmd/5l/noop.c
src/cmd/6g/ggen.c
src/cmd/6g/gobj.c
src/cmd/6l/pass.c
src/cmd/8g/ggen.c
src/cmd/8g/gobj.c
src/cmd/8l/pass.c
src/cmd/gc/fmt.c
src/cmd/gc/gen.c
src/cmd/gc/go.h
src/cmd/gc/inl.c
src/cmd/gc/order.c
src/cmd/gc/racewalk.c
src/cmd/gc/reflect.c
src/cmd/gc/subr.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c

index de1671bb6fe293f6f2e3477ae89847277015174e..d9935ca25af79dee44e84215b426fe9950737a06 100644 (file)
@@ -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;
+       }
 }
 
 /*
index 3bdb3268a4f886d86a5e3e9ef2bab08788872656..ef48a39a061eb795dd5d573bb5f8339b48ec67c0 100644 (file)
@@ -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)
 {
index 99a096a31f07e10152bdbb41df3bf02c137ca086..63a0d9b8334e80a7d4671025812f70f7326d323d 100644 (file)
@@ -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:
index 5e426753c57d278444d44be8e7bcbf575c2764a3..e7c4c7ebfb10c1c0bd938a02e757415252d8594c 100644 (file)
@@ -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;
+       }
 }
 
 /*
index c7e87f1c811a2805ea615f8034ced7605881df7e..28c4ed6faf9f311c29eddbcaf54963109bdca608 100644 (file)
@@ -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)
 {
index 0054b329f498996f26e3d22d8bc9b31c9ed27559..7de0fddf2911357e46c30671a2b386f30145bcd1 100644 (file)
@@ -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;
                }
        }
 }
index 70148106c4058f31c5bef7b81a1a28dbb8e2cf9a..d7d58d917fcf0c0b95288506b62655d87c6a9a90 100644 (file)
@@ -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;
+       }
 }
 
 /*
index f695468cdf201f86df4604de20abdb56f10015b6..4ed3c96e9d27924d7600648e58834284c0478d56 100644 (file)
@@ -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)
 {
index 4871761ff56c363ee95829e95b7f9f0ea4656c93..f668ca8cf1f38b6a4a024c27ce2e23d5671ecc33 100644 (file)
@@ -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;
                }
        }
 }
index 35f01a5c2628da0bccb6ad39fe5da02fe41753d9..d541c967aff8ed8839c2b90e8501d6c7f40f0591 100644 (file)
@@ -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;
index 955ec2c5bbb8b8bd689678019284949198faf8a4..c0cf99cf6352cc90dc5f9eb8c5e379994d36667c 100644 (file)
@@ -489,6 +489,7 @@ gen(Node *n)
                break;
 
        case ORETURN:
+       case ORETJMP:
                cgen_ret(n);
                break;
        
index 6a3a7d8cf6aed0db868831dcde9f1167ee6baf31..eb5e523b5701a06b1b034b6d13adeadc987cdb0d 100644 (file)
@@ -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*);
index f77b51d707677c466530dc55da623f4bd1030fbe..bbb887be23cef33766952d18c8c775090499eb3c 100644 (file)
@@ -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;
index 499a4e746ebaed4a0006e06b9bcf37822d790e2f..7552510e90acd2623b547b09c5c313c15d3a2f87 100644 (file)
@@ -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)
index 790c7efd7cb63a4b970b2ba19a9c9722bb15ad64..8b644e7a45d7c338ab065f8b7c1b298ea1162074 100644 (file)
@@ -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:
index d9906d9cc9979e1e791c7f410e9b72072fd502b1..ccbed50302d5add9ce8ce26faf3239e0dd13b0ff 100644 (file)
@@ -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;
                        }
                }
index 20a15bc7157c7340981cf6ebe2bbfda772a04c6e..a3fd0f4a8e0d9243bb44c21a25c3f743550ac54a 100644 (file)
@@ -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;
-       }
-       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);
index 550021de69054335914807bf004280a273898797..29fc430cbdc049a4ebe194a18eea7575ed9033a9 100644 (file)
@@ -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;
index a4e20e046c857e1c281b42206b8e029b79d2b673..893c77e4d262e97e8b756eeb65729bfa5472e197 100644 (file)
@@ -282,6 +282,9 @@ walkstmt(Node **np)
                n->list = ll;
                break;
 
+       case ORETJMP:
+               break;
+
        case OSELECT:
                walkselect(n);
                break;