blob: e3e50f28a9329f678539aad8a109ef9e9fe39380 [file] [log] [blame]
// Copyright 2014 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 "opt.h"
enum {
LeftRdwr = LeftRead | LeftWrite,
RightRdwr = RightRead | RightWrite,
};
// 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 Power opcode.
[ANOP]= {LeftRead | RightWrite},
// Integer
[AADD]= {SizeQ | LeftRead | RegRead | RightWrite},
[ASUB]= {SizeQ | LeftRead | RegRead | RightWrite},
[ANEG]= {SizeQ | LeftRead | RegRead | RightWrite},
[AAND]= {SizeQ | LeftRead | RegRead | RightWrite},
[AOR]= {SizeQ | LeftRead | RegRead | RightWrite},
[AXOR]= {SizeQ | LeftRead | RegRead | RightWrite},
[AMULLD]= {SizeQ | LeftRead | RegRead | RightWrite},
[AMULLW]= {SizeL | LeftRead | RegRead | RightWrite},
[AMULHD]= {SizeL | LeftRead | RegRead | RightWrite},
[AMULHDU]= {SizeL | LeftRead | RegRead | RightWrite},
[ADIVD]= {SizeQ | LeftRead | RegRead | RightWrite},
[ADIVDU]= {SizeQ | LeftRead | RegRead | RightWrite},
[ASLD]= {SizeQ | LeftRead | RegRead | RightWrite},
[ASRD]= {SizeQ | LeftRead | RegRead | RightWrite},
[ASRAD]= {SizeQ | LeftRead | RegRead | RightWrite},
[ACMP]= {SizeQ | LeftRead | RightRead},
[ACMPU]= {SizeQ | LeftRead | RightRead},
[ATD]= {SizeQ | RightRead},
// Floating point.
[AFADD]= {SizeD | LeftRead | RegRead | RightWrite},
[AFADDS]= {SizeF | LeftRead | RegRead | RightWrite},
[AFSUB]= {SizeD | LeftRead | RegRead | RightWrite},
[AFSUBS]= {SizeF | LeftRead | RegRead | RightWrite},
[AFMUL]= {SizeD | LeftRead | RegRead | RightWrite},
[AFMULS]= {SizeF | LeftRead | RegRead | RightWrite},
[AFDIV]= {SizeD | LeftRead | RegRead | RightWrite},
[AFDIVS]= {SizeF | LeftRead | RegRead | RightWrite},
[AFCTIDZ]= {SizeF | LeftRead | RegRead | RightWrite},
[AFCFID]= {SizeF | LeftRead | RegRead | RightWrite},
[AFCMPU]= {SizeD | LeftRead | RightRead},
[AFRSP]= {SizeD | LeftRead | RightWrite | Conv},
// Moves
[AMOVB]= {SizeB | LeftRead | RightWrite | Move | Conv},
[AMOVBU]= {SizeB | LeftRead | RightWrite | Move | Conv | PostInc},
[AMOVBZ]= {SizeB | LeftRead | RightWrite | Move | Conv},
[AMOVH]= {SizeW | LeftRead | RightWrite | Move | Conv},
[AMOVHU]= {SizeW | LeftRead | RightWrite | Move | Conv | PostInc},
[AMOVHZ]= {SizeW | LeftRead | RightWrite | Move | Conv},
[AMOVW]= {SizeL | LeftRead | RightWrite | Move | Conv},
// there is no AMOVWU.
[AMOVWZU]= {SizeL | LeftRead | RightWrite | Move | Conv | PostInc},
[AMOVWZ]= {SizeL | LeftRead | RightWrite | Move | Conv},
[AMOVD]= {SizeQ | LeftRead | RightWrite | Move},
[AMOVDU]= {SizeQ | LeftRead | RightWrite | Move | PostInc},
[AFMOVS]= {SizeF | LeftRead | RightWrite | Move | Conv},
[AFMOVD]= {SizeD | LeftRead | RightWrite | Move},
// Jumps
[ABR]= {Jump | Break},
[ABL]= {Call},
[ABEQ]= {Cjmp},
[ABNE]= {Cjmp},
[ABGE]= {Cjmp},
[ABLT]= {Cjmp},
[ABGT]= {Cjmp},
[ABLE]= {Cjmp},
[ARETURN]= {Break},
[ADUFFZERO]= {Call},
[ADUFFCOPY]= {Call},
};
void
proginfo(ProgInfo *info, Prog *p)
{
*info = progtable[p->as];
if(info->flags == 0) {
*info = progtable[AADD];
fatal("proginfo: unknown instruction %P", p);
}
if((info->flags & RegRead) && p->reg == NREG) {
info->flags &= ~RegRead;
info->flags |= /*CanRegRead |*/ RightRead;
}
if((p->from.type == D_OREG || p->from.type == D_CONST) && p->from.reg != NREG) {
info->regindex |= RtoB(p->from.reg);
if(info->flags & PostInc) {
info->regset |= RtoB(p->from.reg);
}
}
if((p->to.type == D_OREG || p->to.type == D_CONST) && p->to.reg != NREG) {
info->regindex |= RtoB(p->to.reg);
if(info->flags & PostInc) {
info->regset |= RtoB(p->to.reg);
}
}
if(p->from.type == D_CONST && p->from.sym != nil && (info->flags & LeftRead)) {
info->flags &= ~LeftRead;
info->flags |= LeftAddr;
}
if(p->as == ADUFFZERO) {
info->reguse |= RtoB(0) | RtoB(2);
info->regset |= RtoB(2);
}
if(p->as == ADUFFCOPY) {
info->reguse |= RtoB(0) | RtoB(2) | RtoB(3);
info->regset |= RtoB(2) | RtoB(3);
}
}