+
+ return NULL;
+} /* get_call_result_proj */
+
+/**
+ * Simulate a ia32_Call.
+ *
+ * @param state the x87 state
+ * @param n the node that should be simulated
+ *
+ * @return NO_NODE_ADDED
+ */
+static int sim_Call(x87_state *state, ir_node *n)
+{
+ ir_type *call_tp = get_ia32_call_attr_const(n)->call_tp;
+ ir_type *res_type;
+ ir_mode *mode;
+ ir_node *resproj;
+ const arch_register_t *reg;
+
+ DB((dbg, LEVEL_1, ">>> %+F\n", n));
+
+ /* at the begin of a call the x87 state should be empty */
+ assert(state->depth == 0 && "stack not empty before call");
+
+ if (get_method_n_ress(call_tp) <= 0)
+ goto end_call;
+
+ /*
+ * If the called function returns a float, it is returned in st(0).
+ * This even happens if the return value is NOT used.
+ * Moreover, only one return result is supported.
+ */
+ res_type = get_method_res_type(call_tp, 0);
+ mode = get_type_mode(res_type);
+
+ if (mode == NULL || !mode_is_float(mode))
+ goto end_call;
+
+ resproj = get_call_result_proj(n);
+ assert(resproj != NULL);
+
+ reg = x87_get_irn_register(resproj);
+ x87_push(state, arch_register_get_index(reg), resproj);
+
+end_call:
+ DB((dbg, LEVEL_1, "Stack after: "));
+ DEBUG_ONLY(x87_dump_stack(state));
+
+ return NO_NODE_ADDED;
+} /* sim_Call */
+
+/**
+ * Simulate a be_Spill.
+ *
+ * @param state the x87 state
+ * @param n the node that should be simulated (and patched)
+ *
+ * Should not happen, spills are lowered before x87 simulator see them.
+ */
+static int sim_Spill(x87_state *state, ir_node *n)
+{
+ panic("Spill not lowered");
+ return sim_fst(state, n);
+} /* sim_Spill */
+
+/**
+ * Simulate a be_Reload.
+ *
+ * @param state the x87 state
+ * @param n the node that should be simulated (and patched)
+ *
+ * Should not happen, reloads are lowered before x87 simulator see them.
+ */
+static int sim_Reload(x87_state *state, ir_node *n)
+{
+ panic("Reload not lowered");
+ return sim_fld(state, n);
+} /* sim_Reload */
+
+/**
+ * Simulate a be_Return.
+ *
+ * @param state the x87 state
+ * @param n the node that should be simulated (and patched)
+ *
+ * @return NO_NODE_ADDED
+ */
+static int sim_Return(x87_state *state, ir_node *n)
+{
+ int n_res = be_Return_get_n_rets(n);
+ int i, n_float_res = 0;
+
+ /* only floating point return values must reside on stack */
+ for (i = 0; i < n_res; ++i) {
+ ir_node *res = get_irn_n(n, be_pos_Return_val + i);
+
+ if (mode_is_float(get_irn_mode(res)))
+ ++n_float_res;
+ }
+ assert(x87_get_depth(state) == n_float_res);
+
+ /* pop them virtually */
+ for (i = n_float_res - 1; i >= 0; --i)
+ x87_pop(state);
+
+ return NO_NODE_ADDED;
+} /* sim_Return */
+
+typedef struct _perm_data_t {
+ const arch_register_t *in;
+ const arch_register_t *out;
+} perm_data_t;
+
+/**
+ * Simulate a be_Perm.
+ *
+ * @param state the x87 state
+ * @param irn the node that should be simulated (and patched)
+ *
+ * @return NO_NODE_ADDED
+ */
+static int sim_Perm(x87_state *state, ir_node *irn)
+{
+ int i, n;
+ ir_node *pred = get_irn_n(irn, 0);
+ int *stack_pos;
+ const ir_edge_t *edge;
+
+ /* handle only floating point Perms */
+ if (! mode_is_float(get_irn_mode(pred)))
+ return NO_NODE_ADDED;
+
+ DB((dbg, LEVEL_1, ">>> %+F\n", irn));
+
+ /* Perm is a pure virtual instruction on x87.
+ All inputs must be on the FPU stack and are pairwise
+ different from each other.
+ So, all we need to do is to permutate the stack state. */
+ n = get_irn_arity(irn);
+ NEW_ARR_A(int, stack_pos, n);
+
+ /* collect old stack positions */
+ for (i = 0; i < n; ++i) {
+ const arch_register_t *inreg = x87_get_irn_register(get_irn_n(irn, i));
+ int idx = x87_on_stack(state, arch_register_get_index(inreg));
+
+ assert(idx >= 0 && "Perm argument not on x87 stack");
+
+ stack_pos[i] = idx;
+ }
+ /* now do the permutation */
+ foreach_out_edge(irn, edge) {
+ ir_node *proj = get_edge_src_irn(edge);
+ const arch_register_t *out = x87_get_irn_register(proj);
+ long num = get_Proj_proj(proj);
+
+ assert(0 <= num && num < n && "More Proj's than Perm inputs");
+ x87_set_st(state, arch_register_get_index(out), proj, stack_pos[(unsigned)num]);
+ }
+ DB((dbg, LEVEL_1, "<<< %+F\n", irn));
+
+ return NO_NODE_ADDED;
+} /* sim_Perm */
+
+static int sim_Barrier(x87_state *state, ir_node *node)
+{
+ int i, arity;
+
+ /* materialize unknown if needed */
+ arity = get_irn_arity(node);
+ for (i = 0; i < arity; ++i) {
+ const arch_register_t *reg;
+ ir_node *zero;
+ ir_node *block;
+ ia32_x87_attr_t *attr;
+ ir_node *in = get_irn_n(node, i);
+
+ if (!is_ia32_Unknown_VFP(in))
+ continue;
+
+ /* TODO: not completely correct... */
+ reg = &ia32_vfp_regs[REG_VFP_UKNWN];
+
+ /* create a zero */
+ block = get_nodes_block(node);
+ zero = new_bd_ia32_fldz(NULL, block, mode_E);
+ x87_push(state, arch_register_get_index(reg), zero);
+
+ attr = get_ia32_x87_attr(zero);
+ attr->x87[2] = &ia32_st_regs[0];
+
+ sched_add_before(node, zero);
+
+ set_irn_n(node, i, zero);
+ }
+
+ return NO_NODE_ADDED;
+}
+
+
+/**
+ * Kill any dead registers at block start by popping them from the stack.
+ *
+ * @param sim the simulator handle
+ * @param block the current block
+ * @param start_state the x87 state at the begin of the block
+ *
+ * @return the x87 state after dead register killed
+ */
+static x87_state *x87_kill_deads(x87_simulator *sim, ir_node *block, x87_state *start_state)
+{
+ x87_state *state = start_state;
+ ir_node *first_insn = sched_first(block);
+ ir_node *keep = NULL;
+ unsigned live = vfp_live_args_after(sim, block, 0);
+ unsigned kill_mask;
+ int i, depth, num_pop;
+
+ kill_mask = 0;
+ depth = x87_get_depth(state);
+ for (i = depth - 1; i >= 0; --i) {
+ int reg = x87_get_st_reg(state, i);
+
+ if (! is_vfp_live(reg, live))
+ kill_mask |= (1 << i);
+ }
+
+ if (kill_mask) {
+ /* create a new state, will be changed */
+ state = x87_clone_state(sim, state);
+
+ DB((dbg, LEVEL_1, "Killing deads:\n"));
+ DEBUG_ONLY(vfp_dump_live(live));
+ DEBUG_ONLY(x87_dump_stack(state));
+
+ if (kill_mask != 0 && live == 0) {
+ /* special case: kill all registers */
+ if (ia32_cg_config.use_femms || ia32_cg_config.use_emms) {
+ if (ia32_cg_config.use_femms) {
+ /* use FEMMS on AMD processors to clear all */
+ keep = new_bd_ia32_femms(NULL, block);
+ } else {
+ /* use EMMS to clear all */
+ keep = new_bd_ia32_emms(NULL, block);
+ }
+ sched_add_before(first_insn, keep);
+ keep_alive(keep);
+ x87_emms(state);
+ return state;
+ }
+ }
+ /* now kill registers */
+ while (kill_mask) {
+ /* we can only kill from TOS, so bring them up */
+ if (! (kill_mask & 1)) {
+ /* search from behind, because we can to a double-pop */
+ for (i = depth - 1; i >= 0; --i) {
+ if (kill_mask & (1 << i)) {
+ kill_mask &= ~(1 << i);
+ kill_mask |= 1;
+ break;
+ }
+ }
+
+ if (keep)
+ x87_set_st(state, -1, keep, i);
+ x87_create_fxch(state, first_insn, i);
+ }
+
+ if ((kill_mask & 3) == 3) {
+ /* we can do a double-pop */
+ num_pop = 2;
+ }
+ else {
+ /* only a single pop */
+ num_pop = 1;
+ }
+
+ depth -= num_pop;
+ kill_mask >>= num_pop;
+ keep = x87_create_fpop(state, first_insn, num_pop);
+ }
+ keep_alive(keep);
+ }
+ return state;
+} /* x87_kill_deads */
+
+/**
+ * If we have PhiEs with unknown operands then we have to make sure that some
+ * value is actually put onto the stack.
+ */
+static void fix_unknown_phis(x87_state *state, ir_node *block,
+ ir_node *pred_block, int pos)
+{
+ ir_node *node, *op;
+
+ sched_foreach(block, node) {
+ ir_node *zero;
+ const arch_register_t *reg;
+ ia32_x87_attr_t *attr;
+
+ if (!is_Phi(node))
+ break;
+
+ op = get_Phi_pred(node, pos);
+ if (!is_ia32_Unknown_VFP(op))
+ continue;
+
+ reg = arch_get_irn_register(node);
+
+ /* create a zero at end of pred block */
+ zero = new_bd_ia32_fldz(NULL, pred_block, mode_E);
+ x87_push(state, arch_register_get_index(reg), zero);
+
+ attr = get_ia32_x87_attr(zero);
+ attr->x87[2] = &ia32_st_regs[0];
+
+ assert(is_ia32_fldz(zero));
+ sched_add_before(sched_last(pred_block), zero);
+
+ set_Phi_pred(node, pos, zero);
+ }