Commit afd4e3d6 authored by Matthias Braun's avatar Matthias Braun
Browse files

ia32: Introduce x86_insn_size enum

parent 63ee53cd
This diff is collapsed.
......@@ -39,7 +39,6 @@ extern pmap *ia32_tv_ent; /**< A map of entities that store const tarvals */
/** The mode for the floating point control word. */
extern ir_mode *ia32_mode_fpcw;
extern ir_mode *ia32_mode_8h; /**< Mode for high 8bit registers */
extern ir_mode *ia32_mode_gp;
extern ir_mode *ia32_mode_float64;
extern ir_mode *ia32_mode_float32;
......
......@@ -156,30 +156,31 @@ static const char *get_register_name_16bit(const arch_register_t *reg)
panic("unexpected register");
}
static const char *get_register_name_mode(const arch_register_t *reg,
ir_mode *mode)
{
if (mode == NULL)
return reg->name;
if (mode == ia32_mode_8h)
return get_register_name_8bit_high(reg);
unsigned size = get_mode_size_bits(mode);
if (size == 8)
return get_register_name_8bit_low(reg);
else if (size == 16)
return get_register_name_16bit(reg);
else
return reg->name;
static const char *get_register_name_size(arch_register_t const *const reg,
x86_insn_size_t const size,
bool use_8bit_high)
{
switch (size) {
case X86_SIZE_8:
return use_8bit_high ? get_register_name_8bit_high(reg)
: get_register_name_8bit_low(reg);
case X86_SIZE_16: return get_register_name_16bit(reg);
case X86_SIZE_32: return reg->name;
case X86_SIZE_64:
case X86_SIZE_80:
case X86_SIZE_128:
break;
}
panic("Unexpected size");
}
/**
* emit a register, possible shortened by a mode
* @param reg the register
* @param mode the mode of the register or NULL for full register
*/
static void emit_register(const arch_register_t *reg, ir_mode *mode)
static void emit_register(arch_register_t const *const reg,
x86_insn_size_t const size, bool const use_8bit_high)
{
const char *name = get_register_name_mode(reg, mode);
const char *name = get_register_name_size(reg, size, use_8bit_high);
be_emit_char('%');
be_emit_string(name);
}
......@@ -194,18 +195,20 @@ static void emit_ia32_immediate_attr(bool const prefix,
x86_emit_imm32(&attr->imm);
}
static void ia32_emit_mode_suffix_mode(const ir_mode *mode)
static void ia32_emit_mode_suffix(x86_insn_size_t const size)
{
assert(mode_is_int(mode) || mode_is_reference(mode) || mode == ia32_mode_8h);
switch (get_mode_size_bits(mode)) {
case 8: be_emit_char('b'); return;
case 16: be_emit_char('w'); return;
case 32: be_emit_char('l'); return;
/* gas docu says q is the suffix but gcc, objdump and icc use ll
* apparently */
case 64: be_emit_cstring("ll"); return;
switch (size) {
case X86_SIZE_8: be_emit_char('b'); return;
case X86_SIZE_16: be_emit_char('w'); return;
case X86_SIZE_32: be_emit_char('l'); return;
/* gas docu says q is the suffix but gcc, objdump and icc use ll
* apparently */
case X86_SIZE_64: be_emit_cstring("ll"); return;
case X86_SIZE_80:
case X86_SIZE_128:
break;
}
panic("cannot output mode_suffix for %+F", mode);
panic("Unexpected mode size");
}
static void ia32_emit_x87_mode_suffix(ir_node const *const node)
......@@ -214,50 +217,57 @@ static void ia32_emit_x87_mode_suffix(ir_node const *const node)
if (get_ia32_op_type(node) == ia32_Normal)
return;
ir_mode *mode = get_ia32_ls_mode(node);
assert(mode_is_float(mode));
switch (get_mode_size_bits(mode)) {
case 32: be_emit_char('s'); return;
case 64: be_emit_char('l'); return;
/* long doubles have different sizes due to alignment on different
* platforms. */
case 80:
case 96:
case 128: be_emit_char('t'); return;
ia32_attr_t const *const attr = get_ia32_attr_const(node);
switch (attr->size) {
case X86_SIZE_32: be_emit_char('s'); return;
case X86_SIZE_64: be_emit_char('l'); return;
/* long doubles have different sizes due to alignment on different
* platforms. */
case X86_SIZE_80:
case X86_SIZE_128: be_emit_char('t'); return;
case X86_SIZE_8:
case X86_SIZE_16:
break;
}
panic("cannot output mode_suffix for %+F", mode);
panic("Unexpected size");
}
static void ia32_emit_x87_mode_suffix_int(ir_node const *const node)
{
assert(get_ia32_op_type(node) != ia32_Normal);
ir_mode *mode = get_ia32_ls_mode(node);
assert(mode_is_int(mode) || mode_is_reference(mode));
switch (get_mode_size_bits(mode)) {
case 16: be_emit_char('s'); return;
case 32: be_emit_char('l'); return;
/* gas docu says q is the suffix but gcc, objdump and icc use ll
* apparently */
case 64: be_emit_cstring("ll"); return;
ia32_attr_t const *const attr = get_ia32_attr_const(node);
switch (attr->size) {
case X86_SIZE_16: be_emit_char('s'); return;
case X86_SIZE_32: be_emit_char('l'); return;
/* gas docu says q is the suffix but gcc, objdump and icc use ll
* apparently */
case X86_SIZE_64: be_emit_cstring("ll"); return;
case X86_SIZE_8:
case X86_SIZE_80:
case X86_SIZE_128:
break;
}
panic("cannot output mode_suffix for %+F", mode);
panic("Unexpected size");
}
static char get_xmm_mode_suffix(ir_mode *mode)
static char get_xmm_mode_suffix(x86_insn_size_t const size)
{
assert(mode_is_float(mode));
switch (get_mode_size_bits(mode)) {
case 32: return 's';
case 64: return 'd';
default: panic("invalid XMM mode");
switch (size) {
case X86_SIZE_32: return 's';
case X86_SIZE_64: return 'd';
case X86_SIZE_8:
case X86_SIZE_16:
case X86_SIZE_80:
case X86_SIZE_128:
break;
}
panic("invalid XMM mode");
}
static void ia32_emit_xmm_mode_suffix(ir_node const *const node)
{
ir_mode *mode = get_ia32_ls_mode(node);
assert(mode != NULL);
be_emit_char(get_xmm_mode_suffix(mode));
ia32_attr_t const *const attr = get_ia32_attr_const(node);
be_emit_char(get_xmm_mode_suffix(attr->size));
}
/**
......@@ -427,26 +437,27 @@ emit_AM:
}
case 'B': {
ia32_attr_t const *const attr = get_ia32_attr_const(node);
ir_node const *const src = get_irn_n(node, n_ia32_binary_right);
if (is_ia32_Immediate(src)) {
emit_ia32_immediate_attr(true, src);
be_emit_cstring(", ");
if (get_ia32_op_type(node) == ia32_Normal) {
if (attr->tp == ia32_Normal) {
goto destination_operand;
} else {
ia32_emit_am(node);
}
} else {
if (get_ia32_op_type(node) == ia32_Normal) {
if (attr->tp == ia32_Normal) {
reg = arch_get_irn_register(src);
emit_register(reg, get_ia32_ls_mode(node));
emit_register(reg, attr->size, attr->use_8bit_high);
} else {
ia32_emit_am(node);
}
be_emit_cstring(", ");
destination_operand:
reg = arch_get_irn_register_in(node, n_ia32_binary_left);
emit_register(reg, get_ia32_ls_mode(node));
emit_register(reg, attr->size, attr->use_8bit_high);
}
break;
}
......@@ -520,15 +531,14 @@ emit_I:
break;
case 'M': {
ir_mode *mode = get_ia32_ls_mode(node);
if (!mode)
mode = ia32_mode_gp;
ia32_attr_t const *const attr = get_ia32_attr_const(node);
if (mod & EMIT_32BIT_REG) {
if (get_mode_size_bits(mode) == 32)
assert(is_ia32_Load(node) || is_ia32_Conv_I2I(node));
if (attr->size == X86_SIZE_32)
break;
be_emit_char(mode_is_signed(mode) ? 's' : 'z');
be_emit_char(attr->sign_extend ? 's' : 'z');
}
ia32_emit_mode_suffix_mode(mode);
ia32_emit_mode_suffix(attr->size);
break;
}
......@@ -562,7 +572,9 @@ emit_R:
} else if (mod & EMIT_32BIT_REG) {
name = reg->name;
} else {
name = get_register_name_mode(reg, get_ia32_ls_mode(node));
ia32_attr_t const *const attr = get_ia32_attr_const(node);
name = get_register_name_size(reg, attr->size,
attr->use_8bit_high);
}
be_emit_char('%');
be_emit_string(name);
......@@ -853,11 +865,19 @@ static void emit_ia32_asm_register(const arch_register_t *reg, char modifier,
{
const char *name;
switch (modifier) {
case '\0': name = get_register_name_mode(reg, mode); break;
case 'b': name = get_register_name_8bit_low(reg); break;
case 'h': name = get_register_name_8bit_high(reg); break;
case 'w': name = get_register_name_16bit(reg); break;
case 'k': name = reg->name; break;
case '\0': {
if (mode_is_float(mode)) {
name = reg->name;
} else {
x86_insn_size_t const size = x86_size_from_mode(mode);
name = get_register_name_size(reg, size, false);
}
break;
}
case 'b': name = get_register_name_8bit_low(reg); break;
case 'h': name = get_register_name_8bit_high(reg); break;
case 'w': name = get_register_name_16bit(reg); break;
case 'k': name = reg->name; break;
default:
panic("invalid asm op modifier");
}
......@@ -982,9 +1002,8 @@ static void emit_ia32_CopyB_i(const ir_node *node)
static void emit_ia32_Conv_with_FP(const ir_node *node, const char* conv_f,
const char* conv_d)
{
ir_mode *ls_mode = get_ia32_ls_mode(node);
int ls_bits = get_mode_size_bits(ls_mode);
const char *conv = ls_bits == 32 ? conv_f : conv_d;
x86_insn_size_t const size = get_ia32_attr_const(node)->size;
const char *conv = size == X86_SIZE_32 ? conv_f : conv_d;
ia32_emitf(node, "cvt%s %AS3, %D0", conv);
}
......
......@@ -246,13 +246,18 @@ static void enc_imm32(ir_node const *const node)
}
static void enc_imm(ia32_immediate_attr_t const *const attr,
unsigned const size)
x86_insn_size_t size)
{
switch (size) {
case 8: be_emit8(attr->imm.offset); break;
case 16: be_emit16(attr->imm.offset); break;
case 32: enc_relocation(&attr->imm); break;
case X86_SIZE_8: be_emit8(attr->imm.offset); return;
case X86_SIZE_16: be_emit16(attr->imm.offset); return;
case X86_SIZE_32: enc_relocation(&attr->imm); return;
case X86_SIZE_64:
case X86_SIZE_80:
case X86_SIZE_128:
break;
}
panic("Invalid size");
}
static void enc_mov(arch_register_t const *const src, arch_register_t const *const dst)
......@@ -344,10 +349,10 @@ void ia32_enc_unop(ir_node const *const node, uint8_t const code,
void ia32_enc_unop_mem(ir_node const *const node, uint8_t const code,
uint8_t const ext)
{
unsigned size = get_mode_size_bits(get_ia32_ls_mode(node));
if (size == 16)
x86_insn_size_t const size = get_ia32_attr_const(node)->size;
if (size == X86_SIZE_16)
be_emit8(0x66);
be_emit8(size == 8 ? code : code | OP_16_32);
be_emit8(size == X86_SIZE_8 ? code : code | OP_16_32);
enc_mod_am(ext, node);
}
......@@ -372,19 +377,18 @@ static void enc_binop_reg(ir_node const *const node, unsigned char const code, i
void ia32_enc_binop(ir_node const *const node, unsigned const code)
{
ir_mode *const ls_mode = get_ia32_ls_mode(node);
unsigned size = ls_mode ? get_mode_size_bits(ls_mode) : 32;
if (size == 16)
x86_insn_size_t size = get_ia32_attr_const(node)->size;
if (size == X86_SIZE_16)
be_emit8(0x66);
unsigned op = size == 8 ? OP_8 : OP_16_32;
unsigned op = size == X86_SIZE_8 ? OP_8 : OP_16_32;
ir_node *const right = get_irn_n(node, n_ia32_binary_right);
if (is_ia32_Immediate(right)) {
ia32_immediate_attr_t const *const attr = get_ia32_immediate_attr_const(right);
/* Try to use the short form with 8bit sign extended immediate. */
if (op != OP_8 && ia32_is_8bit_imm(attr)) {
op = OP_16_32_IMM8;
size = 8;
size = X86_SIZE_8;
}
/* Emit the main opcode. */
......@@ -402,18 +406,18 @@ void ia32_enc_binop(ir_node const *const node, unsigned const code)
void ia32_enc_binop_mem(ir_node const *const node, unsigned const code)
{
unsigned size = get_mode_size_bits(get_ia32_ls_mode(node));
if (size == 16)
x86_insn_size_t size = get_ia32_attr_const(node)->size;
if (size == X86_SIZE_16)
be_emit8(0x66);
unsigned op = size == 8 ? OP_8 : OP_16_32;
unsigned op = size == X86_SIZE_8 ? OP_8 : OP_16_32;
ir_node *const val = get_irn_n(node, n_ia32_unary_op);
if (is_ia32_Immediate(val)) {
ia32_immediate_attr_t const *const attr = get_ia32_immediate_attr_const(val);
/* Try to use the short form with 8bit sign extended immediate. */
if (op != OP_8 && ia32_is_8bit_imm(attr)) {
op = OP_16_32_IMM8;
size = 8;
size = X86_SIZE_8;
}
/* Emit the main opcode. */
......@@ -450,22 +454,22 @@ void ia32_enc_shiftop(ir_node const *const node, uint8_t const ext)
void ia32_enc_shiftop_mem(ir_node const *const node, uint8_t const ext)
{
unsigned const size = get_mode_size_bits(get_ia32_ls_mode(node));
if (size == 16)
x86_insn_size_t const size = get_ia32_attr_const(node)->size;
if (size == X86_SIZE_16)
be_emit8(0x66);
ir_node const *const count = get_irn_n(node, 1);
if (is_ia32_Immediate(count)) {
int32_t const offset = get_ia32_immediate_attr_const(count)->imm.offset;
if (offset == 1) {
be_emit8(size == 8 ? 0xD0 : 0xD1);
be_emit8(size == X86_SIZE_8 ? 0xD0 : 0xD1);
enc_mod_am(ext, node);
} else {
be_emit8(size == 8 ? 0xC0 : 0xC1);
be_emit8(size == X86_SIZE_8 ? 0xC0 : 0xC1);
enc_mod_am(ext, node);
be_emit8(offset);
}
} else {
be_emit8(size == 8 ? 0xD2 : 0xD3);
be_emit8(size == X86_SIZE_8 ? 0xD2 : 0xD3);
enc_mod_am(ext, node);
}
}
......@@ -607,11 +611,11 @@ static void enc_cmovcc(const ir_node *node)
static void enc_test(ir_node const *const node)
{
unsigned const size = get_mode_size_bits(get_ia32_ls_mode(node));
if (size == 16)
x86_insn_size_t const size = get_ia32_attr_const(node)->size;
if (size == X86_SIZE_16)
be_emit8(0x66);
unsigned const op = size == 8 ? OP_8 : OP_16_32;
unsigned const op = size == X86_SIZE_8 ? OP_8 : OP_16_32;
ir_node *const right = get_irn_n(node, n_ia32_Test_right);
if (is_ia32_Immediate(right)) {
/* Emit the main opcode. */
......@@ -782,13 +786,13 @@ static void enc_load(const ir_node *node)
*/
static void enc_store(const ir_node *node)
{
const ir_node *value = get_irn_n(node, n_ia32_Store_val);
unsigned size = get_mode_size_bits(get_ia32_ls_mode(node));
ir_node const *const value = get_irn_n(node, n_ia32_Store_val);
x86_insn_size_t const size = get_ia32_attr_const(node)->size;
if (is_ia32_Immediate(value)) {
if (size == 16)
if (size == X86_SIZE_16)
be_emit8(0x66);
be_emit8(0xC6 | (size != 8 ? OP_16_32 : 0));
be_emit8(0xC6 | (size != X86_SIZE_8 ? OP_16_32 : 0));
enc_mod_am(0, node);
enc_imm(get_ia32_immediate_attr_const(value), size);
} else {
......@@ -800,10 +804,10 @@ static void enc_store(const ir_node *node)
if (!base && !idx) {
/* store to constant address from EAX can be encoded as
* 0xA2/0xA3 [offset]*/
if (size == 8) {
if (size == X86_SIZE_8) {
be_emit8(0xA2);
} else {
if (size == 16)
if (size == X86_SIZE_16)
be_emit8(0x66);
be_emit8(0xA3);
}
......@@ -813,9 +817,9 @@ static void enc_store(const ir_node *node)
}
}
if (size == 16)
if (size == X86_SIZE_16)
be_emit8(0x66);
be_emit8(0x88 | (size != 8 ? OP_16_32 : 0));
be_emit8(0x88 | (size != X86_SIZE_8 ? OP_16_32 : 0));
enc_mod_am(in->encoding, node);
}
}
......@@ -825,10 +829,10 @@ static void enc_conv_i2i(const ir_node *node)
/* 8 16 bit source
* movzx B6 B7
* movsx BE BF */
ir_mode *const smaller_mode = get_ia32_ls_mode(node);
unsigned opcode = 0xB6;
if (mode_is_signed(smaller_mode)) opcode |= 0x08;
if (get_mode_size_bits(smaller_mode) == 16) opcode |= 0x01;
ia32_attr_t const *const attr = get_ia32_attr_const(node);
unsigned opcode = 0xB6;
if (attr->sign_extend) opcode |= 0x08;
if (attr->size == X86_SIZE_16) opcode |= 0x01;
ia32_enc_0f_unop_reg(node, opcode, n_ia32_Conv_I2I_val);
}
......@@ -1101,8 +1105,7 @@ void ia32_enc_fbinop(ir_node const *const node, unsigned const op_fwd,
assert(!x87->reg);
assert(!x87->pop);
unsigned const size = get_mode_size_bits(get_ia32_ls_mode(node));
be_emit8(size == 32 ? 0xD8 : 0xDC);
be_emit8(attr->attr.size == X86_SIZE_32 ? 0xD8 : 0xDC);
enc_mod_am(op, node);
}
}
......@@ -1116,77 +1119,91 @@ void ia32_enc_fop_reg(ir_node const *const node, uint8_t const op0,
static void enc_fild(const ir_node *node)
{
switch (get_mode_size_bits(get_ia32_ls_mode(node))) {
case 16:
x86_insn_size_t const size = get_ia32_attr_const(node)->size;
switch (size) {
case X86_SIZE_16:
be_emit8(0xDF); // filds
enc_mod_am(0, node);
return;
case 32:
case X86_SIZE_32:
be_emit8(0xDB); // fildl
enc_mod_am(0, node);
return;
case 64:
case X86_SIZE_64:
be_emit8(0xDF); // fildll
enc_mod_am(5, node);
return;
default:
panic("invalid mode size");
case X86_SIZE_8:
case X86_SIZE_128:
case X86_SIZE_80:
break;
}
panic("invalid mode size");
}
static void enc_fist(const ir_node *node)
{
unsigned op;
unsigned const size = get_mode_size_bits(get_ia32_ls_mode(node));
x86_insn_size_t const size = get_ia32_attr_const(node)->size;
unsigned op;
switch (size) {
case 16: be_emit8(0xDF); op = 2; break; // fist[p]s
case 32: be_emit8(0xDB); op = 2; break; // fist[p]l
case 64: be_emit8(0xDF); op = 6; break; // fistpll
default: panic("invalid mode size");
case X86_SIZE_16: be_emit8(0xDF); op = 2; break; // fist[p]s
case X86_SIZE_32: be_emit8(0xDB); op = 2; break; // fist[p]l
case X86_SIZE_64: be_emit8(0xDF); op = 6; break; // fistpll
case X86_SIZE_8:
case X86_SIZE_80:
case X86_SIZE_128:
panic("invalid mode size");
}
if (get_ia32_x87_attr_const(node)->x87.pop)
++op;
// There is only a pop variant for 64 bit integer store.
assert(size < 64 || get_ia32_x87_attr_const(node)->x87.pop);
assert(size < X86_SIZE_64 || get_ia32_x87_attr_const(node)->x87.pop);
enc_mod_am(op, node);
}
static void enc_fisttp(ir_node const *const node)
{
switch (get_mode_size_bits(get_ia32_ls_mode(node))) {
case 16: be_emit8(0xDF); break; // fisttps
case 32: be_emit8(0xDB); break; // fisttpl
case 64: be_emit8(0xDD); break; // fisttpll
default: panic("invalid mode size");
x86_insn_size_t const size = get_ia32_attr_const(node)->size;
switch (size) {
case X86_SIZE_16: be_emit8(0xDF); break; // fisttps
case X86_SIZE_32: be_emit8(0xDB); break; // fisttpl
case X86_SIZE_64: be_emit8(0xDD); break; // fisttpll
case X86_SIZE_8:
case X86_SIZE_80:
case X86_SIZE_128:
panic("unexpected mode size");
}
enc_mod_am(1, node);
}
static void enc_fld(const ir_node *node)
{
switch (get_mode_size_bits(get_ia32_ls_mode(node))) {
case 32:
x86_insn_size_t const size = get_ia32_attr_const(node)->size;
switch (size) {
case X86_SIZE_32:
be_emit8(0xD9); // flds
enc_mod_am(0, node);
return;
case 64:
case X86_SIZE_64:
be_emit8(0xDD); // fldl
enc_mod_am(0, node);
return;
case 80:
case 96:
case X86_SIZE_80:
be_emit8(0xDB); // fldt
enc_mod_am(5, node);
return;
default:
panic("invalid mode size");
case X86_SIZE_8:
case X86_SIZE_16:
case X86_SIZE_128:
break;
}
panic("unexpected mode size");
}
static void enc_fldcw(const ir_node *node)
......@@ -1197,19 +1214,21 @@ static void enc_fldcw(const ir_node *node)
static void enc_fst(const ir_node *node)
{
unsigned op;
unsigned const size = get_mode_size_bits(get_ia32_ls_mode(node));
x86_insn_size_t const size = get_ia32_attr_const(node)->size;
unsigned op;
switch (size) {
case 32: be_emit8(0xD9); op = 2; break; // fst[p]s
case 64: be_emit8(0xDD); op = 2; break; // fst[p]l
case 80:
case 96: be_emit8(0xDB); op = 6; break; // fstpt
default: panic("invalid mode size");
case X86_SIZE_32: be_emit8(0xD9); op = 2; break; // fst[p]s
case X86_SIZE_64: be_emit8(0xDD); op = 2; break; // fst[p]l
case X86_SIZE_80: be_emit8(0xDB); op = 6; break; // fstpt
case X86_SIZE_8:
case X86_SIZE_16:
case X86_SIZE_128:
panic("unexpected mode size");
}