+ * Simulate a fCondJmp.
+ *
+ * @param state the x87 state
+ * @param n the node that should be simulated (and patched)
+ *
+ * @return NO_NODE_ADDED
+ */
+static int sim_fCmpJmp(x87_state *state, ir_node *n) {
+ int op1_idx;
+ int op2_idx = -1;
+ int pop_cnt = 0;
+ ia32_x87_attr_t *attr;
+ ir_op *dst;
+ x87_simulator *sim = state->sim;
+ ir_node *op1_node = get_irn_n(n, n_ia32_vfCmpJmp_left);
+ ir_node *op2_node = get_irn_n(n, n_ia32_vfCmpJmp_right);
+ const arch_register_t *op1 = x87_get_irn_register(sim, op1_node);
+ const arch_register_t *op2 = x87_get_irn_register(sim, 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);
+
+ 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_NOREG) {
+ /* second operand is a vfp register */
+ op2_idx = x87_on_stack(state, reg_index_2);
+ assert(op2_idx >= 0);
+
+ if (is_vfp_live(arch_register_get_index(op2), live)) {
+ /* second operand is live */
+
+ if (is_vfp_live(arch_register_get_index(op1), live)) {
+ /* both operands are live */
+
+ if (op1_idx == 0) {
+ /* res = tos X op */
+ dst = op_ia32_fcomJmp;
+ } else if (op2_idx == 0) {
+ /* res = op X tos */
+ dst = op_ia32_fcomrJmp;
+ } else {
+ /* bring the first one to tos */
+ x87_create_fxch(state, n, op1_idx);
+ if (op2_idx == 0)
+ op2_idx = op1_idx;
+ op1_idx = 0;
+ /* res = tos X op */
+ dst = op_ia32_fcomJmp;
+ }
+ } 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 */
+ dst = op_ia32_fcompJmp;
+ pop_cnt = 1;
+ }
+ } else {
+ /* second operand is dead */
+ if (is_vfp_live(arch_register_get_index(op1), 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 */
+ dst = op_ia32_fcomrpJmp;
+ pop_cnt = 1;
+ } 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 */
+ dst = op_ia32_fcompJmp;
+ pop_cnt = 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 */
+ dst = op_ia32_fcomppJmp;
+ pop_cnt = 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;
+ }
+ dst = op_ia32_fcomrppJmp;
+ pop_cnt = 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 */
+ dst = op_ia32_fcomrppJmp;
+ pop_cnt = 2;
+ } 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 */
+ dst = op_ia32_fcomppJmp;
+ pop_cnt = 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 */
+ dst = op_ia32_fcomppJmp;
+ pop_cnt = 2;
+ }
+ }
+ }
+ }
+ } else {
+ /* second operand is an address mode */
+ if (is_vfp_live(arch_register_get_index(op1), live)) {
+ /* first operand is live: bring it to TOS */
+ if (op1_idx != 0) {
+ x87_create_fxch(state, n, op1_idx);
+ op1_idx = 0;
+ }
+ dst = op_ia32_fcomJmp;
+ } else {
+ /* first operand is dead: bring it to tos */
+ if (op1_idx != 0) {
+ x87_create_fxch(state, n, op1_idx);
+ op1_idx = 0;
+ }
+ dst = op_ia32_fcompJmp;
+ pop_cnt = 1;
+ }
+ }
+
+ x87_patch_insn(n, dst);
+ assert(pop_cnt < 3);
+ if (pop_cnt >= 2)
+ x87_pop(state);
+ if (pop_cnt >= 1)
+ x87_pop(state);
+
+ /* patch the operation */
+ attr = get_ia32_x87_attr(n);
+ op1 = &ia32_st_regs[op1_idx];
+ attr->x87[0] = op1;
+ if (op2_idx >= 0) {
+ op2 = &ia32_st_regs[op2_idx];
+ attr->x87[1] = op2;
+ }
+ attr->x87[2] = NULL;
+
+ 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;
+} /* sim_fCondJmp */
+
+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;
+ int node_added = NO_NODE_ADDED;
+
+ 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(state->sim->arch_env, 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);
+ node_added = NODE_ADDED;
+ }
+ }
+
+ DB((dbg, LEVEL_1, "Stack after: "));
+ DEBUG_ONLY(x87_dump_stack(state));
+
+ return node_added;
+}
+
+static
+void keep_float_node_alive(x87_state *state, ir_node *node)
+{
+ ir_graph *irg;
+ ir_node *block;
+ ir_node *in[1];
+ ir_node *keep;
+ const arch_register_class_t *cls;
+
+ irg = get_irn_irg(node);
+ block = get_nodes_block(node);
+ cls = arch_get_irn_reg_class(state->sim->arch_env, node, -1);
+ in[0] = node;
+ keep = be_new_Keep(cls, irg, block, 1, in);
+
+ 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