+ ir_node *noreg = ia32_new_NoReg_gp(irg);
+
+ val = get_irn_n(store, n_ia32_unary_op);
+ mem = get_irn_n(store, n_ia32_mem);
+ spreg = arch_get_irn_register(curr_sp);
+
+ push = new_bd_ia32_Push(get_irn_dbg_info(store), block, noreg, noreg,
+ mem, val, curr_sp);
+ copy_mark(store, push);
+
+ if (first_push == NULL)
+ first_push = push;
+
+ sched_add_after(skip_Proj(curr_sp), push);
+
+ /* create stackpointer Proj */
+ curr_sp = new_r_Proj(push, spmode, pn_ia32_Push_stack);
+ arch_set_irn_register(curr_sp, spreg);
+
+ /* create memory Proj */
+ mem_proj = new_r_Proj(push, mode_M, pn_ia32_Push_M);
+
+ /* rewire Store Projs */
+ foreach_out_edge_safe(store, edge, next) {
+ ir_node *proj = get_edge_src_irn(edge);
+ if (!is_Proj(proj))
+ continue;
+ switch (get_Proj_proj(proj)) {
+ case pn_ia32_Store_M:
+ exchange(proj, mem_proj);
+ break;
+ default:
+ panic("unexpected Proj on Store->IncSp");
+ }
+ }
+
+ /* use the memproj now */
+ be_peephole_exchange(store, push);
+
+ inc_ofs -= 4;
+ }
+
+ foreach_out_edge_safe(irn, edge, next) {
+ ir_node *const src = get_edge_src_irn(edge);
+ int const pos = get_edge_src_pos(edge);
+
+ if (src == first_push)
+ continue;
+
+ set_irn_n(src, pos, curr_sp);
+ }
+
+ be_set_IncSP_offset(irn, inc_ofs);
+}
+
+#if 0
+/**
+ * Creates a Push instruction before the given schedule point.
+ *
+ * @param dbgi debug info
+ * @param block the block
+ * @param stack the previous stack value
+ * @param schedpoint the new node is added before this node
+ * @param reg the register to pop
+ *
+ * @return the new stack value
+ */
+static ir_node *create_push(dbg_info *dbgi, ir_node *block,
+ ir_node *stack, ir_node *schedpoint)
+{
+ const arch_register_t *esp = &ia32_registers[REG_ESP];
+
+ ir_node *val = ia32_new_NoReg_gp(cg);
+ ir_node *noreg = ia32_new_NoReg_gp(cg);
+ ir_graph *irg = get_irn_irg(block);
+ ir_node *nomem = get_irg_no_mem(irg);
+ ir_node *push = new_bd_ia32_Push(dbgi, block, noreg, noreg, nomem, val, stack);
+ sched_add_before(schedpoint, push);
+
+ stack = new_r_Proj(push, mode_Iu, pn_ia32_Push_stack);
+ arch_set_irn_register(stack, esp);
+
+ return stack;
+}
+
+static void peephole_store_incsp(ir_node *store)
+{
+ dbg_info *dbgi;
+ ir_node *node;
+ ir_node *block;
+ ir_node *noreg;
+ ir_node *mem;
+ ir_node *push;
+ ir_node *val;
+ ir_node *base;
+ ir_node *index;
+ ir_node *am_base = get_irn_n(store, n_ia32_Store_base);
+ if (!be_is_IncSP(am_base)
+ || get_nodes_block(am_base) != get_nodes_block(store))
+ return;
+ mem = get_irn_n(store, n_ia32_Store_mem);
+ if (!is_ia32_NoReg_GP(get_irn_n(store, n_ia32_Store_index))
+ || !is_NoMem(mem))
+ return;
+
+ int incsp_offset = be_get_IncSP_offset(am_base);
+ if (incsp_offset <= 0)
+ return;
+
+ /* we have to be at offset 0 */
+ int my_offset = get_ia32_am_offs_int(store);
+ if (my_offset != 0) {
+ /* TODO here: find out whether there is a store with offset 0 before
+ * us and whether we can move it down to our place */
+ return;
+ }
+ ir_mode *ls_mode = get_ia32_ls_mode(store);
+ int my_store_size = get_mode_size_bytes(ls_mode);
+
+ if (my_offset + my_store_size > incsp_offset)
+ return;
+
+ /* correctness checking:
+ - noone else must write to that stackslot
+ (because after translation incsp won't allocate it anymore)
+ */
+ sched_foreach_reverse_from(store, node) {
+ int i, arity;
+
+ if (node == am_base)
+ break;
+
+ /* make sure noone else can use the space on the stack */
+ arity = get_irn_arity(node);
+ for (i = 0; i < arity; ++i) {
+ ir_node *pred = get_irn_n(node, i);
+ if (pred != am_base)
+ continue;
+
+ if (i == n_ia32_base &&
+ (get_ia32_op_type(node) == ia32_AddrModeS
+ || get_ia32_op_type(node) == ia32_AddrModeD)) {
+ int node_offset = get_ia32_am_offs_int(node);
+ ir_mode *node_ls_mode = get_ia32_ls_mode(node);
+ int node_size = get_mode_size_bytes(node_ls_mode);
+ /* overlapping with our position? abort */
+ if (node_offset < my_offset + my_store_size
+ && node_offset + node_size >= my_offset)
+ return;
+ /* otherwise it's fine */
+ continue;
+ }
+
+ /* strange use of esp: abort */
+ return;
+ }
+ }
+
+ /* all ok, change to push */
+ dbgi = get_irn_dbg_info(store);
+ block = get_nodes_block(store);
+ noreg = ia32_new_NoReg_gp(cg);
+ val = get_irn_n(store, n_ia32_Store_val);
+
+ push = new_bd_ia32_Push(dbgi, block, noreg, noreg, mem,
+
+ create_push(dbgi, current_ir_graph, block, am_base, store);
+}
+#endif
+
+/**
+ * Return true if a mode can be stored in the GP register set
+ */
+static inline int mode_needs_gp_reg(ir_mode *mode)
+{
+ if (mode == ia32_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;
+}
+
+/**
+ * Tries to create Pops from Load, IncSP combinations.
+ * The Loads are replaced by Pops, the IncSP is modified
+ * (possibly into IncSP 0, but not removed).
+ */
+static void peephole_Load_IncSP_to_pop(ir_node *irn)
+{
+ const arch_register_t *esp = &ia32_registers[REG_ESP];
+ int i, maxslot, inc_ofs, ofs;
+ ir_node *node, *pred_sp, *block;
+ ir_node *loads[MAXPUSH_OPTIMIZE];
+ unsigned regmask = 0;
+ unsigned copymask = ~0;
+
+ memset(loads, 0, sizeof(loads));
+ assert(be_is_IncSP(irn));