-// DBG((dbg, DBG_SPILL, "spill_phi %+F\n", phi));
-
- /* search an existing spill for this context */
- ctx = be_get_spill_ctx(senv->spill_ctxs, phi, ctx_irn);
-
- /* if not found spill the phi */
- if(!ctx->spill) {
- /* build a new PhiM with dummy in-array */
- ins = malloc(n * sizeof(ins[0]));
- for(i=0; i<n; ++i)
- ins[i] = new_r_Unknown(irg, mode_M);
- ctx->spill = new_r_Phi(senv->session->irg, bl, n, ins, mode_M);
- free(ins);
-
- /* re-wire the phiM */
- for(i=0; i<n; ++i) {
- ir_node *arg = get_irn_n(phi, i);
- ir_node *sub_res;
-
- if(is_Phi(arg) && pset_find_ptr(senv->mem_phis, arg))
- sub_res = be_spill_phi(senv, arg, ctx_irn);
- else
- sub_res = be_spill_irn(senv, arg, ctx_irn);
-
- set_irn_n(ctx->spill, i, sub_res);
+
+ /* build a new PhiM */
+ ins = alloca(sizeof(ir_node*) * arity);
+ for(i = 0; i < arity; ++i) {
+ ins[i] = get_irg_bad(env->irg);
+ }
+ spillinfo->spill = new_r_Phi(env->irg, block, arity, ins, mode_M);
+
+ for(i = 0; i < arity; ++i) {
+ ir_node *arg = get_irn_n(phi, i);
+ spill_info_t *arg_info = get_spillinfo(env, arg);
+
+ spill_node(env, arg_info);
+
+ set_irn_n(spillinfo->spill, i, arg_info->spill);
+ }
+
+ // rewire reloads from old_spill to phi
+ if(spillinfo->old_spill != NULL) {
+ const ir_edge_t *edge, *next;
+ ir_node *old_spill = spillinfo->old_spill;
+
+ foreach_out_edge_safe(old_spill, edge, next) {
+ ir_node* reload = get_edge_src_irn(edge);
+ assert(be_is_Reload(reload) || is_Phi(reload));
+ set_irn_n(reload, get_edge_src_pos(edge), spillinfo->spill);
+ }
+ set_irn_n(old_spill, be_pos_Spill_val, new_Bad());
+ //sched_remove(old_spill);
+ spillinfo->old_spill = NULL;
+ }
+}
+
+/**
+ * Spill a node.
+ *
+ * @param senv the spill environment
+ * @param to_spill the node that should be spilled
+ */
+static void spill_node(spill_env_t *env, spill_info_t *spillinfo) {
+ ir_node *to_spill;
+
+ // the node should be tagged for spilling already...
+ if(spillinfo->spill != NULL)
+ return;
+
+ to_spill = spillinfo->spilled_node;
+ if (is_Phi(to_spill) && pset_find_ptr(env->mem_phis, spillinfo->spilled_node)) {
+ spill_phi(env, spillinfo);
+ } else {
+ spill_irn(env, spillinfo);
+ }
+}
+
+/*
+ *
+ * ____ _ _ _ _
+ * | _ \ ___ _ __ ___ __ _| |_ ___ _ __(_) __ _| (_)_______
+ * | |_) / _ \ '_ ` _ \ / _` | __/ _ \ '__| |/ _` | | |_ / _ \
+ * | _ < __/ | | | | | (_| | || __/ | | | (_| | | |/ / __/
+ * |_| \_\___|_| |_| |_|\__,_|\__\___|_| |_|\__,_|_|_/___\___|
+ *
+ */
+
+/**
+ * Tests whether value @p arg is available before node @p reloader
+ * @returns 1 if value is available, 0 otherwise
+ */
+static int is_value_available(spill_env_t *env, ir_node *arg, ir_node *reloader) {
+ if(is_Unknown(arg) || arg == new_NoMem())
+ return 1;
+
+ if(be_is_Spill(arg))
+ return 1;
+
+ if(arg == get_irg_frame(env->irg))
+ return 1;
+
+ // hack for now (happens when command should be inserted at end of block)
+ if(is_Block(reloader)) {
+ return 0;
+ }
+
+ /*
+ * Ignore registers are always available
+ */
+ if(arch_irn_is(env->arch_env, arg, ignore)) {
+ return 1;
+ }
+
+#if 0
+ /* the following test does not work while spilling,
+ * because the liveness info is not adapted yet to the effects of the
+ * additional spills/reloads.
+ */
+
+ /* we want to remat before the insn reloader
+ * thus an arguments is alive if
+ * - it interferes with the reloaders result
+ * - or it is (last-) used by reloader itself
+ */
+ if (values_interfere(env->birg->lv, reloader, arg)) {
+ return 1;
+ }
+
+ arity = get_irn_arity(reloader);
+ for (i = 0; i < arity; ++i) {
+ ir_node *rel_arg = get_irn_n(reloader, i);
+ if (rel_arg == arg)
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+
+/**
+ * Checks whether the node can principally be rematerialized
+ */
+static int is_remat_node(spill_env_t *env, ir_node *node) {
+ const arch_env_t *arch_env = env->arch_env;
+
+ assert(!be_is_Spill(node));
+
+ if(arch_irn_is(arch_env, node, rematerializable)) {
+ return 1;
+ }
+
+ if(be_is_StackParam(node))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Check if a node is rematerializable. This tests for the following conditions:
+ *
+ * - The node itself is rematerializable
+ * - All arguments of the node are available or also rematerialisable
+ * - The costs for the rematerialisation operation is less or equal a limit
+ *
+ * Returns the costs needed for rematerialisation or something
+ * > REMAT_COST_LIMIT if remat is not possible.
+ */
+static int check_remat_conditions_costs(spill_env_t *env, ir_node *spilled, ir_node *reloader, int parentcosts) {
+ int i, arity;
+ int argremats;
+ int costs = 0;
+
+ if(!is_remat_node(env, spilled))
+ return REMAT_COST_LIMIT;
+
+ if(be_is_Reload(spilled)) {
+ costs += 2;
+ } else {
+ costs += arch_get_op_estimated_cost(env->arch_env, spilled);
+ }
+ if(parentcosts + costs >= REMAT_COST_LIMIT) {
+ return REMAT_COST_LIMIT;
+ }
+
+ argremats = 0;
+ for(i = 0, arity = get_irn_arity(spilled); i < arity; ++i) {
+ ir_node *arg = get_irn_n(spilled, i);
+
+ if(is_value_available(env, arg, reloader))
+ continue;
+
+ // we have to rematerialize the argument as well...
+ if(argremats >= 1) {
+ /* we only support rematerializing 1 argument at the moment,
+ * so that we don't have to care about register pressure
+ */
+ return REMAT_COST_LIMIT;