+static INLINE void check_for_keeps(waitq *keeps, ir_node *block, ir_node *irn) {
+ const ir_edge_t *edge;
+
+ foreach_out_edge(irn, edge) {
+ ir_node *user = get_edge_src_irn(edge);
+
+ if (be_is_Keep(user)) {
+ assert(get_nodes_block(user) == block && "Keep must not be in different block.");
+ waitq_put(keeps, user);
+ }
+ }
+}
+
+/**
+ * Adds a node, it's Projs (in case of mode_T nodes) and
+ * it's Keeps to schedule.
+ */
+static void add_to_sched(ir_node *block, ir_node *irn) {
+ const ir_edge_t *edge;
+ waitq *keeps = new_waitq();
+
+ if (get_irn_mode(irn) == mode_M)
+ return;
+
+ sched_add_before(block, irn);
+
+ /* add Projs */
+ if (get_irn_mode(irn) == mode_T) {
+ foreach_out_edge(irn, edge) {
+ ir_node *user = get_edge_src_irn(edge);
+
+ assert(is_Proj(user) && "User of mode_T node must be a Proj");
+
+ if (to_appear_in_schedule(user))
+ sched_add_before(block, user);
+
+ check_for_keeps(keeps, block, user);
+ }
+ }
+ else {
+ check_for_keeps(keeps, block, irn);
+ }
+
+ /* add Keeps */
+ while (! waitq_empty(keeps)) {
+ ir_node *keep = waitq_get(keeps);
+ if (! sched_is_scheduled(keep))
+ sched_add_before(block, keep);
+ }
+
+ del_waitq(keeps);
+}
+
+/**
+ * Schedule all nodes in the given block, according to the ILP solution.
+ */
+static void apply_solution(be_ilpsched_env_t *env, lpp_t *lpp, ir_node *block) {
+ be_ilpsched_irn_t *block_node = get_ilpsched_irn(env, block);
+ ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
+ sched_info_t *info = get_irn_sched_info(block);
+ be_ilpsched_irn_t **sched_nodes;
+ unsigned i, l;
+ ir_node *cfop, *irn;
+ const ir_edge_t *edge;
+
+ /* init block schedule list */
+ INIT_LIST_HEAD(&info->list);
+ info->scheduled = 1;
+
+ /* collect nodes and their scheduling time step */
+ sched_nodes = NEW_ARR_F(be_ilpsched_irn_t *, 0);
+ if (ba->n_interesting_nodes == 0) {
+ /* ignore */
+ }
+ else if (ba->n_interesting_nodes == 1) {
+ be_ilpsched_irn_t *node = get_ilpsched_irn(env, ba->head_ilp_nodes);
+
+ /* add the single node */
+ ARR_APP1(be_ilpsched_irn_t *, sched_nodes, node);
+ }
+ else {
+ foreach_linked_irns(ba->head_ilp_nodes, irn) {
+ be_ilpsched_irn_t *node;
+ ilpsched_node_attr_t *na;
+ int tp_idx, found;
+ unsigned cur_var, t;
+
+ node = get_ilpsched_irn(env, irn);
+ na = get_ilpsched_node_attr(node);
+ cur_var = 0;
+ found = 0;
+
+ for (tp_idx = na->n_unit_types - 1; ! found && tp_idx >= 0; --tp_idx) {
+ for (t = na->asap - 1; ! found && t <= na->alap - 1; ++t) {
+ double val = lpp_get_var_sol(lpp, na->ilp_vars[cur_var++]);
+ if (! LPP_VALUE_IS_0(val)) {
+ na->sched_point = t;
+ ARR_APP1(be_ilpsched_irn_t *, sched_nodes, node);
+ DBG((env->dbg, LEVEL_1, "Schedpoint of %+F is %u at unit type %s\n",
+ irn, t, na->type_info[tp_idx].tp->name));
+ found = 1;
+ }
+ }
+ }
+ }
+
+ /* sort nodes ascending by scheduling time step */
+ qsort(sched_nodes, ARR_LEN(sched_nodes), sizeof(sched_nodes[0]), cmp_ilpsched_irn);
+ }
+
+ /* make all Phis ready and remember the single cf op */
+ cfop = NULL;
+ foreach_out_edge(block, edge) {
+ irn = get_edge_src_irn(edge);
+
+ switch (get_irn_opcode(irn)) {
+ case iro_Phi:
+ add_to_sched(block, irn);
+ break;
+ case iro_Start:
+ case iro_End:
+ case iro_Proj:
+ case iro_Bad:
+ break;
+ default:
+ if (is_cfop(irn)) {
+ assert(cfop == NULL && "Highlander!");
+ cfop = irn;
+ }
+ break;
+ }
+ }
+
+ /* add all nodes from list */
+ for (i = 0, l = ARR_LEN(sched_nodes); i < l; ++i) {
+ add_to_sched(block, sched_nodes[i]->irn);
+ }
+
+ /* schedule control flow node if not already done */
+ if (cfop && ! sched_is_scheduled(cfop))
+ add_to_sched(block, cfop);
+
+ DEL_ARR_F(sched_nodes);
+}
+