]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/6g, cmd/8g: eliminate short integer arithmetic when possible.
authorRémy Oudompheng <oudomphe@phare.normalesup.org>
Sat, 1 Sep 2012 14:40:54 +0000 (16:40 +0200)
committerRémy Oudompheng <oudomphe@phare.normalesup.org>
Sat, 1 Sep 2012 14:40:54 +0000 (16:40 +0200)
Fixes #3909.
Fixes #3910.

R=rsc, nigeltao
CC=golang-dev
https://golang.org/cl/6442114

src/cmd/6g/peep.c
src/cmd/8g/gsubr.c
src/cmd/8g/peep.c
test/fixedbugs/bug440_32.go [moved from test/bugs/bug440.go with 65% similarity]
test/fixedbugs/bug440_64.go [new file with mode: 0644]

index 51f4722149094e60331b823fd7e6029970165510..22eb8dfa712c9227d934c8bdaab08ef3dde3f415 100644 (file)
@@ -34,6 +34,7 @@
 #include "opt.h"
 
 static void    conprop(Reg *r);
+static void elimshortmov(Reg *r);
 static int prevl(Reg *r, int reg);
 static void pushback(Reg *r);
 static int regconsttyp(Adr*);
@@ -48,11 +49,17 @@ needc(Prog *p)
                case AADCQ:
                case ASBBL:
                case ASBBQ:
+               case ARCRB:
+               case ARCRW:
                case ARCRL:
                case ARCRQ:
                        return 1;
+               case AADDB:
+               case AADDW:
                case AADDL:
                case AADDQ:
+               case ASUBB:
+               case ASUBW:
                case ASUBL:
                case ASUBQ:
                case AJMP:
@@ -129,6 +136,9 @@ peep(void)
                }
        }
        
+       // byte, word arithmetic elimination.
+       elimshortmov(r);
+
        // constant propagation
        // find MOV $con,R followed by
        // another MOV $con,R without
@@ -448,6 +458,99 @@ regtyp(Adr *a)
        return 0;
 }
 
