+static int sim_Fucom(x87_state *state, ir_node *n)
+{
+ int op1_idx;
+ int op2_idx = -1;
+ 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_vFucomFnstsw_left);
+ ir_node *op2_node = get_irn_n(n, n_ia32_vFucomFnstsw_right);
+ const arch_register_t *op1 = x87_get_irn_register(op1_node);
+ const arch_register_t *op2 = x87_get_irn_register(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);
+ bool permuted = attr->attr.data.ins_permuted;
+ bool xchg = false;
+ int pops = 0;
+
+ DB((dbg, LEVEL_1, ">>> %+F %s, %s\n", n,
+ arch_register_get_name(op1), arch_register_get_name(op2)));
+ DEBUG_ONLY(vfp_dump_live(live);)
+ DB((dbg, LEVEL_1, "Stack before: "));
+ DEBUG_ONLY(x87_dump_stack(state);)
+
+ op1_idx = x87_on_stack(state, reg_index_1);
+ assert(op1_idx >= 0);
+
+ /* BEWARE: check for comp a,a cases, they might happen */
+ if (reg_index_2 != REG_VFP_VFP_NOREG) {
+ /* second operand is a vfp register */
+ op2_idx = x87_on_stack(state, reg_index_2);
+ assert(op2_idx >= 0);
+
+ if (is_vfp_live(reg_index_2, live)) {
+ /* second operand is live */
+
+ if (is_vfp_live(reg_index_1, live)) {
+ /* both operands are live */
+
+ if (op1_idx == 0) {
+ /* res = tos X op */
+ } else if (op2_idx == 0) {
+ /* res = op X tos */
+ permuted = !permuted;
+ xchg = true;
+ } else {
+ /* bring the first one to tos */
+ x87_create_fxch(state, n, op1_idx);
+ if (op1_idx == op2_idx) {
+ op2_idx = 0;
+ } else if (op2_idx == 0) {
+ op2_idx = op1_idx;
+ }
+ op1_idx = 0;
+ /* res = tos X op */
+ }
+ } else {
+ /* second live, first operand is dead here, bring it to tos.
+ This means further, op1_idx != op2_idx. */
+ assert(op1_idx != op2_idx);
+ if (op1_idx != 0) {
+ x87_create_fxch(state, n, op1_idx);
+ if (op2_idx == 0)
+ op2_idx = op1_idx;
+ op1_idx = 0;
+ }
+ /* res = tos X op, pop */
+ pops = 1;
+ }
+ } else {
+ /* second operand is dead */
+ if (is_vfp_live(reg_index_1, live)) {
+ /* first operand is live: bring second to tos.
+ This means further, op1_idx != op2_idx. */
+ assert(op1_idx != op2_idx);
+ if (op2_idx != 0) {
+ x87_create_fxch(state, n, op2_idx);
+ if (op1_idx == 0)
+ op1_idx = op2_idx;
+ op2_idx = 0;
+ }
+ /* res = op X tos, pop */
+ pops = 1;
+ permuted = !permuted;
+ xchg = true;
+ } else {
+ /* both operands are dead here, check first for identity. */
+ if (op1_idx == op2_idx) {
+ /* identically, one pop needed */
+ if (op1_idx != 0) {
+ x87_create_fxch(state, n, op1_idx);
+ op1_idx = 0;
+ op2_idx = 0;
+ }
+ /* res = tos X op, pop */
+ pops = 1;
+ }
+ /* different, move them to st and st(1) and pop both.
+ The tricky part is to get one into st(1).*/
+ else if (op2_idx == 1) {
+ /* good, second operand is already in the right place, move the first */
+ if (op1_idx != 0) {
+ /* bring the first on top */
+ x87_create_fxch(state, n, op1_idx);
+ assert(op2_idx != 0);
+ op1_idx = 0;
+ }
+ /* res = tos X op, pop, pop */
+ pops = 2;
+ } else if (op1_idx == 1) {
+ /* good, first operand is already in the right place, move the second */
+ if (op2_idx != 0) {
+ /* bring the first on top */
+ x87_create_fxch(state, n, op2_idx);
+ assert(op1_idx != 0);
+ op2_idx = 0;
+ }
+ /* res = op X tos, pop, pop */
+ permuted = !permuted;
+ xchg = true;
+ pops = 2;
+ } else {
+ /* if one is already the TOS, we need two fxch */
+ if (op1_idx == 0) {
+ /* first one is TOS, move to st(1) */
+ x87_create_fxch(state, n, 1);
+ assert(op2_idx != 1);
+ op1_idx = 1;
+ x87_create_fxch(state, n, op2_idx);
+ op2_idx = 0;
+ /* res = op X tos, pop, pop */
+ pops = 2;
+ permuted = !permuted;
+ xchg = true;
+ } else if (op2_idx == 0) {
+ /* second one is TOS, move to st(1) */
+ x87_create_fxch(state, n, 1);
+ assert(op1_idx != 1);
+ op2_idx = 1;
+ x87_create_fxch(state, n, op1_idx);
+ op1_idx = 0;
+ /* res = tos X op, pop, pop */
+ pops = 2;
+ } else {
+ /* none of them is either TOS or st(1), 3 fxch needed */
+ x87_create_fxch(state, n, op2_idx);
+ assert(op1_idx != 0);
+ x87_create_fxch(state, n, 1);
+ op2_idx = 1;
+ x87_create_fxch(state, n, op1_idx);
+ op1_idx = 0;
+ /* res = tos X op, pop, pop */
+ pops = 2;
+ }
+ }
+ }
+ }
+ } else {
+ /* second operand is an address mode */
+ if (is_vfp_live(reg_index_1, live)) {
+ /* first operand is live: bring it to TOS */
+ if (op1_idx != 0) {
+ x87_create_fxch(state, n, op1_idx);
+ op1_idx = 0;
+ }
+ } else {
+ /* first operand is dead: bring it to tos */
+ if (op1_idx != 0) {
+ x87_create_fxch(state, n, op1_idx);
+ op1_idx = 0;
+ }
+ pops = 1;
+ }
+ }
+
+ /* patch the operation */
+ if (is_ia32_vFucomFnstsw(n)) {
+ int i;
+
+ switch (pops) {
+ case 0: dst = op_ia32_FucomFnstsw; break;
+ case 1: dst = op_ia32_FucompFnstsw; break;
+ case 2: dst = op_ia32_FucomppFnstsw; break;
+ default: panic("invalid popcount");
+ }
+
+ for (i = 0; i < pops; ++i) {
+ x87_pop(state);
+ }
+ } else if (is_ia32_vFucomi(n)) {
+ switch (pops) {
+ case 0: dst = op_ia32_Fucomi; break;
+ case 1: dst = op_ia32_Fucompi; x87_pop(state); break;
+ case 2:
+ dst = op_ia32_Fucompi;
+ x87_pop(state);
+ x87_create_fpop(state, sched_next(n), 1);
+ break;
+ default: panic("invalid popcount");
+ }
+ } else {
+ panic("invalid operation %+F", n);
+ }
+
+ x87_patch_insn(n, dst);
+ if (xchg) {
+ int tmp = op1_idx;
+ op1_idx = op2_idx;
+ op2_idx = tmp;
+ }
+
+ op1 = get_st_reg(op1_idx);
+ attr->x87[0] = op1;
+ if (op2_idx >= 0) {
+ op2 = get_st_reg(op2_idx);
+ attr->x87[1] = op2;
+ }
+ attr->x87[2] = NULL;
+ attr->attr.data.ins_permuted = permuted;
+
+ if (op2_idx >= 0) {
+ DB((dbg, LEVEL_1, "<<< %s %s, %s\n", get_irn_opname(n),
+ arch_register_get_name(op1), arch_register_get_name(op2)));
+ } else {
+ DB((dbg, LEVEL_1, "<<< %s %s, [AM]\n", get_irn_opname(n),
+ arch_register_get_name(op1)));
+ }
+
+ return NO_NODE_ADDED;
+}
+
+/**
+ * Simulate a Keep.
+ *
+ * @param state the x87 state
+ * @param n the node that should be simulated (and patched)
+ *
+ * @return NO_NODE_ADDED
+ */
+static int sim_Keep(x87_state *state, ir_node *node)
+{
+ const ir_node *op;
+ const arch_register_t *op_reg;
+ int reg_id;
+ int op_stack_idx;
+ unsigned live;
+ int i, arity;
+
+ DB((dbg, LEVEL_1, ">>> %+F\n", node));
+
+ arity = get_irn_arity(node);
+ for (i = 0; i < arity; ++i) {
+ op = get_irn_n(node, i);
+ op_reg = arch_get_irn_register(op);
+ if (arch_register_get_class(op_reg) != &ia32_reg_classes[CLASS_ia32_vfp])
+ continue;
+
+ reg_id = arch_register_get_index(op_reg);
+ live = vfp_live_args_after(state->sim, node, 0);
+
+ op_stack_idx = x87_on_stack(state, reg_id);
+ if (op_stack_idx >= 0 && !is_vfp_live(reg_id, live))
+ x87_create_fpop(state, sched_next(node), 1);
+ }
+
+ DB((dbg, LEVEL_1, "Stack after: "));
+ DEBUG_ONLY(x87_dump_stack(state);)
+
+ return NO_NODE_ADDED;
+}
+
+/**
+ * Keep the given node alive by adding a be_Keep.
+ *
+ * @param node the node to kept alive
+ */
+static void keep_float_node_alive(ir_node *node)
+{
+ ir_node *block = get_nodes_block(node);
+ ir_node *keep = be_new_Keep(block, 1, &node);
+
+ assert(sched_is_scheduled(node));
+ sched_add_after(node, keep);
+}
+
+/**
+ * Create a copy of a node. Recreate the node if it's a constant.
+ *
+ * @param state the x87 state
+ * @param n the node to be copied
+ *
+ * @return the copy of n
+ */
+static ir_node *create_Copy(x87_state *state, ir_node *n)
+{
+ dbg_info *n_dbg = get_irn_dbg_info(n);