]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: support for "portable" optimization logic
authorRuss Cox <rsc@golang.org>
Mon, 12 Aug 2013 23:14:02 +0000 (19:14 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 12 Aug 2013 23:14:02 +0000 (19:14 -0400)
Code in gc/popt.c is compiled as part of 5g, 6g, and 8g,
meaning it can use arch-specific headers but there's
just one copy of the code.

This is the same arrangement we use for the portable
code generation logic in gc/pgen.c.

Move fixjmp and noreturn there to get the ball rolling.

R=ken2
CC=golang-dev
https://golang.org/cl/12789043

19 files changed:
src/cmd/5g/gg.h
src/cmd/5g/opt.h
src/cmd/5g/peep.c
src/cmd/5g/prog.c
src/cmd/5g/reg.c
src/cmd/6g/gg.h
src/cmd/6g/opt.h
src/cmd/6g/peep.c
src/cmd/6g/prog.c
src/cmd/6g/reg.c
src/cmd/8g/gg.h
src/cmd/8g/opt.h
src/cmd/8g/peep.c
src/cmd/8g/prog.c
src/cmd/8g/reg.c
src/cmd/dist/build.c
src/cmd/gc/pgen.c
src/cmd/gc/popt.c [new file with mode: 0644]
src/cmd/gc/popt.h [new file with mode: 0644]

index 90fcbe394c977105ebef29607b6744094c219286..c0d0393ae2c889417a9b09e801039c1b83e24a9e 100644 (file)
@@ -39,7 +39,7 @@ struct        Prog
        uint32  loc;            // pc offset in this func
        uint32  lineno;         // source line that generated this
        Prog*   link;           // next instruction in this func
-       void*   regp;           // points to enclosing Reg struct
+       void*   opt;            // for optimizer passes
        short   as;             // opcode
        uchar   reg;            // doubles as width in DATA op
        uchar   scond;
index 84c81c849b8b72ecafb9dc7c69f72f09b3b3045d..0c120bd695c3b533ff8c7964be8581edd9c09e66 100644 (file)
@@ -28,6 +28,8 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include       "../gc/popt.h"
+
 #define        Z       N
 #define        Adr     Addr
 
@@ -50,7 +52,7 @@ typedef       struct  Rgn     Rgn;
 // A Reg is a wrapper around a single Prog (one instruction) that holds
 // register optimization information while the optimizer runs.
 // r->prog is the instruction.
-// r->prog->regp points back to r.
+// r->prog->opt points back to r.
 struct Reg
 {
 
@@ -140,7 +142,6 @@ uint32      paint2(Reg*, int);
 void   paint3(Reg*, int, int32, int);
 void   addreg(Adr*, int);
 void   dumpit(char *str, Reg *r0);
-int    noreturn(Prog *p);
 
 /*
  * peep.c
@@ -217,3 +218,10 @@ enum
 };
 
 void proginfo(ProgInfo*, Prog*);
+
+// To allow use of AJMP and ACALL in ../gc/popt.c.
+enum
+{
+       AJMP = AB,
+       ACALL = ABL,
+};
index 71c81ecc40f9afd83e5df29490955556fe48c417..e850399d8e66ebb8b69532dc5484081261620369 100644 (file)
@@ -69,7 +69,7 @@ peep(void)
                        r2->link = r1;
 
                        r2->prog = p;
-                       p->regp = r2;
+                       p->opt = r2;
 
                        r2->p1 = r;
                        r->s1 = r2;
index 63709fbee4b21888cd9e1b10040bab3750815771..054461955f41d910323f10a75e65cb74a47653e9 100644 (file)
@@ -26,6 +26,8 @@ static ProgInfo progtable[ALAST] = {
        [ATEXT]=        {Pseudo},
        [AFUNCDATA]=    {Pseudo},
        [APCDATA]=      {Pseudo},
+       [AUNDEF]=       {OK},
+       [AUSEFIELD]=    {OK},
 
        // NOP is an internal no-op that also stands
        // for USED and SET annotations, not the Intel opcode.
index 368da58fe019f2c60652a02ee9af061d3b1ffb85..e748668f424df56845faef9382dc5dea8e5e85ff 100644 (file)
 
 #define        NREGVAR 32
 #define        REGBITS ((uint32)0xffffffff)
-#define        P2R(p)  (Reg*)(p->reg)
 
        void    addsplits(void);
-       int     noreturn(Prog *p);
 static int     first   = 0;
 
-static void    fixjmp(Prog*);
-
 
 Reg*
 rega(void)
@@ -260,7 +256,7 @@ regopt(Prog *firstp)
                        lastr = r;
                }
                r->prog = p;
-               p->regp = r;
+               p->opt = r;
 
                r1 = r->p1;
                if(r1 != R) {
@@ -329,7 +325,7 @@ regopt(Prog *firstp)
                if(p->to.type == D_BRANCH) {
                        if(p->to.u.branch == P)
                                fatal("pnil %P", p);
-                       r1 = p->to.u.branch->regp;
+                       r1 = p->to.u.branch->opt;
                        if(r1 == R)
                                fatal("rnil %P", p);
                        if(r1 == r) {
@@ -1467,31 +1463,6 @@ BtoF(int32 b)
        return bitno(b) - 16;
 }
 
-static Sym*    symlist[10];
-
-int
-noreturn(Prog *p)
-{
-       Sym *s;
-       int i;
-
-       if(symlist[0] == S) {
-               symlist[0] = pkglookup("panicindex", runtimepkg);
-               symlist[1] = pkglookup("panicslice", runtimepkg);
-               symlist[2] = pkglookup("throwinit", runtimepkg);
-               symlist[3] = pkglookup("panic", runtimepkg);
-               symlist[4] = pkglookup("panicwrap", runtimepkg);
-       }
-
-       s = p->to.sym;
-       if(s == S)
-               return 0;
-       for(i=0; symlist[i]!=S; i++)
-               if(s == symlist[i])
-                       return 1;
-       return 0;
-}
-
 void
 dumpone(Reg *r)
 {
@@ -1559,123 +1530,3 @@ dumpit(char *str, Reg *r0)
 //             }
        }
 }
-
-/*
- * the code generator depends on being able to write out JMP (B)
- * instructions that it can jump to now but fill in later.
- * the linker will resolve them nicely, but they make the code
- * longer and more difficult to follow during debugging.
- * remove them.
- */
-
-/* what instruction does a JMP to p eventually land on? */
-static Prog*
-chasejmp(Prog *p, int *jmploop)
-{
-       int n;
-
-       n = 0;
-       while(p != P && p->as == AB && p->to.type == D_BRANCH) {
-               if(++n > 10) {
-                       *jmploop = 1;
-                       break;
-               }
-               p = p->to.u.branch;
-       }
-       return p;
-}
-
-/*
- * reuse reg pointer for mark/sweep state.
- * leave reg==nil at end because alive==nil.
- */
-#define alive ((void*)0)
-#define dead ((void*)1)
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Prog *firstp)
-{
-       Prog *p;
-       
-       for(p=firstp; p; p=p->link) {
-               if(p->regp != dead)
-                       break;
-               p->regp = alive;
-               if(p->as != ABL && p->to.type == D_BRANCH && p->to.u.branch)
-                       mark(p->to.u.branch);
-               if(p->as == AB || p->as == ARET || (p->as == ABL && noreturn(p)))
-                       break;
-       }
-}
-
-static void
-fixjmp(Prog *firstp)
-{
-       int jmploop;
-       Prog *p, *last;
-       
-       if(debug['R'] && debug['v'])
-               print("\nfixjmp\n");
-
-       // pass 1: resolve jump to B, mark all code as dead.
-       jmploop = 0;
-       for(p=firstp; p; p=p->link) {
-               if(debug['R'] && debug['v'])
-                       print("%P\n", p);
-               if(p->as != ABL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AB) {
-                       p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
-                       if(debug['R'] && debug['v'])
-                               print("->%P\n", p);
-               }
-               p->regp = dead;
-       }
-       if(debug['R'] && debug['v'])
-               print("\n");
-       
-       // pass 2: mark all reachable code alive
-       mark(firstp);
-       
-       // pass 3: delete dead code (mostly JMPs).
-       last = nil;
-       for(p=firstp; p; p=p->link) {
-               if(p->regp == dead) {
-                       if(p->link == P && p->as == ARET && last && last->as != ARET) {
-                               // This is the final ARET, and the code so far doesn't have one.
-                               // Let it stay.
-                       } else {
-                               if(debug['R'] && debug['v'])
-                                       print("del %P\n", p);
-                               continue;
-                       }
-               }
-               if(last)
-                       last->link = p;
-               last = p;
-       }
-       last->link = P;
-       
-       // pass 4: elide JMP to next instruction.
-       // only safe if there are no jumps to JMPs anymore.
-       if(!jmploop) {
-               last = nil;
-               for(p=firstp; p; p=p->link) {
-                       if(p->as == AB && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
-                               if(debug['R'] && debug['v'])
-                                       print("del %P\n", p);
-                               continue;
-                       }
-                       if(last)
-                               last->link = p;
-                       last = p;
-               }
-               last->link = P;
-       }
-       
-       if(debug['R'] && debug['v']) {
-               print("\n");
-               for(p=firstp; p; p=p->link)
-                       print("%P\n", p);
-               print("\n");
-       }
-}
index 74382a248f17da2f19c7f2450c948fe9123e350e..f2f3ac1c16b7366a952e10162e358620422e322b 100644 (file)
@@ -41,7 +41,7 @@ struct        Prog
        Addr    from;           // src address
        Addr    to;             // dst address
        Prog*   link;           // next instruction in this func
-       void*   reg;            // pointer to containing Reg struct
+       void*   opt;            // for optimizer passes
 };
 
 #define TEXTFLAG from.scale
