1
0
mirror of https://github.com/golang/go synced 2024-11-24 15:10:02 -07:00

cmd/6g, cmd/8g: eliminate short integer arithmetic when possible.

Fixes #3909.
Fixes #3910.

R=rsc, nigeltao
CC=golang-dev
https://golang.org/cl/6442114
This commit is contained in:
Rémy Oudompheng 2012-09-01 16:40:54 +02:00
parent 508bfda6d3
commit 8f3c2055bd
5 changed files with 235 additions and 32 deletions

View File

@ -34,6 +34,7 @@
#include "opt.h" #include "opt.h"
static void conprop(Reg *r); static void conprop(Reg *r);
static void elimshortmov(Reg *r);
static int prevl(Reg *r, int reg); static int prevl(Reg *r, int reg);
static void pushback(Reg *r); static void pushback(Reg *r);
static int regconsttyp(Adr*); static int regconsttyp(Adr*);
@ -48,11 +49,17 @@ needc(Prog *p)
case AADCQ: case AADCQ:
case ASBBL: case ASBBL:
case ASBBQ: case ASBBQ:
case ARCRB:
case ARCRW:
case ARCRL: case ARCRL:
case ARCRQ: case ARCRQ:
return 1; return 1;
case AADDB:
case AADDW:
case AADDL: case AADDL:
case AADDQ: case AADDQ:
case ASUBB:
case ASUBW:
case ASUBL: case ASUBL:
case ASUBQ: case ASUBQ:
case AJMP: case AJMP:
@ -129,6 +136,9 @@ peep(void)
} }
} }
// byte, word arithmetic elimination.
elimshortmov(r);
// constant propagation // constant propagation
// find MOV $con,R followed by // find MOV $con,R followed by
// another MOV $con,R without // another MOV $con,R without
@ -448,6 +458,99 @@ regtyp(Adr *a)
return 0; 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 int
regconsttyp(Adr *a) regconsttyp(Adr *a)
{ {

View File

@ -1582,8 +1582,9 @@ gmove(Node *f, Node *t)
p1 = gins(ASHRL, ncon(1), &ax); p1 = gins(ASHRL, ncon(1), &ax);
p1->from.index = D_DX; // double-width shift DX -> AX p1->from.index = D_DX; // double-width shift DX -> AX
p1->from.scale = 0; p1->from.scale = 0;
gins(AMOVL, ncon(0), &cx);
gins(ASETCC, N, &cx); gins(ASETCC, N, &cx);
gins(AORB, &cx, &ax); gins(AORL, &cx, &ax);
gins(ASHRL, ncon(1), &dx); gins(ASHRL, ncon(1), &dx);
gmove(&dx, &thi); gmove(&dx, &thi);
gmove(&ax, &tlo); gmove(&ax, &tlo);

View File

@ -36,6 +36,7 @@
#define REGEXT 0 #define REGEXT 0
static void conprop(Reg *r); static void conprop(Reg *r);
static void elimshortmov(Reg *r);
// do we need the carry bit // do we need the carry bit
static int static int
@ -45,9 +46,15 @@ needc(Prog *p)
switch(p->as) { switch(p->as) {
case AADCL: case AADCL:
case ASBBL: case ASBBL:
case ARCRB:
case ARCRW:
case ARCRL: case ARCRL:
return 1; return 1;
case AADDB:
case AADDW:
case AADDL: case AADDL:
case ASUBB:
case ASUBW:
case ASUBL: case ASUBL:
case AJMP: case AJMP:
case ARET: case ARET:
@ -122,25 +129,9 @@ peep(void)
p = p->link; p = p->link;
} }
} }
// movb elimination. // byte, word arithmetic elimination.
// movb is simulated by the linker elimshortmov(r);
// 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;
}
}
// constant propagation // constant propagation
// find MOV $con,R followed by // find MOV $con,R followed by
@ -173,8 +164,6 @@ loop1:
for(r=firstr; r!=R; r=r->link) { for(r=firstr; r!=R; r=r->link) {
p = r->prog; p = r->prog;
switch(p->as) { switch(p->as) {
case AMOVB:
case AMOVW:
case AMOVL: case AMOVL:
if(regtyp(&p->to)) if(regtyp(&p->to))
if(regtyp(&p->from)) { if(regtyp(&p->from)) {
@ -205,7 +194,6 @@ loop1:
} }
break; break;
case AADDB:
case AADDL: case AADDL:
case AADDW: case AADDW:
if(p->from.type != D_CONST || needc(p->link)) if(p->from.type != D_CONST || needc(p->link))
@ -228,7 +216,6 @@ loop1:
} }
break; break;
case ASUBB:
case ASUBL: case ASUBL:
case ASUBW: case ASUBW:
if(p->from.type != D_CONST || needc(p->link)) if(p->from.type != D_CONST || needc(p->link))
@ -315,6 +302,99 @@ regtyp(Adr *a)
return 0; 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 * the idea is to substitute
* one register for another * one register for another
@ -407,8 +487,6 @@ subprop(Reg *r0)
case AMOVSL: case AMOVSL:
return 0; return 0;
case AMOVB:
case AMOVW:
case AMOVL: case AMOVL:
if(p->to.type == v1->type) if(p->to.type == v1->type)
goto gotit; goto gotit;
@ -589,8 +667,6 @@ copyu(Prog *p, Adr *v, Adr *s)
case ANOP: /* rhs store */ case ANOP: /* rhs store */
case AMOVB:
case AMOVW:
case AMOVL: case AMOVL:
case AMOVBLSX: case AMOVBLSX:
case AMOVBLZX: case AMOVBLZX:
@ -655,6 +731,8 @@ copyu(Prog *p, Adr *v, Adr *s)
case AXORB: case AXORB:
case AXORL: case AXORL:
case AXORW: case AXORW:
case AMOVB:
case AMOVW:
if(copyas(&p->to, v)) if(copyas(&p->to, v))
return 2; return 2;
goto caseread; goto caseread;

View File

@ -1,16 +1,16 @@
// $G $D/$F.go && $L $F.$A && ./$A.out // run
// # switch above to 'run' when bug gets fixed.
// # right now it only breaks on 8g
// Test for 8g register move bug. The optimizer gets confused // Test for 8g register move bug. The optimizer gets confused
// about 16- vs 32-bit moves during splitContractIndex. // about 16- vs 32-bit moves during splitContractIndex.
// Issue 3910.
package main package main
func main() { func main() {
const c = 0x12345678 const c = 0x12345678
index, n, offset := splitContractIndex(c) 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) println("BUG", index, n, offset)
} }
} }

View File

@ -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
}