emit_16bit_register(reg);
return;
} else {
- assert(size == 32);
+ assert(mode_is_float(mode) || size == 32);
}
}
void ia32_emit_x87_mode_suffix(const ir_node *node)
{
ir_mode *mode = get_ia32_ls_mode(node);
- if(mode != NULL)
+ assert(mode != NULL);
+ /* we only need to emit the mode on address mode */
+ if(get_ia32_op_type(node) != ia32_Normal)
ia32_emit_mode_suffix_mode(mode);
}
/**
* Emits registers and/or address mode of a binary operation.
*/
-void ia32_emit_binop(const ir_node *node, int produces_result) {
+void ia32_emit_binop(const ir_node *node) {
const ir_node *right_op = get_irn_n(node, n_ia32_binary_right);
const ir_mode *mode = get_ia32_ls_mode(node);
const arch_register_t *reg_left;
break;
case ia32_AddrModeS:
if(is_ia32_Immediate(right_op)) {
- assert(!produces_result && "Source AM with Const must not produce result");
-
emit_ia32_Immediate(right_op);
be_emit_cstring(", ");
ia32_emit_am(node);
if(is_ia32_Sahf(flags)) {
ir_node *cmp = get_irn_n(flags, n_ia32_Sahf_val);
- if(!is_ia32_FucomFnstsw(cmp) || is_ia32_FucompFnstsw(cmp)
- || is_ia32_FucomppFnstsw(cmp)) {
+ if(!(is_ia32_FucomFnstsw(cmp) || is_ia32_FucompFnstsw(cmp)
+ || is_ia32_FucomppFnstsw(cmp) || is_ia32_FtstFnstsw(cmp))) {
cmp = find_original_value(cmp);
assert(is_ia32_FucomFnstsw(cmp) || is_ia32_FucompFnstsw(cmp)
- || is_ia32_FucomppFnstsw(cmp));
+ || is_ia32_FucomppFnstsw(cmp) || is_ia32_FtstFnstsw(cmp));
}
flags_attr = get_ia32_attr_const(cmp);
- if(flags_attr->data.cmp_flipped)
+ if(flags_attr->data.ins_permuted)
pnc = get_mirrored_pnc(pnc);
pnc |= ia32_pn_Cmp_float;
- } else if(is_ia32_Ucomi(flags)) {
+ } else if(is_ia32_Ucomi(flags) || is_ia32_Fucomi(flags)
+ || is_ia32_Fucompi(flags)) {
flags_attr = get_ia32_attr_const(flags);
- if(flags_attr->data.cmp_flipped)
+ if(flags_attr->data.ins_permuted)
pnc = get_mirrored_pnc(pnc);
pnc |= ia32_pn_Cmp_float;
} else {
|| is_ia32_Cmp8Bit(flags) || is_ia32_Test8Bit(flags));
flags_attr = get_ia32_attr_const(flags);
- if(flags_attr->data.cmp_flipped)
+ if(flags_attr->data.ins_permuted)
pnc = get_mirrored_pnc(pnc);
if(flags_attr->data.cmp_unsigned)
pnc |= ia32_pn_Cmp_unsigned;
void ia32_emit_cmp_suffix_node(const ir_node *node,
int flags_pos)
{
+ const ia32_attr_t *attr = get_ia32_attr_const(node);
+
pn_Cmp pnc = get_ia32_pncode(node);
pnc = determine_final_pnc(node, flags_pos, pnc);
+ if(attr->data.ins_permuted) {
+ if(pnc & ia32_pn_Cmp_float) {
+ pnc = get_negated_pnc(pnc, mode_F);
+ } else {
+ pnc = get_negated_pnc(pnc, mode_Iu);
+ }
+ }
+
ia32_emit_cmp_suffix(pnc);
}
static void emit_ia32_CMov(const ir_node *node)
{
- const arch_register_t *out = arch_get_irn_register(arch_env, node);
+ const ia32_attr_t *attr = get_ia32_attr_const(node);
+ int ins_permuted = attr->data.ins_permuted;
+ const arch_register_t *out = arch_get_irn_register(arch_env, node);
+ pn_Cmp pnc = get_ia32_pncode(node);
const arch_register_t *in_true;
const arch_register_t *in_false;
- pn_Cmp pnc = get_ia32_pncode(node);
pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc);
} else if(out == in_true) {
const arch_register_t *tmp;
- /* swap left/right and negate pnc */
- pnc = get_negated_pnc(pnc, mode_Iu);
+ assert(get_ia32_op_type(node) == ia32_Normal);
+
+ ins_permuted = !ins_permuted;
tmp = in_true;
in_true = in_false;
be_emit_finish_line_gas(node);
}
+ if(ins_permuted) {
+ if(pnc & ia32_pn_Cmp_float) {
+ pnc = get_negated_pnc(pnc, mode_F);
+ } else {
+ pnc = get_negated_pnc(pnc, mode_Iu);
+ }
+ }
+
+ /* TODO: handling of Nans isn't correct yet */
+
be_emit_cstring("\tcmov");
ia32_emit_cmp_suffix(pnc);
be_emit_char(' ');
static const char* emit_asm_operand(const ir_node *node, const char *s)
{
+ const ia32_attr_t *ia32_attr = get_ia32_attr_const(node);
+ const ia32_asm_attr_t *attr = CONST_CAST_IA32_ATTR(ia32_asm_attr_t,
+ ia32_attr);
const arch_register_t *reg;
+ const ia32_asm_reg_t *asm_regs = attr->register_map;
+ const ia32_asm_reg_t *asm_reg;
const char *reg_name;
char c;
char modifier = 0;
int num = -1;
- const ia32_attr_t *attr;
- int n_outs;
int p;
assert(*s == '%');
s += p;
}
+ if(num < 0 || num >= ARR_LEN(asm_regs)) {
+ ir_fprintf(stderr, "Error: Custom assembler references invalid "
+ "input/output (%+F)\n", node);
+ return s;
+ }
+ asm_reg = & asm_regs[num];
+ assert(asm_reg->valid);
+
/* get register */
- attr = get_ia32_attr_const(node);
- n_outs = ARR_LEN(attr->slots);
- if(num < n_outs) {
- reg = get_out_reg(node, num);
+ if(asm_reg->use_input == 0) {
+ reg = get_out_reg(node, asm_reg->inout_pos);
} else {
- ir_node *pred;
- int in = num - n_outs;
- if(in >= get_irn_arity(node)) {
- ir_fprintf(stderr, "Warning: Invalid input %d specified in asm "
- "op (%+F)\n", num, node);
- return s;
- }
- pred = get_irn_n(node, in);
+ ir_node *pred = get_irn_n(node, asm_reg->inout_pos);
+
/* might be an immediate value */
if(is_ia32_Immediate(pred)) {
emit_ia32_Immediate(pred);
return s;
}
- reg = get_in_reg(node, in);
+ reg = get_in_reg(node, asm_reg->inout_pos);
}
if(reg == NULL) {
ir_fprintf(stderr, "Warning: no register assigned for %d asm op "
return s;
}
+ if(asm_reg->memory) {
+ be_emit_char('(');
+ }
+
/* emit it */
- be_emit_char('%');
- switch(modifier) {
- case 0:
- reg_name = arch_register_get_name(reg);
- break;
- case 'b':
- reg_name = ia32_get_mapped_reg_name(isa->regs_8bit, reg);
- break;
- case 'h':
- reg_name = ia32_get_mapped_reg_name(isa->regs_8bit_high, reg);
- break;
- case 'w':
- reg_name = ia32_get_mapped_reg_name(isa->regs_16bit, reg);
- break;
- default:
- panic("Invalid asm op modifier");
+ if(modifier != 0) {
+ be_emit_char('%');
+ switch(modifier) {
+ case 'b':
+ reg_name = ia32_get_mapped_reg_name(isa->regs_8bit, reg);
+ break;
+ case 'h':
+ reg_name = ia32_get_mapped_reg_name(isa->regs_8bit_high, reg);
+ break;
+ case 'w':
+ reg_name = ia32_get_mapped_reg_name(isa->regs_16bit, reg);
+ break;
+ default:
+ panic("Invalid asm op modifier");
+ }
+ be_emit_string(reg_name);
+ } else {
+ emit_register(reg, asm_reg->mode);
+ }
+
+ if(asm_reg->memory) {
+ be_emit_char(')');
}
- be_emit_string(reg_name);
return s;
}
switch(get_ia32_op_type(node)) {
case ia32_Normal:
ia32_emit_source_register(node, n_ia32_unary_op);
- be_emit_cstring(", ");
- ia32_emit_dest_register(node, 0);
break;
case ia32_AddrModeS:
- ia32_emit_dest_register(node, 0);
- be_emit_cstring(", ");
ia32_emit_am(node);
break;
default:
assert(0 && "unsupported op type for Conv");
}
+ be_emit_cstring(", ");
+ ia32_emit_dest_register(node, 0);
be_emit_finish_line_gas(node);
}
be_emit_finish_line_gas(node);
}
-/**
- * Emits code for an 8Bit Int conversion.
- */
-static void emit_ia32_Conv_I2I8Bit(const ir_node *node)
-{
- emit_ia32_Conv_I2I(node);
-}
-
/*******************************************
* _ _
*/
static void emit_ia32_Const(const ir_node *node)
{
- const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
-
- /* a zero? */
- if(attr->symconst == NULL && attr->offset == 0) {
- assert(get_ia32_flags(node) & arch_irn_flags_modify_flags);
- be_emit_cstring("\txorl ");
- ia32_emit_dest_register(node, 0);
- be_emit_cstring(", ");
- ia32_emit_dest_register(node, 0);
- } else {
- be_emit_cstring("\tmovl ");
- emit_ia32_Immediate(node);
- be_emit_cstring(", ");
- ia32_emit_dest_register(node, 0);
- }
+ be_emit_cstring("\tmovl ");
+ emit_ia32_Immediate(node);
+ be_emit_cstring(", ");
+ ia32_emit_dest_register(node, 0);
be_emit_finish_line_gas(node);
}
static void emit_be_Return(const ir_node *node)
{
+ unsigned pop;
be_emit_cstring("\tret");
+
+ pop = be_Return_get_pop(node);
+ if(pop > 0) {
+ be_emit_irprintf(" $%d", pop);
+ }
be_emit_finish_line_gas(node);
}
IA32_EMIT(Conv_FP2I);
IA32_EMIT(Conv_FP2FP);
IA32_EMIT(Conv_I2I);
- IA32_EMIT(Conv_I2I8Bit);
+ IA32_EMIT2(Conv_I2I8Bit, Conv_I2I);
IA32_EMIT(Const);
IA32_EMIT(LdTls);
IA32_EMIT(Minus64Bit);