index 6fb6460dd52e13b28a415880be77f98554c994be..2d98bded030765dd94b3c97491f34f622418a2b1 100644 (file)
@@ -28,6 +28,8 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include       "../gc/popt.h"
+
 #define        Z       N
 #define        Adr     Addr
 
@@ -50,7 +52,7 @@ typedef       struct  Rgn     Rgn;
 // A Reg is a wrapper around a single Prog (one instruction) that holds
 // register optimization information while the optimizer runs.
 // r->prog is the instruction.
-// r->prog->regp points back to r.
+// r->prog->opt points back to r.
 struct Reg
 {
 
@@ -141,7 +143,6 @@ void        paint3(Reg*, int, int32, int);
 void   addreg(Adr*, int);
 void   dumpone(Reg*);
 void   dumpit(char*, Reg*);
-int    noreturn(Prog *p);
 
 /*
  * peep.c
index 6d9ee85f96cee374c8363215005e21bf0258e341..385750a643dab67b3c541a8b2fb3f856f48c5678 100644 (file)
@@ -102,7 +102,7 @@ peep(void)
                        r2->link = r1;
 
                        r2->prog = p;
-                       p->reg = r2;
+                       p->opt = r2;
 
                        r2->p1 = r;
                        r->s1 = r2;
index 23dde99c16f57de3c1c4b80175ae34a6074c0188..f3c48126543c9868249e22003149ce28e6ed5f7f 100644 (file)
@@ -38,12 +38,13 @@ static ProgInfo progtable[ALAST] = {
        [ATEXT]=        {Pseudo},
        [AFUNCDATA]=    {Pseudo},
        [APCDATA]=      {Pseudo},
+       [AUNDEF]=       {OK},
+       [AUSEFIELD]=    {OK},
 
        // NOP is an internal no-op that also stands
        // for USED and SET annotations, not the Intel opcode.
        [ANOP]=         {LeftRead | RightWrite},
 
-
        [AADCL]=        {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
        [AADCQ]=        {SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry},
        [AADCW]=        {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
@@ -269,10 +270,6 @@ static ProgInfo progtable[ALAST] = {
        [AUCOMISD]=     {SizeD | LeftRead | RightRead},
        [AUCOMISS]=     {SizeF | LeftRead | RightRead},
 
-       [AUNDEF]=       {OK},
-
-       [AUSEFIELD]=    {OK},
-
        [AXCHGB]=       {SizeB | LeftRdwr | RightRdwr},
        [AXCHGL]=       {SizeL | LeftRdwr | RightRdwr},
        [AXCHGQ]=       {SizeQ | LeftRdwr | RightRdwr},
index 549fd70a82287a8e3b8ea8add8b85f0e9f3fd92a..dd57f289f5bf74712f5b1bb875c2235288a26b1f 100644 (file)
@@ -35,7 +35,6 @@
 
 #define        NREGVAR 32      /* 16 general + 16 floating */
 #define        REGBITS ((uint32)0xffffffff)
-#define        P2R(p)  (Reg*)(p->reg)
 
 static int     first   = 1;
 
@@ -153,8 +152,6 @@ static char* regname[] = {
 
 static Node* regnodes[NREGVAR];
 
-static void fixjmp(Prog*);
-
 void
 regopt(Prog *firstp)
 {
@@ -234,7 +231,7 @@ regopt(Prog *firstp)
                        lastr = r;
                }
                r->prog = p;
-               p->reg = r;
+               p->opt = r;
 
                r1 = r->p1;
                if(r1 != R) {
@@ -305,7 +302,7 @@ regopt(Prog *firstp)
                if(p->to.type == D_BRANCH) {
                        if(p->to.u.branch == P)
                                fatal("pnil %P", p);
-                       r1 = p->to.u.branch->reg;
+                       r1 = p->to.u.branch->opt;
                        if(r1 == R)
                                fatal("rnil %P", p);
                        if(r1 == r) {
@@ -1400,148 +1397,3 @@ dumpit(char *str, Reg *r0)
 //             }
        }
 }
-
-static Sym*    symlist[10];
-
-int
-noreturn(Prog *p)
-{
-       Sym *s;
-       int i;
-
-       if(symlist[0] == S) {
-               symlist[0] = pkglookup("panicindex", runtimepkg);
-               symlist[1] = pkglookup("panicslice", runtimepkg);
-               symlist[2] = pkglookup("throwinit", runtimepkg);
-               symlist[3] = pkglookup("panic", runtimepkg);
-               symlist[4] = pkglookup("panicwrap", runtimepkg);
-       }
-
-       s = p->to.sym;
-       if(s == S)
-               return 0;
-       for(i=0; symlist[i]!=S; i++)
-               if(s == symlist[i])
-                       return 1;
-       return 0;
-}
-
-/*
- * the code generator depends on being able to write out JMP
- * instructions that it can jump to now but fill in later.
- * the linker will resolve them nicely, but they make the code
- * longer and more difficult to follow during debugging.
- * remove them.
- */
-
-/* what instruction does a JMP to p eventually land on? */
-static Prog*
-chasejmp(Prog *p, int *jmploop)
-{
-       int n;
-
-       n = 0;
-       while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
-               if(++n > 10) {
-                       *jmploop = 1;
-                       break;
-               }
-               p = p->to.u.branch;
-       }
-       return p;
-}
-
-/*
- * reuse reg pointer for mark/sweep state.
- * leave reg==nil at end because alive==nil.
- */
-#define alive ((void*)0)
-#define dead ((void*)1)
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Prog *firstp)
-{
-       Prog *p;
-       
-       for(p=firstp; p; p=p->link) {
-               if(p->reg != dead)
-                       break;
-               p->reg = alive;
-               if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch)
-                       mark(p->to.u.branch);
-               if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
-                       break;
-       }
-}
-
-static void
-fixjmp(Prog *firstp)
-{
-       int jmploop;
-       Prog *p, *last;
-       
-       if(debug['R'] && debug['v'])
-               print("\nfixjmp\n");
-
-       // pass 1: resolve jump to AJMP, mark all code as dead.
-       jmploop = 0;
-       for(p=firstp; p; p=p->link) {
-               if(debug['R'] && debug['v'])
-                       print("%P\n", p);
-               if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
-                       p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
-                       if(debug['R'] && debug['v'])
-                               print("->%P\n", p);
-               }
-               p->reg = dead;
-       }
-       if(debug['R'] && debug['v'])
-               print("\n");
-
-       // pass 2: mark all reachable code alive
-       mark(firstp);
-       
-       // pass 3: delete dead code (mostly JMPs).
-       last = nil;
-       for(p=firstp; p; p=p->link) {
-               if(p->reg == dead) {
-                       if(p->link == P && p->as == ARET && last && last->as != ARET) {
-                               // This is the final ARET, and the code so far doesn't have one.
-                               // Let it stay.
-                       } else {
-                               if(debug['R'] && debug['v'])
-                                       print("del %P\n", p);
-                               continue;
-                       }
-               }
-               if(last)
-                       last->link = p;
-               last = p;
-       }
-       last->link = P;
-       
-       // pass 4: elide JMP to next instruction.
-       // only safe if there are no jumps to JMPs anymore.
-       if(!jmploop) {
-               last = nil;
-               for(p=firstp; p; p=p->link) {
-                       if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
-                               if(debug['R'] && debug['v'])
-                                       print("del %P\n", p);
-                               continue;
-                       }
-                       if(last)
-                               last->link = p;
-                       last = p;
-               }
-               last->link = P;
-       }
-       
-       if(debug['R'] && debug['v']) {
-               print("\n");
-               for(p=firstp; p; p=p->link)
-                       print("%P\n", p);
-               print("\n");
-       }
-}
index 6907d7ebb4f370137708e8ede4bcaeaf8bec35bb..55fdded0b9a9ba6b4067e0124a9ef2a6472de00d 100644 (file)
@@ -42,7 +42,7 @@ struct        Prog
        Addr    from;           // src address
        Addr    to;             // dst address
        Prog*   link;           // next instruction in this func
