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 */ ...@@ -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. */ /** The mode for the floating point control word. */
extern ir_mode *ia32_mode_fpcw; 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_gp;
extern ir_mode *ia32_mode_float64; extern ir_mode *ia32_mode_float64;
extern ir_mode *ia32_mode_float32; extern ir_mode *ia32_mode_float32;
......
...@@ -156,30 +156,31 @@ static const char *get_register_name_16bit(const arch_register_t *reg) ...@@ -156,30 +156,31 @@ static const char *get_register_name_16bit(const arch_register_t *reg)
panic("unexpected register"); panic("unexpected register");
} }
static const char *get_register_name_mode(const arch_register_t *reg, static const char *get_register_name_size(arch_register_t const *const reg,
ir_mode *mode) x86_insn_size_t const size,
{ bool use_8bit_high)
if (mode == NULL) {
return reg->name; switch (size) {
if (mode == ia32_mode_8h) case X86_SIZE_8:
return get_register_name_8bit_high(reg); return use_8bit_high ? get_register_name_8bit_high(reg)
unsigned size = get_mode_size_bits(mode); : get_register_name_8bit_low(reg);
if (size == 8) case X86_SIZE_16: return get_register_name_16bit(reg);
return get_register_name_8bit_low(reg); case X86_SIZE_32: return reg->name;
else if (size == 16) case X86_SIZE_64:
return get_register_name_16bit(reg); case X86_SIZE_80:
else case X86_SIZE_128:
return reg->name; break;
}
panic("Unexpected size");
} }
/** /**
* emit a register, possible shortened by a mode * 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_char('%');
be_emit_string(name); be_emit_string(name);
} }
...@@ -194,18 +195,20 @@ static void emit_ia32_immediate_attr(bool const prefix, ...@@ -194,18 +195,20 @@ static void emit_ia32_immediate_attr(bool const prefix,
x86_emit_imm32(&attr->imm); 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 (size) {
switch (get_mode_size_bits(mode)) { case X86_SIZE_8: be_emit_char('b'); return;
case 8: be_emit_char('b'); return; case X86_SIZE_16: be_emit_char('w'); return;
case 16: be_emit_char('w'); return; case X86_SIZE_32: be_emit_char('l'); return;
case 32: be_emit_char('l'); return; /* gas docu says q is the suffix but gcc, objdump and icc use ll
/* gas docu says q is the suffix but gcc, objdump and icc use ll * apparently */
* apparently */ case X86_SIZE_64: be_emit_cstring("ll"); return;
case 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) 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) ...@@ -214,50 +217,57 @@ static void ia32_emit_x87_mode_suffix(ir_node const *const node)
if (get_ia32_op_type(node) == ia32_Normal) if (get_ia32_op_type(node) == ia32_Normal)
return; return;
ir_mode *mode = get_ia32_ls_mode(node); ia32_attr_t const *const attr = get_ia32_attr_const(node);
assert(mode_is_float(mode)); switch (attr->size) {
switch (get_mode_size_bits(mode)) { case X86_SIZE_32: be_emit_char('s'); return;
case 32: be_emit_char('s'); return; case X86_SIZE_64: be_emit_char('l'); return;
case 64: be_emit_char('l'); return; /* long doubles have different sizes due to alignment on different
/* long doubles have different sizes due to alignment on different * platforms. */
* platforms. */ case X86_SIZE_80:
case 80: case X86_SIZE_128: be_emit_char('t'); return;
case 96: case X86_SIZE_8:
case 128: be_emit_char('t'); return; 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) static void ia32_emit_x87_mode_suffix_int(ir_node const *const node)
{ {
assert(get_ia32_op_type(node) != ia32_Normal); assert(get_ia32_op_type(node) != ia32_Normal);
ir_mode *mode = get_ia32_ls_mode(node); ia32_attr_t const *const attr = get_ia32_attr_const(node);
assert(mode_is_int(mode) || mode_is_reference(mode)); switch (attr->size) {
switch (get_mode_size_bits(mode)) { case X86_SIZE_16: be_emit_char('s'); return;
case 16: be_emit_char('s'); return; case X86_SIZE_32: be_emit_char('l'); return;
case 32: be_emit_char('l'); return; /* gas docu says q is the suffix but gcc, objdump and icc use ll
/* gas docu says q is the suffix but gcc, objdump and icc use ll * apparently */
* apparently */ case X86_SIZE_64: be_emit_cstring("ll"); return;
case 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 (size) {
switch (get_mode_size_bits(mode)) { case X86_SIZE_32: return 's';
case 32: return 's'; case X86_SIZE_64: return 'd';
case 64: return 'd'; case X86_SIZE_8:
default: panic("invalid XMM mode"); 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) static void ia32_emit_xmm_mode_suffix(ir_node const *const node)
{ {
ir_mode *mode = get_ia32_ls_mode(node); ia32_attr_t const *const attr = get_ia32_attr_const(node);
assert(mode != NULL); be_emit_char(get_xmm_mode_suffix(attr->size));
be_emit_char(get_xmm_mode_suffix(mode));
} }
/** /**
...@@ -427,26 +437,27 @@ emit_AM: ...@@ -427,26 +437,27 @@ emit_AM:
} }
case 'B': { 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); ir_node const *const src = get_irn_n(node, n_ia32_binary_right);
if (is_ia32_Immediate(src)) { if (is_ia32_Immediate(src)) {
emit_ia32_immediate_attr(true, src); emit_ia32_immediate_attr(true, src);
be_emit_cstring(", "); be_emit_cstring(", ");
if (get_ia32_op_type(node) == ia32_Normal) { if (attr->tp == ia32_Normal) {
goto destination_operand; goto destination_operand;
} else { } else {
ia32_emit_am(node); ia32_emit_am(node);
} }
} else { } else {
if (get_ia32_op_type(node) == ia32_Normal) { if (attr->tp == ia32_Normal) {
reg = arch_get_irn_register(src); reg = arch_get_irn_register(src);
emit_register(reg, get_ia32_ls_mode(node)); emit_register(reg, attr->size, attr->use_8bit_high);
} else { } else {
ia32_emit_am(node); ia32_emit_am(node);
} }
be_emit_cstring(", "); be_emit_cstring(", ");
destination_operand: destination_operand:
reg = arch_get_irn_register_in(node, n_ia32_binary_left); 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; break;
} }
...@@ -520,15 +531,14 @@ emit_I: ...@@ -520,15 +531,14 @@ emit_I:
break; break;
case 'M': { case 'M': {
ir_mode *mode = get_ia32_ls_mode(node); ia32_attr_t const *const attr = get_ia32_attr_const(node);
if (!mode)
mode = ia32_mode_gp;
if (mod & EMIT_32BIT_REG) { 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; 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; break;
} }
...@@ -562,7 +572,9 @@ emit_R: ...@@ -562,7 +572,9 @@ emit_R:
} else if (mod & EMIT_32BIT_REG) { } else if (mod & EMIT_32BIT_REG) {
name = reg->name; name = reg->name;
} else { } 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_char('%');
be_emit_string(name); be_emit_string(name);
...@@ -853,11 +865,19 @@ static void emit_ia32_asm_register(const arch_register_t *reg, char modifier, ...@@ -853,11 +865,19 @@ static void emit_ia32_asm_register(const arch_register_t *reg, char modifier,
{ {
const char *name; const char *name;
switch (modifier) { switch (modifier) {
case '\0': name = get_register_name_mode(reg, mode); break; case '\0': {
case 'b': name = get_register_name_8bit_low(reg); break; if (mode_is_float(mode)) {
case 'h': name = get_register_name_8bit_high(reg); break; name = reg->name;
case 'w': name = get_register_name_16bit(reg); break; } else {
case 'k': name = reg->name; break; 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: default:
panic("invalid asm op modifier"); panic("invalid asm op modifier");
} }
...@@ -982,9 +1002,8 @@ static void emit_ia32_CopyB_i(const ir_node *node) ...@@ -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, static void emit_ia32_Conv_with_FP(const ir_node *node, const char* conv_f,
const char* conv_d) const char* conv_d)
{ {
ir_mode *ls_mode = get_ia32_ls_mode(node); x86_insn_size_t const size = get_ia32_attr_const(node)->size;
int ls_bits = get_mode_size_bits(ls_mode); const char *conv = size == X86_SIZE_32 ? conv_f : conv_d;
const char *conv = ls_bits == 32 ? conv_f : conv_d;
ia32_emitf(node, "cvt%s %AS3, %D0", conv); ia32_emitf(node, "cvt%s %AS3, %D0", conv);
} }
......
...@@ -246,13 +246,18 @@ static void enc_imm32(ir_node const *const node) ...@@ -246,13 +246,18 @@ static void enc_imm32(ir_node const *const node)
} }
static void enc_imm(ia32_immediate_attr_t const *const attr, static void enc_imm(ia32_immediate_attr_t const *const attr,
unsigned const size) x86_insn_size_t size)
{ {
switch (size) { switch (size) {
case 8: be_emit8(attr->imm.offset); break; case X86_SIZE_8: be_emit8(attr->imm.offset); return;
case 16: be_emit16(attr->imm.offset); break; case X86_SIZE_16: be_emit16(attr->imm.offset); return;
case 32: enc_relocation(&attr->imm); break; 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) 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, ...@@ -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, void ia32_enc_unop_mem(ir_node const *const node, uint8_t const code,
uint8_t const ext) uint8_t const ext)
{ {
unsigned size = get_mode_size_bits(get_ia32_ls_mode(node)); x86_insn_size_t const size = get_ia32_attr_const(node)->size;
if (size == 16) if (size == X86_SIZE_16)
be_emit8(0x66); 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); enc_mod_am(ext, node);
} }
...@@ -372,19 +377,18 @@ static void enc_binop_reg(ir_node const *const node, unsigned char const code, i ...@@ -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) void ia32_enc_binop(ir_node const *const node, unsigned const code)
{ {
ir_mode *const ls_mode = get_ia32_ls_mode(node); x86_insn_size_t size = get_ia32_attr_const(node)->size;
unsigned size = ls_mode ? get_mode_size_bits(ls_mode) : 32; if (size == X86_SIZE_16)
if (size == 16)
be_emit8(0x66); 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); ir_node *const right = get_irn_n(node, n_ia32_binary_right);
if (is_ia32_Immediate(right)) { if (is_ia32_Immediate(right)) {
ia32_immediate_attr_t const *const attr = get_ia32_immediate_attr_const(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. */ /* Try to use the short form with 8bit sign extended immediate. */
if (op != OP_8 && ia32_is_8bit_imm(attr)) { if (op != OP_8 && ia32_is_8bit_imm(attr)) {
op = OP_16_32_IMM8; op = OP_16_32_IMM8;
size = 8; size = X86_SIZE_8;
} }
/* Emit the main opcode. */ /* Emit the main opcode. */
...@@ -402,18 +406,18 @@ void ia32_enc_binop(ir_node const *const node, unsigned const code) ...@@ -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) void ia32_enc_binop_mem(ir_node const *const node, unsigned const code)
{ {
unsigned size = get_mode_size_bits(get_ia32_ls_mode(node)); x86_insn_size_t size = get_ia32_attr_const(node)->size;
if (size == 16) if (size == X86_SIZE_16)
be_emit8(0x66); 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); ir_node *const val = get_irn_n(node, n_ia32_unary_op);
if (is_ia32_Immediate(val)) { if (is_ia32_Immediate(val)) {
ia32_immediate_attr_t const *const attr = get_ia32_immediate_attr_const(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. */ /* Try to use the short form with 8bit sign extended immediate. */
if (op != OP_8 && ia32_is_8bit_imm(attr)) { if (op != OP_8 && ia32_is_8bit_imm(attr)) {
op = OP_16_32_IMM8; op = OP_16_32_IMM8;
size = 8; size = X86_SIZE_8;
} }
/* Emit the main opcode. */ /* Emit the main opcode. */
...@@ -450,22 +454,22 @@ void ia32_enc_shiftop(ir_node const *const node, uint8_t const ext) ...@@ -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) 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)); x86_insn_size_t const size = get_ia32_attr_const(node)->size;
if (size == 16) if (size == X86_SIZE_16)
be_emit8(0x66); be_emit8(0x66);
ir_node const *const count = get_irn_n(node, 1); ir_node const *const count = get_irn_n(node, 1);
if (is_ia32_Immediate(count)) { if (is_ia32_Immediate(count)) {
int32_t const offset = get_ia32_immediate_attr_const(count)->imm.offset; int32_t const offset = get_ia32_immediate_attr_const(count)->imm.offset;
if (offset == 1) { if (offset == 1) {
be_emit8(size == 8 ? 0xD0 : 0xD1); be_emit8(size == X86_SIZE_8 ? 0xD0 : 0xD1);
enc_mod_am(ext, node); enc_mod_am(ext, node);
} else { } else {
be_emit8(size == 8 ? 0xC0 : 0xC1); be_emit8(size == X86_SIZE_8 ? 0xC0 : 0xC1);
enc_mod_am(ext, node); enc_mod_am(ext, node);
be_emit8(offset); be_emit8(offset);
} }
} else { } else {
be_emit8(size == 8 ? 0xD2 : 0xD3); be_emit8(size == X86_SIZE_8 ? 0xD2 : 0xD3);
enc_mod_am(ext, node); enc_mod_am(ext, node);
} }
} }
...@@ -607,11 +611,11 @@ static void enc_cmovcc(const ir_node *node) ...@@ -607,11 +611,11 @@ static void enc_cmovcc(const ir_node *node)
static void enc_test(ir_node const *const node) static void enc_test(ir_node const *const node)
{ {
unsigned const size = get_mode_size_bits(get_ia32_ls_mode(node)); x86_insn_size_t const size = get_ia32_attr_const(node)->size;
if (size == 16) if (size == X86_SIZE_16)
be_emit8(0x66); 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); ir_node *const right = get_irn_n(node, n_ia32_Test_right);
if (is_ia32_Immediate(right)) { if (is_ia32_Immediate(right)) {
/* Emit the main opcode. */ /* Emit the main opcode. */
...@@ -782,13 +786,13 @@ static void enc_load(const ir_node *node) ...@@ -782,13 +786,13 @@ static void enc_load(const ir_node *node)
*/ */
static void enc_store(const ir_node *node) static void enc_store(const ir_node *node)
{ {
const ir_node *value = get_irn_n(node, n_ia32_Store_val); ir_node const *const value = get_irn_n(node, n_ia32_Store_val);
unsigned size = get_mode_size_bits(get_ia32_ls_mode(node)); x86_insn_size_t const size = get_ia32_attr_const(node)->size;
if (is_ia32_Immediate(value)) { if (is_ia32_Immediate(value)) {
if (size == 16) if (size == X86_SIZE_16)
be_emit8(0x66); 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_mod_am(0, node);
enc_imm(get_ia32_immediate_attr_const(value), size); enc_imm(get_ia32_immediate_attr_const(value), size);
} else { } else {
...@@ -800,10 +804,10 @@ static void enc_store(const ir_node *node) ...@@ -800,10 +804,10 @@ static void enc_store(const ir_node *node)
if (!base && !idx) { if (!base && !idx) {
/* store to constant address from EAX can be encoded as /* store to constant address from EAX can be encoded as
* 0xA2/0xA3 [offset]*/ * 0xA2/0xA3 [offset]*/
if (size == 8) { if (size == X86_SIZE_8) {
be_emit8(0xA2); be_emit8(0xA2);
} else { } else {
if (size == 16) if (size == X86_SIZE_16)
be_emit8(0x66); be_emit8(0x66);
be_emit8(0xA3); be_emit8(0xA3);
} }
...@@ -813,9 +817,9 @@ static void enc_store(const ir_node *node) ...@@ -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(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); enc_mod_am(in->encoding, node);
} }
} }
...@@ -825,10 +829,10 @@ static void enc_conv_i2i(const ir_node *node) ...@@ -825,10 +829,10 @@ static void enc_conv_i2i(const ir_node *node)
/* 8 16 bit source /* 8 16 bit source
* movzx B6 B7 * movzx B6 B7
* movsx BE BF */ * movsx BE BF */
ir_mode *const smaller_mode = get_ia32_ls_mode(node); ia32_attr_t const *const attr = get_ia32_attr_const(node);
unsigned opcode = 0xB6; unsigned opcode = 0xB6;
if (mode_is_signed(smaller_mode)) opcode |= 0x08; if (attr->sign_extend) opcode |= 0x08;
if (get_mode_size_bits(smaller_mode) == 16) opcode |= 0x01; if (attr->size == X86_SIZE_16) opcode |= 0x01;
ia32_enc_0f_unop_reg(node, opcode, n_ia32_Conv_I2I_val); 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, ...@@ -1101,8 +1105,7 @@ void ia32_enc_fbinop(ir_node const *const node, unsigned const op_fwd,
assert(!x87->reg); assert(!x87->reg);
assert(!x87->pop); assert(!x87->pop);
unsigned const size = get_mode_size_bits(get_ia32_ls_mode(node)); be_emit8(attr->attr.size == X86_SIZE_32 ? 0xD8 : 0xDC);
be_emit8(size == 32 ? 0xD8 : 0xDC);
enc_mod_am(op, node); enc_mod_am(op, node);