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;
Reg *r, *r1, *r2;
Prog *p, *p1;
int t;
+ ProgInfo info;
/*
* complete R structure
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;
r = r2;
t++;
-
- case ADATA:
- case AGLOBL:
- case ANAME:
- case ASIGNAME:
- case ATYPE:
- p = p->link;
}
}
// 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)
{
}
}
+// is 'a' a register or constant?
static int
regconsttyp(Adr *a)
{
{
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;
subprop(Reg *r0)
{
Prog *p;
+ ProgInfo info;
Adr *v1, *v2;
Reg *r;
int t;
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'])
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;
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)
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;
}
--- /dev/null
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+// Matches real RtoB but can be used in global initializer.
+#define RtoB(r) (1<<((r)-D_AX))
+
+enum {
+ AX = RtoB(D_AX),
+ BX = RtoB(D_BX),
+ CX = RtoB(D_CX),
+ DX = RtoB(D_DX),
+ DI = RtoB(D_DI),
+ SI = RtoB(D_SI),
+
+ LeftRdwr = LeftRead | LeftWrite,
+ RightRdwr = RightRead | RightWrite,
+};
+
+#undef RtoB
+
+// This table gives the basic information about instruction
+// generated by the compiler and processed in the optimizer.
+// See opt.h for bit definitions.
+//
+// Instructions not generated need not be listed.
+// As an exception to that rule, we typically write down all the
+// size variants of an operation even if we just use a subset.
+//
+// The table is formatted for 8-space tabs.
+static ProgInfo progtable[ALAST] = {
+ [ATYPE]= {Pseudo | Skip},
+ [ATEXT]= {Pseudo},
+ [AFUNCDATA]= {Pseudo},
+ [APCDATA]= {Pseudo},
+
+ [AADCL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
+ [AADCQ]= {SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry},
+ [AADCW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
+
+ [AADDB]= {SizeB | LeftRead | RightRdwr | SetCarry},
+ [AADDL]= {SizeL | LeftRead | RightRdwr | SetCarry},
+ [AADDW]= {SizeW | LeftRead | RightRdwr | SetCarry},
+ [AADDQ]= {SizeQ | LeftRead | RightRdwr | SetCarry},
+
+ [AADDSD]= {SizeD | LeftRead | RightRdwr},
+ [AADDSS]= {SizeF | LeftRead | RightRdwr},
+
+ [AANDB]= {SizeB | LeftRead | RightRdwr | SetCarry},
+ [AANDL]= {SizeL | LeftRead | RightRdwr | SetCarry},
+ [AANDQ]= {SizeQ | LeftRead | RightRdwr | SetCarry},
+ [AANDW]= {SizeW | LeftRead | RightRdwr | SetCarry},
+
+ [ACALL]= {RightAddr | Call | KillCarry},
+
+ [ACDQ]= {OK, AX, AX | DX},
+ [ACQO]= {OK, AX, AX | DX},
+ [ACWD]= {OK, AX, AX | DX},
+
+ [ACLD]= {OK},
+ [ASTD]= {OK},
+
+ [ACMPB]= {SizeB | LeftRead | RightRead | SetCarry},
+ [ACMPL]= {SizeL | LeftRead | RightRead | SetCarry},
+ [ACMPQ]= {SizeQ | LeftRead | RightRead | SetCarry},
+ [ACMPW]= {SizeW | LeftRead | RightRead | SetCarry},
+
+ [ACOMISD]= {SizeD | LeftRead | RightRead | SetCarry},
+ [ACOMISS]= {SizeF | LeftRead | RightRead | SetCarry},
+
+ [ACVTSD2SL]= {SizeL | LeftRead | RightWrite | Conv},
+ [ACVTSD2SQ]= {SizeQ | LeftRead | RightWrite | Conv},
+ [ACVTSD2SS]= {SizeF | LeftRead | RightWrite | Conv},
+ [ACVTSL2SD]= {SizeD | LeftRead | RightWrite | Conv},
+ [ACVTSL2SS]= {SizeF | LeftRead | RightWrite | Conv},
+ [ACVTSQ2SD]= {SizeD | LeftRead | RightWrite | Conv},
+ [ACVTSQ2SS]= {SizeF | LeftRead | RightWrite | Conv},
+ [ACVTSS2SD]= {SizeD | LeftRead | RightWrite | Conv},
+ [ACVTSS2SL]= {SizeL | LeftRead | RightWrite | Conv},
+ [ACVTSS2SQ]= {SizeQ | LeftRead | RightWrite | Conv},
+ [ACVTTSD2SL]= {SizeL | LeftRead | RightWrite | Conv},
+ [ACVTTSD2SQ]= {SizeQ | LeftRead | RightWrite | Conv},
+ [ACVTTSS2SL]= {SizeL | LeftRead | RightWrite | Conv},
+ [ACVTTSS2SQ]= {SizeQ | LeftRead | RightWrite | Conv},
+
+ [ADECB]= {SizeB | RightRdwr},
+ [ADECL]= {SizeL | RightRdwr},
+ [ADECQ]= {SizeQ | RightRdwr},
+ [ADECW]= {SizeW | RightRdwr},
+
+ [ADIVB]= {SizeB | LeftRead, AX, AX},
+ [ADIVL]= {SizeL | LeftRead, AX|DX, AX|DX},
+ [ADIVQ]= {SizeQ | LeftRead, AX|DX, AX|DX},
+ [ADIVW]= {SizeW | LeftRead, AX|DX, AX|DX},
+
+ [ADIVSD]= {SizeD | LeftRead | RightRdwr},
+ [ADIVSS]= {SizeF | LeftRead | RightRdwr},
+
+ [AIDIVB]= {SizeB | LeftRead, AX, AX},
+ [AIDIVL]= {SizeL | LeftRead, AX|DX, AX|DX},
+ [AIDIVQ]= {SizeQ | LeftRead, AX|DX, AX|DX},
+ [AIDIVW]= {SizeW | LeftRead, AX|DX, AX|DX},
+
+ [AIMULB]= {SizeB | LeftRead | SetCarry, AX, AX},
+ [AIMULL]= {SizeL | LeftRead | ImulAXDX | SetCarry},
+ [AIMULQ]= {SizeQ | LeftRead | ImulAXDX | SetCarry},
+ [AIMULW]= {SizeW | LeftRead | ImulAXDX | SetCarry},
+
+ [AINCB]= {SizeB | RightRdwr},
+ [AINCL]= {SizeL | RightRdwr},
+ [AINCQ]= {SizeQ | RightRdwr},
+ [AINCW]= {SizeW | RightRdwr},
+
+ [AJCC]= {Cjmp | UseCarry},
+ [AJCS]= {Cjmp | UseCarry},
+ [AJEQ]= {Cjmp | UseCarry},
+ [AJGE]= {Cjmp | UseCarry},
+ [AJGT]= {Cjmp | UseCarry},
+ [AJHI]= {Cjmp | UseCarry},
+ [AJLE]= {Cjmp | UseCarry},
+ [AJLS]= {Cjmp | UseCarry},
+ [AJLT]= {Cjmp | UseCarry},
+ [AJMI]= {Cjmp | UseCarry},
+ [AJNE]= {Cjmp | UseCarry},
+ [AJOC]= {Cjmp | UseCarry},
+ [AJOS]= {Cjmp | UseCarry},
+ [AJPC]= {Cjmp | UseCarry},
+ [AJPL]= {Cjmp | UseCarry},
+ [AJPS]= {Cjmp | UseCarry},
+
+ [AJMP]= {Jump | Break | KillCarry},
+
+ [ALEAQ]= {LeftAddr | RightWrite},
+
+ [AMOVBLSX]= {SizeL | LeftRead | RightWrite | Conv},
+ [AMOVBLZX]= {SizeL | LeftRead | RightWrite | Conv},
+ [AMOVBQSX]= {SizeQ | LeftRead | RightWrite | Conv},
+ [AMOVBQZX]= {SizeQ | LeftRead | RightWrite | Conv},
+ [AMOVBWSX]= {SizeW | LeftRead | RightWrite | Conv},
+ [AMOVBWZX]= {SizeW | LeftRead | RightWrite | Conv},
+ [AMOVLQSX]= {SizeQ | LeftRead | RightWrite | Conv},
+ [AMOVLQZX]= {SizeQ | LeftRead | RightWrite | Conv},
+ [AMOVWLSX]= {SizeL | LeftRead | RightWrite | Conv},
+ [AMOVWLZX]= {SizeL | LeftRead | RightWrite | Conv},
+ [AMOVWQSX]= {SizeQ | LeftRead | RightWrite | Conv},
+ [AMOVWQZX]= {SizeQ | LeftRead | RightWrite | Conv},
+ [AMOVQL]= {SizeL | LeftRead | RightWrite | Conv},
+
+ [AMOVB]= {SizeB | LeftRead | RightWrite | Move},
+ [AMOVL]= {SizeL | LeftRead | RightWrite | Move},
+ [AMOVQ]= {SizeQ | LeftRead | RightWrite | Move},
+ [AMOVW]= {SizeW | LeftRead | RightWrite | Move},
+
+ [AMOVSB]= {OK, DI|SI, DI|SI},
+ [AMOVSL]= {OK, DI|SI, DI|SI},
+ [AMOVSQ]= {OK, DI|SI, DI|SI},
+ [AMOVSW]= {OK, DI|SI, DI|SI},
+
+ [AMOVSD]= {SizeD | LeftRead | RightWrite | Move},
+ [AMOVSS]= {SizeF | LeftRead | RightWrite | Move},
+
+ // We use MOVAPD as a faster synonym for MOVSD.
+ [AMOVAPD]= {SizeD | LeftRead | RightWrite | Move},
+
+ [AMULB]= {SizeB | LeftRead | SetCarry, AX, AX},
+ [AMULL]= {SizeL | LeftRead | SetCarry, AX, AX|DX},
+ [AMULQ]= {SizeQ | LeftRead | SetCarry, AX, AX|DX},
+ [AMULW]= {SizeW | LeftRead | SetCarry, AX, AX|DX},
+
+ [AMULSD]= {SizeD | LeftRead | RightRdwr},
+ [AMULSS]= {SizeF | LeftRead | RightRdwr},
+
+ [ANEGB]= {SizeB | RightRdwr | SetCarry},
+ [ANEGL]= {SizeL | RightRdwr | SetCarry},
+ [ANEGQ]= {SizeQ | RightRdwr | SetCarry},
+ [ANEGW]= {SizeW | RightRdwr | SetCarry},
+
+ // NOP is the opcode for USED and SET annotations, not the Intel opcode.
+ [ANOP]= {LeftRead | RightWrite},
+
+ [ANOTB]= {SizeB | RightRdwr},
+ [ANOTL]= {SizeL | RightRdwr},
+ [ANOTQ]= {SizeQ | RightRdwr},
+ [ANOTW]= {SizeQ | RightRdwr},
+
+ [AORB]= {SizeB | LeftRead | RightRdwr | SetCarry},
+ [AORL]= {SizeL | LeftRead | RightRdwr | SetCarry},
+ [AORQ]= {SizeQ | LeftRead | RightRdwr | SetCarry},
+ [AORW]= {SizeW | LeftRead | RightRdwr | SetCarry},
+
+ [APOPQ]= {SizeQ | RightWrite},
+ [APUSHQ]= {SizeQ | RightWrite},
+
+ [ARCLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+ [ARCLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+ [ARCLQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+ [ARCLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+
+ [ARCRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+ [ARCRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+ [ARCRQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+ [ARCRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+
+ [AREP]= {OK, CX, CX},
+ [AREPN]= {OK, CX, CX},
+
+ [ARET]= {Break | KillCarry},
+
+ [AROLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [AROLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [AROLQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [AROLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+ [ARORB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ARORL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ARORQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ARORW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+ [ASALB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASALL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASALQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASALW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+ [ASARB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASARL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASARQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASARW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+ [ASBBB]= {SizeB | LeftRead | RightRdwr | SetCarry | UseCarry},
+ [ASBBL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
+ [ASBBQ]= {SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry},
+ [ASBBW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
+
+ [ASHLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASHLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASHLQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASHLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+ [ASHRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASHRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASHRQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+ [ASHRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+ [ASTOSB]= {OK, AX|DI, DI},
+ [ASTOSL]= {OK, AX|DI, DI},
+ [ASTOSQ]= {OK, AX|DI, DI},
+ [ASTOSW]= {OK, AX|DI, DI},
+
+ [ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry},
+ [ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry},
+ [ASUBQ]= {SizeQ | LeftRead | RightRdwr | SetCarry},
+ [ASUBW]= {SizeW | LeftRead | RightRdwr | SetCarry},
+
+ [ASUBSD]= {SizeD | LeftRead | RightRdwr},
+ [ASUBSS]= {SizeF | LeftRead | RightRdwr},
+
+ [ATESTB]= {SizeB | LeftRead | RightRead},
+ [ATESTL]= {SizeL | LeftRead | RightRead},
+ [ATESTQ]= {SizeQ | LeftRead | RightRead},
+ [ATESTW]= {SizeW | LeftRead | RightRead},
+
+ [AUCOMISD]= {SizeD | LeftRead | RightRead},
+ [AUCOMISS]= {SizeF | LeftRead | RightRead},
+
+ [AUNDEF]= {OK},
+
+ [AUSEFIELD]= {OK},
+
+ [AXCHGB]= {SizeB | LeftRdwr | RightRdwr},
+ [AXCHGL]= {SizeL | LeftRdwr | RightRdwr},
+ [AXCHGQ]= {SizeQ | LeftRdwr | RightRdwr},
+ [AXCHGW]= {SizeW | LeftRdwr | RightRdwr},
+
+ [AXORB]= {SizeB | LeftRead | RightRdwr | SetCarry},
+ [AXORL]= {SizeL | LeftRead | RightRdwr | SetCarry},
+ [AXORQ]= {SizeQ | LeftRead | RightRdwr | SetCarry},
+ [AXORW]= {SizeW | LeftRead | RightRdwr | SetCarry},
+};
+
+void
+proginfo(ProgInfo *info, Prog *p)
+{
+ *info = progtable[p->as];
+ if(info->flags == 0)
+ fatal("unknown instruction %P", p);
+
+ if((info->flags & ShiftCX) && p->from.type != D_CONST)
+ info->reguse |= CX;
+
+ if(info->flags & ImulAXDX) {
+ if(p->to.type == D_NONE) {
+ info->reguse |= AX;
+ info->regset |= AX | DX;
+ } else {
+ info->flags |= RightRdwr;
+ }
+ }
+
+ // Addressing makes some registers used.
+ if(p->from.type >= D_INDIR)
+ info->regindex |= RtoB(p->from.type-D_INDIR);
+ if(p->from.index != D_NONE)
+ info->regindex |= RtoB(p->from.index);
+ if(p->to.type >= D_INDIR)
+ info->regindex |= RtoB(p->to.type-D_INDIR);
+ if(p->to.index != D_NONE)
+ info->regindex |= RtoB(p->to.index);
+}