-       void*   reg;            // pointer to containing Reg struct
+       void*   opt;            // for optimizer passes
 };
 
 #define TEXTFLAG from.scale
index dc2946108ecfb27455c8f76c99cd1543099c3d79..94a82124a1b798976151dbb418c5db9013767464 100644 (file)
@@ -28,6 +28,8 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+#include       "../gc/popt.h"
+
 #define        Z       N
 #define        Adr     Addr
 
@@ -50,7 +52,7 @@ typedef       struct  Rgn     Rgn;
 // A Reg is a wrapper around a single Prog (one instruction) that holds
 // register optimization information while the optimizer runs.
 // r->prog is the instruction.
-// r->prog->regp points back to r.
+// r->prog->opt points back to r.
 struct Reg
 {
 
@@ -141,7 +143,6 @@ void        paint3(Reg*, int, int32, int);
 void   addreg(Adr*, int);
 void   dumpone(Reg*);
 void   dumpit(char*, Reg*);
-int    noreturn(Prog *p);
 
 /*
  * peep.c
index 51eb6875873f42f5d30b2f47c8ea3cd0c3550b53..b4c092759a3ecc02e948c0a108e40c5bf53da75e 100644 (file)
@@ -99,7 +99,7 @@ peep(void)
                        r2->link = r1;
 
                        r2->prog = p;
-                       p->reg = r2;
+                       p->opt = r2;
 
                        r2->p1 = r;
                        r->s1 = r2;
index 80058ddf37e97e67d7c0f902990f7b75fd75abee..ca877ad128e2beb307e42c3fbcd17f3f2cc26515 100644 (file)
@@ -38,6 +38,8 @@ static ProgInfo progtable[ALAST] = {
        [ATEXT]=        {Pseudo},
        [AFUNCDATA]=    {Pseudo},
        [APCDATA]=      {Pseudo},
+       [AUNDEF]=       {OK},
+       [AUSEFIELD]=    {OK},
 
        // NOP is an internal no-op that also stands
        // for USED and SET annotations, not the Intel opcode.
@@ -287,10 +289,6 @@ static ProgInfo progtable[ALAST] = {
        [AUCOMISD]=     {SizeD | LeftRead | RightRead},
        [AUCOMISS]=     {SizeF | LeftRead | RightRead},
 
-       [AUNDEF]=       {OK},
-
-       [AUSEFIELD]=    {OK},
-
        [AXCHGB]=       {SizeB | LeftRdwr | RightRdwr},
        [AXCHGL]=       {SizeL | LeftRdwr | RightRdwr},
        [AXCHGW]=       {SizeW | LeftRdwr | RightRdwr},
index 519ec774d1da6860d86be3333b98dd6508fe8293..042290cc5d201a25a594d3b7a7dd4a9c7f7d20ae 100644 (file)
 
 #define        NREGVAR 16      /* 8 integer + 8 floating */
 #define        REGBITS ((uint32)0xffff)
-#define        P2R(p)  (Reg*)(p->reg)
 
 static int     first   = 1;
 
-static void    fixjmp(Prog*);
 static void    fixtemp(Prog*);
 
 Reg*
@@ -206,7 +204,7 @@ regopt(Prog *firstp)
                        lastr = r;
                }
                r->prog = p;
