fixed be_Return gen
[libfirm] / ir / be / ia32 / ia32_x87.c
index 3c45ba7..0b5b47a 100644 (file)
@@ -26,7 +26,7 @@
 #include "debug.h"
 
 #include "../belive_t.h"
-#include "../besched.h"
+#include "../besched_t.h"
 #include "../benode_t.h"
 #include "ia32_new_nodes.h"
 #include "gen_ia32_new_nodes.h"
@@ -50,6 +50,9 @@
 /** the debug handle */
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
+/* Forward declaration. */
+typedef struct _x87_simulator x87_simulator;
+
 /**
  * An exchange template.
  * Note that our virtual functions have the same inputs
@@ -79,14 +82,15 @@ typedef struct _x87_state {
        st_entry st[N_x87_REGS];  /**< the register stack */
        int depth;                /**< the current stack depth */
        int tos;                  /**< position of the tos */
+       x87_simulator *sim;       /**< The simulator. */
 } x87_state;
 
 /** An empty state, used for blocks without fp instructions. */
-static const x87_state _empty = { { {0, NULL}, }, 0, 0 };
+static x87_state _empty = { { {0, NULL}, }, 0, 0 };
 static x87_state *empty = (x87_state *)&_empty;
 
 /** The type of an instruction simulator */
-typedef void (*sim_func)(x87_state *state, ir_node *n, const arch_env_t *env);
+typedef int (*sim_func)(x87_state *state, ir_node *n, const arch_env_t *env);
 
 /**
  * A block state: Every block has a x87 state at the beginning and at the end.
@@ -101,11 +105,12 @@ typedef struct _blk_state {
 /**
  * The x87 simulator.
  */
-typedef struct _x87_simulator {
+struct _x87_simulator {
        struct obstack obst;      /**< an obstack for fast allocating */
        pmap *blk_states;         /**< map blocks to states */
-       const arch_env_t *env;          /**< architecture environment */
-} x87_simulator;
+       const arch_env_t *env;    /**< architecture environment */
+       be_lv_t *lv;              /**< Liveness information. */
+};
 
 /**
  * Returns the stack depth.
@@ -246,12 +251,13 @@ static int x87_on_stack(const x87_state *state, int reg_idx) {
 /**
  * Push a virtual Register onto the stack.
  *
- * @param state    the x87 state
- * @param reg_idx  the register vfp index
- * @param node     the node that produces the value of the vfp register
+ * @param state     the x87 state
+ * @param reg_idx   the register vfp index
+ * @param node      the node that produces the value of the vfp register
+ * @param dbl_push  if != 0 double pushes are allowd
  */
