mirror of
https://github.com/golang/go
synced 2024-09-05 07:54:46 +00: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:
parent
508bfda6d3
commit
8f3c2055bd
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
21
test/fixedbugs/bug440_64.go
Normal file
21
test/fixedbugs/bug440_64.go
Normal 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
|
||||
}
|
Loading…
Reference in a new issue