-               p->reg = r;
+               p->opt = r;
 
                r1 = r->p1;
                if(r1 != R) {
@@ -277,7 +275,7 @@ regopt(Prog *firstp)
                if(p->to.type == D_BRANCH) {
                        if(p->to.u.branch == P)
                                fatal("pnil %P", p);
-                       r1 = p->to.u.branch->reg;
+                       r1 = p->to.u.branch->opt;
                        if(r1 == R)
                                fatal("rnil %P", p);
                        if(r1 == r) {
@@ -1366,151 +1364,6 @@ dumpit(char *str, Reg *r0)
        }
 }
 
-static Sym*    symlist[10];
-
-int
-noreturn(Prog *p)
-{
-       Sym *s;
-       int i;
-
-       if(symlist[0] == S) {
-               symlist[0] = pkglookup("panicindex", runtimepkg);
-               symlist[1] = pkglookup("panicslice", runtimepkg);
-               symlist[2] = pkglookup("throwinit", runtimepkg);
-               symlist[3] = pkglookup("panic", runtimepkg);
-               symlist[4] = pkglookup("panicwrap", runtimepkg);
-       }
-
-       s = p->to.sym;
-       if(s == S)
-               return 0;
-       for(i=0; symlist[i]!=S; i++)
-               if(s == symlist[i])
-                       return 1;
-       return 0;
-}
-
-/*
- * the code generator depends on being able to write out JMP
- * instructions that it can jump to now but fill in later.
- * the linker will resolve them nicely, but they make the code
- * longer and more difficult to follow during debugging.
- * remove them.
- */
-
-/* what instruction does a JMP to p eventually land on? */
-static Prog*
-chasejmp(Prog *p, int *jmploop)
-{
-       int n;
-
-       n = 0;
-       while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
-               if(++n > 10) {
-                       *jmploop = 1;
-                       break;
-               }
-               p = p->to.u.branch;
-       }
-       return p;
-}
-
-/*
- * reuse reg pointer for mark/sweep state.
- * leave reg==nil at end because alive==nil.
- */
-#define alive ((void*)0)
-#define dead ((void*)1)
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Prog *firstp)
-{
-       Prog *p;
-       
-       for(p=firstp; p; p=p->link) {
-               if(p->reg != dead)
-                       break;
-               p->reg = alive;
-               if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch)
-                       mark(p->to.u.branch);
-               if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
-                       break;
-       }
-}
-
-static void
-fixjmp(Prog *firstp)
-{
-       int jmploop;
-       Prog *p, *last;
-       
-       if(debug['R'] && debug['v'])
-               print("\nfixjmp\n");
-
-       // pass 1: resolve jump to AJMP, mark all code as dead.
-       jmploop = 0;
-       for(p=firstp; p; p=p->link) {
-               if(debug['R'] && debug['v'])
-                       print("%P\n", p);
-               if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
-                       p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
-                       if(debug['R'] && debug['v'])
-                               print("->%P\n", p);
-               }
-               p->reg = dead;
-       }
-       if(debug['R'] && debug['v'])
-               print("\n");
-
-       // pass 2: mark all reachable code alive
-       mark(firstp);
-       
-       // pass 3: delete dead code (mostly JMPs).
-       last = nil;
-       for(p=firstp; p; p=p->link) {
-               if(p->reg == dead) {
-                       if(p->link == P && p->as == ARET && last && last->as != ARET) {
-                               // This is the final ARET, and the code so far doesn't have one.
-                               // Let it stay.
-                       } else {
-                               if(debug['R'] && debug['v'])
-                                       print("del %P\n", p);
-                               continue;
-                       }
-               }
-               if(last)
-                       last->link = p;
-               last = p;
-       }
-       last->link = P;
-       
-       // pass 4: elide JMP to next instruction.
-       // only safe if there are no jumps to JMPs anymore.
-       if(!jmploop) {
-               last = nil;
-               for(p=firstp; p; p=p->link) {
-                       if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
-                               if(debug['R'] && debug['v'])
-                                       print("del %P\n", p);
-                               continue;
-                       }
-                       if(last)
-                               last->link = p;
-                       last = p;
-               }
-               last->link = P;
-       }
-       
-       if(debug['R'] && debug['v']) {
-               print("\n");
-               for(p=firstp; p; p=p->link)
-                       print("%P\n", p);
-               print("\n");
-       }
-}
-
 static uint32
 fnv1(Sym *sym)
 {
index 4012744a586e395cbd5ab941d08efda5add8bcb5..07a47a39525ada2c7920cdf988de9a431904d460 100644 (file)
@@ -489,6 +489,7 @@ static struct {
        {"cmd/gc", {
                "-cplx.c",
                "-pgen.c",
+               "-popt.c",
                "-y1.tab.c",  // makefile dreg
                "opnames.h",
        }},
@@ -513,18 +514,24 @@ static struct {
        {"cmd/5g", {
                "../gc/cplx.c",
                "../gc/pgen.c",
+               "../gc/popt.c",
+               "../gc/popt.h",
                "../5l/enam.c",
                "$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
        }},
        {"cmd/6g", {
                "../gc/cplx.c",
                "../gc/pgen.c",
+               "../gc/popt.c",
+               "../gc/popt.h",
                "../6l/enam.c",
                "$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
        }},
        {"cmd/8g", {
                "../gc/cplx.c",
                "../gc/pgen.c",
+               "../gc/popt.c",
+               "../gc/popt.h",
                "../8l/enam.c",
                "$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
        }},
index d465ab5c3ce0a7c3103f9404d5b9d8bcf2a5139d..f9ff41c1b0b98b93393f19ded7af6b4bb4c25b2f 100644 (file)
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// "Portable" code generation.
+// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
+// Must code to the intersection of the three back ends.
+
 #include       <u.h>
 #include       <libc.h>
 #include       "gg.h"
diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c
new file mode 100644 (file)
index 0000000..f06587c
--- /dev/null
@@ -0,0 +1,183 @@
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//     Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//     Portions Copyright © 1997-1999 Vita Nuova Limited
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//     Portions Copyright © 2004,2006 Bruce Ellis
+//     Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//     Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// "Portable" optimizations.
+// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
+// Must code to the intersection of the three back ends.
+
+#include       <u.h>
+#include       <libc.h>
+#include       "gg.h"
+#include       "opt.h"
+
+// p is a call instruction. Does the call fail to return?
+int
+noreturn(Prog *p)
+{
+       Sym *s;
+       int i;
+       static Sym*     symlist[10];
+
+       if(symlist[0] == S) {
+               symlist[0] = pkglookup("panicindex", runtimepkg);
+               symlist[1] = pkglookup("panicslice", runtimepkg);
+               symlist[2] = pkglookup("throwinit", runtimepkg);
+               symlist[3] = pkglookup("panic", runtimepkg);
+               symlist[4] = pkglookup("panicwrap", runtimepkg);
+       }
+
+       s = p->to.sym;
+       if(s == S)
+               return 0;
+       for(i=0; symlist[i]!=S; i++)
+               if(s == symlist[i])
+                       return 1;
+       return 0;
+}
+
+// JMP chasing and removal.
+//
+// The code generator depends on being able to write out jump
+// instructions that it can jump to now but fill in later.
+// the linker will resolve them nicely, but they make the code
+// longer and more difficult to follow during debugging.
+// Remove them.
+
+/* what instruction does a JMP to p eventually land on? */
+static Prog*
+chasejmp(Prog *p, int *jmploop)
+{
+       int n;
+
+       n = 0;
+       while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
+               if(++n > 10) {
+                       *jmploop = 1;
+                       break;
+               }
+               p = p->to.u.branch;
+       }
+       return p;
+}
+
+/*
+ * reuse reg pointer for mark/sweep state.
+ * leave reg==nil at end because alive==nil.
+ */
+#define alive ((void*)0)
+#define dead ((void*)1)
+
+/* mark all code reachable from firstp as alive */
+static void
+mark(Prog *firstp)
+{
+       Prog *p;
+       
+       for(p=firstp; p; p=p->link) {
+               if(p->opt != dead)
+                       break;
+               p->opt = alive;
+               if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch)
+                       mark(p->to.u.branch);
+               if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
+                       break;
+       }
+}
+
+void
+fixjmp(Prog *firstp)
+{
+       int jmploop;
+       Prog *p, *last;
+       
+       if(debug['R'] && debug['v'])
+               print("\nfixjmp\n");
+
+       // pass 1: resolve jump to jump, mark all code as dead.
+       jmploop = 0;
+       for(p=firstp; p; p=p->link) {
+               if(debug['R'] && debug['v'])
+                       print("%P\n", p);
+               if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
+                       p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
+                       if(debug['R'] && debug['v'])
+                               print("->%P\n", p);
+               }
+               p->opt = dead;
+       }
+       if(debug['R'] && debug['v'])
+               print("\n");
+
+       // pass 2: mark all reachable code alive
+       mark(firstp);
+       
+       // pass 3: delete dead code (mostly JMPs).
+       last = nil;
+       for(p=firstp; p; p=p->link) {
+               if(p->opt == dead) {
+                       if(p->link == P && p->as == ARET && last && last->as != ARET) {
+                               // This is the final ARET, and the code so far doesn't have one.
+                               // Let it stay.
+                       } else {
+                               if(debug['R'] && debug['v'])
+                                       print("del %P\n", p);
+                               continue;
+                       }
+               }
+               if(last)
+                       last->link = p;
+               last = p;
+       }
+       last->link = P;
+       
+       // pass 4: elide JMP to next instruction.
+       // only safe if there are no jumps to JMPs anymore.
+       if(!jmploop) {
+               last = nil;
+               for(p=firstp; p; p=p->link) {
+                       if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
+                               if(debug['R'] && debug['v'])
+                                       print("del %P\n", p);
+                               continue;
+                       }
+                       if(last)
+                               last->link = p;
+                       last = p;
+               }
+               last->link = P;
+       }
+       
+       if(debug['R'] && debug['v']) {
+               print("\n");
+               for(p=firstp; p; p=p->link)
+                       print("%P\n", p);
+               print("\n");
+       }
+}
diff --git a/src/cmd/gc/popt.h b/src/cmd/gc/popt.h
new file mode 100644 (file)
index 0000000..37875ea
--- /dev/null
@@ -0,0 +1,6 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+void   fixjmp(Prog*);
+int    noreturn(Prog*);