-static void x87_push(x87_state *state, int reg_idx, ir_node *node) {
-       assert(x87_on_stack(state, reg_idx) == -1 && "double push");
+static void x87_push(x87_state *state, int reg_idx, ir_node *node, int dbl_push) {
+       assert((dbl_push || x87_on_stack(state, reg_idx) == -1) && "double push");
        assert(state->depth < N_x87_REGS && "stack overrun");
 
        ++state->depth;
@@ -305,6 +311,7 @@ static blk_state *x87_get_bl_state(x87_simulator *sim, ir_node *block) {
  */
 static x87_state *x87_alloc_state(x87_simulator *sim) {
        x87_state *res = obstack_alloc(&sim->obst, sizeof(*res));
+       res->sim = sim;
        return res;
 }
 
@@ -369,6 +376,27 @@ static ir_node *x87_patch_insn(ir_node *n, ir_op *op) {
        return res;
 }
 
+/**
+ * Returns the first Proj of a mode_T node having a given mode.
+ *
+ * @param n  the mode_T node
+ * @param m  the desired mode of the Proj
+ * @return The first Proj of mode @p m found or NULL.
+ */
+static ir_node *get_irn_Proj_for_mode(ir_node *n, ir_mode *m) {
+       const ir_edge_t *edge;
+
+       assert(get_irn_mode(n) == mode_T && "Need mode_T node");
+
+       foreach_out_edge(n, edge) {
+               ir_node *proj = get_edge_src_irn(edge);
+               if (get_irn_mode(proj) == m)
+                       return proj;
+       }
+
+       return NULL;
+}
+
 /* -------------- x87 perm --------------- */
 
 /**
@@ -602,21 +630,21 @@ static ir_node *x87_create_fxch(x87_state *state, ir_node *n, int pos, int op_id
 /**
  * Create a fpush before node n.
  *
- * @param state   the x87 state
- * @param n       the node before the fpush
- * @param pos     push st(pos) on stack
- * @param op_idx  if >= 0, replace input op_idx of n with the fpush result
+ * @param state     the x87 state
+ * @param n         the node before the fpush
+ * @param pos       push st(pos) on stack
+ * @param op_idx    if >= 0, replace input op_idx of n with the fpush result
+ * @param dbl_push  if != 0 double pushes are allowd
  */
-static void x87_create_fpush(const arch_env_t *env, x87_state *state, ir_node *n, int pos, int op_idx) {
-       ir_node *fpush, *pred;
+static void x87_create_fpush(const arch_env_t *env, x87_state *state, ir_node *n, int pos, int op_idx, int dbl_push) {
+       ir_node *fpush, *pred = get_irn_n(n, op_idx);
        ia32_attr_t *attr;
-       const arch_register_t *out = arch_get_irn_register(env, n);
+       const arch_register_t *out = arch_get_irn_register(env, pred);
 
-       x87_push(state, arch_register_get_index(out), n);
+       x87_push(state, arch_register_get_index(out), pred, dbl_push);
 
-       pred = get_irn_n(n, op_idx);
        fpush = new_rd_ia32_fpush(NULL, get_irn_irg(n), get_nodes_block(n), pred, get_irn_mode(pred));
-       attr = get_ia32_attr(fpush);
+       attr  = get_ia32_attr(fpush);
        attr->x87[0] = &ia32_st_regs[pos];
        attr->x87[2] = &ia32_st_regs[0];
        if (op_idx >= 0)
@@ -697,16 +725,16 @@ static unsigned vfp_liveness_transfer(const arch_env_t *arch_env, ir_node *irn,
  * @param bl       The block.
  * @return The live bitset.
  */
-static unsigned vfp_liveness_end_of_block(const arch_env_t *arch_env, const ir_node *bl)
+static unsigned vfp_liveness_end_of_block(x87_simulator *sim, const ir_node *bl)
 {
-       irn_live_t *li;
+       int i;
        unsigned live = 0;
        const arch_register_class_t *cls = &ia32_reg_classes[CLASS_ia32_vfp];
 
-       live_foreach(bl, li) {
-               ir_node *irn = (ir_node *) li->irn;
-               if (live_is_end(li) && arch_irn_consider_in_reg_alloc(arch_env, cls, irn)) {
-                       const arch_register_t *reg = arch_get_irn_register(arch_env, irn);
+       be_lv_foreach(sim->lv, bl, be_lv_state_end, i) {
+               ir_node *irn = be_lv_get_irn(sim->lv, bl, i);
+               if (arch_irn_consider_in_reg_alloc(sim->env, cls, irn)) {
+                       const arch_register_t *reg = arch_get_irn_register(sim->env, irn);
                        live |= 1 << reg->index;
                }
        }
@@ -720,14 +748,13 @@ static unsigned vfp_liveness_end_of_block(const arch_env_t *arch_env, const ir_n
  * @param pos      The node.
  * @return The live bitset.
  */
-static unsigned vfp_liveness_nodes_live_at(const arch_env_t *arch_env, const ir_node *pos)
+static unsigned vfp_liveness_nodes_live_at(x87_simulator *sim, const ir_node *pos)
 {
        const ir_node *bl = is_Block(pos) ? pos : get_nodes_block(pos);
-       const arch_register_class_t *cls = &ia32_reg_classes[CLASS_ia32_vfp];
        ir_node *irn;
        unsigned live;
 
-       live = vfp_liveness_end_of_block(arch_env, bl);
+       live = vfp_liveness_end_of_block(sim, bl);
 
        sched_foreach_reverse(bl, irn) {
                /*
@@ -737,7 +764,7 @@ static unsigned vfp_liveness_nodes_live_at(const arch_env_t *arch_env, const ir_
                if (irn == pos)
                        return live;
 
-               live = vfp_liveness_transfer(arch_env, irn, live);
+               live = vfp_liveness_transfer(sim->env, irn, live);
        }
 
        return live;
@@ -784,7 +811,7 @@ static void vfp_dump_live(unsigned live) {
  * @param env    the architecture environment
  * @param tmpl   the template containing the 4 possible x87 opcodes
  */
-static void sim_binop(x87_state *state, ir_node *n, const arch_env_t *env, const exchange_tmpl *tmpl) {
+static int sim_binop(x87_state *state, ir_node *n, const arch_env_t *env, const exchange_tmpl *tmpl) {
        int op2_idx, op1_idx = -1;
        int out_idx, do_pop =0;
        ia32_attr_t *attr;
@@ -792,7 +819,7 @@ static void sim_binop(x87_state *state, ir_node *n, const arch_env_t *env, const
        const arch_register_t *op1 = arch_get_irn_register(env, get_irn_n(n, BINOP_IDX_1));
        const arch_register_t *op2 = arch_get_irn_register(env, get_irn_n(n, BINOP_IDX_2));
        const arch_register_t *out = arch_get_irn_register(env, n);
-       unsigned live = vfp_liveness_nodes_live_at(env, n);
+       unsigned live = vfp_liveness_nodes_live_at(state->sim, n);
 
        DB((dbg, LEVEL_1, ">>> %s %s, %s -> %s\n", get_irn_opname(n),
                arch_register_get_name(op1), arch_register_get_name(op2),
@@ -811,7 +838,7 @@ static void sim_binop(x87_state *state, ir_node *n, const arch_env_t *env, const
                        if (is_vfp_live(op1->index, live)) {
                                /* Both operands are live: push the first one.
                                   This works even for op1 == op2. */
-                               x87_create_fpush(env, state, n, op2_idx, BINOP_IDX_2);
+                               x87_create_fpush(env, state, n, op2_idx, BINOP_IDX_2, 0);
                                out_idx = op2_idx = 0;
                                ++op1_idx;
                                dst = tmpl->normal_op;
@@ -892,7 +919,7 @@ static void sim_binop(x87_state *state, ir_node *n, const arch_env_t *env, const
                /* second operand is an address mode */
                if (is_vfp_live(op1->index, live)) {
                        /* first operand is live: push it here */
-                       x87_create_fpush(env, state, n, op1_idx, BINOP_IDX_1);
+                       x87_create_fpush(env, state, n, op1_idx, BINOP_IDX_1, 0);
                }
                else {
                        /* first operand is dead: bring it to tos */
@@ -923,6 +950,8 @@ static void sim_binop(x87_state *state, ir_node *n, const arch_env_t *env, const
                DB((dbg, LEVEL_1, "<<< %s %s, [AM] -> %s\n", get_irn_opname(n),
                        arch_register_get_name(op1),
                        arch_register_get_name(out)));
+
+       return 0;
 }
 
 /**
@@ -933,12 +962,12 @@ static void sim_binop(x87_state *state, ir_node *n, const arch_env_t *env, const
  * @param env    the architecture environment
  * @param op     the x87 opcode that will replace n's opcode
  */
-static void sim_unop(x87_state *state, ir_node *n, const arch_env_t *env, ir_op *op) {
+static int sim_unop(x87_state *state, ir_node *n, const arch_env_t *env, ir_op *op) {
        int op1_idx, out_idx;
        const arch_register_t *op1 = arch_get_irn_register(env, get_irn_n(n, UNOP_IDX));
        const arch_register_t *out = arch_get_irn_register(env, n);
        ia32_attr_t *attr;
-       unsigned live = vfp_liveness_nodes_live_at(env, n);
+       unsigned live = vfp_liveness_nodes_live_at(state->sim, n);
 
        DB((dbg, LEVEL_1, ">>> %s -> %s\n", get_irn_opname(n), out->name));
        DEBUG_ONLY(vfp_dump_live(live));
@@ -947,7 +976,7 @@ static void sim_unop(x87_state *state, ir_node *n, const arch_env_t *env, ir_op
 
        if (is_vfp_live(op1->index, live)) {
                /* push the operand here */
-               x87_create_fpush(env, state, n, op1_idx, UNOP_IDX);
+               x87_create_fpush(env, state, n, op1_idx, UNOP_IDX, 0);
        }
        else {
                /* operand is dead, bring it to tos */
@@ -961,6 +990,8 @@ static void sim_unop(x87_state *state, ir_node *n, const arch_env_t *env, ir_op
        attr->x87[0] = op1 = &ia32_st_regs[0];
        attr->x87[2] = out = &ia32_st_regs[0];
        DB((dbg, LEVEL_1, "<<< %s -> %s\n", get_irn_opname(n), out->name));
+
+       return 0;
 }
 
 /**
@@ -971,15 +1002,45 @@ static void sim_unop(x87_state *state, ir_node *n, const arch_env_t *env, ir_op
  * @param env    the architecture environment
  * @param op     the x87 opcode that will replace n's opcode
  */
-static void sim_load(x87_state *state, ir_node *n, const arch_env_t *env, ir_op *op) {
+static int sim_load(x87_state *state, ir_node *n, const arch_env_t *env, ir_op *op) {
        const arch_register_t *out = arch_get_irn_register(env, n);
        ia32_attr_t *attr;
 
        DB((dbg, LEVEL_1, ">>> %s -> %s\n", get_irn_opname(n), arch_register_get_name(out)));
-       x87_push(state, arch_register_get_index(out), x87_patch_insn(n, op));
+       x87_push(state, arch_register_get_index(out), x87_patch_insn(n, op), 0);
        attr = get_ia32_attr(n);
        attr->x87[2] = out = &ia32_st_regs[0];
        DB((dbg, LEVEL_1, "<<< %s -> %s\n", get_irn_opname(n), arch_register_get_name(out)));
+
+       return 0;
+}
+
+/**
+ * Rewire all users of @p old_val to @new_val iff they are scheduled after @p store.
+ *
+ * @param store   The store
+ * @param old_val The former value
+ * @param new_val The new value
+ */
+static void collect_and_rewire_users(ir_node *store, ir_node *old_val, ir_node *new_val) {
+       const ir_edge_t *edge, *ne;
+
+       foreach_out_edge_safe(old_val, edge, ne) {
+               ir_node *user = get_edge_src_irn(edge);
+
+               if (! user || user == store)
+                       continue;
+
+               /* if the user is scheduled after the store: rewire */
+               if (sched_is_scheduled(user) && sched_comes_after(store, user)) {
+                       int i;
+                       /* find the input of the user pointing to the old value */
+                       for (i = get_irn_arity(user) - 1; i >= 0; i--) {
+                               if (get_irn_n(user, i) == old_val)
+                                       set_irn_n(user, i, new_val);
+                       }
+               }
+       }
 }
 
 /**
@@ -991,23 +1052,94 @@ static void sim_load(x87_state *state, ir_node *n, const arch_env_t *env, ir_op
  * @param op     the x87 store opcode
  * @param op_p   the x87 store and pop opcode
  */
-static void sim_store(x87_state *state, ir_node *n, const arch_env_t *env, ir_op *op, ir_op *op_p) {
-       int op2_idx;
-       const arch_register_t *op2 = arch_get_irn_register(env, get_irn_n(n, STORE_VAL_IDX));
+static int sim_store(x87_state *state, ir_node *n, const arch_env_t *env, ir_op *op, ir_op *op_p) {
+       ir_node               *val = get_irn_n(n, STORE_VAL_IDX);
+       const arch_register_t *op2 = arch_get_irn_register(env, val);
+       unsigned              live = vfp_liveness_nodes_live_at(state->sim, n);
+       int                   insn = 0;
        ia32_attr_t *attr;
-       unsigned live = vfp_liveness_nodes_live_at(env, n);
+       int op2_idx, depth;
+       ir_mode *mode;
 
        op2_idx = x87_on_stack(state, arch_register_get_index(op2));
        assert(op2_idx >= 0);
 
        DB((dbg, LEVEL_1, ">>> %s %s ->\n", get_irn_opname(n), arch_register_get_name(op2)));
 
-       /* we can only store the tos to memory */
-       if (op2_idx != 0)
+       mode  = get_ia32_ls_mode(n);
+       depth = x87_get_depth(state);
+
+       /*
+               We can only store the tos to memory.
+               A store of mode_E with free registers
+               pushes value to tos, so skip it here.
+       */
+       if (! (mode == mode_E && depth < N_x87_REGS) && op2_idx != 0)
                x87_create_fxch(state, n, op2_idx, STORE_VAL_IDX);
 
-       if (is_vfp_live(op2->index, live))
-               x87_patch_insn(n, op);
+       if (is_vfp_live(op2->index, live)) {
+               /*
+                       Problem: fst doesn't support mode_E (spills), only fstp does
+                       Solution:
+                               - stack not full: push value and fstp
+                               - stack full: fstp value and load again
+               */
+               if (mode == mode_E) {
+                       if (depth < N_x87_REGS) {
+                               /* ok, we have a free register: push + fstp */
+                               x87_create_fpush(env, state, n, op2_idx, STORE_VAL_IDX, 1);
+                               x87_pop(state);
+                               x87_patch_insn(n, op_p);
+                       }
+                       else {
+                               ir_node  *vfld, *mem, *block, *rproj, *mproj;
+                               ir_graph *irg;
+
+                               /* stack full here: need fstp + load */
+                               x87_pop(state);
+                               x87_patch_insn(n, op_p);
+
+                               block = get_nodes_block(n);
+                               irg   = get_irn_irg(n);
+                               vfld  = new_rd_ia32_vfld(NULL, irg, block, get_irn_n(n, 0), get_irn_n(n, 1), new_rd_NoMem(irg));
+
+                               /* copy all attributes */
+                               set_ia32_frame_ent(vfld, get_ia32_frame_ent(n));
+                               if (is_ia32_use_frame(n))
+                                       set_ia32_use_frame(vfld);
+                               set_ia32_am_flavour(vfld, get_ia32_am_flavour(n));
+                               set_ia32_op_type(vfld, ia32_am_Source);
+                               add_ia32_am_offs(vfld, get_ia32_am_offs(n));
+                               set_ia32_am_sc(vfld, get_ia32_am_sc(n));
+                               set_ia32_ls_mode(vfld, get_ia32_ls_mode(n));
+
+                               rproj = new_r_Proj(irg, block, vfld, get_ia32_ls_mode(vfld), pn_ia32_vfld_res);
+                               mproj = new_r_Proj(irg, block, vfld, mode_M, pn_ia32_vfld_M);
+                               mem   = get_irn_Proj_for_mode(n, mode_M);
+
+                               assert(mem && "Store memory not found");
+
+                               arch_set_irn_register(env, rproj, op2);
+
+                               /* reroute all former users of the store memory to the load memory */
+                               edges_reroute(mem, mproj, irg);
+                               /* set the memory input of the load to the store memory */
+                               set_irn_n(vfld, 2, mem);
+
+                               sched_add_after(n, vfld);
+                               sched_add_after(vfld, rproj);
+
+                               /* rewire all users, scheduled after the store, to the loaded value */
+                               collect_and_rewire_users(n, val, rproj);
+
+                               insn = 1;
+                       }
+               }
+               else {
+                       /* mode != mode_E -> use normal fst */
+                       x87_patch_insn(n, op);
+               }
+       }
        else {
                x87_pop(state);
                x87_patch_insn(n, op_p);
@@ -1016,6 +1148,8 @@ static void sim_store(x87_state *state, ir_node *n, const arch_env_t *env, ir_op
        attr = get_ia32_attr(n);
        attr->x87[1] = op2 = &ia32_st_regs[0];
        DB((dbg, LEVEL_1, "<<< %s %s ->\n", get_irn_opname(n), arch_register_get_name(op2)));
+
+       return insn;
 }
 
 /**
@@ -1026,38 +1160,40 @@ static void sim_store(x87_state *state, ir_node *n, const arch_env_t *env, ir_op
  * @param n      the node that should be simulated (and patched)
  * @param env    the architecture environment
  */
-static void sim_Phi(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_Phi(x87_state *state, ir_node *n, const arch_env_t *env) {
        ir_mode *mode = get_irn_mode(n);
 
        if (mode_is_float(mode))
                set_irn_mode(n, mode_E);
+
+       return 0;
 }
 
 
 #define _GEN_BINOP(op, rev) \
-static void sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
+static int sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
        exchange_tmpl tmpl = { op_ia32_##op, op_ia32_##rev, op_ia32_##op##p, op_ia32_##rev##p }; \
-       sim_binop(state, n, env, &tmpl); \
+       return sim_binop(state, n, env, &tmpl); \
 }
 
-#define GEN_BINOP(op)    _GEN_BINOP(op, op)
+#define GEN_BINOP(op)   _GEN_BINOP(op, op)
 #define GEN_BINOPR(op) _GEN_BINOP(op, op##r)
 
 #define GEN_LOAD2(op, nop) \
-static void sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
-       sim_load(state, n, env, op_ia32_##nop); \
+static int sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
+       return sim_load(state, n, env, op_ia32_##nop); \
 }
 
 #define GEN_LOAD(op)   GEN_LOAD2(op, op)
 
 #define GEN_UNOP(op) \
-static void sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
-       sim_unop(state, n, env, op_ia32_##op); \
+static int sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
+       return sim_unop(state, n, env, op_ia32_##op); \
 }
 
 #define GEN_STORE(op) \
-static void sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
-       sim_store(state, n, env, op_ia32_##op, op_ia32_##op##p); \
+static int sim_##op(x87_state *state, ir_node *n, const arch_env_t *env) { \
+       return sim_store(state, n, env, op_ia32_##op, op_ia32_##op##p); \
 }
 
 /* all stubs */
@@ -1088,13 +1224,13 @@ GEN_STORE(fist)
  * @param n      the node that should be simulated (and patched)
  * @param env    the architecture environment
  */
-static void sim_fCondJmp(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_fCondJmp(x87_state *state, ir_node *n, const arch_env_t *env) {
        int op2_idx, op1_idx = -1, pop_cnt = 0;
        ia32_attr_t *attr;
        ir_op *dst;
        const arch_register_t *op1 = arch_get_irn_register(env, get_irn_n(n, BINOP_IDX_1));
        const arch_register_t *op2 = arch_get_irn_register(env, get_irn_n(n, BINOP_IDX_2));
-       unsigned live = vfp_liveness_nodes_live_at(env, n);
+       unsigned live = vfp_liveness_nodes_live_at(state->sim, n);
 
        DB((dbg, LEVEL_1, ">>> %s %s, %s\n", get_irn_opname(n),
                arch_register_get_name(op1), arch_register_get_name(op2)));
@@ -1261,6 +1397,8 @@ static void sim_fCondJmp(x87_state *state, ir_node *n, const arch_env_t *env) {
        else
                DB((dbg, LEVEL_1, "<<< %s %s, [AM]\n", get_irn_opname(n),
                        arch_register_get_name(op1)));
+
+       return 0;
 }
 
 /**
@@ -1270,7 +1408,7 @@ static void sim_fCondJmp(x87_state *state, ir_node *n, const arch_env_t *env) {
  * @param n      the node that should be simulated (and patched)
  * @param env    the architecture environment
  */
-static void sim_Copy(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_Copy(x87_state *state, ir_node *n, const arch_env_t *env) {
        ir_mode *mode = get_irn_mode(n);
 
        if (mode_is_float(mode)) {
@@ -1279,7 +1417,7 @@ static void sim_Copy(x87_state *state, ir_node *n, const arch_env_t *env) {
                ir_node *node, *next;
                ia32_attr_t *attr;
                int op1_idx, out_idx;
-               unsigned live = vfp_liveness_nodes_live_at(env, n);
+               unsigned live = vfp_liveness_nodes_live_at(state->sim, n);
 
                op1_idx = x87_on_stack(state, arch_register_get_index(op1));
 
@@ -1292,7 +1430,7 @@ static void sim_Copy(x87_state *state, ir_node *n, const arch_env_t *env) {
                        node = new_rd_ia32_fpush(get_irn_dbg_info(n), get_irn_irg(n), get_nodes_block(n), get_irn_n(n, 0), mode);
                        arch_set_irn_register(env, node, out);
 
-                       x87_push(state, arch_register_get_index(out), node);
+                       x87_push(state, arch_register_get_index(out), node, 0);
 
                        attr = get_ia32_attr(node);
                        attr->x87[0] = op1 = &ia32_st_regs[op1_idx];
@@ -1342,6 +1480,8 @@ static void sim_Copy(x87_state *state, ir_node *n, const arch_env_t *env) {
                        }
                }
        }
+
+       return 0;
 }
 
 /**
@@ -1351,7 +1491,7 @@ static void sim_Copy(x87_state *state, ir_node *n, const arch_env_t *env) {
  * @param n      the node that should be simulated
  * @param env    the architecture environment
  */
-static void sim_Call(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_Call(x87_state *state, ir_node *n, const arch_env_t *env) {
        ir_type *call_tp = be_Call_get_type(n);
 
        /* at the begin of a call the x87 state should be empty */
@@ -1371,9 +1511,11 @@ static void sim_Call(x87_state *state, ir_node *n, const arch_env_t *env) {
                         * TODO: what to push here? The result might be unused and currently
                         * we have no possibility to detect this :-(
                         */
-                       x87_push(state, 0, n);
+                       x87_push(state, 0, n, 0);
                }
        }
+
+       return 0;
 }
 
 /**
@@ -1385,9 +1527,9 @@ static void sim_Call(x87_state *state, ir_node *n, const arch_env_t *env) {
  *
  * Should not happen, spills are lowered before x87 simulator see them.
  */
-static void sim_Spill(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_Spill(x87_state *state, ir_node *n, const arch_env_t *env) {
        assert(0 && "Spill not lowered");
-       sim_fst(state, n, env);
+       return sim_fst(state, n, env);
 }
 
 /**
@@ -1399,9 +1541,9 @@ static void sim_Spill(x87_state *state, ir_node *n, const arch_env_t *env) {
  *
  * Should not happen, reloads are lowered before x87 simulator see them.
  */
-static void sim_Reload(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_Reload(x87_state *state, ir_node *n, const arch_env_t *env) {
        assert(0 && "Reload not lowered");
-       sim_fld(state, n, env);
+       return sim_fld(state, n, env);
 }
 
 /**
@@ -1411,7 +1553,7 @@ static void sim_Reload(x87_state *state, ir_node *n, const arch_env_t *env) {
  * @param n      the node that should be simulated (and patched)
  * @param env    the architecture environment
  */
-static void sim_Return(x87_state *state, ir_node *n, const arch_env_t *env) {
+static int sim_Return(x87_state *state, ir_node *n, const arch_env_t *env) {
        int n_res = be_Return_get_n_rets(n);
        int i, n_float_res = 0;
 
@@ -1427,6 +1569,8 @@ static void sim_Return(x87_state *state, ir_node *n, const arch_env_t *env) {
        /* pop them virtually */
        for (i = n_float_res - 1; i >= 0; --i)
                x87_pop(state);
+
+       return 0;
 }
 
 /**
@@ -1440,7 +1584,7 @@ static x87_state *x87_kill_deads(x87_simulator *sim, ir_node *block, x87_state *
        x87_state *state = start_state;
        ir_node *first_insn = sched_first(block);
        ir_node *keep = NULL;
-       unsigned live = vfp_liveness_nodes_live_at(sim->env, block);
+       unsigned live = vfp_liveness_nodes_live_at(sim, block);
        unsigned kill_mask;
        int i, depth, num_pop;
 
@@ -1532,6 +1676,7 @@ static int x87_simulate_block(x87_simulator *sim, ir_node *block) {
 
                next = sched_next(n);
                if (op->ops.generic) {
+                       int node_inserted;
                        sim_func func = (sim_func)op->ops.generic;
 
                        /* have work to do */
@@ -1541,7 +1686,16 @@ static int x87_simulate_block(x87_simulator *sim, ir_node *block) {
                        }
 
                        /* simulate it */
-                       (*func)(state, n, sim->env);
+                       node_inserted = (*func)(state, n, sim->env);
+
+                       /*
+                               sim_func might have added additional nodes after n,
+                               so update next node
+                               beware: n must not be changed by sim_func
+                               (i.e. removed from schedule) in this case
+                       */
+                       if (node_inserted)
+                               next = sched_next(n);
                }
        }
 
@@ -1588,6 +1742,7 @@ static void x87_init_simulator(x87_simulator *sim, ir_graph *irg, const arch_env
        obstack_init(&sim->obst);
        sim->blk_states = pmap_create();
        sim->env        = env;
+       sim->lv         = be_liveness(irg);
 
        FIRM_DBG_REGISTER(dbg, "firm.be.ia32.x87");
 
@@ -1637,6 +1792,7 @@ static void x87_init_simulator(x87_simulator *sim, ir_graph *irg, const arch_env
 static void x87_destroy_simulator(x87_simulator *sim) {
        pmap_destroy(sim->blk_states);
        obstack_free(&sim->obst, NULL);
+       be_liveness_free(sim->lv);
        DB((dbg, LEVEL_1, "x87 Simulator stopped\n\n"));
 }
 
@@ -1656,9 +1812,6 @@ void x87_simulate_graph(const arch_env_t *env, ir_graph *irg, ir_node **blk_list
        x87_simulator sim;
        int i;
 
-       /* we need liveness info for the current graph */
-       be_liveness(irg);
-
        /* create the simulator */
        x87_init_simulator(&sim, irg, env);
 
@@ -1667,6 +1820,7 @@ void x87_simulate_graph(const arch_env_t *env, ir_graph *irg, ir_node **blk_list
 
        /* start with the empty state */
        bl_state->begin = empty;
+       empty->sim      = &sim;
 
        worklist = new_pdeq();