+// movb elimination.
+// movb is simulated by the linker
+// when a register other than ax, bx, cx, dx
+// is used, so rewrite to other instructions
+// when possible.  a movb into a register
+// can smash the entire 32-bit register without
+// causing any trouble.
+static void
+elimshortmov(Reg *r)
+{
+       Prog *p;
+
+       for(r=firstr; r!=R; r=r->link) {
+               p = r->prog;
+               if(regtyp(&p->to)) {
+                       switch(p->as) {
+                       case AINCB:
+                       case AINCW:
+                               p->as = AINCQ;
+                               break;
+                       case ADECB:
+                       case ADECW:
+                               p->as = ADECQ;
+                               break;
+                       case ANEGB:
+                       case ANEGW:
+                               p->as = ANEGQ;
+                               break;
+                       case ANOTB:
+                       case ANOTW:
+                               p->as = ANOTQ;
+                               break;
+                       }
+                       if(regtyp(&p->from) || p->from.type == D_CONST) {
+                               // move or artihmetic into partial register.
+                               // from another register or constant can be movl.
+                               // we don't switch to 64-bit arithmetic if it can
+                               // change how the carry bit is set (and the carry bit is needed).
+                               switch(p->as) {
+                               case AMOVB:
+                               case AMOVW:
+                                       p->as = AMOVQ;
+                                       break;
+                               case AADDB:
+                               case AADDW:
+                                       if(!needc(p->link))
+                                               p->as = AADDQ;
+                                       break;
+                               case ASUBB:
+                               case ASUBW:
+                                       if(!needc(p->link))
+                                               p->as = ASUBQ;
+                                       break;
+                               case AMULB:
+                               case AMULW:
+                                       p->as = AMULQ;
+                                       break;
+                               case AIMULB:
+                               case AIMULW:
+                                       p->as = AIMULQ;
+                                       break;
+                               case AANDB:
+                               case AANDW:
+                                       p->as = AANDQ;
+                                       break;
+                               case AORB:
+                               case AORW:
+                                       p->as = AORQ;
+                                       break;
+                               case AXORB:
+                               case AXORW:
+                                       p->as = AXORQ;
+                                       break;
+                               case ASHLB:
+                               case ASHLW:
+                                       p->as = ASHLQ;
+                                       break;
+                               }
+                       } else {
+                               // explicit zero extension
+                               switch(p->as) {
+                               case AMOVB:
+                                       p->as = AMOVBQZX;
+                                       break;
+                               case AMOVW:
+                                       p->as = AMOVWQZX;
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
 int
 regconsttyp(Adr *a)
 {
index ca54b862792464e089b80ae613c9e3b74bc258a9..4e4261804cc60485af905bc6cb93e950e210b933 100644 (file)
@@ -1582,8 +1582,9 @@ gmove(Node *f, Node *t)
                p1 = gins(ASHRL, ncon(1), &ax);
                p1->from.index = D_DX;  // double-width shift DX -> AX
                p1->from.scale = 0;
+               gins(AMOVL, ncon(0), &cx);
                gins(ASETCC, N, &cx);
-               gins(AORB, &cx, &ax);
+               gins(AORL, &cx, &ax);
                gins(ASHRL, ncon(1), &dx);
                gmove(&dx, &thi);
                gmove(&ax, &tlo);
index 38674d02a140ec867b33d45a17f8e46560b48807..91e7bdecdd800c540a2095a589bca6bbb9a5f6a1 100644 (file)
@@ -36,6 +36,7 @@
 #define        REGEXT  0
 
 static void    conprop(Reg *r);
+static void elimshortmov(Reg *r);
 
 // do we need the carry bit
 static int
@@ -45,9 +46,15 @@ needc(Prog *p)
                switch(p->as) {
                case AADCL:
                case ASBBL:
+               case ARCRB:
+               case ARCRW:
                case ARCRL:
                        return 1;
+               case AADDB:
+               case AADDW:
                case AADDL:
+               case ASUBB:
+               case ASUBW:
                case ASUBL:
                case AJMP:
                case ARET:
@@ -122,25 +129,9 @@ peep(void)
                        p = p->link;
                }
        }
-       
-       // movb elimination.
-       // movb is simulated by the linker
-       // when a register other than ax, bx, cx, dx
-       // is used, so rewrite to other instructions
-       // when possible.  a movb into a register
-       // can smash the entire 32-bit register without
-       // causing any trouble.
-       for(r=firstr; r!=R; r=r->link) {
-               p = r->prog;
-               if(p->as == AMOVB && regtyp(&p->to)) {
-                       // movb into register.
-                       // from another register or constant can be movl.
-                       if(regtyp(&p->from) || p->from.type == D_CONST)
-                               p->as = AMOVL;
-                       else
-                               p->as = AMOVBLZX;
-               }
-       }
+  
+       // byte, word arithmetic elimination.
+       elimshortmov(r);
 
        // constant propagation
        // find MOV $con,R followed by
@@ -173,8 +164,6 @@ loop1:
        for(r=firstr; r!=R; r=r->link) {
                p = r->prog;
                switch(p->as) {
-               case AMOVB:
-               case AMOVW:
                case AMOVL:
                        if(regtyp(&p->to))
                        if(regtyp(&p->from)) {
@@ -205,7 +194,6 @@ loop1:
                        }
                        break;
 
-               case AADDB:
                case AADDL:
                case AADDW:
                        if(p->from.type != D_CONST || needc(p->link))
@@ -228,7 +216,6 @@ loop1:
                        }
                        break;
 
-               case ASUBB:
                case ASUBL:
                case ASUBW:
                        if(p->from.type != D_CONST || needc(p->link))
@@ -315,6 +302,99 @@ regtyp(Adr *a)
        return 0;
 }
 
+// movb elimination.
+// movb is simulated by the linker
+// when a register other than ax, bx, cx, dx
+// is used, so rewrite to other instructions
+// when possible.  a movb into a register
+// can smash the entire 64-bit register without
+// causing any trouble.
+static void
+elimshortmov(Reg *r)
+{
+       Prog *p;
+
+       for(r=firstr; r!=R; r=r->link) {
+               p = r->prog;
+               if(regtyp(&p->to)) {
+                       switch(p->as) {
+                       case AINCB:
+                       case AINCW:
+                               p->as = AINCL;
+                               break;
+                       case ADECB:
+                       case ADECW:
+                               p->as = ADECL;
+                               break;
+                       case ANEGB:
+                       case ANEGW:
+                               p->as = ANEGL;
+                               break;
+                       case ANOTB:
+                       case ANOTW:
+                               p->as = ANOTL;
+                               break;
+                       }
+                       if(regtyp(&p->from) || p->from.type == D_CONST) {
+                               // move or artihmetic into partial register.
+                               // from another register or constant can be movl.
+                               // we don't switch to 32-bit arithmetic if it can
+                               // change how the carry bit is set (and the carry bit is needed).
+                               switch(p->as) {
+                               case AMOVB:
+                               case AMOVW:
+                                       p->as = AMOVL;
+                                       break;
+                               case AADDB:
+                               case AADDW:
+                                       if(!needc(p->link))
+                                               p->as = AADDL;
+                                       break;
+                               case ASUBB:
+                               case ASUBW:
+                                       if(!needc(p->link))
+                                               p->as = ASUBL;
+                                       break;
+                               case AMULB:
+                               case AMULW:
+                                       p->as = AMULL;
+                                       break;
+                               case AIMULB:
+                               case AIMULW:
+                                       p->as = AIMULL;
+                                       break;
+                               case AANDB:
+                               case AANDW:
+                                       p->as = AANDL;
+                                       break;
+                               case AORB:
+                               case AORW:
+                                       p->as = AORL;
+                                       break;
+                               case AXORB:
+                               case AXORW:
+                                       p->as = AXORL;
+                                       break;
+                               case ASHLB:
+                               case ASHLW:
+                                       p->as = ASHLL;
+                                       break;
+                               }
+                       } else {
+                               // explicit zero extension
+                               switch(p->as) {
+                               case AMOVB:
+                                       p->as = AMOVBLZX;
+                                       break;
+                               case AMOVW:
+                                       p->as = AMOVWLZX;
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
 /*
  * the idea is to substitute
  * one register for another
@@ -407,8 +487,6 @@ subprop(Reg *r0)
                case AMOVSL:
                        return 0;
 
-               case AMOVB:
-               case AMOVW:
                case AMOVL:
                        if(p->to.type == v1->type)
                                goto gotit;
@@ -589,8 +667,6 @@ copyu(Prog *p, Adr *v, Adr *s)
 
 
        case ANOP:      /* rhs store */
-       case AMOVB:
-       case AMOVW:
        case AMOVL:
        case AMOVBLSX:
        case AMOVBLZX:
@@ -655,6 +731,8 @@ copyu(Prog *p, Adr *v, Adr *s)
        case AXORB:
        case AXORL:
        case AXORW:
+       case AMOVB:
+       case AMOVW:
                if(copyas(&p->to, v))
                        return 2;
                goto caseread;
similarity index 65%
rename from test/bugs/bug440.go
rename to test/fixedbugs/bug440_32.go
index 816a18c58062a3a8ed68bffdfcde1245846752f1..2d26fbb90ab80c1e18bf81dd744b98f85a8bb7a3 100644 (file)
@@ -1,16 +1,16 @@
-// $G $D/$F.go && $L $F.$A && ./$A.out
-// # switch above to 'run' when bug gets fixed.
-// # right now it only breaks on 8g
+// run
 
 // Test for 8g register move bug.  The optimizer gets confused
 // about 16- vs 32-bit moves during splitContractIndex.
 
+// Issue 3910.
+
 package main
 
 func main() {
        const c = 0x12345678
        index, n, offset := splitContractIndex(c)
-       if index != int((c&0xffff)>>5) || n != int(c & (1<<5-1)) || offset != (c>>16)&(1<<14-1) {
+       if index != int((c&0xffff)>>5) || n != int(c&(1<<5-1)) || offset != (c>>16)&(1<<14-1) {
                println("BUG", index, n, offset)
        }
 }
diff --git a/test/fixedbugs/bug440_64.go b/test/fixedbugs/bug440_64.go
new file mode 100644 (file)
index 0000000..3ab3e56
--- /dev/null
@@ -0,0 +1,21 @@
+// run
+
+// Test for 6g register move bug.  The optimizer gets confused
+// about 32- vs 64-bit moves during splitContractIndex.
+
+// Issue 3918.
+
+package main
+
+func main() {
+       const c = 0x123400005678
+       index, offset := splitContractIndex(c)
+       if index != (c&0xffffffff)>>5 || offset != c+1 {
+               println("BUG", index, offset)
+       }
+}
+
+func splitContractIndex(ce uint64) (index uint32, offset uint64) {
+       h := uint32(ce)
+       return h >> 5, ce + 1
+}