// Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include <u.h> #include <libc.h> #include "gg.h" #include "../gc/popt.h" // Matches real RtoB but can be used in global initializer. #define RtoB(r) (1<<((r)-REG_AX)) enum { AX = RtoB(REG_AX), BX = RtoB(REG_BX), CX = RtoB(REG_CX), DX = RtoB(REG_DX), DI = RtoB(REG_DI), SI = RtoB(REG_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}, [AUNDEF]= {Break}, [AUSEFIELD]= {OK}, [ACHECKNIL]= {LeftRead}, [AVARDEF]= {Pseudo | RightWrite}, [AVARKILL]= {Pseudo | RightWrite}, // NOP is an internal no-op that also stands // for USED and SET annotations, not the Intel opcode. [ANOP]= {LeftRead | RightWrite}, [AADCL]= {SizeL | 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}, [AADDSD]= {SizeD | LeftRead | RightRdwr}, [AADDSS]= {SizeF | LeftRead | RightRdwr}, [AANDB]= {SizeB | LeftRead | RightRdwr | SetCarry}, [AANDL]= {SizeL | LeftRead | RightRdwr | SetCarry}, [AANDW]= {SizeW | LeftRead | RightRdwr | SetCarry}, [ACALL]= {RightAddr | Call | KillCarry}, [ACDQ]= {OK, AX, AX | DX}, [ACWD]= {OK, AX, AX | DX}, [ACLD]= {OK}, [ASTD]= {OK}, [ACMPB]= {SizeB | LeftRead | RightRead | SetCarry}, [ACMPL]= {SizeL | LeftRead | RightRead | SetCarry}, [ACMPW]= {SizeW | LeftRead | RightRead | SetCarry}, [ACOMISD]= {SizeD | LeftRead | RightRead | SetCarry}, [ACOMISS]= {SizeF | LeftRead | RightRead | SetCarry}, [ACVTSD2SL]= {SizeL | LeftRead | RightWrite | Conv}, [ACVTSD2SS]= {SizeF | LeftRead | RightWrite | Conv}, [ACVTSL2SD]= {SizeD | LeftRead | RightWrite | Conv}, [ACVTSL2SS]= {SizeF | LeftRead | RightWrite | Conv}, [ACVTSS2SD]= {SizeD | LeftRead | RightWrite | Conv}, [ACVTSS2SL]= {SizeL | LeftRead | RightWrite | Conv}, [ACVTTSD2SL]= {SizeL | LeftRead | RightWrite | Conv}, [ACVTTSS2SL]= {SizeL | LeftRead | RightWrite | Conv}, [ADECB]= {SizeB | RightRdwr}, [ADECL]= {SizeL | RightRdwr}, [ADECW]= {SizeW | RightRdwr}, [ADIVB]= {SizeB | LeftRead | SetCarry, AX, AX}, [ADIVL]= {SizeL | LeftRead | SetCarry, AX|DX, AX|DX}, [ADIVW]= {SizeW | LeftRead | SetCarry, AX|DX, AX|DX}, [ADIVSD]= {SizeD | LeftRead | RightRdwr}, [ADIVSS]= {SizeF | LeftRead | RightRdwr}, [AFLDCW]= {SizeW | LeftAddr}, [AFSTCW]= {SizeW | RightAddr}, [AFSTSW]= {SizeW | RightAddr | RightWrite}, [AFADDD]= {SizeD | LeftAddr | RightRdwr}, [AFADDDP]= {SizeD | LeftAddr | RightRdwr}, [AFADDF]= {SizeF | LeftAddr | RightRdwr}, [AFCOMD]= {SizeD | LeftAddr | RightRead}, [AFCOMDP]= {SizeD | LeftAddr | RightRead}, [AFCOMDPP]= {SizeD | LeftAddr | RightRead}, [AFCOMF]= {SizeF | LeftAddr | RightRead}, [AFCOMFP]= {SizeF | LeftAddr | RightRead}, [AFUCOMIP]= {SizeF | LeftAddr | RightRead}, [AFCHS]= {SizeD | RightRdwr}, // also SizeF [AFDIVDP]= {SizeD | LeftAddr | RightRdwr}, [AFDIVF]= {SizeF | LeftAddr | RightRdwr}, [AFDIVD]= {SizeD | LeftAddr | RightRdwr}, [AFDIVRDP]= {SizeD | LeftAddr | RightRdwr}, [AFDIVRF]= {SizeF | LeftAddr | RightRdwr}, [AFDIVRD]= {SizeD | LeftAddr | RightRdwr}, [AFXCHD]= {SizeD | LeftRdwr | RightRdwr}, [AFSUBD]= {SizeD | LeftAddr | RightRdwr}, [AFSUBDP]= {SizeD | LeftAddr | RightRdwr}, [AFSUBF]= {SizeF | LeftAddr | RightRdwr}, [AFSUBRD]= {SizeD | LeftAddr | RightRdwr}, [AFSUBRDP]= {SizeD | LeftAddr | RightRdwr}, [AFSUBRF]= {SizeF | LeftAddr | RightRdwr}, [AFMOVD]= {SizeD | LeftAddr | RightWrite}, [AFMOVF]= {SizeF | LeftAddr | RightWrite}, [AFMOVL]= {SizeL | LeftAddr | RightWrite}, [AFMOVW]= {SizeW | LeftAddr | RightWrite}, [AFMOVV]= {SizeQ | LeftAddr | RightWrite}, // These instructions are marked as RightAddr // so that the register optimizer does not try to replace the // memory references with integer register references. // But they do not use the previous value at the address, so // we also mark them RightWrite. [AFMOVDP]= {SizeD | LeftRead | RightWrite | RightAddr}, [AFMOVFP]= {SizeF | LeftRead | RightWrite | RightAddr}, [AFMOVLP]= {SizeL | LeftRead | RightWrite | RightAddr}, [AFMOVWP]= {SizeW | LeftRead | RightWrite | RightAddr}, [AFMOVVP]= {SizeQ | LeftRead | RightWrite | RightAddr}, [AFMULD]= {SizeD | LeftAddr | RightRdwr}, [AFMULDP]= {SizeD | LeftAddr | RightRdwr}, [AFMULF]= {SizeF | LeftAddr | RightRdwr}, [AIDIVB]= {SizeB | LeftRead | SetCarry, AX, AX}, [AIDIVL]= {SizeL | LeftRead | SetCarry, AX|DX, AX|DX}, [AIDIVW]= {SizeW | LeftRead | SetCarry, AX|DX, AX|DX}, [AIMULB]= {SizeB | LeftRead | SetCarry, AX, AX}, [AIMULL]= {SizeL | LeftRead | ImulAXDX | SetCarry}, [AIMULW]= {SizeW | LeftRead | ImulAXDX | SetCarry}, [AINCB]= {SizeB | RightRdwr}, [AINCL]= {SizeL | 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}, [ALEAL]= {LeftAddr | RightWrite}, [AMOVBLSX]= {SizeL | LeftRead | RightWrite | Conv}, [AMOVBLZX]= {SizeL | LeftRead | RightWrite | Conv}, [AMOVBWSX]= {SizeW | LeftRead | RightWrite | Conv}, [AMOVBWZX]= {SizeW | LeftRead | RightWrite | Conv}, [AMOVWLSX]= {SizeL | LeftRead | RightWrite | Conv}, [AMOVWLZX]= {SizeL | LeftRead | RightWrite | Conv}, [AMOVB]= {SizeB | LeftRead | RightWrite | Move}, [AMOVL]= {SizeL | LeftRead | RightWrite | Move}, [AMOVW]= {SizeW | LeftRead | RightWrite | Move}, [AMOVSB]= {OK, DI|SI, DI|SI}, [AMOVSL]= {OK, DI|SI, DI|SI}, [AMOVSW]= {OK, DI|SI, DI|SI}, [ADUFFCOPY]= {OK, DI|SI, DI|SI|CX}, [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}, [AMULW]= {SizeW | LeftRead | SetCarry, AX, AX|DX}, [AMULSD]= {SizeD | LeftRead | RightRdwr}, [AMULSS]= {SizeF | LeftRead | RightRdwr}, [ANEGB]= {SizeB | RightRdwr | SetCarry}, [ANEGL]= {SizeL | RightRdwr | SetCarry}, [ANEGW]= {SizeW | RightRdwr | SetCarry}, [ANOTB]= {SizeB | RightRdwr}, [ANOTL]= {SizeL | RightRdwr}, [ANOTW]= {SizeW | RightRdwr}, [AORB]= {SizeB | LeftRead | RightRdwr | SetCarry}, [AORL]= {SizeL | LeftRead | RightRdwr | SetCarry}, [AORW]= {SizeW | LeftRead | RightRdwr | SetCarry}, [APOPL]= {SizeL | RightWrite}, [APUSHL]= {SizeL | LeftRead}, [ARCLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, [ARCLL]= {SizeL | 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}, [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}, [AROLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ARORB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ARORL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ARORW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASAHF]= {OK, AX, AX}, [ASALB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASALL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASALW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASARB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASARL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASARW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASBBB]= {SizeB | LeftRead | RightRdwr | SetCarry | UseCarry}, [ASBBL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry}, [ASBBW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry}, [ASETCC]= {SizeB | RightRdwr | UseCarry}, [ASETCS]= {SizeB | RightRdwr | UseCarry}, [ASETEQ]= {SizeB | RightRdwr | UseCarry}, [ASETGE]= {SizeB | RightRdwr | UseCarry}, [ASETGT]= {SizeB | RightRdwr | UseCarry}, [ASETHI]= {SizeB | RightRdwr | UseCarry}, [ASETLE]= {SizeB | RightRdwr | UseCarry}, [ASETLS]= {SizeB | RightRdwr | UseCarry}, [ASETLT]= {SizeB | RightRdwr | UseCarry}, [ASETMI]= {SizeB | RightRdwr | UseCarry}, [ASETNE]= {SizeB | RightRdwr | UseCarry}, [ASETOC]= {SizeB | RightRdwr | UseCarry}, [ASETOS]= {SizeB | RightRdwr | UseCarry}, [ASETPC]= {SizeB | RightRdwr | UseCarry}, [ASETPL]= {SizeB | RightRdwr | UseCarry}, [ASETPS]= {SizeB | RightRdwr | UseCarry}, [ASHLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASHLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASHLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASHRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASHRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASHRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, [ASTOSB]= {OK, AX|DI, DI}, [ASTOSL]= {OK, AX|DI, DI}, [ASTOSW]= {OK, AX|DI, DI}, [ADUFFZERO]= {OK, AX|DI, DI}, [ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry}, [ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry}, [ASUBW]= {SizeW | LeftRead | RightRdwr | SetCarry}, [ASUBSD]= {SizeD | LeftRead | RightRdwr}, [ASUBSS]= {SizeF | LeftRead | RightRdwr}, [ATESTB]= {SizeB | LeftRead | RightRead | SetCarry}, [ATESTL]= {SizeL | LeftRead | RightRead | SetCarry}, [ATESTW]= {SizeW | LeftRead | RightRead | SetCarry}, [AUCOMISD]= {SizeD | LeftRead | RightRead}, [AUCOMISS]= {SizeF | LeftRead | RightRead}, [AXCHGB]= {SizeB | LeftRdwr | RightRdwr}, [AXCHGL]= {SizeL | LeftRdwr | RightRdwr}, [AXCHGW]= {SizeW | LeftRdwr | RightRdwr}, [AXORB]= {SizeB | LeftRead | RightRdwr | SetCarry}, [AXORL]= {SizeL | 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 != TYPE_CONST) info->reguse |= CX; if(info->flags & ImulAXDX) { if(p->to.type == TYPE_NONE) { info->reguse |= AX; info->regset |= AX | DX; } else { info->flags |= RightRdwr; } } // Addressing makes some registers used. if(p->from.type == TYPE_MEM && p->from.name == NAME_NONE) info->regindex |= RtoB(p->from.reg); if(p->from.index != REG_NONE) info->regindex |= RtoB(p->from.index); if(p->to.type == TYPE_MEM && p->to.name == NAME_NONE) info->regindex |= RtoB(p->to.reg); if(p->to.index != REG_NONE) info->regindex |= RtoB(p->to.index); }