- sched_env_t *env = env_ptr;
- block_sched_env_t be;
-
- ir_node *irn;
- int i, n, j, m;
- int phi_seen = 0;
- sched_info_t *info = get_irn_sched_info(block);
-
- /* Initialize the block's list head that will hold the schedule. */
- INIT_LIST_HEAD(&info->list);
-
- /* Initialize the block scheduling environment */
- be.dbg = firm_dbg_register("firm.be.sched");
- be.block = block;
- be.curr_time = 0;
- be.ready_set = new_pset(node_cmp_func, get_irn_n_outs(block));
- be.already_scheduled = new_pset(node_cmp_func, get_irn_n_outs(block));
-
- DBG((be.dbg, LEVEL_1, "scheduling %n\n", block));
-
- /* Then one can add all nodes are ready to the set. */
- for(i = 0, n = get_irn_n_outs(block); i < n; ++i) {
- ir_node *irn = get_irn_out(block, i);
-
- /* Skip the end node because of keepalive edges. */
- if(get_irn_opcode(irn) == iro_End)
- continue;
-
- /* Phi functions are scheduled immediately, since they only transfer
- * data flow from the predecessors to this block. */
- if(is_Phi(irn)) {
- add_to_sched(&be, irn);
- make_users_ready(&be, irn);
- phi_seen = 1;
- }
-
- /* Other nodes must have all operands in other blocks to be made
- * ready */
- else {
- bool ready = true;
-
- /* Check, if the operands of a node are not local to this block */
- for(j = 0, m = get_irn_arity(irn); j < m; ++j) {
- ir_node *operand = get_irn_n(irn, j);
-
- if(get_nodes_block(operand) == block) {
- ready = false;
- break;
- }
- }
-
- /* Make the node ready, if all operands live in a foreign block */
- if(ready) {
- DBG((be.dbg, LEVEL_2, "\timmediately ready: %n\n", irn));
- make_ready(&be, irn);
- }
- }
- }
+ sched_env_t *env = env_ptr;
+ const list_sched_selector_t *selector = env->selector;
+ ir_node *start_node = get_irg_start(get_irn_irg(block));
+
+ block_sched_env_t be;
+ const ir_edge_t *edge;
+ ir_node *irn;
+ int j, m;
+
+ /* Initialize the block's list head that will hold the schedule. */
+ sched_init_block(block);
+
+ /* Initialize the block scheduling environment */
+ be.sched_info = env->sched_info;
+ be.block = block;
+ ir_nodeset_init_size(&be.cands, get_irn_n_edges(block));
+ ir_nodeset_init_size(&be.live, get_irn_n_edges(block));
+ be.selector = selector;
+ be.sched_env = env;
+
+ DBG((dbg, LEVEL_1, "scheduling %+F\n", block));
+
+ if (selector->init_block)
+ be.selector_block_env = selector->init_block(env->selector_env, block);
+
+ /* Then one can add all nodes are ready to the set. */
+ foreach_out_edge(block, edge) {
+ ir_node *irn = get_edge_src_irn(edge);
+ ir_opcode code = get_irn_opcode(irn);
+ int users;
+
+ if (code == iro_End) {
+ /* Skip the end node because of keep-alive edges. */
+ continue;
+ } else if (code == iro_Block) {
+ /* A Block-Block edge. This should be the MacroBlock
+ * edge, ignore it. */
+ assert(get_Block_MacroBlock(irn) == block && "Block-Block edge found");
+ continue;
+ }
+
+ users = get_irn_n_edges(irn);
+ if (users == 0)
+ continue;
+ else if (users == 1) { /* ignore nodes that are only hold by the anchor */
+ const ir_edge_t *edge = get_irn_out_edge_first_kind(irn, EDGE_KIND_NORMAL);
+ ir_node *user = get_edge_src_irn(edge);
+ if (is_Anchor(user))
+ continue;
+ }
+
+ if (is_Phi(irn)) {
+ /*
+ Phi functions are scheduled immediately, since they only
+ transfer data flow from the predecessors to this block.
+ */
+ add_to_sched(&be, irn);
+ }
+ else if (irn == start_node) {
+ /* The start block will be scheduled as the first node */
+ add_to_sched(&be, irn);
+ }
+ else {
+ /* Other nodes must have all operands in other blocks to be made
+ * ready */
+ int ready = 1;
+
+ /* Check, if the operands of a node are not local to this block */
+ for (j = 0, m = get_irn_ins_or_deps(irn); j < m; ++j) {
+ ir_node *operand = get_irn_in_or_dep(irn, j);
+
+ if (get_nodes_block(operand) == block) {
+ ready = 0;
+ break;
+ } else {
+ /* live in values increase register pressure */
+ ir_nodeset_insert(&be.live, operand);
+ }
+ }
+
+ /* Make the node ready, if all operands live in a foreign block */
+ if (ready) {
+ DBG((dbg, LEVEL_2, "\timmediately ready: %+F\n", irn));
+ make_ready(&be, NULL, irn);
+ }
+ }
+ }
+
+ /* Iterate over all remaining nodes */
+ while (ir_nodeset_size(&be.cands) > 0) {
+ ir_nodeset_iterator_t iter;
+
+ /* Keeps must be scheduled immediately */
+ foreach_ir_nodeset(&be.cands, irn, iter) {
+ if (be_is_Keep(irn) || be_is_CopyKeep(irn) || is_Sync(irn)) {
+ break;
+ }
+ }
+
+ if (! irn) {
+ /* Keeps must be immediately scheduled */
+ irn = be.selector->select(be.selector_block_env, &be.cands, &be.live);
+ }
+
+ DB((dbg, LEVEL_2, "\tpicked node %+F\n", irn));
+
+ /* Add the node to the schedule. */
+ add_to_sched(&be, irn);
+
+ /* remove the scheduled node from the ready list. */
+ ir_nodeset_remove(&be.cands, irn);
+ }
+
+ if (selector->finish_block)
+ selector->finish_block(be.selector_block_env);
+
+ ir_nodeset_destroy(&be.cands);
+ ir_nodeset_destroy(&be.live);
+}