+ sched_add_before(node, xorn);
+
+ copy_mark(node, xorn);
+ be_peephole_exchange(node, xorn);
+}
+
+static inline int is_noreg(const ir_node *node)
+{
+ return is_ia32_NoReg_GP(node);
+}
+
+ir_node *ia32_immediate_from_long(long val)
+{
+ ir_graph *irg = current_ir_graph;
+ ir_node *start_block = get_irg_start_block(irg);
+ ir_node *immediate
+ = new_bd_ia32_Immediate(NULL, start_block, NULL, 0, 0, val);
+ arch_set_irn_register(immediate, &ia32_registers[REG_GP_NOREG]);
+
+ return immediate;
+}
+
+static ir_node *create_immediate_from_am(const ir_node *node)
+{
+ ir_node *block = get_nodes_block(node);
+ int offset = get_ia32_am_offs_int(node);
+ int sc_sign = is_ia32_am_sc_sign(node);
+ const ia32_attr_t *attr = get_ia32_attr_const(node);
+ int sc_no_pic_adjust = attr->data.am_sc_no_pic_adjust;
+ ir_entity *entity = get_ia32_am_sc(node);
+ ir_node *res;
+
+ res = new_bd_ia32_Immediate(NULL, block, entity, sc_sign, sc_no_pic_adjust,
+ offset);
+ arch_set_irn_register(res, &ia32_registers[REG_GP_NOREG]);
+ return res;
+}
+
+static int is_am_one(const ir_node *node)
+{
+ int offset = get_ia32_am_offs_int(node);
+ ir_entity *entity = get_ia32_am_sc(node);
+
+ return offset == 1 && entity == NULL;
+}
+
+static int is_am_minus_one(const ir_node *node)
+{
+ int offset = get_ia32_am_offs_int(node);
+ ir_entity *entity = get_ia32_am_sc(node);
+
+ return offset == -1 && entity == NULL;
+}
+
+/**
+ * Transforms a LEA into an Add or SHL if possible.
+ */
+static void peephole_ia32_Lea(ir_node *node)
+{
+ ir_graph *irg;
+ ir_node *base;
+ ir_node *index;
+ const arch_register_t *base_reg;
+ const arch_register_t *index_reg;
+ const arch_register_t *out_reg;
+ int scale;
+ int has_immediates;
+ ir_node *op1;
+ ir_node *op2;
+ dbg_info *dbgi;
+ ir_node *block;
+ ir_node *res;
+ ir_node *noreg;
+ ir_node *nomem;
+
+ assert(is_ia32_Lea(node));
+
+ /* we can only do this if it is allowed to clobber the flags */
+ if (be_peephole_get_value(CLASS_ia32_flags, REG_FLAGS_EFLAGS) != NULL)
+ return;
+
+ base = get_irn_n(node, n_ia32_Lea_base);
+ index = get_irn_n(node, n_ia32_Lea_index);
+
+ if (is_noreg(base)) {
+ base = NULL;
+ base_reg = NULL;
+ } else {
+ base_reg = arch_get_irn_register(base);
+ }
+ if (is_noreg(index)) {
+ index = NULL;
+ index_reg = NULL;
+ } else {
+ index_reg = arch_get_irn_register(index);
+ }
+
+ if (base == NULL && index == NULL) {
+ /* we shouldn't construct these in the first place... */
+#ifdef DEBUG_libfirm
+ ir_fprintf(stderr, "Optimisation warning: found immediate only lea\n");
+#endif
+ return;
+ }
+
+ out_reg = arch_get_irn_register(node);
+ scale = get_ia32_am_scale(node);
+ assert(!is_ia32_need_stackent(node) || get_ia32_frame_ent(node) != NULL);
+ /* check if we have immediates values (frame entities should already be
+ * expressed in the offsets) */
+ if (get_ia32_am_offs_int(node) != 0 || get_ia32_am_sc(node) != NULL) {
+ has_immediates = 1;
+ } else {
+ has_immediates = 0;
+ }
+
+ /* we can transform leas where the out register is the same as either the
+ * base or index register back to an Add or Shl */
+ if (out_reg == base_reg) {
+ if (index == NULL) {
+#ifdef DEBUG_libfirm
+ if (!has_immediates) {
+ ir_fprintf(stderr, "Optimisation warning: found lea which is "
+ "just a copy\n");
+ }
+#endif
+ op1 = base;
+ goto make_add_immediate;
+ }
+ if (scale == 0 && !has_immediates) {
+ op1 = base;
+ op2 = index;
+ goto make_add;
+ }
+ /* can't create an add */
+ return;
+ } else if (out_reg == index_reg) {
+ if (base == NULL) {
+ if (has_immediates && scale == 0) {
+ op1 = index;
+ goto make_add_immediate;
+ } else if (!has_immediates && scale > 0) {
+ op1 = index;
+ op2 = ia32_immediate_from_long(scale);
+ goto make_shl;
+ } else if (!has_immediates) {
+#ifdef DEBUG_libfirm
+ ir_fprintf(stderr, "Optimisation warning: found lea which is "
+ "just a copy\n");
+#endif
+ }
+ } else if (scale == 0 && !has_immediates) {
+ op1 = index;
+ op2 = base;
+ goto make_add;
+ }
+ /* can't create an add */
+ return;
+ } else {
+ /* can't create an add */
+ return;
+ }
+
+make_add_immediate:
+ if (ia32_cg_config.use_incdec) {
+ if (is_am_one(node)) {
+ dbgi = get_irn_dbg_info(node);
+ block = get_nodes_block(node);
+ res = new_bd_ia32_Inc(dbgi, block, op1);
+ arch_set_irn_register(res, out_reg);
+ goto exchange;
+ }
+ if (is_am_minus_one(node)) {
+ dbgi = get_irn_dbg_info(node);
+ block = get_nodes_block(node);
+ res = new_bd_ia32_Dec(dbgi, block, op1);
+ arch_set_irn_register(res, out_reg);
+ goto exchange;
+ }
+ }
+ op2 = create_immediate_from_am(node);
+
+make_add:
+ dbgi = get_irn_dbg_info(node);
+ block = get_nodes_block(node);
+ irg = get_irn_irg(node);
+ noreg = ia32_new_NoReg_gp(irg);
+ nomem = new_r_NoMem(irg);
+ res = new_bd_ia32_Add(dbgi, block, noreg, noreg, nomem, op1, op2);
+ arch_set_irn_register(res, out_reg);
+ set_ia32_commutative(res);
+ goto exchange;
+
+make_shl:
+ dbgi = get_irn_dbg_info(node);
+ block = get_nodes_block(node);
+ irg = get_irn_irg(node);
+ noreg = ia32_new_NoReg_gp(irg);
+ nomem = new_r_NoMem(irg);
+ res = new_bd_ia32_Shl(dbgi, block, op1, op2);
+ arch_set_irn_register(res, out_reg);
+ goto exchange;
+
+exchange:
+ SET_IA32_ORIG_NODE(res, node);
+
+ /* add new ADD/SHL to schedule */
+ DBG_OPT_LEA2ADD(node, res);
+
+ /* exchange the Add and the LEA */
+ sched_add_before(node, res);
+ copy_mark(node, res);
+ be_peephole_exchange(node, res);
+}
+
+/**
+ * Split a Imul mem, imm into a Load mem and Imul reg, imm if possible.
+ */
+static void peephole_ia32_Imul_split(ir_node *imul)
+{
+ const ir_node *right = get_irn_n(imul, n_ia32_IMul_right);
+ const arch_register_t *reg;
+ ir_node *res;
+
+ if (!is_ia32_Immediate(right) || get_ia32_op_type(imul) != ia32_AddrModeS) {
+ /* no memory, imm form ignore */
+ return;
+ }
+ /* we need a free register */
+ reg = get_free_gp_reg(get_irn_irg(imul));
+ if (reg == NULL)
+ return;
+
+ /* fine, we can rebuild it */
+ res = ia32_turn_back_am(imul);
+ arch_set_irn_register(res, reg);
+}