+/**
+ * Replace Cmp(x, 0) by a Test(x, x)
+ */
+static void peephole_ia32_Cmp(ir_node *const node)
+{
+ ir_node *right;
+ ia32_immediate_attr_t const *imm;
+ dbg_info *dbgi;
+ ir_graph *irg;
+ ir_node *block;
+ ir_node *noreg;
+ ir_node *nomem;
+ ir_node *op;
+ ia32_attr_t const *attr;
+ int ins_permuted;
+ int cmp_unsigned;
+ ir_node *test;
+ arch_register_t const *reg;
+ ir_edge_t const *edge;
+ ir_edge_t const *tmp;
+
+ if (get_ia32_op_type(node) != ia32_Normal)
+ return;
+
+ right = get_irn_n(node, n_ia32_Cmp_right);
+ if (!is_ia32_Immediate(right))
+ return;
+
+ imm = get_ia32_immediate_attr_const(right);
+ if (imm->symconst != NULL || imm->offset != 0)
+ return;
+
+ dbgi = get_irn_dbg_info(node);
+ irg = current_ir_graph;
+ block = get_nodes_block(node);
+ noreg = ia32_new_NoReg_gp(cg);
+ nomem = get_irg_no_mem(irg);
+ op = get_irn_n(node, n_ia32_Cmp_left);
+ attr = get_irn_generic_attr(node);
+ ins_permuted = attr->data.ins_permuted;
+ cmp_unsigned = attr->data.cmp_unsigned;
+
+ if (is_ia32_Cmp(node)) {
+ test = new_rd_ia32_Test(dbgi, irg, block, noreg, noreg, nomem,
+ op, op, ins_permuted, cmp_unsigned);
+ } else {
+ test = new_rd_ia32_Test8Bit(dbgi, irg, block, noreg, noreg, nomem,
+ op, op, ins_permuted, cmp_unsigned);
+ }
+ set_ia32_ls_mode(test, get_ia32_ls_mode(node));
+
+ reg = arch_get_irn_register(arch_env, node);
+ arch_set_irn_register(arch_env, test, reg);
+
+ foreach_out_edge_safe(node, edge, tmp) {
+ ir_node *const user = get_edge_src_irn(edge);
+
+ if (is_Proj(user))
+ exchange(user, test);
+ }
+
+ sched_add_before(node, test);
+ be_peephole_exchange(node, test);
+}
+
+/**
+ * Peephole optimization for Test instructions.
+ * We can remove the Test, if a zero flags was produced which is still
+ * live.
+ */
+static void peephole_ia32_Test(ir_node *node)
+{
+ ir_node *left = get_irn_n(node, n_ia32_Test_left);
+ ir_node *right = get_irn_n(node, n_ia32_Test_right);
+ ir_node *flags_proj;
+ ir_node *block;
+ ir_mode *flags_mode;
+ int pn = -1;
+ ir_node *schedpoint;
+ const ir_edge_t *edge;
+
+ assert(n_ia32_Test_left == n_ia32_Test8Bit_left
+ && n_ia32_Test_right == n_ia32_Test8Bit_right);
+
+ /* we need a test for 0 */
+ if(left != right)
+ return;
+
+ block = get_nodes_block(node);
+ if(get_nodes_block(left) != block)
+ return;
+
+ if(is_Proj(left)) {
+ pn = get_Proj_proj(left);
+ left = get_Proj_pred(left);
+ }
+
+ /* happens rarely, but if it does code will panic' */
+ if (is_ia32_Unknown_GP(left))
+ return;
+
+ /* walk schedule up and abort when we find left or some other node destroys
+ the flags */
+ schedpoint = sched_prev(node);
+ while(schedpoint != left) {
+ schedpoint = sched_prev(schedpoint);
+ if(arch_irn_is(arch_env, schedpoint, modify_flags))
+ return;
+ if(schedpoint == block)
+ panic("couldn't find left");
+ }
+
+ /* make sure only Lg/Eq tests are used */
+ foreach_out_edge(node, edge) {
+ ir_node *user = get_edge_src_irn(edge);
+ int pnc = get_ia32_condcode(user);
+
+ if(pnc != pn_Cmp_Eq && pnc != pn_Cmp_Lg) {
+ return;
+ }
+ }
+
+ if(!produces_zero_flag(left, pn))
+ return;
+
+ left = turn_into_mode_t(left);
+
+ flags_mode = ia32_reg_classes[CLASS_ia32_flags].mode;
+ flags_proj = new_r_Proj(current_ir_graph, block, left, flags_mode,
+ pn_ia32_flags);
+ arch_set_irn_register(arch_env, flags_proj, &ia32_flags_regs[REG_EFLAGS]);
+
+ assert(get_irn_mode(node) != mode_T);
+
+ be_peephole_exchange(node, flags_proj);
+}