+/**
+ * Create ILP bundle constraints:
+ * - assure, at most bundle_size * bundles_per_cycle instructions
+ * can be started at a certain point.
+ */
+static void create_bundle_constraints(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node) {
+ char buf[1024];
+ unsigned t;
+ unsigned num_cst_bundle = 0;
+ unsigned n_instr_max = env->cpu->bundle_size * env->cpu->bundels_per_cycle;
+ ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
+ ir_timer_t *t_cst_bundle = ir_timer_register("beilpsched_cst_bundle", "create bundle constraints");
+
+ ilp_timer_push(t_cst_bundle);
+ for (t = 0; t < ba->max_steps; ++t) {
+ ir_node *irn;
+ int cst;
+ int *tmp_var_idx = NEW_ARR_F(int, 0);
+
+ snprintf(buf, sizeof(buf), "bundle_cst_%u", t);
+ cst = lpp_add_cst_uniq(lpp, buf, lpp_less, (double)n_instr_max);
+ DBG((env->dbg, LEVEL_2, "added constraint %s\n", buf));
+ num_cst_bundle++;
+
+ foreach_linked_irns(ba->head_ilp_nodes, irn) {
+ be_ilpsched_irn_t *node;
+ ilpsched_node_attr_t *na;
+ int tp_idx;
+
+ /* Projs and Keeps do not contribute to bundle size */
+ if (is_Proj(irn) || be_is_Keep(irn))
+ continue;
+
+ node = get_ilpsched_irn(env, irn);
+ na = get_ilpsched_node_attr(node);
+
+ /* nodes assigned to DUMMY unit do not contribute to bundle size */
+ if (na->is_dummy_node)
+ continue;
+
+ if (t >= na->asap - 1 && t <= na->alap - 1) {
+ for (tp_idx = na->n_unit_types - 1; tp_idx >= 0; --tp_idx) {
+ int idx = ILPVAR_IDX(na, tp_idx, t);
+ ARR_APP1(int, tmp_var_idx, na->ilp_vars.x[idx]);
+ }
+ }
+ }
+
+ if (ARR_LEN(tmp_var_idx) > 0)
+ lpp_set_factor_fast_bulk(lpp, cst, tmp_var_idx, ARR_LEN(tmp_var_idx), 1.0);
+
+ DEL_ARR_F(tmp_var_idx);
+ }
+ ilp_timer_pop();
+ DBG((env->dbg, LEVEL_1, "\t%u bundle constraints (%g sec)\n",
+ num_cst_bundle, ilp_timer_elapsed_usec(t_cst_bundle) / 1000000.0));
+}
+
+/**
+ * Create ILP alive nodes constraints:
+ * - set variable a_{nt}^k to 1 if nodes n is alive at step t on unit k
+ */
+static void create_alive_nodes_constraint(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node) {
+ char buf[1024];
+ ir_node *irn;
+ unsigned num_cst = 0;
+ ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
+ ir_timer_t *t_cst = ir_timer_register("beilpsched_cst_alive_nodes", "create alive nodes constraints");
+
+ ilp_timer_push(t_cst);
+ /* for each node */
+ foreach_linked_irns(ba->head_ilp_nodes, irn) {
+ be_ilpsched_irn_t *node = get_ilpsched_irn(env, irn);
+ ilpsched_node_attr_t *na = get_ilpsched_node_attr(node);
+ unsigned t;
+
+ /* we ignore nodes assigned to dummy unit here */
+ if (na->is_dummy_node)
+ continue;
+
+ /* check check all time steps: asap(n) <= t <= U */
+ for (t = na->asap - 1; t < ba->max_steps; ++t) {
+ int node_tp_idx;
+
+ /* for all unit types available for this node */
+ for (node_tp_idx = na->n_unit_types - 1; node_tp_idx >= 0; --node_tp_idx) {
+ unsigned tn, tn_max, idx;
+ int cst, i;
+ int *tmp_var_idx_n = NEW_ARR_F(int, 0);
+ int *tmp_var_idx_m = NEW_ARR_F(int, 0);
+
+ snprintf(buf, sizeof(buf), "alive_node_cst_%u_n%u_%s",
+ t, get_irn_idx(irn), na->type_info[node_tp_idx].tp->name);
+ cst = lpp_add_cst_uniq(lpp, buf, lpp_less, 0.0);
+ DBG((env->dbg, LEVEL_2, "added constraint %s\n", buf));
+ num_cst++;
+
+ tn_max = MIN(na->alap - 1, t);
+ /* check if the node has been scheduled so far */
+ for (tn = na->asap - 1; tn <= tn_max; ++tn) {
+ int idx = ILPVAR_IDX(na, node_tp_idx, tn);
+ ARR_APP1(int, tmp_var_idx_n, na->ilp_vars.x[idx]);
+ }
+
+ if (ARR_LEN(tmp_var_idx_n) > 0)
+ lpp_set_factor_fast_bulk(lpp, cst, tmp_var_idx_n, ARR_LEN(tmp_var_idx_n), (double)(na->n_consumer));
+ DEL_ARR_F(tmp_var_idx_n);
+
+ /* subtract the number of consumer scheduled so far */
+ for (i = ARR_LEN(na->block_consumer) - 1; i >= 0; --i) {
+ be_ilpsched_irn_t *cons = get_ilpsched_irn(env, na->block_consumer[i]);
+ ilpsched_node_attr_t *ca = get_ilpsched_node_attr(cons);
+ int tp_idx;
+ unsigned tm, tm_max;
+
+ tm_max = MIN(ca->alap - 1, t);
+ for (tp_idx = ca->n_unit_types - 1; tp_idx >= 0; --tp_idx) {
+ for (tm = ca->asap - 1; tm <= tm_max; ++tm) {
+ int idx = ILPVAR_IDX(ca, tp_idx, tm);
+ ARR_APP1(int, tmp_var_idx_m, ca->ilp_vars.x[idx]);
+ }
+ }
+ }
+
+ if (ARR_LEN(tmp_var_idx_m) > 0)
+ lpp_set_factor_fast_bulk(lpp, cst, tmp_var_idx_m, ARR_LEN(tmp_var_idx_m), -1.0);
+ DEL_ARR_F(tmp_var_idx_m);
+
+ /* -c * a_{nt}^k */
+ idx = ILPVAR_IDX_DEAD(ba, na, node_tp_idx, t);
+ lpp_set_factor_fast(lpp, cst, na->ilp_vars.a[idx], 0.0 - (double)(na->n_consumer));
+
+ }
+ }
+ }
+ ilp_timer_pop();
+ DBG((env->dbg, LEVEL_1, "\t%u alive nodes constraints (%g sec)\n",
+ num_cst, ilp_timer_elapsed_usec(t_cst) / 1000000.0));
+}
+
+/**
+ * Create ILP alive nodes constraints for live-in nodes:
+ * - set variable a_{nt}^k to 1 if nodes n is alive at step t on unit k
+ */
+static void create_alive_livein_nodes_constraint(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node) {
+ char buf[1024];
+ ilp_livein_node_t *livein;
+ unsigned num_cst = 0;
+ ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
+ ir_timer_t *t_cst = ir_timer_register("beilpsched_cst_alive_livein_nodes", "create alive livein nodes constraints");
+
+ ilp_timer_push(t_cst);
+ /* for each node */
+ foreach_pset(ba->livein_nodes, livein) {
+ ir_node *irn = livein->irn;
+ be_ilpsched_irn_t *node = get_ilpsched_irn(env, irn);
+ ilpsched_node_attr_t *na = get_ilpsched_node_attr(node);
+ unsigned t;
+
+ /* check check all time steps: 0 <= t < max_alive_steps */
+ for (t = 0; t < livein->max_alive_steps; ++t) {
+ int node_tp_idx;
+
+ /* for all unit types available for this node */
+ for (node_tp_idx = na->n_unit_types - 1; node_tp_idx >= 0; --node_tp_idx) {
+ const ir_edge_t *edge;
+ unsigned idx;
+ int cst, num_block_user;
+ int *tmp_var_idx_m = NEW_ARR_F(int, 0);
+
+ /* check the number of consumer scheduled so far */
+ num_block_user = 0;
+ foreach_out_edge(irn, edge) {
+ ir_node *user = get_edge_src_irn(edge);
+ be_ilpsched_irn_t *cons;
+ ilpsched_node_attr_t *ca;
+ int tp_idx;
+ unsigned tm, tm_max;
+
+ /* check only users within current block */
+ if (get_nodes_block(user) != block_node->irn)
+ continue;
+
+ num_block_user++;
+ cons = get_ilpsched_irn(env, user);
+ ca = get_ilpsched_node_attr(cons);
+
+ tm_max = MIN(ca->alap - 1, t);
+ for (tp_idx = ca->n_unit_types - 1; tp_idx >= 0; --tp_idx) {
+ for (tm = ca->asap - 1; tm <= tm_max; ++tm) {
+ int idx = ILPVAR_IDX(ca, tp_idx, tm);
+ ARR_APP1(int, tmp_var_idx_m, ca->ilp_vars.x[idx]);
+ }
+ }
+ }
+
+ snprintf(buf, sizeof(buf), "alive_livein_node_cst_%u_n%u_%s",
+ t, get_irn_idx(irn), na->type_info[node_tp_idx].tp->name);
+ cst = lpp_add_cst_uniq(lpp, buf, lpp_greater, (double)num_block_user);
+ DBG((env->dbg, LEVEL_2, "added constraint %s\n", buf));
+ num_cst++;
+
+ /* sum(scheduled users) */
+ if (ARR_LEN(tmp_var_idx_m) > 0)
+ lpp_set_factor_fast_bulk(lpp, cst, tmp_var_idx_m, ARR_LEN(tmp_var_idx_m), 1.0);
+ DEL_ARR_F(tmp_var_idx_m);
+
+ /* + c * a_{nt}^k */
+ idx = node_tp_idx * livein->max_alive_steps + t;
+ lpp_set_factor_fast(lpp, cst, livein->a[idx], (double)(num_block_user));
+ }
+ }
+ }
+ ilp_timer_pop();
+ DBG((env->dbg, LEVEL_1, "\t%u alive livein nodes constraints (%g sec)\n",
+ num_cst, ilp_timer_elapsed_usec(t_cst) / 1000000.0));
+}
+
+/**
+ * Create ILP pressure constraints, based on alive nodes:
+ * - add additional costs to objective function if a node is scheduled
+ * on a unit although all units of this type are currently occupied
+ */
+static void create_pressure_alive_constraint(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node) {
+ char buf[1024];
+ ir_node *cur_irn;
+ unsigned num_cst = 0;
+ ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
+ ir_timer_t *t_cst = ir_timer_register("beilpsched_cst_pressure", "create pressure constraints");
+
+ ilp_timer_push(t_cst);
+ /* y_{nt}^k is set for each node and timestep and unit type */
+ foreach_linked_irns(ba->head_ilp_nodes, cur_irn) {
+ unsigned cur_idx = get_irn_idx(cur_irn);
+ be_ilpsched_irn_t *cur_node = get_ilpsched_irn(env, cur_irn);
+ ilpsched_node_attr_t *cur_na = get_ilpsched_node_attr(cur_node);
+ int glob_type_idx;
+
+ /* we ignore nodes assigned to DUMMY unit here */
+ if (cur_na->is_dummy_node)
+ continue;
+
+ /* for all types */