ir_mode *mode_bp = env->isa->bp->reg_class->mode;
ir_graph *irg = current_ir_graph;
- /* gcc always emits a leave at the end of a routine */
if (ARCH_AMD(isa->opt_arch)) {
ir_node *leave;
/* leave */
- leave = new_rd_ia32_Leave(NULL, env->irg, bl, curr_sp, curr_bp);
+ leave = new_rd_ia32_Leave(NULL, irg, bl, curr_sp, curr_bp);
set_ia32_flags(leave, arch_irn_flags_ignore);
curr_bp = new_r_Proj(irg, bl, leave, mode_bp, pn_ia32_Leave_frame);
curr_sp = new_r_Proj(irg, bl, leave, get_irn_mode(curr_sp), pn_ia32_Leave_stack);
if (cg->dump)
be_dump(cg->irg, "-am", dump_ir_block_graph_sched);
- /* do code placement, (optimize position of constants and argument loads) */
+ /* do code placement, to optimize the position of constants */
place_code(cg->irg);
if (cg->dump)
ir_node *base = get_irn_n(node, n_ia32_base);
ir_node *index = get_irn_n(node, n_ia32_index);
ir_node *mem = get_irn_n(node, n_ia32_mem);
+ ir_node *noreg = ia32_new_NoReg_gp(ia32_current_cg);
ir_node *load;
ir_node *load_res;
ir_node *mem_proj;
if(get_ia32_am_arity(node) == ia32_am_unary) {
set_irn_n(node, n_ia32_unary_op, load_res);
} else if(get_ia32_am_arity(node) == ia32_am_binary) {
- set_irn_n(node, n_ia32_binary_right, load_res);
+ if(is_ia32_Immediate(get_irn_n(node, n_ia32_Cmp_right))) {
+ assert(is_ia32_Cmp(node) || is_ia32_Cmp8Bit(node)
+ || is_ia32_Test(node) || is_ia32_Test8Bit(node));
+ set_irn_n(node, n_ia32_binary_left, load_res);
+ } else {
+ set_irn_n(node, n_ia32_binary_right, load_res);
+ }
} else if(get_ia32_am_arity(node) == ia32_am_ternary) {
set_irn_n(node, n_ia32_binary_right, load_res);
}
+ set_irn_n(node, n_ia32_base, noreg);
+ set_irn_n(node, n_ia32_index, noreg);
+ set_ia32_am_offs_int(node, 0);
+ set_ia32_am_sc(node, NULL);
+ set_ia32_am_scale(node, 0);
+ clear_ia32_am_sc_sign(node);
/* rewire mem-proj */
if(get_irn_mode(node) == mode_T) {
static ir_node *flags_remat(ir_node *node, ir_node *after)
{
/* we should turn back source address mode when rematerializing nodes */
- ia32_op_type_t type = get_ia32_op_type(node);
+ ia32_op_type_t type = get_ia32_op_type(node);
+ ir_node *block;
ir_node *copy;
+ if(is_Block(after)) {
+ block = after;
+ } else {
+ block = get_nodes_block(after);
+ }
+
if (type == ia32_AddrModeS) {
turn_back_am(node);
} else if (type == ia32_AddrModeD) {
}
copy = exact_copy(node);
+ ir_fprintf(stderr, "Remated: %+F\n", copy);
+ set_nodes_block(copy, block);
sched_add_after(after, copy);
return copy;
panic("Can't output mode_suffix for %+F\n", mode);
}
-static
-int produces_result(const ir_node *node) {
- return
- !is_ia32_CmpSet(node) &&
- !is_ia32_CmpSet8Bit(node) &&
- !is_ia32_CmpJmp(node) &&
- !is_ia32_CmpJmp8Bit(node) &&
- !is_ia32_St(node) &&
- !is_ia32_SwitchJmp(node) &&
- !is_ia32_TestJmp(node) &&
- !is_ia32_TestJmp8Bit(node) &&
- !is_ia32_xCmpSet(node) &&
- !is_ia32_xCmpJmp(node) &&
- !is_ia32_CmpCMov(node) &&
- !is_ia32_CmpCMov8Bit(node) &&
- !is_ia32_TestCMov(node) &&
- !is_ia32_TestCMov8Bit(node) &&
- !is_ia32_CmpSet(node) &&
- !is_ia32_TestSet(node);
-}
-
static
const char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode,
const arch_register_t *reg) {
be_emit_char(env, 'x');
}
+void ia32_emit_8bit_dest_register(ia32_emit_env_t *env, const ir_node *node,
+ int pos)
+{
+ const arch_register_t *reg = get_out_reg(env, node, pos);
+ const char *reg_name = arch_register_get_name(reg);
+
+ be_emit_char(env, '%');
+ be_emit_char(env, reg_name[1]);
+ be_emit_char(env, 'l');
+}
+
void ia32_emit_source_register_or_immediate(ia32_emit_env_t *env,
const ir_node *node, int pos)
{
/**
* Emits registers and/or address mode of a binary operation.
*/
-void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) {
+void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node, int produces_result) {
const ir_node *right_op = get_irn_n(node, n_ia32_binary_right);
switch(get_ia32_op_type(node)) {
} else {
const arch_register_t *in1 = get_in_reg(env, node, n_ia32_binary_left);
const arch_register_t *in2 = get_in_reg(env, node, n_ia32_binary_right);
- const arch_register_t *out = produces_result(node) ? get_out_reg(env, node, 0) : NULL;
+ const arch_register_t *out = produces_result ? get_out_reg(env, node, 0) : NULL;
const arch_register_t *in;
const char *in_name;
break;
case ia32_AddrModeS:
if(is_ia32_Immediate(right_op)) {
- assert(!produces_result(node) &&
- "Source AM with Const must not produce result");
+ assert(!produces_result && "Source AM with Const must not produce result");
emit_ia32_Immediate(env, right_op);
be_emit_cstring(env, ", ");
ia32_emit_am(env, node);
- } else if (produces_result(node)) {
+ } else if (produces_result) {
ia32_emit_am(env, node);
be_emit_cstring(env, ", ");
ia32_emit_dest_register(env, node, 0);
}
break;
case ia32_AddrModeS:
- case ia32_AddrModeD:
ia32_emit_am(env, node);
break;
+ case ia32_AddrModeD:
default:
assert(0 && "unsupported op type");
}
*/
struct cmp2conditon_t {
const char *name;
- pn_Cmp num;
+ int num;
};
/*
* positive conditions for signed compares
*/
-static
-const struct cmp2conditon_t cmp2condition_s[] = {
+static const struct cmp2conditon_t cmp2condition_s[] = {
{ NULL, pn_Cmp_False }, /* always false */
{ "e", pn_Cmp_Eq }, /* == */
{ "l", pn_Cmp_Lt }, /* < */
{ "g", pn_Cmp_Gt }, /* > */
{ "ge", pn_Cmp_Ge }, /* >= */
{ "ne", pn_Cmp_Lg }, /* != */
- { NULL, pn_Cmp_Leg}, /* Floating point: ordered */
+ { NULL, pn_Cmp_Leg}, /* always true */
};
/*
* positive conditions for unsigned compares
*/
-static
-const struct cmp2conditon_t cmp2condition_u[] = {
+static const struct cmp2conditon_t cmp2condition_u[] = {
{ NULL, pn_Cmp_False }, /* always false */
{ "e", pn_Cmp_Eq }, /* == */
{ "b", pn_Cmp_Lt }, /* < */
{ "a", pn_Cmp_Gt }, /* > */
{ "ae", pn_Cmp_Ge }, /* >= */
{ "ne", pn_Cmp_Lg }, /* != */
- { NULL, pn_Cmp_True }, /* always true */
+ { NULL, pn_Cmp_Leg }, /* always true */
};
-/*
- * returns the condition code
+enum {
+ ia32_pn_Cmp_unsigned = 0x1000,
+ ia32_pn_Cmp_float = 0x2000,
+};
+
+/**
+ * walks up a tree of copies/perms/spills/reloads to find the original value
+ * that is moved around
*/
-static
-const char *get_cmp_suffix(pn_Cmp cmp_code)
+static ir_node *find_original_value(ir_node *node)
+{
+ inc_irg_visited(current_ir_graph);
+ while(1) {
+ mark_irn_visited(node);
+ if(be_is_Copy(node)) {
+ node = be_get_Copy_op(node);
+ } else if(be_is_CopyKeep(node)) {
+ node = be_get_CopyKeep_op(node);
+ } else if(is_Proj(node)) {
+ ir_node *pred = get_Proj_pred(node);
+ if(be_is_Perm(pred)) {
+ node = get_irn_n(pred, get_Proj_proj(node));
+ } else if(be_is_MemPerm(pred)) {
+ node = get_irn_n(pred, get_Proj_proj(node) + 1);
+ } else if(is_ia32_Load(pred)) {
+ node = get_irn_n(pred, n_ia32_Load_mem);
+ } else {
+ return node;
+ }
+ } else if(is_Store(node)) {
+ node = get_irn_n(node, n_ia32_Store_val);
+ } else if(is_Phi(node)) {
+ int i, arity;
+ arity = get_irn_arity(node);
+ for(i = 0; i < arity; ++i) {
+ ir_node *in = get_irn_n(node, i);
+ if(irn_visited(in))
+ continue;
+ node = in;
+ break;
+ }
+ assert(i < arity);
+ } else {
+ return node;
+ }
+ }
+}
+
+static int determine_final_pnc(const ir_node *node, int flags_pos,
+ int pnc)
{
- assert( (cmp2condition_s[cmp_code & 7].num) == (cmp_code & 7));
- assert( (cmp2condition_u[cmp_code & 7].num) == (cmp_code & 7));
+ ir_node *flags = get_irn_n(node, flags_pos);
+ const ia32_attr_t *flags_attr;
+ flags = skip_Proj(flags);
+
+ 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)) {
+ cmp = find_original_value(cmp);
+ assert(is_ia32_FucomFnstsw(cmp) || is_ia32_FucompFnstsw(cmp)
+ || is_ia32_FucomppFnstsw(cmp));
+ }
- if((cmp_code & ia32_pn_Cmp_Unsigned)) {
- return cmp2condition_u[cmp_code & 7].name;
+ flags_attr = get_ia32_attr_const(cmp);
+ if(flags_attr->data.cmp_flipped)
+ pnc = get_mirrored_pnc(pnc);
+ pnc |= ia32_pn_Cmp_float;
+ } else if(is_ia32_Ucomi(flags)) {
+ flags_attr = get_ia32_attr_const(flags);
+
+ if(flags_attr->data.cmp_flipped)
+ pnc = get_mirrored_pnc(pnc);
+ pnc |= ia32_pn_Cmp_float;
} else {
- return cmp2condition_s[cmp_code & 7].name;
+ assert(is_ia32_Cmp(flags) || is_ia32_Test(flags)
+ || is_ia32_Cmp8Bit(flags) || is_ia32_Test8Bit(flags));
+ flags_attr = get_ia32_attr_const(flags);
+
+ if(flags_attr->data.cmp_flipped)
+ pnc = get_mirrored_pnc(pnc);
+ if(flags_attr->data.cmp_unsigned)
+ pnc |= ia32_pn_Cmp_unsigned;
}
+
+ return pnc;
}
-void ia32_emit_cmp_suffix(ia32_emit_env_t *env, long pnc)
+static void ia32_emit_cmp_suffix(ia32_emit_env_t *env, int pnc)
{
- be_emit_string(env, get_cmp_suffix(pnc));
+ const char *str;
+
+ if((pnc & ia32_pn_Cmp_float) || (pnc & ia32_pn_Cmp_unsigned)) {
+ pnc = pnc & 7;
+ assert(cmp2condition_u[pnc].num == pnc);
+ str = cmp2condition_u[pnc].name;
+ } else {
+ pnc = pnc & 7;
+ assert(cmp2condition_s[pnc].num == pnc);
+ str = cmp2condition_s[pnc].name;
+ }
+
+ be_emit_string(env, str);
}
+void ia32_emit_cmp_suffix_node(ia32_emit_env_t *env, const ir_node *node,
+ int flags_pos)
+{
+ pn_Cmp pnc = get_ia32_pncode(node);
+
+ pnc = determine_final_pnc(node, flags_pos, pnc);
+ ia32_emit_cmp_suffix(env, pnc);
+}
/**
* Returns the target block for a control flow node.
/**
* Returns the Proj with projection number proj and NOT mode_M
*/
-static
-ir_node *get_proj(const ir_node *node, long proj) {
+static ir_node *get_proj(const ir_node *node, long proj) {
const ir_edge_t *edge;
ir_node *src;
/**
* Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
*/
-static
-void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode,
- long pnc) {
+static void emit_ia32_Jcc(ia32_emit_env_t *env, const ir_node *node)
+{
const ir_node *proj_true;
const ir_node *proj_false;
const ir_node *block;
const ir_node *next_block;
- int flipped = 0;
+ pn_Cmp pnc = get_ia32_pncode(node);
- /* get both Proj's */
- proj_true = get_proj(node, pn_Cond_true);
- assert(proj_true && "CondJmp without true Proj");
+ pnc = determine_final_pnc(node, 0, pnc);
- proj_false = get_proj(node, pn_Cond_false);
- assert(proj_false && "CondJmp without false Proj");
+ /* get both Projs */
+ proj_true = get_proj(node, pn_ia32_Jcc_true);
+ assert(proj_true && "Jcc without true Proj");
- /* for now, the code works for scheduled and non-schedules blocks */
- block = get_nodes_block(node);
+ proj_false = get_proj(node, pn_ia32_Jcc_false);
+ assert(proj_false && "Jcc without false Proj");
- /* we have a block schedule */
+ block = get_nodes_block(node);
next_block = next_blk_sched(block);
if (get_cfop_target_block(proj_true) == next_block) {
proj_true = proj_false;
proj_false = t;
- flipped = 1;
- pnc = get_negated_pnc(pnc, mode);
+ if(pnc & ia32_pn_Cmp_float) {
+ pnc = get_negated_pnc(pnc, mode_F);
+ } else {
+ pnc = get_negated_pnc(pnc, mode_Iu);
+ }
}
- if (mode_is_float(mode)) {
- /* Some floating point comparisons require a test of the parity flag, which
- * indicates that the result is unordered */
- switch (pnc & ~ia32_pn_Cmp_Unsigned) {
+ if (pnc & ia32_pn_Cmp_float) {
+ /* Some floating point comparisons require a test of the parity flag,
+ * which indicates that the result is unordered */
+ switch (pnc & 15) {
case pn_Cmp_Uo:
be_emit_cstring(env, "\tjp ");
ia32_emit_cfop_target(env, proj_true);
be_emit_cstring(env, "\tjp ");
ia32_emit_cfop_target(env, proj_false);
be_emit_finish_line_gas(env, proj_false);
- goto float_jcc;
+ goto emit_jcc;
case pn_Cmp_Ug:
case pn_Cmp_Uge:
be_emit_cstring(env, "\tjp ");
ia32_emit_cfop_target(env, proj_true);
be_emit_finish_line_gas(env, proj_true);
- goto float_jcc;
+ goto emit_jcc;
default:
- float_jcc:
- /* The bits set by floating point compares correspond to unsigned
- * comparisons */
- pnc |= ia32_pn_Cmp_Unsigned;
goto emit_jcc;
}
} else {
}
}
-/**
- * Emits code for conditional jump.
- */
-static
-void CondJmp_emitter(ia32_emit_env_t *env, const ir_node *node) {
- be_emit_cstring(env, "\tcmp");
- ia32_emit_mode_suffix(env, node);
- be_emit_char(env, ' ');
- ia32_emit_binop(env, node);
- be_emit_finish_line_gas(env, node);
-
- finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node));
-}
-
-/**
- * Emits code for conditional jump with two variables.
- */
-static
-void emit_ia32_CmpJmp(ia32_emit_env_t *env, const ir_node *node) {
- CondJmp_emitter(env, node);
-}
-
-/**
- * Emits code for conditional test and jump.
- */
-static
-void TestJmp_emitter(ia32_emit_env_t *env, const ir_node *node) {
- be_emit_cstring(env, "\ttest");
- ia32_emit_mode_suffix(env, node);
- be_emit_char(env, ' ');
-
- ia32_emit_binop(env, node);
- be_emit_finish_line_gas(env, node);
-
- finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node));
-}
-
-/**
- * Emits code for conditional test and jump with two variables.
- */
-static
-void emit_ia32_TestJmp(ia32_emit_env_t *env, const ir_node *node) {
- TestJmp_emitter(env, node);
-}
-
+#if 0
/**
* Emits code for conditional SSE floating point jump with two variables.
*/
be_emit_cstring(env, "\tucomi");
ia32_emit_xmm_mode_suffix(env, node);
be_emit_char(env, ' ');
- ia32_emit_binop(env, node);
+ ia32_emit_binop(env, node, 0);
be_emit_finish_line_gas(env, node);
finish_CondJmp(env, node, mode_F, get_ia32_pncode(node));
finish_CondJmp(env, node, mode_E, pnc);
}
+#endif
-static
-void CMov_emitter(ia32_emit_env_t *env, const ir_node *node)
+static void emit_ia32_CMov(ia32_emit_env_t *env, const ir_node *node)
{
- const arch_register_t *in1, *in2, *out;
- long pnc = get_ia32_pncode(node);
-
- out = arch_get_irn_register(env->arch_env, node);
-
- /* we have to emit the cmp first, because the destination register */
- /* could be one of the compare registers */
- if (is_ia32_xCmpCMov(node)) {
- be_emit_cstring(env, "\tucomis");
- ia32_emit_mode_suffix_mode(env, get_irn_mode(node));
- be_emit_char(env, ' ');
- ia32_emit_source_register(env, node, 1);
- be_emit_cstring(env, ", ");
- ia32_emit_source_register(env, node, 0);
-
- in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, 2));
- in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, 3));
+ const arch_register_t *out = arch_get_irn_register(env->arch_env, 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);
+
+ in_true = arch_get_irn_register(env->arch_env,
+ get_irn_n(node, n_ia32_CMov_val_true));
+ in_false = arch_get_irn_register(env->arch_env,
+ get_irn_n(node, n_ia32_CMov_val_false));
+
+ /* should be same constraint fullfilled? */
+ if(out == in_false) {
+ /* yes -> nothing to do */
+ } else if(out == in_true) {
+ const arch_register_t *tmp;
+
+ /* swap left/right and negate pnc */
+ pnc = get_negated_pnc(pnc, mode_Iu);
+
+ tmp = in_true;
+ in_true = in_false;
+ in_false = tmp;
} else {
- if (is_ia32_CmpCMov(node) || is_ia32_CmpCMov8Bit(node)) {
- be_emit_cstring(env, "\tcmp ");
- } else {
- assert(is_ia32_TestCMov(node) || is_ia32_TestCMov8Bit(node));
- be_emit_cstring(env, "\ttest ");
- }
- ia32_emit_binop(env, node);
-
- in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, 5));
- in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, 6));
- }
- be_emit_finish_line_gas(env, node);
-
- if (out == in2) {
- /* best case: default in == out -> do nothing */
- } else if(in2 == &ia32_gp_regs[REG_GP_UKNWN]) {
- /* also nothign to do for unknown regs */
- } else if (out == in1) {
- const arch_register_t *t;
- /* true in == out -> need complement compare and exchange true and
- * default in */
- t = in1;
- in1 = in2;
- in2 = t;
- pnc = get_negated_pnc(pnc, get_irn_mode(node));
- } else {
- /* out is different from both ins: need copy default -> out */
+ /* we need a mov */
be_emit_cstring(env, "\tmovl ");
- ia32_emit_register(env, in2);
+ ia32_emit_register(env, in_false);
be_emit_cstring(env, ", ");
ia32_emit_register(env, out);
be_emit_finish_line_gas(env, node);
}
be_emit_cstring(env, "\tcmov");
- ia32_emit_cmp_suffix(env, pnc );
- be_emit_cstring(env, "l ");
- ia32_emit_register(env, in1);
- be_emit_cstring(env, ", ");
- ia32_emit_register(env, out);
-
- be_emit_finish_line_gas(env, node);
-}
-
-static
-void emit_ia32_CmpCMov(ia32_emit_env_t *env, const ir_node *node)
-{
- CMov_emitter(env, node);
-}
-
-static
-void emit_ia32_TestCMov(ia32_emit_env_t *env, const ir_node *node)
-{
- CMov_emitter(env, node);
-}
-
-static
-void emit_ia32_xCmpCMov(ia32_emit_env_t *env, const ir_node *node)
-{
- CMov_emitter(env, node);
-}
-
-static
-void Set_emitter(ia32_emit_env_t *env, const ir_node *node)
-{
- long pnc = get_ia32_pncode(node);
- const char *reg8bit;
- const arch_register_t *out;
-
- out = arch_get_irn_register(env->arch_env, node);
- reg8bit = ia32_get_mapped_reg_name(env->isa->regs_8bit, out);
-
- if(is_ia32_xCmpSet(node)) {
- be_emit_cstring(env, "\tucomis");
- ia32_emit_mode_suffix_mode(env, get_irn_mode(get_irn_n(node, n_ia32_binary_left)));
- be_emit_char(env, ' ');
- ia32_emit_binop(env, node);
+ ia32_emit_cmp_suffix(env, pnc);
+ be_emit_char(env, ' ');
+ if(get_ia32_op_type(node) == ia32_AddrModeS) {
+ ia32_emit_am(env, node);
} else {
- if (is_ia32_CmpSet(node) || is_ia32_CmpSet8Bit(node)) {
- be_emit_cstring(env, "\tcmp");
- } else {
- assert(is_ia32_TestSet(node) || is_ia32_TestSet8Bit(node));
- be_emit_cstring(env, "\ttest");
- }
- ia32_emit_mode_suffix(env, node);
- be_emit_char(env, ' ');
- ia32_emit_binop(env, node);
+ ia32_emit_register(env, in_true);
}
+ be_emit_cstring(env, ", ");
+ ia32_emit_register(env, out);
be_emit_finish_line_gas(env, node);
-
- be_emit_cstring(env, "\tset");
- ia32_emit_cmp_suffix(env, pnc);
- be_emit_cstring(env, " %");
- be_emit_string(env, reg8bit);
- be_emit_finish_line_gas(env, node);
-}
-
-static
-void emit_ia32_CmpSet(ia32_emit_env_t *env, const ir_node *node) {
- Set_emitter(env, node);
-}
-
-static
-void emit_ia32_TestSet(ia32_emit_env_t *env, const ir_node *node) {
- Set_emitter(env, node);
-}
-
-static
-void emit_ia32_xCmpSet(ia32_emit_env_t *env, const ir_node *node) {
- Set_emitter(env, node);
}
+#if 0
static
void emit_ia32_xCmp(ia32_emit_env_t *env, const ir_node *node) {
int sse_pnc = -1;
be_emit_finish_line_gas(env, node);
be_emit_cstring(env, "\tcmpsd $3, ");
- ia32_emit_binop(env, node);
+ ia32_emit_binop(env, node, 0);
be_emit_finish_line_gas(env, node);
be_emit_cstring(env, "\tmovsd ");
be_emit_cstring(env, "\tcmpsd ");
be_emit_irprintf(env->emit, "%d, ", sse_pnc);
- ia32_emit_binop(env, node);
+ ia32_emit_binop(env, node, 0);
be_emit_finish_line_gas(env, node);
if (unord && sse_pnc != 3) {
be_emit_finish_line_gas(env, node);
}
}
+#endif
/*********************************************************
* _ _ _
/* a zero? */
if(attr->symconst == NULL && attr->offset == 0) {
- if (env->isa->opt_arch == arch_pentium_4) {
- /* P4 prefers sub r, r, others xor r, r */
- be_emit_cstring(env, "\tsubl ");
- } else {
- be_emit_cstring(env, "\txorl ");
- }
+ assert(get_ia32_flags(node) & arch_irn_flags_modify_flags);
+ be_emit_cstring(env, "\txorl ");
ia32_emit_dest_register(env, node, 0);
be_emit_cstring(env, ", ");
ia32_emit_dest_register(env, node, 0);
/* helper function for emit_ia32_Minus64Bit */
static void emit_zero(ia32_emit_env_t *env, const ir_node* node, const arch_register_t *reg)
{
- if (env->isa->opt_arch == arch_pentium_4) {
- /* P4 prefers sub r, r, others xor r, r */
- be_emit_cstring(env, "\tsubl ");
- } else {
- be_emit_cstring(env, "\txorl ");
- }
+ be_emit_cstring(env, "\txorl ");
ia32_emit_register(env, reg);
be_emit_cstring(env, ", ");
ia32_emit_register(env, reg);
/* other ia32 emitter functions */
IA32_EMIT(Asm);
- IA32_EMIT(CmpJmp);
- IA32_EMIT2(CmpJmp8Bit, CmpJmp);
- IA32_EMIT(TestJmp);
- IA32_EMIT2(TestJmp8Bit, TestJmp);
- IA32_EMIT(CmpCMov);
- IA32_EMIT2(CmpCMov8Bit, CmpCMov);
- IA32_EMIT(TestCMov);
- IA32_EMIT2(TestCMov8Bit, TestCMov);
- IA32_EMIT(CmpSet);
- IA32_EMIT2(CmpSet8Bit, CmpSet);
- IA32_EMIT(TestSet);
- IA32_EMIT2(TestSet8Bit, TestSet);
+ IA32_EMIT(CMov);
IA32_EMIT(SwitchJmp);
IA32_EMIT(CopyB);
IA32_EMIT(CopyB_i);
IA32_EMIT(Const);
IA32_EMIT(LdTls);
IA32_EMIT(Minus64Bit);
+ IA32_EMIT(Jcc);
+#if 0
IA32_EMIT(xCmp);
- IA32_EMIT(xCmpSet);
- IA32_EMIT(xCmpCMov);
IA32_EMIT(xCmpJmp);
IA32_EMIT2(fcomJmp, x87CmpJmp);
IA32_EMIT2(fcompJmp, x87CmpJmp);
IA32_EMIT2(fcomrJmp, x87CmpJmp);
IA32_EMIT2(fcomrpJmp, x87CmpJmp);
IA32_EMIT2(fcomrppJmp, x87CmpJmp);
+#endif
/* benode emitter */
BE_EMIT(Call);
void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos);
void ia32_emit_8bit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos);
void ia32_emit_16bit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos);
+void ia32_emit_8bit_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos);
void ia32_emit_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos);
void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos);
void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node);
void ia32_emit_xmm_mode_suffix(ia32_emit_env_t *env, const ir_node *node);
void ia32_emit_xmm_mode_suffix_s(ia32_emit_env_t *env, const ir_node *node);
void ia32_emit_extend_suffix(ia32_emit_env_t *env, const ir_mode *mode);
-void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node);
+void ia32_emit_cmp_suffix_node(ia32_emit_env_t *env, const ir_node *node,
+ int flags_pos);
+void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node, int produces_result);
void ia32_emit_am_or_dest_register(ia32_emit_env_t *env, const ir_node *node,
int pos);
void ia32_emit_unop(ia32_emit_env_t *env, const ir_node *node, int pos);
return ! is_ia32_Lea(irn) &&
! is_ia32_Conv_I2I(irn) &&
! is_ia32_Conv_I2I8Bit(irn) &&
- ! is_ia32_TestCMov(irn) &&
- ! is_ia32_CmpCMov(irn);
+ ! is_ia32_CMov(irn);
}
/**
}
}
}
-
- /* check xCmp: try to avoid unordered cmp */
- if ((is_ia32_xCmp(node) || is_ia32_xCmpCMov(node) || is_ia32_xCmpSet(node)) &&
- op_tp == ia32_Normal)
- {
- long pnc = get_ia32_pncode(node);
-
- if (pnc & pn_Cmp_Uo) {
- ir_node *tmp;
- int idx1 = n_ia32_binary_left;
- int idx2 = n_ia32_binary_right;
-
- if (is_ia32_xCmpCMov(node)) {
- idx1 = 0;
- idx2 = 1;
- }
-
- /** Matze: TODO this looks wrong, I assume we should exchange
- * the proj numbers and not the inputs... */
-
- tmp = get_irn_n(node, idx1);
- set_irn_n(node, idx1, get_irn_n(node, idx2));
- set_irn_n(node, idx2, tmp);
-
- set_ia32_pncode(node, get_negated_pnc(pnc, mode_E));
- }
- }
}
/**
if(is_ia32_SwitchJmp(n) || is_ia32_CopyB(n) || is_ia32_CopyB_i(n)) {
fprintf(F, "pn_code = %ld\n", get_ia32_pncode(n));
} else {
- if(get_ia32_pncode(n) & ia32_pn_Cmp_Unsigned) {
- long pnc = get_ia32_pncode(n);
- fprintf(F, "pn_code = %ld (%s, unsigned)\n",
- pnc, get_pnc_string(pnc & ~ia32_pn_Cmp_Unsigned));
- } else {
- fprintf(F, "pn_code = %ld (%s)\n", get_ia32_pncode(n),
- get_pnc_string(get_ia32_pncode(n)));
- }
+ fprintf(F, "pn_code = %ld (%s)\n", get_ia32_pncode(n),
+ get_pnc_string(get_ia32_pncode(n)));
}
/* dump n_res */
void ia32_swap_left_right(ir_node *node)
{
- ir_node *left = get_irn_n(node, n_ia32_binary_left);
- ir_node *right = get_irn_n(node, n_ia32_binary_right);
+ ia32_attr_t *attr = get_ia32_attr(node);
+ ir_node *left = get_irn_n(node, n_ia32_binary_left);
+ ir_node *right = get_irn_n(node, n_ia32_binary_right);
+
+ attr->data.cmp_flipped = !attr->data.cmp_flipped;
assert(is_ia32_commutative(node));
set_irn_n(node, n_ia32_binary_left, right);
set_irn_n(node, n_ia32_binary_right, left);
if (a->data.except_label != b->data.except_label)
return 1;
+ if (a->data.cmp_flipped != b->data.cmp_flipped
+ || a->data.cmp_unsigned != b->data.cmp_unsigned)
+ return 1;
+
return 0;
}
ia32_S = (1 << 3) /**< S - Scale is set */
};
-enum {
- ia32_pn_Cmp_Unsigned = 0x100 /**< set this flag in a pnc to indicate an unsigned compare operation */
-};
-
#ifndef NDEBUG
typedef enum {
IA32_ATTR_INVALID = 0,
unsigned need_stackent:1; /**< Set to 1 if node need space on stack. */
unsigned need_64bit_stackent:1; /**< needs a 64bit stack entity (see double->unsigned int conv) */
unsigned need_32bit_stackent:1; /**< needs a 32bit stack entity */
+ unsigned cmp_flipped : 1;
+ unsigned cmp_unsigned : 1;
} data;
int *out_flags; /**< flags for each produced value */
{ name => "mm5", type => 4 },
{ name => "mm6", type => 4 },
{ name => "mm7", type => 4 },
- { mode => "mode_E", flags => "manual_ra" }
+ { mode => "mode_E", flags => "manual_ra" }
],
xmm => [
{ name => "xmm0", type => 1 },
{ name => "st5", realname => "st(5)", type => 4 },
{ name => "st6", realname => "st(6)", type => 4 },
{ name => "st7", realname => "st(7)", type => 4 },
- { mode => "mode_E", flags => "manual_ra" }
+ { mode => "mode_E", flags => "manual_ra" }
],
fp_cw => [ # the floating point control word
- { name => "fpcw", type => 4 | 32},
- { mode => "mode_fpcw", flags => "manual_ra|state" }
+ { name => "fpcw", type => 4|32 },
+ { mode => "mode_fpcw", flags => "manual_ra|state" }
],
flags => [
- { name => "eflags", type => 4 },
- { mode => "mode_Iu", flags => "manual_ra" }
+ { name => "eflags", type => 0 },
+ { mode => "mode_Iu", flags => "manual_ra" }
],
); # %reg_classes
D3 => "${arch}_emit_dest_register(env, node, 3);",
D4 => "${arch}_emit_dest_register(env, node, 4);",
D5 => "${arch}_emit_dest_register(env, node, 5);",
+ DB0 => "${arch}_emit_8bit_dest_register(env, node, 0);",
X0 => "${arch}_emit_x87_name(env, node, 0);",
X1 => "${arch}_emit_x87_name(env, node, 1);",
X2 => "${arch}_emit_x87_name(env, node, 2);",
unop5 => "${arch}_emit_unop(env, node, 5);",
DAM0 => "${arch}_emit_am_or_dest_register(env, node, 0);",
DAM1 => "${arch}_emit_am_or_dest_register(env, node, 1);",
- binop => "${arch}_emit_binop(env, node);",
+ binop => "${arch}_emit_binop(env, node, 1);",
+ binop_nores => "${arch}_emit_binop(env, node, 0);",
x87_binop => "${arch}_emit_x87_binop(env, node);",
+ CMP0 => "${arch}_emit_cmp_suffix_node(env, node, 0);",
);
#--------------------------------------------------#
$mode_xmm = "mode_E";
$mode_gp = "mode_Iu";
+$mode_flags = "mode_Iu";
$mode_fpcw = "mode_fpcw";
$status_flags = [ "CF", "PF", "AF", "ZF", "SF", "OF" ];
$fpcw_flags = [ "FP_IM", "FP_DM", "FP_ZM", "FP_OM", "FP_UM", "FP_PM",
modified_flags => $status_flags
},
+AddMem8Bit => {
+ irn_flags => "R",
+ reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] },
+ ins => [ "base", "index", "mem", "val" ],
+ emit => ". add%M %SB3, %AM",
+ units => [ "GP" ],
+ mode => "mode_M",
+ modified_flags => $status_flags
+},
+
Adc => {
reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "flags" ], out => [ "in_r4" ] },
ins => [ "base", "index", "mem", "left", "right", "eflags" ],
modified_flags => $status_flags
},
+AndMem8Bit => {
+ irn_flags => "R",
+ reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] },
+ ins => [ "base", "index", "mem", "val" ],
+ emit => '. and%M %SB3, %AM',
+ units => [ "GP" ],
+ mode => "mode_M",
+ modified_flags => $status_flags
+},
+
Or => {
irn_flags => "R",
reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4" ] },
modified_flags => $status_flags
},
+OrMem8Bit => {
+ irn_flags => "R",
+ reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] },
+ ins => [ "base", "index", "mem", "val" ],
+ emit => '. or%M %SB3, %AM',
+ units => [ "GP" ],
+ mode => "mode_M",
+ modified_flags => $status_flags
+},
+
Xor => {
irn_flags => "R",
reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4" ] },
modified_flags => $status_flags
},
+XorMem8Bit => {
+ irn_flags => "R",
+ reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] },
+ ins => [ "base", "index", "mem", "val" ],
+ emit => '. xor%M %SB3, %AM',
+ units => [ "GP" ],
+ mode => "mode_M",
+ modified_flags => $status_flags
+},
+
# not commutative operations
Sub => {
modified_flags => $status_flags
},
+SubMem8Bit => {
+ irn_flags => "R",
+ reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx" ], out => [ "none" ] },
+ ins => [ "base", "index", "mem", "val" ],
+ emit => '. sub%M %SB3, %AM',
+ units => [ "GP" ],
+ mode => 'mode_M',
+ modified_flags => $status_flags
+},
+
Sbb => {
reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "in_r4 !in_r5" ] },
ins => [ "base", "index", "mem", "left", "right" ],
# other operations
-CmpJmp => {
- state => "pinned",
- op_flags => "L|X|Y",
- reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "none", "none"] },
+Cmp => {
+ irn_flags => "R",
+ reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ] , out => [ "flags" ] },
ins => [ "base", "index", "mem", "left", "right" ],
- outs => [ "false", "true" ],
- attr => "long pnc",
+ outs => [ "eflags" ],
am => "source,binary",
- init_attr => "attr->pn_code = pnc;",
- latency => 3,
- units => [ "BRANCH" ],
+ emit => '. cmp%M %binop_nores',
+ attr => "int flipped, int cmp_unsigned",
+ init_attr => "attr->data.cmp_flipped = flipped;\n".
+ "\tattr->data.cmp_unsigned = cmp_unsigned;\n",
+ latency => 1,
+ units => [ "GP" ],
+ mode => $mode_flags,
+ modified_flags => $status_flags
},
-CmpJmp8Bit => {
- state => "pinned",
- op_flags => "L|X|Y",
- reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ], out => [ "none", "none"] },
+Cmp8Bit => {
+ irn_flags => "R",
+ reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , out => [ "flags" ] },
ins => [ "base", "index", "mem", "left", "right" ],
- outs => [ "false", "true" ],
- attr => "long pnc",
+ outs => [ "eflags" ],
am => "source,binary",
- init_attr => "attr->pn_code = pnc;",
- latency => 3,
- units => [ "BRANCH" ],
+ emit => '. cmpb %binop_nores',
+ attr => "int flipped, int cmp_unsigned",
+ init_attr => "attr->data.cmp_flipped = flipped;\n".
+ "\tattr->data.cmp_unsigned = cmp_unsigned;\n",
+ latency => 1,
+ units => [ "GP" ],
+ mode => $mode_flags,
+ modified_flags => $status_flags
},
-TestJmp => {
- state => "pinned",
- op_flags => "L|X|Y",
- reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "none", "none" ] },
+Test => {
+ irn_flags => "R",
+ reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ] , out => [ "flags" ] },
ins => [ "base", "index", "mem", "left", "right" ],
- outs => [ "false", "true" ],
- attr => "long pnc",
+ outs => [ "eflags" ],
am => "source,binary",
+ emit => '. test%M %binop_nores',
+ attr => "int flipped, int cmp_unsigned",
+ init_attr => "attr->data.cmp_flipped = flipped;\n".
+ "\tattr->data.cmp_unsigned = cmp_unsigned;\n",
+ latency => 1,
+ units => [ "GP" ],
+ mode => $mode_flags,
+ modified_flags => $status_flags
+},
+
+Test8Bit => {
+ irn_flags => "R",
+ reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ] , out => [ "flags" ] },
+ ins => [ "base", "index", "mem", "left", "right" ],
+ outs => [ "eflags" ],
+ am => "source,binary",
+ emit => '. testb %binop_nores',
+ attr => "int flipped, int cmp_unsigned",
+ init_attr => "attr->data.cmp_flipped = flipped;\n".
+ "\tattr->data.cmp_unsigned = cmp_unsigned;\n",
+ latency => 1,
+ units => [ "GP" ],
+ mode => $mode_flags,
+ modified_flags => $status_flags
+},
+
+Set => {
+ #irn_flags => "R",
+ reg_req => { in => [ "eflags" ], out => [ "eax ebx ecx edx" ] },
+ ins => [ "eflags" ],
+ am => "dest,unary",
+ attr => "pn_Cmp pnc",
init_attr => "attr->pn_code = pnc;",
- latency => 3,
- units => [ "BRANCH" ],
+ emit => '. set%CMP0 %DB0',
+ latency => 1,
+ units => [ "GP" ],
+ mode => $mode_gp,
+},
+
+CMov => {
+ #irn_flags => "R",
+ # (note: leave the false,true order intact to make it compatible with other
+ # ia32_binary ops)
+ reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "eflags" ], out => [ "in_r4" ] },
+ ins => [ "base", "index", "mem", "val_false", "val_true", "eflags" ],
+ am => "source,binary",
+ attr => "pn_Cmp pn_code",
+ init_attr => "attr->pn_code = pn_code;",
+ latency => 1,
+ units => [ "GP" ],
+ mode => $mode_gp,
},
-TestJmp8Bit => {
+Jcc => {
state => "pinned",
op_flags => "L|X|Y",
- reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ], out => [ "none", "none" ] },
- ins => [ "base", "index", "mem", "left", "right" ],
+ reg_req => { in => [ "eflags" ], out => [ "none", "none" ] },
+ ins => [ "eflags" ],
outs => [ "false", "true" ],
- attr => "long pnc",
- am => "source,binary",
+ attr => "pn_Cmp pnc",
init_attr => "attr->pn_code = pnc;",
- latency => 3,
+ latency => 2,
units => [ "BRANCH" ],
},
latency => 3,
units => [ "BRANCH" ],
mode => "mode_T",
+ modified_flags => $status_flags
},
IJmp => {
attr => "ir_entity *symconst, int symconst_sign, long offset",
attr_type => "ia32_immediate_attr_t",
mode => $mode_gp,
+# depends on the const and is set in ia32_transform
+# modified_flags => $status_flags
},
Unknown_GP => {
latency => 2,
units => [ "GP" ],
mode => $mode_gp,
+# well this isn't true for Lea, but we often transform Lea back to Add, Inc
+# or Dec, so we set the flag
+ modified_flags => 1,
},
Push => {
# other operations
-xCmp => {
+Ucomi => {
irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "in_r4 !in_r5" ] },
+ reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "eflags" ] },
ins => [ "base", "index", "mem", "left", "right" ],
+ outs => [ "flags" ],
+ am => "source,binary",
+ attr => "int flipped",
+ init_attr => "attr->data.cmp_flipped = flipped;",
+ emit => ' .ucomi%XXM %binop_nores',
latency => 3,
units => [ "SSE" ],
- mode => "mode_E",
-},
-
-xCmpJmp => {
- state => "pinned",
- op_flags => "L|X|Y",
- reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "none", "none" ] },
- ins => [ "base", "index", "mem", "left", "right" ],
- outs => [ "false", "true" ],
- attr => "long pnc",
- init_attr => "attr->pn_code = pnc;",
- latency => 5,
- units => [ "SSE" ],
+ mode => $mode_flags,
+ modified_flags => 1,
},
# Load / Store
attr => "ir_mode *smaller_mode",
init_attr => "attr->ls_mode = smaller_mode;",
mode => $mode_gp,
- modified_flags => $status_flags
},
Conv_I2I8Bit => {
attr => "ir_mode *smaller_mode",
init_attr => "attr->ls_mode = smaller_mode;",
mode => $mode_gp,
- modified_flags => $status_flags
},
Conv_I2FP => {
mode => "mode_E",
},
-CmpCMov => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "gp", "gp" ], out => [ "in_r7" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right", "val_true", "val_false" ],
- attr => "pn_Cmp pn_code",
- init_attr => "attr->pn_code = pn_code;",
- latency => 2,
- units => [ "GP" ],
- mode => $mode_gp,
-},
-
-CmpCMov8Bit => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "gp", "gp" ], out => [ "in_r7" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right", "val_true", "val_false" ],
- attr => "pn_Cmp pn_code",
- init_attr => "attr->pn_code = pn_code;",
- latency => 2,
- units => [ "GP" ],
- mode => $mode_gp,
-},
-
-TestCMov => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "gp", "gp" ], out => [ "in_r7" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right", "val_true", "val_false" ],
- attr => "pn_Cmp pn_code",
- init_attr => "attr->pn_code = pn_code;",
- latency => 2,
- units => [ "GP" ],
- mode => $mode_gp,
-},
-
-TestCMov8Bit => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "gp", "gp" ], out => [ "in_r7" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right", "val_true", "val_false" ],
- attr => "pn_Cmp pn_code",
- init_attr => "attr->pn_code = pn_code;",
- latency => 2,
- units => [ "GP" ],
- mode => $mode_gp,
-},
-
-xCmpCMov => {
- irn_flags => "R",
- reg_req => { in => [ "xmm", "xmm", "gp", "gp" ], out => [ "in_r4" ] },
- latency => 5,
- units => [ "SSE" ],
- mode => $mode_gp,
-},
-
-vfCmpCMov => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp", "gp", "gp" ], out => [ "in_r7" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right", "val_true", "val_false" ],
- latency => 10,
- units => [ "VFP", "GP" ],
- mode => $mode_gp,
- attr_type => "ia32_x87_attr_t",
-},
-
-CmpSet => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "eax ebx ecx edx" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ],
- attr => "pn_Cmp pn_code",
- init_attr => "attr->pn_code = pn_code;",
- latency => 2,
- units => [ "GP" ],
- mode => $mode_gp,
-},
-
-CmpSet8Bit => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ], out => [ "eax ebx ecx edx" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ],
- attr => "pn_Cmp pn_code",
- init_attr => "attr->pn_code = pn_code;",
- latency => 2,
- units => [ "GP" ],
- mode => $mode_gp,
-},
-
-TestSet => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "gp", "gp" ], out => [ "eax ebx ecx edx" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ],
- attr => "pn_Cmp pn_code",
- init_attr => "attr->pn_code = pn_code;",
- latency => 2,
- units => [ "GP" ],
- mode => $mode_gp,
-},
-
-TestSet8Bit => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "eax ebx ecx edx", "eax ebx ecx edx" ], out => [ "eax ebx ecx edx" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ],
- attr => "pn_Cmp pn_code",
- init_attr => "attr->pn_code = pn_code;",
- latency => 2,
- units => [ "GP" ],
- mode => $mode_gp,
-},
-
-xCmpSet => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "xmm", "xmm" ], out => [ "eax ebx ecx edx" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ],
- latency => 5,
- units => [ "SSE" ],
- mode => $mode_gp,
-},
-
-vfCmpSet => {
- irn_flags => "R",
- reg_req => { in => [ "gp", "gp", "none", "vfp", "vfp" ], out => [ "eax ebx ecx edx" ] },
- ins => [ "base", "index", "mem", "cmp_left", "cmp_right" ],
- latency => 10,
- units => [ "VFP" ],
- mode => $mode_gp,
- attr_type => "ia32_x87_attr_t",
-},
-
-vfCMov => {
- irn_flags => "R",
- reg_req => { in => [ "vfp", "vfp", "vfp", "vfp" ], out => [ "vfp" ] },
- latency => 10,
- units => [ "VFP" ],
- mode => "mode_E",
- attr_type => "ia32_x87_attr_t",
-},
-
#----------------------------------------------------------#
# _ _ _ __ _ _ #
# (_) | | | | / _| | | | #
# other
-vfCmpJmp => {
- state => "pinned",
- op_flags => "L|X|Y",
- reg_req => { in => [ "vfp", "vfp" ], out => [ "none", "none", "eax" ] },
+vFucomFnstsw => {
+# we can't allow to rematerialize this node so we don't have
+# accidently produce Phi(Fucom, Fucom(flipped))
+# irn_flags => "R",
+ reg_req => { in => [ "vfp", "vfp" ], out => [ "eax" ] },
ins => [ "left", "right" ],
- outs => [ "false", "true", "temp_reg_eax" ],
- attr => "long pnc",
- init_attr => "attr->attr.pn_code = pnc;",
- latency => 10,
+ outs => [ "flags" ],
+ am => "source,binary",
+ attr => "int flipped",
+ init_attr => "attr->attr.data.cmp_flipped = flipped;",
+ latency => 3,
units => [ "VFP" ],
attr_type => "ia32_x87_attr_t",
+ mode => $mode_gp
+},
+
+Sahf => {
+ irn_flags => "R",
+ reg_req => { in => [ "eax" ], out => [ "eflags" ] },
+ ins => [ "val" ],
+ outs => [ "flags" ],
+ emit => '. sahf',
+ units => [ "GP" ],
+ mode => $mode_flags,
},
#------------------------------------------------------------------------#
# compare
-fcomJmp => {
- op_flags => "L|X|Y",
- reg_req => { },
- attr_type => "ia32_x87_attr_t",
-},
-
-fcompJmp => {
- op_flags => "L|X|Y",
- reg_req => { },
- attr_type => "ia32_x87_attr_t",
-},
-
-fcomppJmp => {
- op_flags => "L|X|Y",
- reg_req => { },
- attr_type => "ia32_x87_attr_t",
-},
-
-fcomrJmp => {
- op_flags => "L|X|Y",
+FucomFnstsw => {
+ op_flags => "R",
reg_req => { },
+ emit => ". fucom %X1\n".
+ ". fnstsw",
attr_type => "ia32_x87_attr_t",
},
-fcomrpJmp => {
- op_flags => "L|X|Y",
+FucompFnstsw => {
+ op_flags => "R",
reg_req => { },
+ emit => ". fucomp %X1\n".
+ ". fnstsw",
attr_type => "ia32_x87_attr_t",
},
-fcomrppJmp => {
- op_flags => "L|X|Y",
+FucomppFnstsw => {
+ op_flags => "R",
reg_req => { },
+ emit => ". fucompp\n".
+ ". fnstsw",
attr_type => "ia32_x87_attr_t",
},
static INLINE int mode_needs_gp_reg(ir_mode *mode) {
if(mode == mode_fpcw)
return 0;
+ if(get_mode_size_bits(mode) > 32)
+ return 0;
return mode_is_int(mode) || mode_is_reference(mode) || mode == mode_b;
}
cnst = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, val);
SET_IA32_ORIG_NODE(cnst, ia32_get_old_node_name(env_cg, node));
+ if(val == 0) {
+ set_ia32_flags(cnst,
+ get_ia32_flags(cnst) | arch_irn_flags_modify_flags);
+ }
/* see above */
if (get_irg_start_block(irg) == block) {
set_ia32_commutative(node);
}
+typedef enum {
+ match_commutative = 1 << 0,
+ match_am_and_immediates = 1 << 1,
+ match_no_am = 1 << 2,
+ match_8_16_bit_am = 1 << 3
+} match_flags_t;
+
static void match_arguments(ia32_address_mode_t *am, ir_node *block,
- ir_node *op1, ir_node *op2, int commutative,
- int use_am_and_immediates, int use_am,
- int use_8_16_bit_am)
+ ir_node *op1, ir_node *op2, match_flags_t flags)
{
ia32_address_t *addr = &am->addr;
ir_node *noreg_gp = ia32_new_NoReg_gp(env_cg);
ir_node *new_op1;
ir_node *new_op2;
+ int use_am;
+ int commutative;
+ int use_am_and_immediates;
memset(am, 0, sizeof(am[0]));
- if(!use_8_16_bit_am && get_mode_size_bits(get_irn_mode(op1)) < 32)
+ commutative = (flags & match_commutative) != 0;
+ use_am_and_immediates = (flags & match_am_and_immediates) != 0;
+ use_am = ! (flags & match_no_am);
+ if(!(flags & match_8_16_bit_am)
+ && get_mode_size_bits(get_irn_mode(op1)) < 32)
use_am = 0;
new_op2 = try_create_Immediate(op2, 0);
ir_node *new_node;
ia32_address_mode_t am;
ia32_address_t *addr = &am.addr;
+ match_flags_t flags = 0;
- match_arguments(&am, src_block, op1, op2, commutative, 0, 1, 0);
+ if(commutative)
+ flags |= match_commutative;
+
+ match_arguments(&am, src_block, op1, op2, flags);
new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem,
am.new_op1, am.new_op2);
produceval);
} else {
sign_extension = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, 0);
+ set_ia32_flags(sign_extension, get_ia32_flags(sign_extension) | arch_irn_flags_modify_flags);
add_irn_dep(sign_extension, get_irg_frame(irg));
}
static ir_node *dest_am_binop(ir_node *node, ir_node *op1, ir_node *op2,
ir_node *mem, ir_node *ptr, ir_mode *mode,
- construct_binop_dest_func *func, int commutative)
+ construct_binop_dest_func *func,
+ construct_binop_dest_func *func8bit,
+ int commutative)
{
ir_node *src_block = get_nodes_block(node);
ir_node *block;
dbgi = get_irn_dbg_info(node);
block = be_transform_node(src_block);
- new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem, new_op);
+ if(get_mode_size_bits(mode) == 8) {
+ new_node = func8bit(dbgi, irg, block, addr->base, addr->index,
+ addr->mem, new_op);
+ } else {
+ new_node = func(dbgi, irg, block, addr->base, addr->index, addr->mem,
+ new_op);
+ }
set_address(new_node, addr);
set_ia32_op_type(new_node, ia32_AddrModeD);
set_ia32_ls_mode(new_node, mode);
if(!mode_needs_gp_reg(mode))
return NULL;
- /* TODO0000 8bit operations have stricter constraints. This is not handled yet */
- if (get_mode_size_bits(mode) < 16)
- return NULL;
-
/* store must be the only user of the val node */
if(get_irn_n_edges(val) > 1)
return NULL;
break;
}
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
- new_rd_ia32_AddMem, 1);
+ new_rd_ia32_AddMem, new_rd_ia32_AddMem8Bit, 1);
break;
case iro_Sub:
op1 = get_Sub_left(val);
op2 = get_Sub_right(val);
+ if(is_Const(op2)) {
+ ir_fprintf(stderr, "Optimisation warning: not-normalize sub ,C"
+ "found\n");
+ }
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
- new_rd_ia32_SubMem, 0);
+ new_rd_ia32_SubMem, new_rd_ia32_SubMem8Bit, 0);
break;
case iro_And:
op1 = get_And_left(val);
op2 = get_And_right(val);
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
- new_rd_ia32_AndMem, 1);
+ new_rd_ia32_AndMem, new_rd_ia32_AndMem8Bit, 1);
break;
case iro_Or:
op1 = get_Or_left(val);
op2 = get_Or_right(val);
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
- new_rd_ia32_OrMem, 1);
+ new_rd_ia32_OrMem, new_rd_ia32_OrMem8Bit, 1);
break;
case iro_Eor:
op1 = get_Eor_left(val);
op2 = get_Eor_right(val);
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
- new_rd_ia32_XorMem, 1);
+ new_rd_ia32_XorMem, new_rd_ia32_XorMem8Bit, 1);
break;
case iro_Shl:
op1 = get_Shl_left(val);
op2 = get_Shl_right(val);
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
- new_rd_ia32_ShlMem, 0);
+ new_rd_ia32_ShlMem, new_rd_ia32_ShlMem, 0);
break;
case iro_Shr:
op1 = get_Shr_left(val);
op2 = get_Shr_right(val);
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
- new_rd_ia32_ShrMem, 0);
+ new_rd_ia32_ShrMem, new_rd_ia32_ShrMem, 0);
break;
case iro_Shrs:
op1 = get_Shrs_left(val);
op2 = get_Shrs_right(val);
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
- new_rd_ia32_SarMem, 0);
+ new_rd_ia32_SarMem, new_rd_ia32_SarMem, 0);
break;
case iro_Rot:
op1 = get_Rot_left(val);
op2 = get_Rot_right(val);
new_node = dest_am_binop(val, op1, op2, mem, ptr, mode,
- new_rd_ia32_RolMem, 0);
+ new_rd_ia32_RolMem, new_rd_ia32_RolMem, 0);
break;
/* TODO: match ROR patterns... */
case iro_Minus:
new_node = dest_am_unop(val, op1, mem, ptr, mode, new_rd_ia32_NegMem);
break;
case iro_Not:
- /* TODO this would be ^ 1 with DestAM */
- if(mode == mode_b)
- return NULL;
+ /* should be lowered already */
+ assert(mode != mode_b);
op1 = get_Not_op(val);
new_node = dest_am_unop(val, op1, mem, ptr, mode, new_rd_ia32_NotMem);
break;
return new_op;
}
-static ir_node *try_create_TestJmp(ir_node *block, dbg_info *dbgi, long pnc,
- ir_node *cmp_left, ir_node *cmp_right,
- int use_am)
-{
- ir_node *arg_left;
- ir_node *arg_right;
- ir_node *res;
- ir_mode *mode;
- long pure_pnc = pnc & ~ia32_pn_Cmp_Unsigned;
- ia32_address_mode_t am;
- ia32_address_t *addr = &am.addr;
-
- if(cmp_right != NULL && !is_Const_0(cmp_right))
- return NULL;
-
- if(is_And(cmp_left) && (pure_pnc == pn_Cmp_Eq || pure_pnc == pn_Cmp_Lg)) {
- mode = get_irn_mode(cmp_left);
- arg_left = get_And_left(cmp_left);
- arg_right = get_And_right(cmp_left);
- } else {
- mode = get_irn_mode(cmp_left);
- arg_left = cmp_left;
- arg_right = cmp_left;
- }
-
- if(mode == mode_b)
- mode = mode_Iu;
-
- assert(get_mode_size_bits(mode) <= 32);
- match_arguments(&am, block, arg_left, arg_right, 1, 1, use_am, 1);
- if(am.flipped)
- pnc = get_inversed_pnc(pnc);
-
- if(get_mode_size_bits(mode) == 8) {
- res = new_rd_ia32_TestJmp8Bit(dbgi, current_ir_graph, block, addr->base,
- addr->index, addr->mem, am.new_op1,
- am.new_op2, pnc);
- } else {
- res = new_rd_ia32_TestJmp(dbgi, current_ir_graph, block, addr->base,
- addr->index, addr->mem, am.new_op1, am.new_op2,
- pnc);
- }
- set_am_attributes(res, &am);
- set_ia32_ls_mode(res, mode);
-
- res = fix_mem_proj(res, &am);
-
- return res;
-}
-
static ir_node *create_Switch(ir_node *node)
{
ir_graph *irg = current_ir_graph;
return res;
}
-/**
- * Transforms a Cond -> Proj[b] -> Cmp into a CondJmp, CondJmp_i or TestJmp
- *
- * @return The transformed node.
- */
+static ir_node *get_flags_node(ir_node *node, pn_Cmp *pnc_out)
+{
+ ir_graph *irg = current_ir_graph;
+ ir_node *flags;
+ ir_node *new_op;
+ ir_node *noreg;
+ ir_node *nomem;
+ ir_node *new_block;
+ dbg_info *dbgi;
+
+ /* we have a Cmp as input */
+ if(is_Proj(node)) {
+ ir_node *pred = get_Proj_pred(node);
+ if(is_Cmp(pred)) {
+ flags = be_transform_node(pred);
+ *pnc_out = get_Proj_proj(node);
+ return flags;
+ }
+ }
+
+ /* a mode_b value, we have to compare it against 0 */
+ dbgi = get_irn_dbg_info(node);
+ new_block = be_transform_node(get_nodes_block(node));
+ new_op = be_transform_node(node);
+ noreg = ia32_new_NoReg_gp(env_cg);
+ nomem = new_NoMem();
+ flags = new_rd_ia32_Test(dbgi, irg, new_block, noreg, noreg, nomem,
+ new_op, new_op, 0, 0);
+ *pnc_out = pn_Cmp_Lg;
+ return flags;
+}
+
static ir_node *gen_Cond(ir_node *node) {
- ir_node *src_block = get_nodes_block(node);
- ir_node *block = be_transform_node(src_block);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
ir_graph *irg = current_ir_graph;
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *sel = get_Cond_selector(node);
ir_mode *sel_mode = get_irn_mode(sel);
- ir_node *res = NULL;
- ir_node *noreg = ia32_new_NoReg_gp(env_cg);
- ir_node *nomem = new_NoMem();
- ir_node *cmp;
- ir_node *cmp_a;
- ir_node *cmp_b;
- ir_node *new_cmp_a;
- ir_node *new_cmp_b;
- ir_mode *cmp_mode;
- long pnc;
- int use_am;
+ ir_node *res;
+ ir_node *flags = NULL;
+ pn_Cmp pnc;
if (sel_mode != mode_b) {
return create_Switch(node);
}
- if(!is_Proj(sel) || !is_Cmp(get_Proj_pred(sel))) {
- /* it's some mode_b value but not a direct comparison -> create a
- * testjmp */
- res = try_create_TestJmp(block, dbgi, pn_Cmp_Lg, sel, NULL, 1);
- SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
- return res;
- }
-
- /* address mode makes only sense when we're the only user of the cmp */
- use_am = get_irn_n_edges(node) <= 1;
-
- cmp = get_Proj_pred(sel);
- cmp_a = get_Cmp_left(cmp);
- cmp_b = get_Cmp_right(cmp);
- cmp_mode = get_irn_mode(cmp_a);
- pnc = get_Proj_proj(sel);
- if(mode_is_float(cmp_mode) || !mode_is_signed(cmp_mode)) {
- pnc |= ia32_pn_Cmp_Unsigned;
- }
-
- if(mode_needs_gp_reg(cmp_mode)) {
- res = try_create_TestJmp(block, dbgi, pnc, cmp_a, cmp_b, use_am);
- if(res != NULL) {
- SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
- return res;
- }
- }
-
- if (mode_is_float(cmp_mode)) {
- new_cmp_a = be_transform_node(cmp_a);
- new_cmp_b = create_immediate_or_transform(cmp_b, 0);
- if (USE_SSE2(env_cg)) {
- res = new_rd_ia32_xCmpJmp(dbgi, irg, block, noreg, noreg, nomem, cmp_a,
- cmp_b, pnc);
- set_ia32_commutative(res);
- set_ia32_ls_mode(res, cmp_mode);
- } else {
- res = new_rd_ia32_vfCmpJmp(dbgi, irg, block, cmp_a, cmp_b, pnc);
- set_ia32_commutative(res);
- }
- } else {
- ia32_address_mode_t am;
- ia32_address_t *addr = &am.addr;
- match_arguments(&am, src_block, cmp_a, cmp_b, 1, 1, use_am, 1);
- if(am.flipped)
- pnc = get_inversed_pnc(pnc);
-
- if(get_mode_size_bits(cmp_mode) == 8) {
- res = new_rd_ia32_CmpJmp8Bit(dbgi, irg, block, addr->base, addr->index,
- addr->mem, am.new_op1, am.new_op2, pnc);
- } else {
- res = new_rd_ia32_CmpJmp(dbgi, irg, block, addr->base, addr->index,
- addr->mem, am.new_op1, am.new_op2, pnc);
- }
- set_am_attributes(res, &am);
- assert(cmp_mode != NULL);
- set_ia32_ls_mode(res, cmp_mode);
-
- res = fix_mem_proj(res, &am);
- }
+ /* we get flags from a cmp */
+ flags = get_flags_node(sel, &pnc);
+ res = new_rd_ia32_Jcc(dbgi, irg, new_block, flags, pnc);
SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
return res;
size >>= 2;
res = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, size);
+ if(size == 0) {
+ ir_fprintf(stderr, "Optimisation warning copyb %+F with size <4\n",
+ node);
+ set_ia32_flags(res, get_ia32_flags(res) | arch_irn_flags_modify_flags);
+ }
add_irn_dep(res, get_irg_frame(irg));
res = new_rd_ia32_CopyB(dbgi, irg, block, new_dst, new_src, res, new_mem);
return res;
}
-static
-ir_node *gen_be_Copy(ir_node *node)
+static ir_node *gen_be_Copy(ir_node *node)
{
ir_node *result = be_duplicate_node(node);
ir_mode *mode = get_irn_mode(result);
return result;
}
+/**
+ * helper function: checks wether all Cmp projs are Lg or Eq which is needed
+ * to fold an and into a test node
+ */
+static int can_fold_test_and(ir_node *node)
+{
+ const ir_edge_t *edge;
-static ir_node *create_set(long pnc, ir_node *cmp_left, ir_node *cmp_right,
- dbg_info *dbgi, ir_node *block, int use_am)
+ /** we can only have eq and lg projs */
+ foreach_out_edge(node, edge) {
+ ir_node *proj = get_edge_src_irn(edge);
+ pn_Cmp pnc = get_Proj_proj(proj);
+ if(pnc != pn_Cmp_Eq && pnc != pn_Cmp_Lg)
+ return 0;
+ }
+
+ return 1;
+}
+
+static ir_node *try_create_Test(ir_node *node)
{
ir_graph *irg = current_ir_graph;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
ir_node *new_block = be_transform_node(block);
- ir_node *noreg = ia32_new_NoReg_gp(env_cg);
- ir_node *nomem = new_rd_NoMem(irg);
+ ir_node *cmp_left = get_Cmp_left(node);
+ ir_node *cmp_right = get_Cmp_right(node);
ir_mode *mode;
- ir_node *arg_left;
- ir_node *arg_right;
+ ir_node *left;
+ ir_node *right;
ir_node *res;
ia32_address_mode_t am;
ia32_address_t *addr = &am.addr;
+ int cmp_unsigned;
/* can we use a test instruction? */
- if(cmp_right == NULL || is_Const_0(cmp_right)) {
- long pure_pnc = pnc & ~ia32_pn_Cmp_Unsigned;
- if(is_And(cmp_left) &&
- (pure_pnc == pn_Cmp_Eq || pure_pnc == pn_Cmp_Lg)) {
- ir_node *and_left = get_And_left(cmp_left);
- ir_node *and_right = get_And_right(cmp_left);
-
- mode = get_irn_mode(and_left);
- arg_left = and_left;
- arg_right = and_right;
- } else {
- mode = get_irn_mode(cmp_left);
- arg_left = cmp_left;
- arg_right = cmp_left;
- }
-
- assert(get_mode_size_bits(mode) <= 32);
-
- match_arguments(&am, block, arg_left, arg_right, 1, 1, use_am, 1);
- if(am.flipped)
- pnc = get_inversed_pnc(pnc);
-
- if(get_mode_size_bits(mode) == 8) {
- res = new_rd_ia32_TestSet8Bit(dbgi, irg, new_block, addr->base,
- addr->index, addr->mem, am.new_op1,
- am.new_op2, pnc);
- } else {
- res = new_rd_ia32_TestSet(dbgi, irg, new_block, addr->base, addr->index,
- addr->mem, am.new_op1, am.new_op2, pnc);
- }
- set_am_attributes(res, &am);
- set_ia32_ls_mode(res, mode);
-
- res = fix_mem_proj(res, &am);
+ if(!is_Const_0(cmp_right))
+ return NULL;
- res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, noreg, noreg, nomem,
- res, mode_Bu);
+ if(is_And(cmp_left) && can_fold_test_and(node)) {
+ ir_node *and_left = get_And_left(cmp_left);
+ ir_node *and_right = get_And_right(cmp_left);
- return res;
+ mode = get_irn_mode(and_left);
+ left = and_left;
+ right = and_right;
+ } else {
+ mode = get_irn_mode(cmp_left);
+ left = cmp_left;
+ right = cmp_left;
}
- mode = get_irn_mode(cmp_left);
assert(get_mode_size_bits(mode) <= 32);
- match_arguments(&am, block, cmp_left, cmp_right, 1, 1, use_am, 1);
- if(am.flipped)
- pnc = get_inversed_pnc(pnc);
+ match_arguments(&am, block, left, right, match_commutative |
+ match_8_16_bit_am | match_am_and_immediates);
+ cmp_unsigned = !mode_is_signed(mode);
if(get_mode_size_bits(mode) == 8) {
- res = new_rd_ia32_CmpSet8Bit(dbgi, irg, new_block, addr->base, addr->index,
- addr->mem, am.new_op1, am.new_op2, pnc);
+ res = new_rd_ia32_Test8Bit(dbgi, irg, new_block, addr->base,
+ addr->index, addr->mem, am.new_op1,
+ am.new_op2, am.flipped, cmp_unsigned);
} else {
- res = new_rd_ia32_CmpSet(dbgi, irg, new_block, addr->base, addr->index,
- addr->mem, am.new_op1, am.new_op2, pnc);
+ res = new_rd_ia32_Test(dbgi, irg, new_block, addr->base, addr->index,
+ addr->mem, am.new_op1, am.new_op2, am.flipped,
+ cmp_unsigned);
}
set_am_attributes(res, &am);
+ assert(mode != NULL);
set_ia32_ls_mode(res, mode);
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
+
res = fix_mem_proj(res, &am);
+ return res;
+}
- res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, noreg, noreg, nomem, res,
- mode_Bu);
+static ir_node *create_Fucom(ir_node *node)
+{
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ ir_node *left = get_Cmp_left(node);
+ ir_node *new_left = be_transform_node(left);
+ ir_node *right = get_Cmp_right(node);
+ ir_node *new_right = be_transform_node(right);
+ ir_node *res;
+
+ res = new_rd_ia32_vFucomFnstsw(dbgi, irg, new_block, new_left, new_right,
+ 0);
+ set_ia32_commutative(res);
+
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
+
+ res = new_rd_ia32_Sahf(dbgi, irg, new_block, res);
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
return res;
}
-static ir_node *create_cmov(long pnc, ir_node *cmp_left, ir_node *cmp_right,
- ir_node *val_true, ir_node *val_false,
- dbg_info *dbgi, ir_node *block)
+static ir_node *create_Ucomi(ir_node *node)
{
- ir_graph *irg = current_ir_graph;
- ir_node *new_block = be_transform_node(block);
- ir_node *new_val_true = be_transform_node(val_true);
- ir_node *new_val_false = be_transform_node(val_false);
- ir_node *noreg = ia32_new_NoReg_gp(env_cg);
- ir_node *nomem = new_NoMem();
- ir_node *new_cmp_left;
- ir_node *new_cmp_right;
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ ir_node *left = get_Cmp_left(node);
+ ir_node *new_left = be_transform_node(left);
+ ir_node *right = get_Cmp_right(node);
+ ir_node *new_right = be_transform_node(right);
+ ir_mode *mode = get_irn_mode(left);
+ ir_node *noreg = ia32_new_NoReg_gp(env_cg);
+ ir_node *nomem = new_NoMem();
ir_node *res;
- ir_mode *mode;
- /* cmovs with unknowns are pointless... */
- if(is_Unknown(val_true)) {
-#ifdef DEBUG_libfirm
- ir_fprintf(stderr, "Optimisation warning: psi with unknown operand\n");
-#endif
- return new_val_false;
- }
- if(is_Unknown(val_false)) {
-#ifdef DEBUG_libfirm
- ir_fprintf(stderr, "Optimisation warning: psi with unknown operand\n");
-#endif
- return new_val_true;
- }
+ res = new_rd_ia32_Ucomi(dbgi, irg, new_block, noreg, noreg, nomem, new_left,
+ new_right, 0);
+ set_ia32_commutative(res);
+ set_ia32_ls_mode(res, mode);
- /* can we use a test instruction? */
- if(is_Const_0(cmp_right)) {
- long pure_pnc = pnc & ~ia32_pn_Cmp_Unsigned;
- if(is_And(cmp_left) &&
- (pure_pnc == pn_Cmp_Eq || pure_pnc == pn_Cmp_Lg)) {
- ir_node *and_left = get_And_left(cmp_left);
- ir_node *and_right = get_And_right(cmp_left);
-
- mode = get_irn_mode(and_left);
- new_cmp_left = be_transform_node(and_left);
- new_cmp_right = create_immediate_or_transform(and_right, 0);
- } else {
- mode = get_irn_mode(cmp_left);
- new_cmp_left = be_transform_node(cmp_left);
- new_cmp_right = be_transform_node(cmp_left);
- }
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
- assert(get_mode_size_bits(mode) <= 32);
+ return res;
+}
- if(get_mode_size_bits(mode) == 8) {
- res = new_rd_ia32_TestCMov8Bit(dbgi, current_ir_graph, new_block, noreg,
- noreg, nomem, new_cmp_left, new_cmp_right,
- new_val_true, new_val_false, pnc);
+static ir_node *gen_Cmp(ir_node *node)
+{
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ ir_node *left = get_Cmp_left(node);
+ ir_node *right = get_Cmp_right(node);
+ ir_mode *cmp_mode = get_irn_mode(left);
+ ir_node *res;
+ ia32_address_mode_t am;
+ ia32_address_t *addr = &am.addr;
+ int cmp_unsigned;
+
+ if(mode_is_float(cmp_mode)) {
+ if (USE_SSE2(env_cg)) {
+ return create_Ucomi(node);
} else {
- res = new_rd_ia32_TestCMov(dbgi, current_ir_graph, new_block, noreg,
- noreg, nomem, new_cmp_left, new_cmp_right,
- new_val_true, new_val_false, pnc);
+ return create_Fucom(node);
}
- set_ia32_ls_mode(res, mode);
-
- return res;
}
- mode = get_irn_mode(cmp_left);
- new_cmp_left = be_transform_node(cmp_left);
- new_cmp_right = create_immediate_or_transform(cmp_right, 0);
+ assert(mode_needs_gp_reg(cmp_mode));
- /* no support for 8,16 bit modes yet */
- assert(get_mode_size_bits(mode) <= 32);
+ /* we prefer the Test instruction where possible except cases where
+ * we can use SourceAM */
+ if(!use_source_address_mode(block, left, right) &&
+ !use_source_address_mode(block, right, left)) {
+ res = try_create_Test(node);
+ if(res != NULL)
+ return res;
+ }
- if(get_mode_size_bits(mode) == 8) {
- res = new_rd_ia32_CmpCMov8Bit(dbgi, irg, new_block, noreg, noreg, nomem,
- new_cmp_left, new_cmp_right, new_val_true,
- new_val_false, pnc);
+ match_arguments(&am, block, left, right,
+ match_commutative | match_8_16_bit_am |
+ match_am_and_immediates);
+
+ cmp_unsigned = !mode_is_signed(get_irn_mode(left));
+ if(get_mode_size_bits(cmp_mode) == 8) {
+ res = new_rd_ia32_Cmp8Bit(dbgi, irg, new_block, addr->base, addr->index,
+ addr->mem, am.new_op1, am.new_op2,
+ am.flipped, cmp_unsigned);
} else {
- res = new_rd_ia32_CmpCMov(dbgi, irg, new_block, noreg, noreg, nomem,
- new_cmp_left, new_cmp_right, new_val_true,
- new_val_false, pnc);
+ res = new_rd_ia32_Cmp(dbgi, irg, new_block, addr->base, addr->index,
+ addr->mem, am.new_op1, am.new_op2, am.flipped,
+ cmp_unsigned);
}
- set_ia32_ls_mode(res, mode);
+ set_am_attributes(res, &am);
+ assert(cmp_mode != NULL);
+ set_ia32_ls_mode(res, cmp_mode);
+
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
+
+ res = fix_mem_proj(res, &am);
return res;
}
+static ir_node *create_CMov(ir_node *node, ir_node *new_flags, pn_Cmp pnc)
+{
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ ir_node *val_true = get_Psi_val(node, 0);
+ ir_node *new_val_true = be_transform_node(val_true);
+ ir_node *val_false = get_Psi_default(node);
+ ir_node *new_val_false = be_transform_node(val_false);
+ ir_mode *mode = get_irn_mode(node);
+ ir_node *noreg = ia32_new_NoReg_gp(env_cg);
+ ir_node *nomem = new_NoMem();
+ ir_node *res;
+
+ assert(mode_needs_gp_reg(mode));
+
+ res = new_rd_ia32_CMov(dbgi, irg, new_block, noreg, noreg, nomem,
+ new_val_false, new_val_true, new_flags, pnc);
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
+
+ return res;
+}
+
+
+
+static ir_node *create_set_32bit(dbg_info *dbgi, ir_node *new_block,
+ ir_node *flags, pn_Cmp pnc, ir_node *orig_node)
+{
+ ir_graph *irg = current_ir_graph;
+ ir_node *noreg = ia32_new_NoReg_gp(env_cg);
+ ir_node *nomem = new_NoMem();
+ ir_node *res;
+
+ res = new_rd_ia32_Set(dbgi, irg, new_block, flags, pnc);
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, orig_node));
+ res = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, noreg, noreg,
+ nomem, res, mode_Bu);
+ SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, orig_node));
+
+ return res;
+}
/**
* Transforms a Psi node into CMov.
*
* @return The transformed node.
*/
-static ir_node *gen_Psi(ir_node *node) {
+static ir_node *gen_Psi(ir_node *node)
+{
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
ir_node *psi_true = get_Psi_val(node, 0);
ir_node *psi_default = get_Psi_default(node);
- ia32_code_gen_t *cg = env_cg;
ir_node *cond = get_Psi_cond(node, 0);
- ir_node *block = get_nodes_block(node);
- dbg_info *dbgi = get_irn_dbg_info(node);
- ir_node *new_op;
- ir_node *cmp_left;
- ir_node *cmp_right;
+ ir_node *flags = NULL;
+ ir_node *res;
ir_mode *cmp_mode;
- long pnc;
+ pn_Cmp pnc;
assert(get_Psi_n_conds(node) == 1);
assert(get_irn_mode(cond) == mode_b);
assert(mode_needs_gp_reg(get_irn_mode(node)));
- if(!is_Proj(cond) || !is_Cmp(get_Proj_pred(cond))) {
- /* a mode_b value, we have to compare it against 0 */
- cmp_left = cond;
- cmp_right = new_Const_long(mode_Iu, 0);
- pnc = pn_Cmp_Lg;
- cmp_mode = mode_Iu;
- } else {
- ir_node *cmp = get_Proj_pred(cond);
-
- cmp_left = get_Cmp_left(cmp);
- cmp_right = get_Cmp_right(cmp);
- cmp_mode = get_irn_mode(cmp_left);
- pnc = get_Proj_proj(cond);
-
- assert(!mode_is_float(cmp_mode));
-
- if (!mode_is_signed(cmp_mode)) {
- pnc |= ia32_pn_Cmp_Unsigned;
- }
- }
+ flags = get_flags_node(cond, &pnc);
if(is_Const_1(psi_true) && is_Const_0(psi_default)) {
- new_op = create_set(pnc, cmp_left, cmp_right, dbgi, block, 1);
+ res = create_set_32bit(dbgi, new_block, flags, pnc, node);
} else if(is_Const_0(psi_true) && is_Const_1(psi_default)) {
pnc = get_negated_pnc(pnc, cmp_mode);
- new_op = create_set(pnc, cmp_left, cmp_right, dbgi, block, 1);
+ res = create_set_32bit(dbgi, new_block, flags, pnc, node);
} else {
- new_op = create_cmov(pnc, cmp_left, cmp_right, psi_true, psi_default,
- dbgi, block);
+ res = create_CMov(node, flags, pnc);
}
- SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node));
- return new_op;
+ return res;
}
return res;
}
-static
-int check_immediate_constraint(long val, char immediate_constraint_type)
+static int check_immediate_constraint(long val, char immediate_constraint_type)
{
switch (immediate_constraint_type) {
case 0:
return 0;
}
-static
-ir_node *try_create_Immediate(ir_node *node, char immediate_constraint_type)
+static ir_node *try_create_Immediate(ir_node *node,
+ char immediate_constraint_type)
{
int minus = 0;
tarval *offset = NULL;
return NULL;
}
+ /* unfortunately the assembler/linker doesn't support -symconst */
+ if(symconst_sign)
+ return NULL;
+
if(get_SymConst_kind(symconst) != symconst_addr_ent)
return NULL;
symconst_ent = get_SymConst_entity(symconst);
return res;
}
-static
-ir_node *create_immediate_or_transform(ir_node *node, char immediate_constraint_type)
+static ir_node *create_immediate_or_transform(ir_node *node,
+ char immediate_constraint_type)
{
ir_node *new_node = try_create_Immediate(node, immediate_constraint_type);
if (new_node == NULL) {
constraint->immediate_type = immediate_type;
}
-static
-void parse_clobber(ir_node *node, int pos, constraint_t *constraint,
- const char *c)
+static void parse_clobber(ir_node *node, int pos, constraint_t *constraint,
+ const char *c)
{
(void) node;
(void) pos;
ia32_address_mode_t am;
ia32_address_t *addr = &am.addr;
- match_arguments(&am, src_block, op1, op2, 1, 0, 1, 0);
+ match_arguments(&am, src_block, op1, op2, match_commutative);
new_node = new_rd_ia32_Adc(dbgi, irg, block, addr->base, addr->index,
addr->mem, am.new_op1, am.new_op2, new_flags);
return res;
}
+static ir_node *gen_be_Call(ir_node *node) {
+ ir_node *res = be_duplicate_node(node);
+ be_node_add_flags(res, -1, arch_irn_flags_modify_flags);
+
+ return res;
+}
+
+static ir_node *gen_be_IncSP(ir_node *node) {
+ ir_node *res = be_duplicate_node(node);
+ be_node_add_flags(res, -1, arch_irn_flags_modify_flags);
+
+ return res;
+}
+
/**
* Transform the Projs from a be_Call.
*/
{
/* normally Cmps are processed when looking at Cond nodes, but this case
* can happen in complicated Psi conditions */
-
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
ir_node *cmp = get_Proj_pred(node);
+ ir_node *new_cmp = be_transform_node(cmp);
long pnc = get_Proj_proj(node);
- ir_node *cmp_left = get_Cmp_left(cmp);
- ir_node *cmp_right = get_Cmp_right(cmp);
- ir_mode *cmp_mode = get_irn_mode(cmp_left);
- dbg_info *dbgi = get_irn_dbg_info(cmp);
- ir_node *block = get_nodes_block(node);
ir_node *res;
- int use_am;
-
- assert(!mode_is_float(cmp_mode));
-
- if(!mode_is_signed(cmp_mode)) {
- pnc |= ia32_pn_Cmp_Unsigned;
- }
-
- /**
- * address mode makes only sense when we'll be the only node using the cmp
- */
- use_am = get_irn_n_edges(cmp) <= 1;
- res = create_set(pnc, cmp_left, cmp_right, dbgi, block, use_am);
- SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, cmp));
+ res = create_set_32bit(dbgi, new_block, new_cmp, pnc, node);
return res;
}
GEN(Store);
GEN(Cond);
+ GEN(Cmp);
GEN(ASM);
GEN(CopyB);
BAD(Mux);
/* handle generic backend nodes */
GEN(be_FrameAddr);
- //GEN(be_Call);
+ GEN(be_Call);
+ GEN(be_IncSP);
GEN(be_Return);
GEN(be_AddSP);
GEN(be_SubSP);
* Walker, checks if all ia32 nodes producing more than one result have
* its Projs, other wise creates new projs and keep them using a be_Keep node.
*/
-static
-void add_missing_keep_walker(ir_node *node, void *data)
+static void add_missing_keep_walker(ir_node *node, void *data)
{
int n_outs, i;
unsigned found_projs = 0;
GEN_STORE(fist)
/**
- * Simulate a fCondJmp.
- *
* @param state the x87 state
* @param n the node that should be simulated (and patched)
*
* @return NO_NODE_ADDED
*/
-static int sim_fCmpJmp(x87_state *state, ir_node *n) {
+static int sim_FucomFnstsw(x87_state *state, ir_node *n) {
int op1_idx;
int op2_idx = -1;
int pop_cnt = 0;
- ia32_x87_attr_t *attr;
+ ia32_x87_attr_t *attr = get_ia32_x87_attr(n);
ir_op *dst;
x87_simulator *sim = state->sim;
- ir_node *op1_node = get_irn_n(n, n_ia32_vfCmpJmp_left);
- ir_node *op2_node = get_irn_n(n, n_ia32_vfCmpJmp_right);
+ ir_node *op1_node = get_irn_n(n, n_ia32_vFucomFnstsw_left);
+ ir_node *op2_node = get_irn_n(n, n_ia32_vFucomFnstsw_right);
const arch_register_t *op1 = x87_get_irn_register(sim, op1_node);
const arch_register_t *op2 = x87_get_irn_register(sim, op2_node);
int reg_index_1 = arch_register_get_index(op1);
int reg_index_2 = arch_register_get_index(op2);
unsigned live = vfp_live_args_after(sim, n, 0);
+ int flipped = attr->attr.data.cmp_flipped;
+ int xchg = 0;
DB((dbg, LEVEL_1, ">>> %+F %s, %s\n", n,
arch_register_get_name(op1), arch_register_get_name(op2)));
if (op1_idx == 0) {
/* res = tos X op */
- dst = op_ia32_fcomJmp;
+ dst = op_ia32_FucomFnstsw;
} else if (op2_idx == 0) {
/* res = op X tos */
- dst = op_ia32_fcomrJmp;
+ dst = op_ia32_FucomFnstsw;
+ flipped = !flipped;
+ xchg = 1;
} else {
/* bring the first one to tos */
x87_create_fxch(state, n, op1_idx);
op2_idx = op1_idx;
op1_idx = 0;
/* res = tos X op */
- dst = op_ia32_fcomJmp;
+ dst = op_ia32_FucomFnstsw;
}
} else {
/* second live, first operand is dead here, bring it to tos.
op1_idx = 0;
}
/* res = tos X op, pop */
- dst = op_ia32_fcompJmp;
+ dst = op_ia32_FucompFnstsw;
pop_cnt = 1;
}
} else {
op2_idx = 0;
}
/* res = op X tos, pop */
- dst = op_ia32_fcomrpJmp;
+ dst = op_ia32_FucompFnstsw;
+ flipped = !flipped;
+ xchg = 1;
pop_cnt = 1;
} else {
/* both operands are dead here, check first for identity. */
op2_idx = 0;
}
/* res = tos X op, pop */
- dst = op_ia32_fcompJmp;
+ dst = op_ia32_FucompFnstsw;
pop_cnt = 1;
}
/* different, move them to st and st(1) and pop both.
op1_idx = 0;
}
/* res = tos X op, pop, pop */
- dst = op_ia32_fcomppJmp;
+ dst = op_ia32_FucomppFnstsw;
pop_cnt = 2;
} else if (op1_idx == 1) {
/* good, first operand is already in the right place, move the second */
assert(op1_idx != 0);
op2_idx = 0;
}
- dst = op_ia32_fcomrppJmp;
+ /* res = op X tos, pop, pop */
+ dst = op_ia32_FucomppFnstsw;
+ flipped = !flipped;
+ xchg = 1;
pop_cnt = 2;
} else {
/* if one is already the TOS, we need two fxch */
x87_create_fxch(state, n, op2_idx);
op2_idx = 0;
/* res = op X tos, pop, pop */
- dst = op_ia32_fcomrppJmp;
+ dst = op_ia32_FucomppFnstsw;
+ flipped = !flipped;
+ xchg = 1;
pop_cnt = 2;
} else if (op2_idx == 0) {
/* second one is TOS, move to st(1) */
x87_create_fxch(state, n, op1_idx);
op1_idx = 0;
/* res = tos X op, pop, pop */
- dst = op_ia32_fcomppJmp;
+ dst = op_ia32_FucomppFnstsw;
pop_cnt = 2;
} else {
/* none of them is either TOS or st(1), 3 fxch needed */
x87_create_fxch(state, n, op1_idx);
op1_idx = 0;
/* res = tos X op, pop, pop */
- dst = op_ia32_fcomppJmp;
+ dst = op_ia32_FucomppFnstsw;
pop_cnt = 2;
}
}
x87_create_fxch(state, n, op1_idx);
op1_idx = 0;
}
- dst = op_ia32_fcomJmp;
+ dst = op_ia32_FucomFnstsw;
} else {
/* first operand is dead: bring it to tos */
if (op1_idx != 0) {
x87_create_fxch(state, n, op1_idx);
op1_idx = 0;
}
- dst = op_ia32_fcompJmp;
+ dst = op_ia32_FucompFnstsw;
pop_cnt = 1;
}
}
if (pop_cnt >= 1)
x87_pop(state);
+ if(xchg) {
+ int tmp = op1_idx;
+ op1_idx = op2_idx;
+ op2_idx = tmp;
+ }
+
/* patch the operation */
- attr = get_ia32_x87_attr(n);
op1 = &ia32_st_regs[op1_idx];
attr->x87[0] = op1;
if (op2_idx >= 0) {
attr->x87[1] = op2;
}
attr->x87[2] = NULL;
+ attr->attr.data.cmp_flipped = flipped;
if (op2_idx >= 0)
DB((dbg, LEVEL_1, "<<< %s %s, %s\n", get_irn_opname(n),
arch_register_get_name(op1)));
return NO_NODE_ADDED;
-} /* sim_fCondJmp */
+}
-static
-int sim_Keep(x87_state *state, ir_node *node)
+static int sim_Keep(x87_state *state, ir_node *node)
{
const ir_node *op;
const arch_register_t *op_reg;
ASSOC_IA32(fchs);
ASSOC_IA32(fist);
ASSOC_IA32(fst);
- ASSOC_IA32(fCmpJmp);
+ ASSOC_IA32(FucomFnstsw);
ASSOC_BE(Copy);
ASSOC_BE(Call);
ASSOC_BE(Spill);