Commit 24c8035f authored by Russ Cox's avatar Russ Cox

cmd/6g: move opt instruction decode into common function

Add new proginfo function that returns information about a
Prog*. The information includes various instruction
description bits as well as a list of required registers set
and used and indexing registers used.

Convert the large instruction switches to use proginfo.

This information was formerly duplicated in multiple
optimization passes, inconsistently. For example, the
information about which registers an instruction requires
appeared three times for most instructions.

Most of the switches were incomplete or incorrect in some way.
For example, the switch in copyu did not list cases for INCB,
JPS, MOVAPD, MOVBWSX, MOVBWZX, PCDATA, POPQ, PUSHQ, STD,
TESTB, TESTQ, and XCHGL. Those were all falling into the
"unknown instruction" default case and stopping the rewrite,
perhaps unnecessarily. Similarly, the switch in needc only
listed a handful of the instructions that use or set the carry bit.

We still need to decide whether to use proginfo to generalize
a few of the remaining smaller switches in peep.c.

If this goes well, we'll make similar changes in 8g and 5g.

R=ken2
CC=golang-dev
https://golang.org/cl/12637051
parent 9baac2bf
......@@ -166,3 +166,64 @@ int32 RtoB(int);
int32 FtoB(int);
int BtoR(int32);
int BtoF(int32);
/*
* prog.c
*/
typedef struct ProgInfo ProgInfo;
struct ProgInfo
{
uint32 flags; // the bits below
uint32 reguse; // required registers used by this instruction
uint32 regset; // required registers set by this instruction
uint32 regindex; // registers used by addressing mode
};
enum
{
// Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
Pseudo = 1<<1,
// There's nothing to say about the instruction,
// but it's still okay to see.
OK = 1<<2,
// Size of right-side write, or right-side read if no write.
SizeB = 1<<3,
SizeW = 1<<4,
SizeL = 1<<5,
SizeQ = 1<<6,
SizeF = 1<<7, // float aka float32
SizeD = 1<<8, // double aka float64
// Left side: address taken, read, write.
LeftAddr = 1<<9,
LeftRead = 1<<10,
LeftWrite = 1<<11,
// Right side: address taken, read, write.
RightAddr = 1<<12,
RightRead = 1<<13,
RightWrite = 1<<14,
// Set, use, or kill of carry bit.
// Kill means we never look at the carry bit after this kind of instruction.
SetCarry = 1<<15,
UseCarry = 1<<16,
KillCarry = 1<<17,
// Instruction kinds
Move = 1<<18, // straight move
Conv = 1<<19, // size conversion
Cjmp = 1<<20, // conditional jump
Break = 1<<21, // breaks control flow (no fallthrough)
Call = 1<<22, // function call
Jump = 1<<23, // jump
Skip = 1<<24, // data instruction
// Special cases for register use.
ShiftCX = 1<<25, // possible shift by CX
ImulAXDX = 1<<26, // possible multiply into DX:AX
};
void proginfo(ProgInfo*, Prog*);
......@@ -43,33 +43,14 @@ static int regconsttyp(Adr*);
static int
needc(Prog *p)
{
ProgInfo info;
while(p != P) {
switch(p->as) {
case AADCL:
case AADCQ:
case ASBBL:
case ASBBQ:
case ARCRB:
case ARCRW:
case ARCRL:
case ARCRQ:
proginfo(&info, p);
if(info.flags & UseCarry)
return 1;
case AADDB:
case AADDW:
case AADDL:
case AADDQ:
case ASUBB:
case ASUBW:
case ASUBL:
case ASUBQ:
case AJMP:
case ARET:
case ACALL:
if(info.flags & (SetCarry|KillCarry))
return 0;
default:
if(p->to.type == D_BRANCH)
return 0;
}
p = p->link;
}
return 0;
......@@ -100,6 +81,7 @@ peep(void)
Reg *r, *r1, *r2;
Prog *p, *p1;
int t;
ProgInfo info;
/*
* complete R structure
......@@ -110,9 +92,11 @@ peep(void)
if(r1 == R)
break;
p = r->prog->link;
while(p != r1->prog)
switch(p->as) {
default:
for(p = r->prog->link; p != r1->prog; p = p->link) {
proginfo(&info, p);
if(info.flags & Skip)
continue;
r2 = rega();
r->link = r2;
r2->link = r1;
......@@ -127,13 +111,6 @@ peep(void)
r = r2;
t++;
case ADATA:
case AGLOBL:
case ANAME:
case ASIGNAME:
case ATYPE:
p = p->link;
}
}
......@@ -467,6 +444,9 @@ regtyp(Adr *a)
// when possible. a movb into a register
// can smash the entire 32-bit register without
// causing any trouble.
//
// TODO: Using the Q forms here instead of the L forms
// seems unnecessary, and it makes the instructions longer.
static void
elimshortmov(Reg *r)
{
......@@ -556,6 +536,7 @@ elimshortmov(Reg *r)
}
}
// is 'a' a register or constant?
static int
regconsttyp(Adr *a)
{
......@@ -577,34 +558,17 @@ prevl(Reg *r0, int reg)
{
Prog *p;
Reg *r;
ProgInfo info;
for(r=uniqp(r0); r!=R; r=uniqp(r)) {
p = r->prog;
if(p->to.type == reg) {
switch(p->as) {
case AADDL:
case AANDL:
case ADECL:
case ADIVL:
case AIDIVL:
case AIMULL:
case AINCL:
case AMOVL:
case AMULL:
case AORL:
case ARCLL:
case ARCRL:
case AROLL:
case ARORL:
case ASALL:
case ASARL:
case ASHLL:
case ASHRL:
case ASUBL:
case AXORL:
return 1;
proginfo(&info, p);
if(info.flags & RightWrite) {
if(info.flags & SizeL)
return 1;
return 0;
}
return 0;
}
}
return 0;
......@@ -628,6 +592,7 @@ int
subprop(Reg *r0)
{
Prog *p;
ProgInfo info;
Adr *v1, *v2;
Reg *r;
int t;
......@@ -656,95 +621,22 @@ subprop(Reg *r0)
break;
}
p = r->prog;
switch(p->as) {
case ACALL:
proginfo(&info, p);
if(info.flags & Call) {
if(debug['P'] && debug['v'])
print("\tfound %P; return 0\n", p);
return 0;
}
case AIMULL:
case AIMULQ:
case AIMULW:
if(p->to.type != D_NONE)
break;
goto giveup;
case ARCLB:
case ARCLL:
case ARCLQ:
case ARCLW:
case ARCRB:
case ARCRL:
case ARCRQ:
case ARCRW:
case AROLB:
case AROLL:
case AROLQ:
case AROLW:
case ARORB:
case ARORL:
case ARORQ:
case ARORW:
case ASALB:
case ASALL:
case ASALQ:
case ASALW:
case ASARB:
case ASARL:
case ASARQ:
case ASARW:
case ASHLB:
case ASHLL:
case ASHLQ:
case ASHLW:
case ASHRB:
case ASHRL:
case ASHRQ:
case ASHRW:
if(p->from.type == D_CONST)
break;
goto giveup;
case ADIVB:
case ADIVL:
case ADIVQ:
case ADIVW:
case AIDIVB:
case AIDIVL:
case AIDIVQ:
case AIDIVW:
case AIMULB:
case AMULB:
case AMULL:
case AMULQ:
case AMULW:
case AREP:
case AREPN:
case ACWD:
case ACDQ:
case ACQO:
case ASTOSB:
case ASTOSL:
case ASTOSQ:
case AMOVSB:
case AMOVSL:
case AMOVSQ:
giveup:
if(info.reguse | info.regset) {
if(debug['P'] && debug['v'])
print("\tfound %P; return 0\n", p);
return 0;
case AMOVL:
case AMOVQ:
case AMOVSS:
case AMOVSD:
if(p->to.type == v1->type)
goto gotit;
break;
}
if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
goto gotit;
if(copyau(&p->from, v2) ||
copyau(&p->to, v2)) {
if(debug['P'] && debug['v'])
......@@ -904,255 +796,10 @@ copy1(Adr *v1, Adr *v2, Reg *r, int f)
int
copyu(Prog *p, Adr *v, Adr *s)
{
ProgInfo info;
switch(p->as) {
default:
if(debug['P'])
print("unknown op %A\n", p->as);
/* SBBL; ADCL; FLD1; SAHF */
return 2;
case ANEGB:
case ANEGW:
case ANEGL:
case ANEGQ:
case ANOTB:
case ANOTW:
case ANOTL:
case ANOTQ:
if(copyas(&p->to, v))
return 2;
break;
case ALEAL: /* lhs addr, rhs store */
case ALEAQ:
if(copyas(&p->from, v))
return 2;
case ANOP: /* rhs store */
case AMOVL:
case AMOVQ:
case AMOVBLSX:
case AMOVBLZX:
case AMOVBQSX:
case AMOVBQZX:
case AMOVLQSX:
case AMOVLQZX:
case AMOVWLSX:
case AMOVWLZX:
case AMOVWQSX:
case AMOVWQZX:
case AMOVQL:
case AMOVSS:
case AMOVSD:
case ACVTSD2SL:
case ACVTSD2SQ:
case ACVTSD2SS:
case ACVTSL2SD:
case ACVTSL2SS:
case ACVTSQ2SD:
case ACVTSQ2SS:
case ACVTSS2SD:
case ACVTSS2SL:
case ACVTSS2SQ:
case ACVTTSD2SL:
case ACVTTSD2SQ:
case ACVTTSS2SL:
case ACVTTSS2SQ:
if(copyas(&p->to, v)) {
if(s != A)
return copysub(&p->from, v, s, 1);
if(copyau(&p->from, v))
return 4;
return 3;
}
goto caseread;
case ARCLB:
case ARCLL:
case ARCLQ:
case ARCLW:
case ARCRB:
case ARCRL:
case ARCRQ:
case ARCRW:
case AROLB:
case AROLL:
case AROLQ:
case AROLW:
case ARORB:
case ARORL:
case ARORQ:
case ARORW:
case ASALB:
case ASALL:
case ASALQ:
case ASALW:
case ASARB:
case ASARL:
case ASARQ:
case ASARW:
case ASHLB:
case ASHLL:
case ASHLQ:
case ASHLW:
case ASHRB:
case ASHRL:
case ASHRQ:
case ASHRW:
if(copyas(&p->to, v))
return 2;
if(copyas(&p->from, v))
if(p->from.type == D_CX)
return 2;
goto caseread;
case AADDB: /* rhs rar */
case AADDL:
case AADDQ:
case AADDW:
case AANDB:
case AANDL:
case AANDQ:
case AANDW:
case ADECL:
case ADECQ:
case ADECW:
case AINCL:
case AINCQ:
case AINCW:
case ASUBB:
case ASUBL:
case ASUBQ:
case ASUBW:
case AORB:
case AORL:
case AORQ:
case AORW:
case AXORB:
case AXORL:
case AXORQ:
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;
case ACMPL: /* read only */
case ACMPW:
case ACMPB:
case ACMPQ:
case ACOMISD:
case ACOMISS:
case AUCOMISD:
case AUCOMISS:
caseread:
if(s != A) {
if(copysub(&p->from, v, s, 1))
return 1;
return copysub(&p->to, v, s, 1);
}
if(copyau(&p->from, v))
return 1;
if(copyau(&p->to, v))
return 1;
break;
case AJGE: /* no reference */
case AJNE:
case AJLE:
case AJEQ:
case AJHI:
case AJLS:
case AJMI:
case AJPL:
case AJGT:
case AJLT:
case AJCC:
case AJCS:
case AADJSP:
case AWAIT:
case ACLD:
break;
case AIMULL:
case AIMULQ:
case AIMULW:
if(p->to.type != D_NONE) {
if(copyas(&p->to, v))
return 2;
goto caseread;
}
case ADIVB:
case ADIVL:
case ADIVQ:
case ADIVW:
case AIDIVB:
case AIDIVL:
case AIDIVQ:
case AIDIVW:
case AIMULB:
case AMULB:
case AMULL:
case AMULQ:
case AMULW:
case ACWD:
case ACDQ:
case ACQO:
if(v->type == D_AX || v->type == D_DX)
return 2;
goto caseread;
case AREP:
case AREPN:
if(v->type == D_CX)
return 2;
goto caseread;
case AMOVSB:
case AMOVSL:
case AMOVSQ:
if(v->type == D_DI || v->type == D_SI)
return 2;
goto caseread;
case ASTOSB:
case ASTOSL:
case ASTOSQ:
if(v->type == D_AX || v->type == D_DI)
return 2;
goto caseread;
case AJMP: /* funny */
case AJMP:
if(s != A) {
if(copysub(&p->to, v, s, 1))
return 1;
......@@ -1162,12 +809,12 @@ copyu(Prog *p, Adr *v, Adr *s)
return 1;
return 0;
case ARET: /* funny */
case ARET:
if(s != A)
return 1;
return 3;
case ACALL: /* funny */
case ACALL:
if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
return 2;
if(REGARG >= 0 && v->type == (uchar)REGARG)
......@@ -1184,11 +831,47 @@ copyu(Prog *p, Adr *v, Adr *s)
return 4;
return 3;
case ATEXT: /* funny */
case ATEXT:
if(REGARG >= 0 && v->type == (uchar)REGARG)
return 3;
return 0;
}
proginfo(&info, p);
if((info.reguse|info.regset) & RtoB(v->type))
return 2;
if(info.flags & LeftAddr)
if(copyas(&p->from, v))
return 2;
if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
if(copyas(&p->to, v))
return 2;
if(info.flags & RightWrite) {
if(copyas(&p->to, v)) {
if(s != A)
return copysub(&p->from, v, s, 1);
if(copyau(&p->from, v))
return 4;
return 3;
}
}
if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
if(s != A) {
if(copysub(&p->from, v, s, 1))
return 1;
return copysub(&p->to, v, s, 1);
}
if(copyau(&p->from, v))
return 1;
if(copyau(&p->to, v))
return 1;
}
return 0;
}
......
This diff is collapsed.
......@@ -160,6 +160,7 @@ regopt(Prog *firstp)
{
Reg *r, *r1;
Prog *p;
ProgInfo info, info2;
int i, z, nr;
uint32 vreg;
Bits bit;
......@@ -218,14 +219,9 @@ regopt(Prog *firstp)
*/
nr = 0;
for(p=firstp; p!=P; p=p->link) {
switch(p->as) {
case ADATA:
case AGLOBL:
case ANAME:
case ASIGNAME:
case ATYPE:
proginfo(&info, p);
if(info.flags & Skip)
continue;
}
r = rega();
nr++;
if(firstr == R) {
......@@ -242,11 +238,8 @@ regopt(Prog *firstp)
r1 = r->p1;
if(r1 != R) {
switch(r1->prog->as) {
case ARET:
case AJMP:
case AIRETL:
case AIRETQ:
proginfo(&info2, r1->prog);
if(info2.flags & Break) {
r->p1 = R;
r1->s1 = R;
}
......@@ -256,335 +249,31 @@ regopt(Prog *firstp)
if(p->as == ACALL && p->to.type == D_EXTERN)
continue;
// Addressing makes some registers used.
if(p->from.type >= D_INDIR)
r->use1.b[0] |= RtoB(p->from.type-D_INDIR);
if(p->from.index != D_NONE)
r->use1.b[0] |= RtoB(p->from.index);
if(p->to.type >= D_INDIR)
r->use2.b[0] |= RtoB(p->to.type-D_INDIR);
if(p->to.index != D_NONE)
r->use2.b[0] |= RtoB(p->to.index);
r->use1.b[0] |= info.reguse | info.regindex;
r->set.b[0] |= info.regset;
bit = mkvar(r, &p->from);
if(bany(&bit))
switch(p->as) {
/*
* funny
*/
case ALEAL:
case ALEAQ:
setaddrs(bit);
break;
/*
* left side read
*/
default:
for(z=0; z<BITS; z++)
r->use1.b[z] |= bit.b[z];
break;
/*
* left side read+write
*/
case AXCHGB:
case AXCHGW:
case AXCHGL:
case AXCHGQ:
for(z=0; z<BITS; z++) {
r->use1.b[z] |= bit.b[z];
r->set.b[z] |= bit.b[z];
}
break;
if(bany(&bit)) {
if(info.flags & LeftAddr)
setaddrs(bit);
if(info.flags & LeftRead)
for(z=0; z<BITS; z++)
r->use1.b[z] |= bit.b[z];
if(info.flags & LeftWrite)
for(z=0; z<BITS; z++)
r->set.b[z] |= bit.b[z];
}
bit = mkvar(r, &p->to);
if(bany(&bit))
switch(p->as) {
default:
yyerror("reg: unknown op: %A", p->as);
break;
/*
* right side read
*/
case ACMPB:
case ACMPL:
case ACMPQ:
case ACMPW:
case ACOMISS:
case ACOMISD:
case AUCOMISS:
case AUCOMISD:
case ATESTB:
case ATESTL:
case ATESTQ:
for(z=0; z<BITS; z++)
r->use2.b[z] |= bit.b[z];
break;
/*
* right side write
*/
case ALEAQ:
case ANOP:
case AMOVL:
case AMOVQ:
case AMOVB:
case AMOVW:
case AMOVBLSX:
case AMOVBLZX:
case AMOVBWSX:
case AMOVBWZX:
case AMOVBQSX:
case AMOVBQZX:
case AMOVLQSX:
case AMOVLQZX:
case AMOVWLSX:
case AMOVWLZX:
case AMOVWQSX:
case AMOVWQZX:
case AMOVQL:
case APOPQ:
case AMOVSS:
case AMOVSD:
case ACVTSD2SL:
case ACVTSD2SQ:
case ACVTSD2SS:
case ACVTSL2SD:
case ACVTSL2SS:
case ACVTSQ2SD:
case ACVTSQ2SS:
case ACVTSS2SD:
case ACVTSS2SL:
case ACVTSS2SQ:
case ACVTTSD2SL:
case ACVTTSD2SQ:
case ACVTTSS2SL:
case ACVTTSS2SQ:
for(z=0; z<BITS; z++)
r->set.b[z] |= bit.b[z];
break;
/*
* right side read+write
*/
case AINCB:
case AINCL:
case AINCQ:
case AINCW:
case ADECB:
case ADECL:
case ADECQ:
case ADECW:
case AADDB:
case AADDL:
case AADDQ:
case AADDW:
case AANDB:
case AANDL:
case AANDQ:
case AANDW:
case ASUBB:
case ASUBL:
case ASUBQ:
case ASUBW:
case AORB:
case AORL:
case AORQ:
case AORW:
case AXORB:
case AXORL:
case AXORQ:
case AXORW:
case ASALB:
case ASALL:
case ASALQ:
case ASALW:
case ASARB:
case ASARL:
case ASARQ:
case ASARW:
case ARCLB:
case ARCLL:
case ARCLQ:
case ARCLW:
case ARCRB:
case ARCRL:
case ARCRQ:
case ARCRW:
case AROLB:
case AROLL:
case AROLQ:
case AROLW:
case ARORB:
case ARORL:
case ARORQ:
case ARORW:
case ASHLB:
case ASHLL:
case ASHLQ:
case ASHLW:
case ASHRB:
case ASHRL:
case ASHRQ:
case ASHRW:
case AIMULL:
case AIMULQ:
case AIMULW:
case ANEGB:
case ANEGW:
case ANEGL:
case ANEGQ:
case ANOTL:
case ANOTQ:
case AADCL:
case AADCQ:
case ASBBL:
case ASBBQ:
case ASETCC:
case ASETCS:
case ASETEQ:
case ASETGE:
case ASETGT:
case ASETHI:
case ASETLE:
case ASETLS:
case ASETLT:
case ASETMI:
case ASETNE:
case ASETOC:
case ASETOS:
case ASETPC:
case ASETPL:
case ASETPS:
case AXCHGB:
case AXCHGW:
case AXCHGL:
case AXCHGQ:
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:
for(z=0; z<BITS; z++) {
r->set.b[z] |= bit.b[z];
r->use2.b[z] |= bit.b[z];
}
break;
/*
* funny
*/
case ACALL:
setaddrs(bit);
break;
}
switch(p->as) {
case AIMULL:
case AIMULQ:
case AIMULW:
if(p->to.type != D_NONE)
break;
case AIDIVL:
case AIDIVW:
case AIDIVQ:
case ADIVL:
case ADIVW:
case ADIVQ:
case AMULL:
case AMULW:
case AMULQ:
r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DX);
break;
case AIDIVB:
case AIMULB:
case ADIVB:
case AMULB:
r->set.b[0] |= RtoB(D_AX);
r->use1.b[0] |= RtoB(D_AX);
break;
case ACWD:
r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
r->use1.b[0] |= RtoB(D_AX);
break;
case ACDQ:
r->set.b[0] |= RtoB(D_DX);
r->use1.b[0] |= RtoB(D_AX);
break;
case AREP:
case AREPN:
case ALOOP:
case ALOOPEQ:
case ALOOPNE:
r->set.b[0] |= RtoB(D_CX);
r->use1.b[0] |= RtoB(D_CX);
break;
case AMOVSB:
case AMOVSL:
case AMOVSQ:
case AMOVSW:
case ACMPSB:
case ACMPSL:
case ACMPSQ:
case ACMPSW:
r->set.b[0] |= RtoB(D_SI) | RtoB(D_DI);
r->use1.b[0] |= RtoB(D_SI) | RtoB(D_DI);
break;
case ASTOSB:
case ASTOSL:
case ASTOSQ:
case ASTOSW:
case ASCASB:
case ASCASL:
case ASCASQ:
case ASCASW:
r->set.b[0] |= RtoB(D_DI);
r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DI);
break;
case AINSB:
case AINSL:
case AINSW:
r->set.b[0] |= RtoB(D_DX) | RtoB(D_DI);
r->use1.b[0] |= RtoB(D_DI);
break;
case AOUTSB:
case AOUTSL:
case AOUTSW:
r->set.b[0] |= RtoB(D_DI);
r->use1.b[0] |= RtoB(D_DX) | RtoB(D_DI);
break;
if(bany(&bit)) {
if(info.flags & RightAddr)
setaddrs(bit);
if(info.flags & RightRead)
for(z=0; z<BITS; z++)
r->use2.b[z] |= bit.b[z];
if(info.flags & RightWrite)
for(z=0; z<BITS; z++)
r->set.b[z] |= bit.b[z];
}
}
if(firstr == R)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment