2 * Scheduling algorithms.
3 * An ILP scheduler based on
4 * "ILP-based Instruction Scheduling for IA-64"
5 * by Daniel Kaestner and Sebastian Winkel
8 * @author Christian Wuerdig
26 #include "irphase_t.h"
34 #include <lpp/lpp_net.h>
37 #include <libcore/lc_opts.h>
38 #include <libcore/lc_opts_enum.h>
39 #include <libcore/lc_timing.h>
40 #endif /* WITH_LIBCORE */
44 #include "besched_t.h"
46 typedef struct _ilpsched_options_t {
51 typedef struct _unit_type_info_t {
53 const be_execution_unit_type_t *tp;
57 * holding the ILP variables of the different types
59 typedef struct _ilp_var_types_t {
60 int *x; /* x_{nt}^k variables */
61 int *d; /* d_{nt}^k variables */
62 int *y; /* y_{nt}^k variables */
65 /* attributes for a node */
66 typedef struct _ilpsched_node_attr_t {
67 unsigned asap; /**< The ASAP scheduling control step */
68 unsigned alap; /**< The ALAP scheduling control step */
69 unsigned sched_point; /**< the step in which the node is finally scheduled */
70 unsigned visit_idx; /**< Index of the node having visited this node last */
71 unsigned consumer_idx; /**< Index of the node having counted this node as consumer last */
72 unsigned n_consumer; /**< Number of consumers */
73 ir_node **block_consumer; /**< List of consumer being in the same block */
74 unsigned block_idx : 31; /**< A unique per block index */
75 unsigned enqueued : 1; /**< Node is already enqueued for ALAP calculation */
76 bitset_t *transitive_block_nodes; /**< Set of transitive block nodes (predecessors
77 for ASAP, successors for ALAP */
78 unsigned n_unit_types; /**< number of allowed execution unit types */
79 unit_type_info_t *type_info; /**< list of allowed execution unit types */
80 ilp_var_types_t ilp_vars; /**< the different ILP variables */
81 } ilpsched_node_attr_t;
83 /* attributes for a block */
84 typedef struct _ilpsched_block_attr_t {
85 unsigned block_last_idx; /**< The highest node index in block so far */
86 unsigned n_interesting_nodes; /**< The number of nodes interesting for scheduling */
87 unsigned max_steps; /**< Upper bound for block execution */
88 waitq *root_nodes; /**< A queue of nodes having no user in current block */
89 ir_node *head_ilp_nodes; /**< A linked list of nodes which will contribute to ILP */
90 } ilpsched_block_attr_t;
92 typedef union _ilpsched_attr_ {
93 ilpsched_node_attr_t node_attr;
94 ilpsched_block_attr_t block_attr;
97 /* A irn for the phase and it's attributes (either node or block) */
100 ilpsched_attr_t attr;
103 /* The ILP scheduling environment */
105 phase_t ph; /**< The phase */
106 ir_graph *irg; /**< The current irg */
107 waitq *alap_queue; /**< An queue of nodes waiting for final ALAP calculation */
108 const arch_env_t *arch_env;
109 const be_main_env_t *main_env;
110 const be_machine_t *cpu; /**< the current abstract machine */
111 ilpsched_options_t *opts; /**< the ilp options for current irg */
112 DEBUG_ONLY(firm_dbg_module_t *dbg);
115 /* convenience macros to handle phase irn data */
116 #define get_ilpsched_irn(ilpsched_env, irn) (phase_get_or_set_irn_data(&(ilpsched_env)->ph, (irn)))
117 #define is_ilpsched_block(node) (is_Block((node)->irn))
118 #define get_ilpsched_block_attr(block) (&(block)->attr.block_attr)
119 #define get_ilpsched_node_attr(node) (&(node)->attr.node_attr)
121 /* iterate over a list of ir_nodes linked by link field */
122 #define foreach_linked_irns(head, iter) for ((iter) = (head); (iter); (iter) = get_irn_link((iter)))
124 /* check if node is considered for ILP scheduling */
125 #define consider_for_sched(irn) \
126 (! (is_Block(irn) || \
135 /* gives the valid scheduling time step interval for a node */
136 #define VALID_SCHED_INTERVAL(na) ((na)->alap - (na)->asap + 1)
138 /* gives the valid interval where a node can die */
139 #define VALID_KILL_INTERVAL(ba, na) ((ba)->max_steps - (na)->asap + 1)
141 /* gives the corresponding ILP variable for given node, unit and time step */
142 #define ILPVAR_IDX(na, unit, control_step) \
143 ((unit) * VALID_SCHED_INTERVAL((na)) + (control_step) - (na)->asap + 1)
145 /* gives the corresponding dead nodes ILP variable for given node, unit and time step */
146 #define ILPVAR_IDX_DEAD(ba, na, unit, control_step) \
147 ((unit) * VALID_KILL_INTERVAL((ba), (na)) + (control_step) - (na)->asap + 1)
149 /* check if a double value is within an epsilon environment of 0 */
150 #define LPP_VALUE_IS_0(dbl) (fabs((dbl)) <= 1e-10)
153 #define ilp_timer_push(t) lc_timer_push((t))
154 #define ilp_timer_pop() lc_timer_pop()
155 #define ilp_timer_elapsed_usec(t) lc_timer_elapsed_usec((t))
156 #else /* WITH_LIBCORE */
157 #define ilp_timer_push(t)
158 #define ilp_timer_pop()
159 #define ilp_timer_elapsed_usec(t) 0.0
160 #endif /* WITH_LIBCORE */
162 /* option variable */
163 static ilpsched_options_t ilp_opts = {
164 120, /* 120 sec per block time limit */
170 static const lc_opt_table_entry_t ilpsched_option_table[] = {
171 LC_OPT_ENT_INT("time_limit", "ILP time limit per block", &ilp_opts.time_limit),
172 LC_OPT_ENT_STR("lpp_log", "LPP logfile (stderr and stdout are supported)", ilp_opts.log_file, sizeof(ilp_opts.log_file)),
175 #endif /* WITH_LIBCORE */
178 * Compare scheduling time steps of two be_ilpsched_irn's.
180 static int cmp_ilpsched_irn(const void *a, const void *b) {
181 be_ilpsched_irn_t *n1 = *(be_ilpsched_irn_t **)a;
182 be_ilpsched_irn_t *n2 = *(be_ilpsched_irn_t **)b;
183 ilpsched_node_attr_t *n1_a = get_ilpsched_node_attr(n1);
184 ilpsched_node_attr_t *n2_a = get_ilpsched_node_attr(n2);
186 return QSORT_CMP(n1_a->sched_point, n2_a->sched_point);
190 * In case there is no phase information for irn, initialize it.
192 static void *init_ilpsched_irn(phase_t *ph, ir_node *irn, void *old) {
193 be_ilpsched_irn_t *res = old ? old : phase_alloc(ph, sizeof(res[0]));
196 /* if we have already some data: check for reinitialization */
198 if (! is_Block(irn)) {
199 ilpsched_node_attr_t *na = get_ilpsched_node_attr(res);
201 if (! na->transitive_block_nodes) {
202 ir_node *block = get_nodes_block(irn);
203 be_ilpsched_irn_t *block_node = phase_get_or_set_irn_data(ph, block);
204 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
206 /* we are called after the block indicees have been build: create bitset */
207 na->transitive_block_nodes = bitset_obstack_alloc(phase_obst(ph), ba->block_last_idx);
210 /* we are called from reinit block data: clear the bitset */
211 bitset_clear_all(na->transitive_block_nodes);
220 /* set ilpsched irn attributes (either block or irn) */
222 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(res);
224 ba->n_interesting_nodes = 0;
225 ba->block_last_idx = 0;
226 ba->root_nodes = new_waitq();
227 ba->head_ilp_nodes = NULL;
230 ilpsched_node_attr_t *na = get_ilpsched_node_attr(res);
231 memset(na, 0, sizeof(*na));
238 * Assign a per block unique number to each node.
240 static void build_block_idx(ir_node *irn, void *walk_env) {
241 be_ilpsched_env_t *env = walk_env;
242 be_ilpsched_irn_t *node, *block_node;
243 ilpsched_node_attr_t *na;
244 ilpsched_block_attr_t *ba;
246 if (! consider_for_sched(irn))
249 node = get_ilpsched_irn(env, irn);
250 na = get_ilpsched_node_attr(node);
251 block_node = get_ilpsched_irn(env, get_nodes_block(irn));
252 ba = get_ilpsched_block_attr(block_node);
254 na->block_idx = ba->block_last_idx++;
257 /********************************************************
260 * __ _ ___ __ _ _ __ / / __ _| | __ _ _ __
261 * / _` / __|/ _` | '_ \ / / / _` | |/ _` | '_ \
262 * | (_| \__ \ (_| | |_) | / / | (_| | | (_| | |_) |
263 * \__,_|___/\__,_| .__/ /_/ \__,_|_|\__,_| .__/
266 ********************************************************/
269 * Add all nodes having no user in current block to last_nodes list.
271 static void collect_alap_root_nodes(ir_node *irn, void *walk_env) {
273 const ir_edge_t *edge;
274 be_ilpsched_irn_t *block_node, *node;
275 ilpsched_block_attr_t *ba;
276 ilpsched_node_attr_t *na;
278 be_ilpsched_env_t *env = walk_env;
279 int has_block_user = 0;
280 unsigned n_consumer = 0;
281 ir_edge_kind_t ekind[2] = { EDGE_KIND_NORMAL, EDGE_KIND_DEP };
285 if (! consider_for_sched(irn))
288 block = get_nodes_block(irn);
289 idx = get_irn_idx(irn);
290 consumer = NEW_ARR_F(ir_node *, 0);
292 DBG((env->dbg, LEVEL_3, "%+F (%+F) is interesting, examining ... ", irn, block));
294 /* check data and dependency out edges */
295 for (i = 0; i < 2 && ! has_block_user; ++i) {
296 foreach_out_edge_kind(irn, edge, ekind[i]) {
297 ir_node *user = get_edge_src_irn(edge);
300 const ir_edge_t *user_edge;
302 if (get_irn_mode(user) == mode_X)
305 /* The ABI ensures, that there will be no ProjT nodes in the graph. */
306 for (j = 0; j < 2; ++j) {
307 foreach_out_edge_kind(user, user_edge, ekind[j]) {
308 ir_node *real_user = get_edge_src_irn(user_edge);
310 if (! is_Phi(real_user) && ! be_is_Keep(real_user)) {
311 be_ilpsched_irn_t *node = get_ilpsched_irn(env, real_user);
312 ilpsched_node_attr_t *ua = get_ilpsched_node_attr(node);
314 /* skip already visited nodes */
315 if (ua->consumer_idx == idx)
318 /* check if node has user in this block and collect the user if it's a data user */
319 if (get_nodes_block(real_user) == block) {
320 if (i == 0 && j == 0)
321 ARR_APP1(ir_node *, consumer, real_user);
325 /* only count data consumer */
329 /* mark user as visited by this node */
330 ua->consumer_idx = idx;
335 else if (is_Block(user)) {
338 else if (! is_Phi(user) && ! be_is_Keep(user)) {
339 be_ilpsched_irn_t *node = get_ilpsched_irn(env, user);
340 ilpsched_node_attr_t *ua = get_ilpsched_node_attr(node);
342 /* skip already visited nodes */
343 if (ua->consumer_idx == idx)
346 /* check if node has user in this block and collect the user if it's a data user */
347 if (get_nodes_block(user) == block) {
349 ARR_APP1(ir_node *, consumer, user);
353 /* only count data consumer */
357 /* mark user visited by this node */
358 ua->consumer_idx = idx;
363 block_node = get_ilpsched_irn(env, block);
364 ba = get_ilpsched_block_attr(block_node);
366 ba->n_interesting_nodes++;
368 /* current irn has no user inside this block, add to queue */
369 if (! has_block_user) {
370 DB((env->dbg, LEVEL_3, "root node\n"));
371 waitq_put(ba->root_nodes, irn);
374 DB((env->dbg, LEVEL_3, "normal node\n"));
377 /* record number of all consumer and the consumer within the same block */
378 node = get_ilpsched_irn(env, irn);
379 na = get_ilpsched_node_attr(node);
380 na->n_consumer = n_consumer;
381 na->block_consumer = NEW_ARR_D(ir_node *, phase_obst(&env->ph), ARR_LEN(consumer));
382 memcpy(na->block_consumer, consumer, ARR_LEN(consumer) * sizeof(na->block_consumer[0]));
387 * Calculate the ASAP scheduling step for current irn.
389 static void calculate_irn_asap(ir_node *irn, void *walk_env) {
390 be_ilpsched_irn_t *node;
391 be_ilpsched_env_t *env = walk_env;
394 ilpsched_node_attr_t *na;
396 /* These nodes are handled separate */
397 if (! consider_for_sched(irn))
400 DBG((env->dbg, LEVEL_2, "Calculating ASAP of node %+F\n", irn));
402 node = get_ilpsched_irn(env, irn);
403 block = get_nodes_block(irn);
404 na = get_ilpsched_node_attr(node);
406 /* accumulate all transitive predecessors of current node */
407 for (i = get_irn_ins_or_deps(irn) - 1; i >= 0; --i) {
408 ir_node *pred = skip_Proj(get_irn_in_or_dep(irn, i));
409 be_ilpsched_irn_t *pred_node;
410 ilpsched_node_attr_t *pna;
413 if (be_is_Keep(pred))
414 pred = skip_Proj(get_irn_n(pred, 0));
416 if (is_Phi(pred) || block != get_nodes_block(pred) || is_NoMem(pred))
419 pred_node = get_ilpsched_irn(env, pred);
420 pna = get_ilpsched_node_attr(pred_node);
421 idx = get_irn_idx(irn);
423 assert(pna->asap && "missing ASAP of predecessor");
426 We have not already visited this predecessor
427 -> accumulate it's predecessors
429 if (pna->visit_idx != idx) {
430 pna->visit_idx = idx;
431 na->transitive_block_nodes = bitset_or(na->transitive_block_nodes, pna->transitive_block_nodes);
432 DBG((env->dbg, LEVEL_3, "\taccumulating preds of %+F\n", pred));
436 /* every node is it's own transitive predecessor in block */
437 bitset_set(na->transitive_block_nodes, na->block_idx);
439 /* asap = number of transitive predecessors in this block */
440 na->asap = bitset_popcnt(na->transitive_block_nodes);
442 DBG((env->dbg, LEVEL_2, "\tcalculated ASAP is %u\n", na->asap));
446 * Accumulate the successors of all nodes from irn on upwards.
448 static void accumulate_succs(be_ilpsched_env_t *env, ir_node *irn) {
450 be_ilpsched_irn_t *node = get_ilpsched_irn(env, irn);
451 ilpsched_node_attr_t *na = get_ilpsched_node_attr(node);
452 ir_node *block = get_nodes_block(irn);
453 waitq *wq = new_waitq();
455 DBG((env->dbg, LEVEL_3, "\taccumulating succs of %+F\n", irn));
457 /* enqueue node for final alap calculation */
458 if (! na->enqueued) {
459 be_ilpsched_irn_t *block_node = get_ilpsched_irn(env, block);
460 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
463 na->alap = ba->n_interesting_nodes;
464 waitq_put(env->alap_queue, node);
466 set_irn_link(irn, ba->head_ilp_nodes);
467 ba->head_ilp_nodes = irn;
468 DBG((env->dbg, LEVEL_5, "\t\tlinked %+F to ilp nodes of %+F, attr %p\n", irn, block, ba));
469 DBG((env->dbg, LEVEL_4, "\t\tenqueueing %+F for final ALAP calculation\n", irn));
472 for (i = 0, n = get_irn_ins_or_deps(irn); i < n; ++i) {
473 ir_node *pred = skip_Proj(get_irn_in_or_dep(irn, i));
475 be_ilpsched_irn_t *pred_node;
476 ilpsched_node_attr_t *pna;
478 if (be_is_Keep(pred))
479 pred = skip_Proj(get_irn_n(pred, 0));
481 if (is_Phi(pred) || block != get_nodes_block(pred) || is_NoMem(pred))
484 pred_node = get_ilpsched_irn(env, pred);
485 pna = get_ilpsched_node_attr(pred_node);
486 idx = get_irn_idx(irn);
488 /* accumulate the successors */
489 if (pna->visit_idx != idx) {
490 pna->visit_idx = idx;
491 pna->transitive_block_nodes = bitset_or(pna->transitive_block_nodes, na->transitive_block_nodes);
493 /* set current node as successor */
494 bitset_set(pna->transitive_block_nodes, na->block_idx);
497 DBG((env->dbg, LEVEL_3, "\taccumulating succs of %+F to %+F\n", irn, pred));
501 /* process all predecessors */
502 while (! waitq_empty(wq)) {
503 accumulate_succs(env, waitq_get(wq));
510 * Calculate the ALAP scheduling step of all irns in current block.
511 * Depends on ASAP being calculated.
513 static void calculate_block_alap(ir_node *block, void *walk_env) {
514 be_ilpsched_env_t *env = walk_env;
515 be_ilpsched_irn_t *block_node = get_ilpsched_irn(env, block);
516 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
518 assert(is_Block(block));
520 DBG((env->dbg, LEVEL_2, "Calculating ALAP for nodes in %+F (%u nodes)\n", block, ba->n_interesting_nodes));
522 /* TODO: Might be faster to use out edges and call phase_reinit_single_irn_data */
523 phase_reinit_block_irn_data(&env->ph, block);
525 /* calculate the alap of all nodes, starting at collected roots upwards */
526 while (! waitq_empty(ba->root_nodes)) {
527 accumulate_succs(env, waitq_get(ba->root_nodes));
530 /* we don't need it anymore */
531 del_waitq(ba->root_nodes);
532 ba->root_nodes = NULL;
534 /* all interesting nodes should have their successors accumulated now */
535 while (! waitq_empty(env->alap_queue)) {
536 be_ilpsched_irn_t *node = waitq_get(env->alap_queue);
537 ilpsched_node_attr_t *na = get_ilpsched_node_attr(node);
539 /* control flow ops must always be scheduled last */
540 if (is_cfop(node->irn) && ! is_Start(node->irn) && get_irn_opcode(node->irn) != iro_End)
543 na->alap -= bitset_popcnt(na->transitive_block_nodes);
544 DBG((env->dbg, LEVEL_2, "\tALAP of %+F is %u (%u succs, %u consumer)\n",
545 node->irn, na->alap, bitset_popcnt(na->transitive_block_nodes), na->n_consumer));
547 /* maximum block steps is maximum alap of all nodes */
548 ba->max_steps = MAX(ba->max_steps, na->alap);
552 /*******************************************
555 * ___ ___| |__ ___ __| |_ _| | ___
556 * / __|/ __| '_ \ / _ \/ _` | | | | |/ _ \
557 * \__ \ (__| | | | __/ (_| | |_| | | __/
558 * |___/\___|_| |_|\___|\__,_|\__,_|_|\___|
560 *******************************************/
562 static INLINE void check_for_keeps(waitq *keeps, ir_node *block, ir_node *irn) {
563 const ir_edge_t *edge;
565 foreach_out_edge(irn, edge) {
566 ir_node *user = get_edge_src_irn(edge);
568 if (be_is_Keep(user)) {
569 assert(get_nodes_block(user) == block && "Keep must not be in different block.");
570 waitq_put(keeps, user);
576 * Adds a node, it's Projs (in case of mode_T nodes) and
577 * it's Keeps to schedule.
579 static void add_to_sched(ir_node *block, ir_node *irn) {
580 const ir_edge_t *edge;
581 waitq *keeps = new_waitq();
583 /* mode_M nodes are not scheduled */
584 if (get_irn_mode(irn) == mode_M)
587 sched_add_before(block, irn);
590 if (get_irn_mode(irn) == mode_T) {
591 foreach_out_edge(irn, edge) {
592 ir_node *user = get_edge_src_irn(edge);
594 assert(is_Proj(user) && "User of mode_T node must be a Proj");
596 if (to_appear_in_schedule(user))
597 sched_add_before(block, user);
599 check_for_keeps(keeps, block, user);
603 check_for_keeps(keeps, block, irn);
607 while (! waitq_empty(keeps)) {
608 ir_node *keep = waitq_get(keeps);
609 if (! sched_is_scheduled(keep))
610 sched_add_before(block, keep);
617 * Schedule all nodes in the given block, according to the ILP solution.
619 static void apply_solution(be_ilpsched_env_t *env, lpp_t *lpp, ir_node *block) {
620 be_ilpsched_irn_t *block_node = get_ilpsched_irn(env, block);
621 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
622 sched_info_t *info = get_irn_sched_info(block);
623 be_ilpsched_irn_t **sched_nodes;
626 const ir_edge_t *edge;
628 /* init block schedule list */
629 INIT_LIST_HEAD(&info->list);
632 /* collect nodes and their scheduling time step */
633 sched_nodes = NEW_ARR_F(be_ilpsched_irn_t *, 0);
634 if (ba->n_interesting_nodes == 0) {
637 else if (ba->n_interesting_nodes == 1) {
638 be_ilpsched_irn_t *node = get_ilpsched_irn(env, ba->head_ilp_nodes);
640 /* add the single node */
641 ARR_APP1(be_ilpsched_irn_t *, sched_nodes, node);
644 /* check all nodes for their positive solution */
645 foreach_linked_irns(ba->head_ilp_nodes, irn) {
646 be_ilpsched_irn_t *node;
647 ilpsched_node_attr_t *na;
651 node = get_ilpsched_irn(env, irn);
652 na = get_ilpsched_node_attr(node);
656 /* go over all variables of a node until the non-zero one is found */
657 for (tp_idx = na->n_unit_types - 1; ! found && tp_idx >= 0; --tp_idx) {
658 for (t = na->asap - 1; ! found && t <= na->alap - 1; ++t) {
659 double val = lpp_get_var_sol(lpp, na->ilp_vars.x[cur_var++]);
661 /* check, if variable is set to one (it's not zero then :) */
662 if (! LPP_VALUE_IS_0(val)) {
664 ARR_APP1(be_ilpsched_irn_t *, sched_nodes, node);
665 DBG((env->dbg, LEVEL_1, "Schedpoint of %+F is %u at unit type %s\n",
666 irn, t, na->type_info[tp_idx].tp->name));
673 /* sort nodes ascending by scheduling time step */
674 qsort(sched_nodes, ARR_LEN(sched_nodes), sizeof(sched_nodes[0]), cmp_ilpsched_irn);
677 /* make all Phis ready and remember the single cf op */
679 foreach_out_edge(block, edge) {
680 irn = get_edge_src_irn(edge);
682 switch (get_irn_opcode(irn)) {
684 add_to_sched(block, irn);
693 assert(cfop == NULL && "Highlander - there can be only one");
700 /* add all nodes from list */
701 for (i = 0, l = ARR_LEN(sched_nodes); i < l; ++i) {
702 add_to_sched(block, sched_nodes[i]->irn);
705 /* schedule control flow node if not already done */
706 if (cfop && ! sched_is_scheduled(cfop))
707 add_to_sched(block, cfop);
709 DEL_ARR_F(sched_nodes);
712 /***************************************************************
713 * _____ _ _____ _____ _ _
714 * |_ _| | | __ \ / ____| | | (_)
715 * | | | | | |__) | | (___ ___ ___| |_ _ ___ _ __
716 * | | | | | ___/ \___ \ / _ \/ __| __| |/ _ \| '_ \
717 * _| |_| |____| | ____) | __/ (__| |_| | (_) | | | |
718 * |_____|______|_| |_____/ \___|\___|\__|_|\___/|_| |_|
720 ***************************************************************/
723 * Check if node can be executed on given unit type.
725 static INLINE int is_valid_unit_type_for_node(const be_execution_unit_type_t *tp, be_ilpsched_irn_t *node) {
727 ilpsched_node_attr_t *na = get_ilpsched_node_attr(node);
729 for (i = na->n_unit_types - 1; i >= 0; --i) {
730 if (na->type_info[i].tp == tp)
737 /************************************************
740 * __ ____ _ _ __ _ __ _| |__ | | ___ ___
741 * \ \ / / _` | '__| |/ _` | '_ \| |/ _ \/ __|
742 * \ V / (_| | | | | (_| | |_) | | __/\__ \
743 * \_/ \__,_|_| |_|\__,_|_.__/|_|\___||___/
745 ************************************************/
748 * Create the following variables:
749 * - x_{nt}^k binary weigthed with: t
750 * node n is scheduled at time step t to unit type k
751 * ==>> These variables represent the schedule
754 * - d_{nt}^k binary weighted with: t
755 * node n dies at time step t on unit type k
757 * - y_{nt}^k binary weighted with: num_nodes^2
758 * node n is scheduled at time step t to unit type k
759 * although all units of this type are occupied
760 * ==>> These variables represent the register pressure
762 static void create_variables(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node, struct obstack *var_obst) {
765 unsigned num_block_var, num_nodes;
766 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
767 unsigned weigth_y = ba->n_interesting_nodes * ba->n_interesting_nodes;
769 lc_timer_t *t_var = lc_timer_register("beilpsched_var", "create ilp variables");
770 #endif /* WITH_LIBCORE */
772 ilp_timer_push(t_var);
773 num_block_var = num_nodes = 0;
774 foreach_linked_irns(ba->head_ilp_nodes, irn) {
775 const be_execution_unit_t ***execunits = arch_isa_get_allowed_execution_units(env->arch_env->isa, irn);
776 be_ilpsched_irn_t *node;
777 ilpsched_node_attr_t *na;
778 unsigned n_unit_types, tp_idx, unit_idx, n_var, cur_unit;
779 unsigned cur_var_d, cur_var_x, cur_var_y, num_die;
781 /* count number of available unit types for this node */
782 for (n_unit_types = 0; execunits[n_unit_types]; ++n_unit_types)
785 node = get_ilpsched_irn(env, irn);
786 na = get_ilpsched_node_attr(node);
788 na->n_unit_types = n_unit_types;
789 na->type_info = NEW_ARR_D(unit_type_info_t, var_obst, n_unit_types);
791 /* fill the type info array */
792 for (tp_idx = 0; tp_idx < n_unit_types; ++tp_idx) {
793 for (unit_idx = 0; execunits[tp_idx][unit_idx]; ++unit_idx)
794 /* just count units of this type */;
796 na->type_info[tp_idx].tp = execunits[tp_idx][0]->tp;
797 na->type_info[tp_idx].n_units = unit_idx;
800 /* allocate space for ilp variables */
801 na->ilp_vars.x = NEW_ARR_D(int, var_obst, n_unit_types * VALID_SCHED_INTERVAL(na));
802 na->ilp_vars.y = NEW_ARR_D(int, var_obst, n_unit_types * VALID_SCHED_INTERVAL(na));
803 memset(na->ilp_vars.x, -1, ARR_LEN(na->ilp_vars.x) * sizeof(na->ilp_vars.x[0]));
804 memset(na->ilp_vars.y, -1, ARR_LEN(na->ilp_vars.y) * sizeof(na->ilp_vars.y[0]));
806 num_die = ba->max_steps - na->asap + 1;
807 na->ilp_vars.d = NEW_ARR_D(int, var_obst, n_unit_types * num_die);
808 memset(na->ilp_vars.d, -1, ARR_LEN(na->ilp_vars.d) * sizeof(na->ilp_vars.d[0]));
810 DBG((env->dbg, LEVEL_3, "\thandling %+F (asap %u, alap %u, unit types %u):\n",
811 irn, na->asap, na->alap, na->n_unit_types));
813 cur_var_x = cur_var_d = cur_var_y = cur_unit = n_var = 0;
814 /* create variables */
815 for (tp_idx = 0; tp_idx < n_unit_types; ++tp_idx) {
818 for (t = na->asap - 1; t <= na->alap - 1; ++t) {
819 /* x_{nt}^k variables */
820 snprintf(buf, sizeof(buf), "x_n%u_%s_%u",
821 get_irn_idx(irn), na->type_info[tp_idx].tp->name, t);
822 na->ilp_vars.x[cur_var_x++] = lpp_add_var(lpp, buf, lpp_binary, (double)(t + 1));
823 DBG((env->dbg, LEVEL_4, "\t\tcreated ILP variable %s\n", buf));
825 /* y_{nt}^k variables */
826 snprintf(buf, sizeof(buf), "y_n%u_%s_%u",
827 get_irn_idx(irn), na->type_info[tp_idx].tp->name, t);
828 na->ilp_vars.y[cur_var_y++] = lpp_add_var(lpp, buf, lpp_binary, (double)(weigth_y));
829 DBG((env->dbg, LEVEL_4, "\t\tcreated ILP variable %s\n", buf));
831 /* variable counter */
836 /* a node can die at any step t: asap(n) <= t <= U */
837 for (t = na->asap - 1; t <= ba->max_steps; ++t) {
838 /* d_{nt}^k variables */
839 snprintf(buf, sizeof(buf), "d_n%u_%s_%u",
840 get_irn_idx(irn), na->type_info[tp_idx].tp->name, t);
841 na->ilp_vars.d[cur_var_d++] = lpp_add_var(lpp, buf, lpp_binary, (double)(t + 1));
842 DBG((env->dbg, LEVEL_4, "\t\tcreated ILP variable %s\n", buf));
844 /* variable counter */
850 DB((env->dbg, LEVEL_3, "%u variables created\n", n_var));
854 DBG((env->dbg, LEVEL_1, "... %u variables for %u nodes created (%g sec)\n",
855 num_block_var, num_nodes, ilp_timer_elapsed_usec(t_var) / 1000000.0));
858 /*******************************************************
861 * ___ ___ _ __ ___| |_ _ __ __ _ _ _ __ | |_ ___
862 * / __/ _ \| '_ \/ __| __| '__/ _` | | '_ \| __/ __|
863 * | (_| (_) | | | \__ \ |_| | | (_| | | | | | |_\__ \
864 * \___\___/|_| |_|___/\__|_| \__,_|_|_| |_|\__|___/
866 *******************************************************/
869 * Create following ILP constraints:
870 * - the assignment constraints:
871 * assure each node is executed once by exactly one (allowed) execution unit
872 * - the dead node assignment constraints:
873 * assure a node can only die at most once
874 * - the precedence constraints:
875 * assure that no data dependencies are violated
877 static void create_assignment_and_precedence_constraints(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node) {
878 unsigned num_cst_assign, num_cst_prec, num_cst_dead;
881 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
882 bitset_t *bs_block_irns = bitset_alloca(ba->block_last_idx);
884 lc_timer_t *t_cst_assign = lc_timer_register("beilpsched_cst_assign", "create assignment constraints");
885 lc_timer_t *t_cst_dead = lc_timer_register("beilpsched_cst_assign_dead", "create dead node assignment constraints");
886 lc_timer_t *t_cst_prec = lc_timer_register("beilpsched_cst_prec", "create precedence constraints");
887 #endif /* WITH_LIBCORE */
889 num_cst_assign = num_cst_prec = num_cst_dead = 0;
890 foreach_linked_irns(ba->head_ilp_nodes, irn) {
893 be_ilpsched_irn_t *node;
894 ilpsched_node_attr_t *na;
896 node = get_ilpsched_irn(env, irn);
897 na = get_ilpsched_node_attr(node);
900 /* the assignment constraint */
901 ilp_timer_push(t_cst_assign);
902 snprintf(buf, sizeof(buf), "assignment_cst_n%u", get_irn_idx(irn));
903 cst = lpp_add_cst_uniq(lpp, buf, lpp_equal, 1.0);
904 DBG((env->dbg, LEVEL_2, "added constraint %s\n", buf));
907 lpp_set_factor_fast_bulk(lpp, cst, na->ilp_vars.x, ARR_LEN(na->ilp_vars.x), 1.0);
910 /* the dead node assignment constraint */
911 ilp_timer_push(t_cst_dead);
912 snprintf(buf, sizeof(buf), "dead_node_assign_cst_n%u", get_irn_idx(irn));
913 cst = lpp_add_cst_uniq(lpp, buf, lpp_less, 1.0);
914 DBG((env->dbg, LEVEL_2, "added constraint %s\n", buf));
916 lpp_set_factor_fast_bulk(lpp, cst, na->ilp_vars.d, ARR_LEN(na->ilp_vars.d), 1.0);
919 /* the precedence constraints */
920 ilp_timer_push(t_cst_prec);
921 bs_block_irns = bitset_clear_all(bs_block_irns);
922 for (i = get_irn_ins_or_deps(irn) - 1; i >= 0; --i) {
923 ir_node *pred = skip_Proj(get_irn_in_or_dep(irn, i));
924 unsigned t_low, t_high, t;
925 be_ilpsched_irn_t *pred_node;
926 ilpsched_node_attr_t *pna;
928 if (be_is_Keep(pred))
929 pred = skip_Proj(get_irn_n(pred, 0));
931 if (is_Phi(pred) || block_node->irn != get_nodes_block(pred) || is_NoMem(pred))
934 pred_node = get_ilpsched_irn(env, pred);
935 pna = get_ilpsched_node_attr(pred_node);
937 assert(pna->asap > 0 && pna->alap >= pna->asap && "Invalid scheduling interval.");
939 if (! bitset_is_set(bs_block_irns, pna->block_idx))
940 bitset_set(bs_block_irns, pna->block_idx);
944 /* irn = n, pred = m */
945 t_low = MAX(na->asap, pna->asap);
946 t_high = MIN(na->alap, pna->alap);
947 for (t = t_low - 1; t <= t_high - 1; ++t) {
949 int int_na = (t >= na->asap - 1) ? t - na->asap + 2 : 0;
950 int int_pna = (t < pna->alap) ? pna->alap - t : 0;
951 int *tmp_var_idx = NEW_ARR_F(int, int_na * na->n_unit_types + int_pna * pna->n_unit_types);
953 snprintf(buf, sizeof(buf), "precedence_n%u_n%u_%u", get_irn_idx(pred), get_irn_idx(irn), t);
954 cst = lpp_add_cst_uniq(lpp, buf, lpp_less, 1.0);
955 DBG((env->dbg, LEVEL_2, "added constraint %s\n", buf));
960 /* lpp_set_factor_fast_bulk needs variables sorted ascending by index */
961 if (na->ilp_vars.x[0] < pna->ilp_vars.x[0]) {
962 /* node variables have smaller index than pred variables */
963 for (tp_idx = na->n_unit_types - 1; tp_idx >= 0; --tp_idx) {
964 for (tn = na->asap - 1; tn <= t; ++tn) {
965 unsigned idx = ILPVAR_IDX(na, tp_idx, tn);
966 tmp_var_idx[cur_idx++] = na->ilp_vars.x[idx];
970 for (tp_idx = pna->n_unit_types - 1; tp_idx >= 0; --tp_idx) {
971 for (tm = t; tm < pna->alap; ++tm) {
972 unsigned idx = ILPVAR_IDX(pna, tp_idx, tm);
973 tmp_var_idx[cur_idx++] = pna->ilp_vars.x[idx];
978 /* pred variables have smaller index than node variables */
979 for (tp_idx = pna->n_unit_types - 1; tp_idx >= 0; --tp_idx) {
980 for (tm = t; tm < pna->alap; ++tm) {
981 unsigned idx = ILPVAR_IDX(pna, tp_idx, tm);
982 tmp_var_idx[cur_idx++] = pna->ilp_vars.x[idx];
986 for (tp_idx = na->n_unit_types - 1; tp_idx >= 0; --tp_idx) {
987 for (tn = na->asap - 1; tn <= t; ++tn) {
988 unsigned idx = ILPVAR_IDX(na, tp_idx, tn);
989 tmp_var_idx[cur_idx++] = na->ilp_vars.x[idx];
994 lpp_set_factor_fast_bulk(lpp, cst, tmp_var_idx, ARR_LEN(tmp_var_idx), 1.0);
996 DEL_ARR_F(tmp_var_idx);
1001 DBG((env->dbg, LEVEL_1, "\t%u assignement constraints (%g sec)\n",
1002 num_cst_assign, ilp_timer_elapsed_usec(t_cst_assign) / 1000000.0));
1003 DBG((env->dbg, LEVEL_1, "\t%u precedence constraints (%g sec)\n",
1004 num_cst_prec, ilp_timer_elapsed_usec(t_cst_prec) / 1000000.0));
1008 * Create ILP resource constraints:
1009 * - assure that for each time step not more instructions are scheduled
1010 * to the same unit types as units of this type are available
1012 static void create_ressource_constraints(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node) {
1015 unsigned num_cst_resrc = 0;
1016 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
1018 lc_timer_t *t_cst_rsrc = lc_timer_register("beilpsched_cst_rsrc", "create resource constraints");
1019 #endif /* WITH_LIBCORE */
1021 ilp_timer_push(t_cst_rsrc);
1022 for (glob_type_idx = env->cpu->n_unit_types - 1; glob_type_idx >= 0; --glob_type_idx) {
1024 be_execution_unit_type_t *cur_tp = &env->cpu->unit_types[glob_type_idx];
1026 for (t = 0; t < ba->max_steps; ++t) {
1029 int *tmp_var_idx = NEW_ARR_F(int, ba->max_steps);
1032 snprintf(buf, sizeof(buf), "resource_cst_%s_%u", cur_tp->name, t);
1033 cst = lpp_add_cst_uniq(lpp, buf, lpp_less, (double)cur_tp->n_units);
1034 DBG((env->dbg, LEVEL_2, "added constraint %s\n", buf));
1037 foreach_linked_irns(ba->head_ilp_nodes, irn) {
1038 be_ilpsched_irn_t *node = get_ilpsched_irn(env, irn);
1039 ilpsched_node_attr_t *na = get_ilpsched_node_attr(node);
1042 tp_idx = is_valid_unit_type_for_node(cur_tp, node);
1044 if (tp_idx >= 0 && t >= na->asap - 1 && t <= na->alap - 1) {
1045 int cur_var = ILPVAR_IDX(na, tp_idx, t);
1046 tmp_var_idx[cur_idx++] = na->ilp_vars.x[cur_var];
1050 /* set constraints if we have some */
1052 lpp_set_factor_fast_bulk(lpp, cst, tmp_var_idx, ARR_LEN(tmp_var_idx), 1.0);
1054 DEL_ARR_F(tmp_var_idx);
1058 DBG((env->dbg, LEVEL_1, "\t%u resource constraints (%g sec)\n",
1059 num_cst_resrc, ilp_timer_elapsed_usec(t_cst_rsrc) / 1000000.0));
1063 * Create ILP bundle constraints:
1064 * - assure, at most bundle_size * bundles_per_cycle instructions
1065 * can be started at a certain point.
1067 static void create_bundle_constraints(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node) {
1070 unsigned num_cst_bundle = 0;
1071 unsigned n_instr_max = env->cpu->bundle_size * env->cpu->bundels_per_cycle;
1072 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
1074 lc_timer_t *t_cst_bundle = lc_timer_register("beilpsched_cst_bundle", "create bundle constraints");
1075 #endif /* WITH_LIBCORE */
1077 ilp_timer_push(t_cst_bundle);
1078 for (t = 0; t < ba->max_steps; ++t) {
1081 int *tmp_var_idx = NEW_ARR_F(int, 0);
1083 snprintf(buf, sizeof(buf), "bundle_cst_%u", t);
1084 cst = lpp_add_cst_uniq(lpp, buf, lpp_less, (double)n_instr_max);
1085 DBG((env->dbg, LEVEL_2, "added constraint %s\n", buf));
1088 foreach_linked_irns(ba->head_ilp_nodes, irn) {
1089 be_ilpsched_irn_t *node;
1090 ilpsched_node_attr_t *na;
1093 node = get_ilpsched_irn(env, irn);
1094 na = get_ilpsched_node_attr(node);
1096 if (t >= na->asap - 1 && t <= na->alap - 1) {
1097 for (tp_idx = na->n_unit_types - 1; tp_idx >= 0; --tp_idx) {
1098 int idx = ILPVAR_IDX(na, tp_idx, t);
1099 ARR_APP1(int, tmp_var_idx, na->ilp_vars.x[idx]);
1104 if (ARR_LEN(tmp_var_idx) > 0)
1105 lpp_set_factor_fast_bulk(lpp, cst, tmp_var_idx, ARR_LEN(tmp_var_idx), 1.0);
1107 DEL_ARR_F(tmp_var_idx);
1110 DBG((env->dbg, LEVEL_1, "\t%u bundle constraints (%g sec)\n",
1111 num_cst_bundle, ilp_timer_elapsed_usec(t_cst_bundle) / 1000000.0));
1115 * Create ILP dying nodes constraints:
1116 * - set variable d_{nt}^k to 1 if nodes n dies at step t on unit k
1118 static void create_dying_nodes_constraint(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node) {
1121 unsigned num_cst = 0;
1122 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
1124 lc_timer_t *t_cst = lc_timer_register("beilpsched_cst_dying_nodes", "create dying nodes constraints");
1125 #endif /* WITH_LIBCORE */
1127 ilp_timer_push(t_cst);
1128 /* check all time_steps */
1129 for (t = 0; t < ba->max_steps; ++t) {
1133 foreach_linked_irns(ba->head_ilp_nodes, irn) {
1134 be_ilpsched_irn_t *node = get_ilpsched_irn(env, irn);
1135 ilpsched_node_attr_t *na = get_ilpsched_node_attr(node);
1137 /* if node has no consumer within current block, it cannot die here */
1138 if (ARR_LEN(na->block_consumer) < 1)
1141 /* node can only die here if t at least asap(n) */
1142 if (t >= na->asap - 1) {
1145 /* for all unit types */
1146 for (node_tp_idx = na->n_unit_types - 1; node_tp_idx >= 0; --node_tp_idx) {
1148 int *tmp_var_idx = NEW_ARR_F(int, 0);
1150 snprintf(buf, sizeof(buf), "dying_node_cst_%u_n%u", t, get_irn_idx(irn));
1151 cst = lpp_add_cst_uniq(lpp, buf, lpp_less, (double)(na->n_consumer - 1));
1152 DBG((env->dbg, LEVEL_2, "added constraint %s\n", buf));
1155 /* number of consumer scheduled till t */
1156 for (i = ARR_LEN(na->block_consumer) - 1; i >= 0; --i) {
1157 be_ilpsched_irn_t *cons = get_ilpsched_irn(env, na->block_consumer[i]);
1158 ilpsched_node_attr_t *ca = get_ilpsched_node_attr(cons);
1160 for (tp_idx = ca->n_unit_types - 1; tp_idx >= 0; --tp_idx) {
1163 for (tm = ca->asap - 1; tm <= t && tm <= ca->alap - 1; ++tm) {
1164 int idx = ILPVAR_IDX(ca, tp_idx, tm);
1165 ARR_APP1(int, tmp_var_idx, ca->ilp_vars.x[idx]);
1170 /* could be that no consumer can be scheduled at this point */
1171 if (ARR_LEN(tmp_var_idx)) {
1175 /* subtract possible prior kill points */
1176 for (tn = na->asap - 1; tn < t; ++tn) {
1177 idx = ILPVAR_IDX_DEAD(ba, na, node_tp_idx, tn);
1178 lpp_set_factor_fast(lpp, cst, na->ilp_vars.d[idx], -1.0);
1181 idx = ILPVAR_IDX_DEAD(ba, na, node_tp_idx, t);
1182 lpp_set_factor_fast(lpp, cst, na->ilp_vars.d[idx], 0.0 - (double)(na->n_consumer));
1183 lpp_set_factor_fast_bulk(lpp, cst, tmp_var_idx, ARR_LEN(tmp_var_idx), 1.0);
1186 DEL_ARR_F(tmp_var_idx);
1193 DBG((env->dbg, LEVEL_1, "\t%u dying nodes constraints (%g sec)\n",
1194 num_cst, ilp_timer_elapsed_usec(t_cst) / 1000000.0));
1198 * Create ILP pressure constraints:
1199 * - add additional costs to objective function if a node is scheduled
1200 * on a unit although all units of this type are currently occupied
1202 static void create_pressure_constraint(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node) {
1205 unsigned num_cst = 0;
1206 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
1208 lc_timer_t *t_cst = lc_timer_register("beilpsched_cst_pressure", "create pressure constraints");
1209 #endif /* WITH_LIBCORE */
1211 ilp_timer_push(t_cst);
1212 /* check all time_steps */
1213 for (t = 0; t < ba->max_steps; ++t) {
1217 for (glob_type_idx = env->cpu->n_unit_types - 1; glob_type_idx >= 0; --glob_type_idx) {
1218 be_execution_unit_type_t *cur_tp = &env->cpu->unit_types[glob_type_idx];
1221 snprintf(buf, sizeof(buf), "pressure_cst_%u_%s", t, cur_tp->name);
1222 cst = lpp_add_cst_uniq(lpp, buf, lpp_less, (double)(cur_tp->n_units - 1));
1223 DBG((env->dbg, LEVEL_2, "added constraint %s\n", buf));
1226 /* to be continued ... */
1230 DBG((env->dbg, LEVEL_1, "\t%u pressure constraints (%g sec)\n",
1231 num_cst, ilp_timer_elapsed_usec(t_cst) / 1000000.0));
1234 /***************************************************
1236 * |_ _| | | __ \ (_)
1237 * | | | | | |__) | _ __ ___ __ _ _ _ __
1238 * | | | | | ___/ | '_ ` _ \ / _` | | '_ \
1239 * _| |_| |____| | | | | | | | (_| | | | | |
1240 * |_____|______|_| |_| |_| |_|\__,_|_|_| |_|
1242 ***************************************************/
1245 * Create the ilp (add variables, build constraints, solve, build schedule from solution).
1247 static void create_ilp(ir_node *block, void *walk_env) {
1248 be_ilpsched_env_t *env = walk_env;
1249 be_ilpsched_irn_t *block_node = get_ilpsched_irn(env, block);
1250 ilpsched_block_attr_t *ba = get_ilpsched_block_attr(block_node);
1251 FILE *logfile = NULL;
1253 struct obstack var_obst;
1255 DBG((env->dbg, 255, "\n\n\n=========================================\n"));
1256 DBG((env->dbg, 255, " ILP Scheduling for %+F\n", block));
1257 DBG((env->dbg, 255, "=========================================\n\n"));
1259 DBG((env->dbg, LEVEL_1, "Creating ILP Variables for nodes in %+F (%u interesting nodes)\n",
1260 block, ba->n_interesting_nodes));
1262 /* if we have less than two interesting nodes, there is no need to create the ILP */
1263 if (ba->n_interesting_nodes > 1) {
1264 double fact_var = ba->n_interesting_nodes > 25 ? 1.1 : 1.2;
1265 double fact_cst = ba->n_interesting_nodes > 25 ? 0.7 : 1.5;
1266 int base_num = ba->n_interesting_nodes * ba->n_interesting_nodes;
1267 int estimated_n_var = (int)((double)base_num * fact_var);
1268 int estimated_n_cst = (int)((double)base_num * fact_cst);
1270 DBG((env->dbg, LEVEL_1, "Creating LPP with estimed numbers: %d vars, %d cst\n",
1271 estimated_n_var, estimated_n_cst));
1273 /* set up the LPP object */
1274 lpp = new_lpp_userdef(
1275 "be ilp scheduling",
1277 estimated_n_cst + 1, /* num vars */
1278 estimated_n_cst + 20, /* num cst */
1279 1.2); /* grow factor */
1280 obstack_init(&var_obst);
1282 /* create ILP variables */
1283 create_variables(env, lpp, block_node, &var_obst);
1285 /* create ILP constraints */
1286 DBG((env->dbg, LEVEL_1, "Creating constraints for nodes in %+F:\n", block));
1287 create_assignment_and_precedence_constraints(env, lpp, block_node);
1288 create_ressource_constraints(env, lpp, block_node);
1289 create_bundle_constraints(env, lpp, block_node);
1290 create_dying_nodes_constraint(env, lpp, block_node);
1292 DBG((env->dbg, LEVEL_1, "ILP to solve: %u variables, %u constraints\n", lpp->var_next, lpp->cst_next));
1294 /* debug stuff, dump lpp when debugging is on */
1296 if (firm_dbg_get_mask(env->dbg) > 0) {
1300 snprintf(buf, sizeof(buf), "lpp_block_%lu.txt", get_irn_node_nr(block));
1301 f = fopen(buf, "w");
1302 lpp_dump_plain(lpp, f);
1304 snprintf(buf, sizeof(buf), "lpp_block_%lu.mps", get_irn_node_nr(block));
1309 /* set solve time limit */
1310 lpp_set_time_limit(lpp, env->opts->time_limit);
1312 /* set logfile if requested */
1313 if (strlen(env->opts->log_file) > 0) {
1314 if (strcasecmp(env->opts->log_file, "stdout") == 0)
1315 lpp_set_log(lpp, stdout);
1316 else if (strcasecmp(env->opts->log_file, "stderr") == 0)
1317 lpp_set_log(lpp, stderr);
1319 logfile = fopen(env->opts->log_file, "w");
1321 fprintf(stderr, "Could not open logfile '%s'! Logging disabled.\n", env->opts->log_file);
1323 lpp_set_log(lpp, logfile);
1328 lpp_solve_net(lpp, env->main_env->options->ilp_server, env->main_env->options->ilp_solver);
1333 /* check for valid solution */
1334 if (! lpp_is_sol_valid(lpp)) {
1338 snprintf(buf, sizeof(buf), "lpp_block_%lu.assert.txt", get_irn_node_nr(block));
1339 f = fopen(buf, "w");
1340 lpp_dump_plain(lpp, f);
1342 snprintf(buf, sizeof(buf), "lpp_block_%lu.assert.mps", get_irn_node_nr(block));
1344 dump_ir_block_graph(env->irg, "-assert");
1346 assert(0 && "ILP solution is not feasible!");
1349 DBG((env->dbg, LEVEL_1, "\nSolution:\n"));
1350 DBG((env->dbg, LEVEL_1, "\tsend time: %g sec\n", lpp->send_time / 1000000.0));
1351 DBG((env->dbg, LEVEL_1, "\treceive time: %g sec\n", lpp->recv_time / 1000000.0));
1352 DBG((env->dbg, LEVEL_1, "\titerations: %d\n", lpp->iterations));
1353 DBG((env->dbg, LEVEL_1, "\tsolution time: %g\n", lpp->sol_time));
1354 DBG((env->dbg, LEVEL_1, "\tobjective function: %g\n", LPP_VALUE_IS_0(lpp->objval) ? 0.0 : lpp->objval));
1355 DBG((env->dbg, LEVEL_1, "\tbest bound: %g\n", LPP_VALUE_IS_0(lpp->best_bound) ? 0.0 : lpp->best_bound));
1357 DBG((env->dbg, LEVEL_1, "variables used %u bytes\n", obstack_memory_used(&var_obst)));
1360 /* apply solution */
1361 apply_solution(env, lpp, block);
1368 * Perform ILP scheduling on the given irg.
1370 void be_ilp_sched(const be_irg_t *birg) {
1371 be_ilpsched_env_t env;
1372 const char *name = "be ilp scheduling";
1374 FIRM_DBG_REGISTER(env.dbg, "firm.be.sched.ilp");
1376 //firm_dbg_set_mask(env.dbg, 31);
1378 env.irg = birg->irg;
1379 env.main_env = birg->main_env;
1380 env.alap_queue = new_waitq();
1381 env.arch_env = birg->main_env->arch_env;
1382 env.cpu = arch_isa_get_machine(birg->main_env->arch_env->isa);
1383 env.opts = &ilp_opts;
1384 phase_init(&env.ph, name, env.irg, PHASE_DEFAULT_GROWTH, init_ilpsched_irn);
1386 /* assigne a unique per block number to all interesting nodes */
1387 irg_walk_in_or_dep_graph(env.irg, NULL, build_block_idx, &env);
1390 The block indicees are completely build after the walk,
1391 now we can allocate the bitsets (size depends on block indicees)
1394 phase_reinit_irn_data(&env.ph);
1396 /* Collect all root nodes (having no user in their block) and calculate ASAP. */
1397 irg_walk_in_or_dep_blkwise_graph(env.irg, collect_alap_root_nodes, calculate_irn_asap, &env);
1399 /* calculate ALAP and perform ILP scheduling */
1400 irg_block_walk_graph(env.irg, calculate_block_alap, create_ilp, &env);
1403 if (firm_dbg_get_mask(env.dbg)) {
1405 phase_stat_t *stat_ptr = phase_stat(&env.ph, &stat);
1407 fprintf(stderr, "Phase used: %u bytes\n", stat_ptr->overall_bytes);
1411 /* free all allocated object */
1412 del_waitq(env.alap_queue);
1413 phase_free(&env.ph);
1418 * Register ILP scheduler options.
1420 void ilpsched_register_options(lc_opt_entry_t *grp) {
1421 static int run_once = 0;
1422 lc_opt_entry_t *sched_grp;
1426 sched_grp = lc_opt_get_grp(grp, "ilpsched");
1428 lc_opt_add_table(sched_grp, ilpsched_option_table);
1431 #endif /* WITH_LIBCORE */
1433 #else /* WITH_ILP */
1435 static int some_picky_compiler_do_not_allow_empty_files;
1437 #endif /* WITH_ILP */