+static void belady(ir_node *blk, void *env);
+
+/**
+ * Collects all values live-in at block @p blk and all phi results in this block.
+ * Then it adds the best values (at most n_regs) to the blocks start_workset.
+ * The phis among the remaining values get spilled: Introduce psudo-copies of
+ * their args to break interference and make it possible to spill them to the
+ * same spill slot.
+ */
+static block_info_t *compute_block_start_info(ir_node *blk, void *env) {
+ belady_env_t *bel = env;
+ ir_node *irn, *first;
+ irn_live_t *li;
+ int i, count, ws_count;
+ loc_t loc, *starters;
+ ir_graph *irg = get_irn_irg(blk);
+ struct obstack ob;
+ block_info_t *res = get_block_info(blk);
+
+ /* Have we seen this block before? */
+ if (res)
+ return res;
+
+ /* Create the block info for this block. */
+ res = new_block_info(&bel->ob);
+ set_block_info(blk, res);
+
+
+ /* Get all values living at the block start sorted by next use*/
+ obstack_init(&ob);
+
+ DBG((dbg, DBG_START, "Living at start of %+F:\n", blk));
+ first = sched_first(blk);
+ count = 0;
+ sched_foreach(blk, irn)
+ if (is_Phi(irn) && arch_get_irn_reg_class(bel->arch, irn, -1) == bel->cls) {
+ loc.irn = irn;
+ loc.time = get_distance(bel, first, 0, irn, 0);
+ obstack_grow(&ob, &loc, sizeof(loc));
+ DBG((dbg, DBG_START, " %+F:\n", irn));
+ count++;
+ } else
+ break;
+
+ live_foreach(blk, li)
+ if (live_is_in(li) && arch_get_irn_reg_class(bel->arch, li->irn, -1) == bel->cls) {
+ loc.irn = (ir_node *)li->irn;
+ loc.time = get_distance(bel, first, 0, li->irn, 0);
+ obstack_grow(&ob, &loc, sizeof(loc));
+ DBG((dbg, DBG_START, " %+F:\n", irn));
+ count++;
+ }
+
+ starters = obstack_finish(&ob);
+ qsort(starters, count, sizeof(starters[0]), loc_compare);
+
+
+ /* If we have only one predecessor, we want the start_set of blk to be the end_set of pred */
+ if (get_Block_n_cfgpreds(blk) == 1 && blk != get_irg_start_block(get_irn_irg(blk))) {
+ ir_node *pred_blk = get_Block_cfgpred_block(blk, 0);
+ block_info_t *pred_info = get_block_info(pred_blk);
+
+ /* if pred block has not been processed yet, do it now */
+ if (! pred_info) {
+ belady(pred_blk, bel);
+ pred_info = get_block_info(pred_blk);
+ }
+
+ /* now we have an end_set of pred */
+ assert(pred_info->ws_end && "The recursive call (above) is supposed to compute an end_set");
+ res->ws_start = workset_clone(&bel->ob, pred_info->ws_end);
+
+ } else
+
+ /* Else we want the start_set to be the values used 'the closest' */
+ {
+ /* Copy the best ones from starters to start workset */
+ ws_count = MIN(count, bel->n_regs);
+ res->ws_start = new_workset(&bel->ob, bel);
+ workset_bulk_fill(res->ws_start, ws_count, starters);
+ }
+
+
+ /* The phis of this block which are not in the start set have to be spilled later.
+ * Therefore we add temporary copies in the pred_blocks so the spills can spill
+ * into the same spill slot.
+ * After spilling these copies get deleted. */
+ for (i=workset_get_length(res->ws_start); i<count; ++i) {
+ int o, max;
+
+ irn = starters[i].irn;
+ if (!is_Phi(irn) || get_nodes_block(irn) != blk)
+ continue;
+
+ DBG((dbg, DBG_START, "For %+F:\n", irn));
+
+ for (max=get_irn_arity(irn), o=0; o<max; ++o) {
+ ir_node *arg = get_irn_n(irn, o);
+ ir_node *pred_block = get_Block_cfgpred_block(get_nodes_block(irn), o);
+ ir_node *cpy = be_new_Copy(bel->cls, irg, pred_block, arg);
+ pset_insert_ptr(bel->copies, cpy);
+ DBG((dbg, DBG_START, " place a %+F of %+F in %+F\n", cpy, arg, pred_block));
+ sched_add_before(pred_block, cpy);
+ set_irn_n(irn, o, cpy);
+ }
+ }
+
+ obstack_free(&ob, NULL);
+ return res;
+}
+
+