blob: e77a026a93ca611cd3f6b9385311f5e9a776b073 [file] [log] [blame]
// 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);
}