summaryrefslogtreecommitdiff
path: root/src/cmd/8g/peep.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/8g/peep.c')
-rw-r--r--src/cmd/8g/peep.c228
1 files changed, 186 insertions, 42 deletions
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
index b8a2825e5..e5a3149cf 100644
--- a/src/cmd/8g/peep.c
+++ b/src/cmd/8g/peep.c
@@ -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:
@@ -119,28 +126,14 @@ peep(void)
case AGLOBL:
case ANAME:
case ASIGNAME:
+ case ALOCALS:
+ case ATYPE:
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
@@ -158,6 +151,8 @@ peep(void)
case AMOVB:
case AMOVW:
case AMOVL:
+ case AMOVSS:
+ case AMOVSD:
if(regtyp(&p->to))
if(p->from.type == D_CONST)
conprop(r);
@@ -173,9 +168,9 @@ loop1:
for(r=firstr; r!=R; r=r->link) {
p = r->prog;
switch(p->as) {
- case AMOVB:
- case AMOVW:
case AMOVL:
+ case AMOVSS:
+ case AMOVSD:
if(regtyp(&p->to))
if(regtyp(&p->from)) {
if(copyprop(r)) {
@@ -205,7 +200,6 @@ loop1:
}
break;
- case AADDB:
case AADDL:
case AADDW:
if(p->from.type != D_CONST || needc(p->link))
@@ -228,7 +222,6 @@ loop1:
}
break;
- case ASUBB:
case ASUBL:
case ASUBW:
if(p->from.type != D_CONST || needc(p->link))
@@ -254,6 +247,19 @@ loop1:
}
if(t)
goto loop1;
+
+ // MOVSD removal.
+ // We never use packed registers, so a MOVSD between registers
+ // can be replaced by MOVAPD, which moves the pair of float64s
+ // instead of just the lower one. We only use the lower one, but
+ // the processor can do better if we do moves using both.
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->as == AMOVSD)
+ if(regtyp(&p->from))
+ if(regtyp(&p->to))
+ p->as = AMOVAPD;
+ }
}
void
@@ -312,9 +318,104 @@ regtyp(Adr *a)
t = a->type;
if(t >= D_AX && t <= D_DI)
return 1;
+ if(t >= D_X0 && t <= D_X7)
+ return 1;
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
@@ -357,17 +458,6 @@ subprop(Reg *r0)
if(p->to.type != D_NONE)
break;
- case ADIVB:
- case ADIVL:
- case ADIVW:
- case AIDIVB:
- case AIDIVL:
- case AIDIVW:
- case AIMULB:
- case AMULB:
- case AMULL:
- case AMULW:
-
case ARCLB:
case ARCLL:
case ARCLW:
@@ -392,6 +482,19 @@ subprop(Reg *r0)
case ASHRB:
case ASHRL:
case ASHRW:
+ if(p->from.type == D_CONST)
+ break;
+
+ case ADIVB:
+ case ADIVL:
+ case ADIVW:
+ case AIDIVB:
+ case AIDIVL:
+ case AIDIVW:
+ case AIMULB:
+ case AMULB:
+ case AMULL:
+ case AMULW:
case AREP:
case AREPN:
@@ -403,11 +506,16 @@ subprop(Reg *r0)
case ASTOSL:
case AMOVSB:
case AMOVSL:
+
+ case AFMOVF:
+ case AFMOVD:
+ case AFMOVFP:
+ case AFMOVDP:
return 0;
- case AMOVB:
- case AMOVW:
case AMOVL:
+ case AMOVSS:
+ case AMOVSD:
if(p->to.type == v1->type)
goto gotit;
break;
@@ -587,13 +695,22 @@ copyu(Prog *p, Adr *v, Adr *s)
case ANOP: /* rhs store */
- case AMOVB:
- case AMOVW:
case AMOVL:
case AMOVBLSX:
case AMOVBLZX:
case AMOVWLSX:
case AMOVWLZX:
+
+ case AMOVSS:
+ case AMOVSD:
+ case ACVTSD2SL:
+ case ACVTSD2SS:
+ case ACVTSL2SD:
+ case ACVTSL2SS:
+ case ACVTSS2SD:
+ case ACVTSS2SL:
+ case ACVTTSD2SL:
+ case ACVTTSS2SL:
if(copyas(&p->to, v)) {
if(s != A)
return copysub(&p->from, v, s, 1);
@@ -653,6 +770,28 @@ copyu(Prog *p, Adr *v, Adr *s)
case AXORB:
case AXORL:
case AXORW:
+ case AMOVB:
+ case AMOVW:
+
+ case AADDSD:
+ case AADDSS:
+ case ACMPSD:
+ case ACMPSS:
+ case ADIVSD:
+ case ADIVSS:
+ case AMAXSD:
+ case AMAXSS:
+ case AMINSD:
+ case AMINSS:
+ case AMULSD:
+ case AMULSS:
+ case ARCPSS:
+ case ARSQRTSS:
+ case ASQRTSD:
+ case ASQRTSS:
+ case ASUBSD:
+ case ASUBSS:
+ case AXORPD:
if(copyas(&p->to, v))
return 2;
goto caseread;
@@ -660,6 +799,11 @@ copyu(Prog *p, Adr *v, Adr *s)
case ACMPL: /* read only */
case ACMPW:
case ACMPB:
+
+ case ACOMISD:
+ case ACOMISS:
+ case AUCOMISD:
+ case AUCOMISS:
caseread:
if(s != A) {
if(copysub(&p->from, v, s, 1))
@@ -744,8 +888,6 @@ copyu(Prog *p, Adr *v, Adr *s)
return 0;
case ARET: /* funny */
- if(v->type == REGRET || v->type == FREGRET)
- return 2;
if(s != A)
return 1;
return 3;
@@ -755,6 +897,8 @@ copyu(Prog *p, Adr *v, Adr *s)
return 2;
if(REGARG >= 0 && v->type == (uchar)REGARG)
return 2;
+ if(v->type == p->from.type)
+ return 2;
if(s != A) {
if(copysub(&p->to, v, s, 1))
@@ -820,7 +964,7 @@ copysub(Adr *a, Adr *v, Adr *s, int f)
if(copyas(a, v)) {
t = s->type;
- if(t >= D_AX && t <= D_DI) {
+ if(t >= D_AX && t <= D_DI || t >= D_X0 && t <= D_X7) {
if(f)
a->type = t;
}
@@ -881,7 +1025,7 @@ loop:
if(p->from.node == p0->from.node)
if(p->from.offset == p0->from.offset)
if(p->from.scale == p0->from.scale)
- if(p->from.dval == p0->from.dval)
+ if(p->from.u.vval == p0->from.u.vval)
if(p->from.index == p0->from.index) {
excise(r);
goto loop;