copy-opt (phi-opt + register constrained nodes).
Additionally slightliy changed algo for copy-opt heuristic.
becopystat has to be done when new bemain.c is ready.
SOURCES += Makefile.in besched.h belistsched.h belistsched.c \
beutil.h bemain.c besched.c bemain.c belive.c belive.h benumb.h \
benumb_t.h benumb.c bechordal.c bera.c beutil.c phistat.c \
- bephiopt.c bephicoal.c bephicoalilp.c bera.h bechordalspill.c \
- beasm_dump_globals.c beasm_asm_gnu.c bearch.h bearch.c
+ bera.h bechordalspill.c beasm_dump_globals.c beasm_asm_gnu.c \
+ bearch.h bearch.c sp_matrix.c becopyoptmain.c becopyopt.c becopyheur.c \
+ becopyilp.c becopystat.c
include $(topdir)/MakeRules
--- /dev/null
+/**
+ * Heuristic for minimizing copies using a queue which holds 'qnodes' not yet
+ * examined. A qnode has a 'target color', nodes out of the opt unit and
+ * a 'conflict graph'. A 'max indep set' is determined form these. We try to
+ * color this mis using a color-exchanging mechanism. Occuring conflicts are
+ * modeled with 'conflict edges' and the qnode is reinserted in the queue. The
+ * first qnode colored without conflicts is the best one.
+ * @author Daniel Grund
+ * @date 12.04.2005
+ */
+
+#include "becopyopt.h"
+
+#define DEBUG_LVL SET_LEVEL_1
+static firm_dbg_module_t *dbg = NULL;
+
+#define SLOTS_PINNED_GLOBAL 256
+#define SLOTS_CONFLICTS 8
+#define SLOTS_CHANGED_NODES 32
+
+#define MIN(a,b) ((a<b)?a:b)
+#define list_entry_queue(lh) list_entry(lh, qnode_t, queue)
+#define HASH_CONFLICT(c) (HASH_PTR(c.n1) ^ HASH_PTR(c.n2))
+
+/**
+ * Modeling additional conflicts between nodes. NOT live range interference
+ */
+typedef struct _conflict_t {
+ const ir_node *n1, *n2;
+} conflict_t;
+
+/**
+ * If an irn is changed, the changes first get stored in a node_stat_t,
+ * to allow undo of changes (=drop new data) in case of conflicts.
+ */
+typedef struct _node_stat_t {
+ const ir_node *irn;
+ int new_color;
+ int pinned_local :1;
+} node_stat_t;
+
+/**
+ * Represents a node in the optimization queue.
+ */
+typedef struct _qnode_t {
+ struct list_head queue; /**< chaining of unit_t->queue */
+ int color; /**< target color */
+ bitset_t *nodes; /**< marks the nodes of unit_t->nodes[i] beeing part of this qnode */
+ set *conflicts; /**< contains conflict_t's. All internal conflicts */
+ int size; /**< number of nodes in the mis. equals number of set bits in mis */
+ bitset_t *mis; /**< marks the nodes of unit_t->nodes[i] beeing part of the max idependent set */
+ set *changed_nodes; /**< contains node_stat_t's. */
+} qnode_t;
+
+
+static int set_cmp_conflict_t(const void *x, const void *y, size_t size) {
+ const conflict_t *xx = x;
+ const conflict_t *yy = y;
+ return ! (xx->n1 == yy->n1 && xx->n2 == yy->n2);
+}
+
+/**
+ * If a local pinned conflict occurs, a new edge in the conflict graph is added.
+ * The next maximum independent set build, will regard it.
+ */
+static INLINE void qnode_add_conflict(const qnode_t *qn, const ir_node *n1, const ir_node *n2) {
+ conflict_t c;
+ DBG((dbg, LEVEL_3, "\t %n -- %n\n", n1, n2));
+
+ if ((int)n1 < (int)n2) {
+ c.n1 = n1;
+ c.n2 = n2;
+ } else {
+ c.n1 = n2;
+ c.n2 = n1;
+ }
+ set_insert(qn->conflicts, &c, sizeof(c), HASH_CONFLICT(c));
+}
+
+/**
+ * Checks if two nodes are in a conflict.
+ */
+static INLINE int qnode_are_conflicting(const qnode_t *qn, const ir_node *n1, const ir_node *n2) {
+ conflict_t c;
+ /* search for live range interference */
+ if (values_interfere(n1, n2))
+ return 1;
+ /* search for recoloring conflicts */
+ if ((int)n1 < (int)n2) {
+ c.n1 = n1;
+ c.n2 = n2;
+ } else {
+ c.n1 = n2;
+ c.n2 = n1;
+ }
+ return (int) set_find(qn->conflicts, &c, sizeof(c), HASH_CONFLICT(c));
+}
+
+static int set_cmp_node_stat_t(const void *x, const void *y, size_t size) {
+ return ((node_stat_t *)x)->irn != ((node_stat_t *)y)->irn;
+}
+
+/**
+ * Finds a node status entry of a node if existent. Otherwise return NULL
+ */
+static INLINE node_stat_t *qnode_find_node(const qnode_t *qn, const ir_node *irn) {
+ node_stat_t find;
+ find.irn = irn;
+ return set_find(qn->changed_nodes, &find, sizeof(find), HASH_PTR(irn));
+}
+
+/**
+ * Finds a node status entry of a node if existent. Otherwise it will return
+ * an initialized new entry for this node.
+ */
+static INLINE node_stat_t *qnode_find_or_insert_node(const qnode_t *qn, const ir_node *irn) {
+ node_stat_t find;
+ find.irn = irn;
+ find.new_color = NO_COLOR;
+ find.pinned_local = 0;
+ return set_insert(qn->changed_nodes, &find, sizeof(find), HASH_PTR(irn));
+}
+
+/**
+ * Returns the virtual color of a node if set before, else returns the real color.
+ */
+static INLINE int qnode_get_new_color(const qnode_t *qn, const ir_node *irn) {
+ node_stat_t *found = qnode_find_node(qn, irn);
+ if (found)
+ return found->new_color;
+ else
+ return get_irn_color(irn);
+}
+
+/**
+ * Sets the virtual color of a node.
+ */
+static INLINE void qnode_set_new_color(const qnode_t *qn, const ir_node *irn, int color) {
+ node_stat_t *found = qnode_find_or_insert_node(qn, irn);
+ found->new_color = color;
+}
+
+/**
+ * Checks if a node is local pinned. A node is local pinned, iff it belongs
+ * to the same optimization unit and has been optimized before the current
+ * processed node.
+ */
+static INLINE int qnode_is_pinned_local(const qnode_t *qn, const ir_node *irn) {
+ node_stat_t *found = qnode_find_node(qn, irn);
+ if (found)
+ return found->pinned_local;
+ else
+ return 0;
+}
+
+/**
+ * Local-pins a node, so optimizations of further nodes of the same opt unit
+ * can handle situations in which a color change would undo prior optimizations.
+ */
+static INLINE void qnode_pin_local(const qnode_t *qn, const ir_node *irn) {
+ node_stat_t *found = qnode_find_or_insert_node(qn, irn);
+ found->pinned_local = 1;
+}
+
+/**
+ * Possible return values of qnode_color_irn()
+ */
+#define CHANGE_SAVE NULL
+#define CHANGE_IMPOSSIBLE (ir_node *)1
+#define is_conflicting_node(n) (((int)n) > 1)
+
+/**
+ * Performs virtual re-coloring of node @p n to color @p col. Virtual colors of
+ * other nodes are changed too, as required to preserve correctness. Function is
+ * aware of local and global pinning. Recursive.
+ * @param irn The node to set the color for
+ * @param col The color to set
+ * @param trigger The irn that caused the wish to change the color of the irn
+ * @return CHANGE_SAVE iff setting the color is possible, with all transiteve effects.
+ * CHANGE_IMPOSSIBLE iff conflicts with reg-constraintsis occured.
+ * Else the first conflicting ir_node encountered is returned.
+ *
+ * ASSUMPTION: Assumes that a life range of a single value can't be spilt into
+ * several smaller intervals where other values can live in between.
+ * This should be true in SSA.
+ */
+static const ir_node *qnode_color_irn(const qnode_t *qn, const ir_node *irn, int col, const ir_node *trigger, const copy_opt_t *co) {
+ const ir_node *res;
+ struct obstack confl_ob;
+ ir_node **confl, *cn;
+ int i, irn_col;
+
+ DBG((dbg, LEVEL_3, "\t\t%n \tcaused col(%n) \t%2d --> %2d\n", trigger, irn, qnode_get_new_color(qn, irn), col));
+ obstack_init(&confl_ob);
+ irn_col = qnode_get_new_color(qn, irn);
+
+ if (irn_col == col)
+ goto ret_save;
+ if (pset_find_ptr(co->pinned_global, irn) || qnode_is_pinned_local(qn, irn)) {
+ res = irn;
+ goto ret_confl;
+ }
+
+ /* get all nodes which would conflict with this change */
+ {
+ struct obstack q;
+ int in, out;
+ ir_node *irn_bl;
+
+ irn_bl = get_nodes_block(irn);
+
+ /* first check for a conflicting node which is 'living in' the irns block */
+ {
+ ir_node *n;
+ pset *live_ins = get_live_in(irn_bl);
+ for (n = pset_first(live_ins); n; n = pset_next(live_ins))
+ if (is_allocatable_irn(n) && n != trigger && qnode_get_new_color(qn, n) == col && values_interfere(irn, n)) {
+ DBG((dbg, LEVEL_4, "\t\t %n\ttroubles\n", n));
+ obstack_ptr_grow(&confl_ob, n);
+ pset_break(live_ins);
+ break;
+ }
+ }
+
+ /* setup the queue of blocks. */
+ obstack_init(&q);
+ obstack_ptr_grow(&q, irn_bl);
+ in = 1;
+ out = 0;
+
+ /* process the queue. The code below checks for every block dominated
+ * by the irns one, and in which the irn is live, if there are
+ * conflicting nodes */
+ while (out < in) {
+ ir_node *curr_bl, *sub_bl;
+ int i, max;
+
+ curr_bl = ((ir_node **)obstack_base(&q))[out++];
+
+ /* Add to the result all nodes in the block, which have
+ * the target color and interfere with the irn */
+ for (i = 0, max = get_irn_n_outs(curr_bl); i < max; ++i) {
+ ir_node *n = get_irn_out(curr_bl, i);
+ if (is_allocatable_irn(n) && n != trigger && qnode_get_new_color(qn, n) == col && values_interfere(irn, n)) {
+ DBG((dbg, LEVEL_4, "\t\t %n\ttroubles\n", n));
+ obstack_ptr_grow(&confl_ob, n);
+ }
+ }
+
+ /* If irn lives out check i-dominated blocks where the irn lives in */
+ /* Fill the queue */
+ if (is_live_out(curr_bl, irn)) {
+ dominates_for_each(curr_bl, sub_bl)
+ if (is_live_in(sub_bl, irn)) {
+ obstack_ptr_grow(&q, sub_bl);
+ in++;
+ }
+ }
+ }
+ obstack_free(&q, NULL);
+ obstack_ptr_grow(&confl_ob, NULL);
+ confl = (ir_node **) obstack_finish(&confl_ob);
+ }
+
+ /* process all nodes which would conflict with this change */
+ for (i = 0, cn = confl[0]; cn; cn = confl[++i]) {
+ const ir_node *sub_res;
+
+ /* try to color the conflicting node cn with the color of the irn itself */
+ sub_res = qnode_color_irn(qn, cn, irn_col, irn, co);
+ if (sub_res != CHANGE_SAVE) {
+ res = sub_res;
+ goto ret_confl;
+ }
+ }
+ /* if we arrive here all sub changes can be applied, so it's save to change this irn */
+
+ret_save:
+ DBG((dbg, LEVEL_3, "\t\t%n save\n", irn));
+ obstack_free(&confl_ob, NULL);
+ qnode_set_new_color(qn, irn, col);
+ return CHANGE_SAVE;
+
+ret_confl:
+ DBG((dbg, LEVEL_3, "\t\t%n conflicting\n", irn));
+ obstack_free(&confl_ob, NULL);
+ return res;
+}
+
+/**
+ * Tries to set the colors for all members of this queue node;
+ * to the target color qn->color
+ * @returns 1 iff all members colors could be set
+ * 0 else
+ */
+static int qnode_try_color(const qnode_t *qn, const unit_t *ou, const copy_opt_t *co) {
+ int i;
+ bitset_foreach(qn->mis, i) {
+ const ir_node *test_node, *confl_node;
+
+ test_node = ou->nodes[i];
+ DBG((dbg, LEVEL_2, "\t Testing %n\n", test_node));
+ confl_node = qnode_color_irn(qn, test_node, qn->color, test_node, co);
+
+ if (confl_node == CHANGE_SAVE) {
+ DBG((dbg, LEVEL_2, "\t Save\n"));
+ qnode_pin_local(qn, test_node);
+ } else if (confl_node == CHANGE_IMPOSSIBLE) {
+ DBG((dbg, LEVEL_2, "\t Impossible\n"));
+ bitset_clear(qn->nodes, i);
+ } else {
+ DBG((dbg, LEVEL_2, "\t Conflicting\n"));
+ if (qnode_is_pinned_local(qn, confl_node)) {
+ /* changing test_node would change back a node of current ou */
+ qnode_add_conflict(qn, confl_node, test_node);
+ }
+ if (pset_find_ptr(co->pinned_global, confl_node)) {
+ /* changing test_node would change back a node of a prior ou */
+ bitset_clear(qn->nodes, i);
+ }
+ }
+
+ if (confl_node != CHANGE_SAVE)
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * Creates a new qnode
+ */
+static INLINE qnode_t *new_qnode(const unit_t *ou, int color) {
+ qnode_t *qn = malloc(sizeof(*qn));
+ qn->color = color;
+ qn->mis = bitset_malloc(ou->node_count-1);
+ qn->nodes = bitset_malloc(ou->node_count-1);
+ bitset_set_all(qn->nodes);
+ qn->conflicts = new_set(set_cmp_conflict_t, SLOTS_CONFLICTS);
+ qn->changed_nodes = new_set(set_cmp_node_stat_t, SLOTS_CHANGED_NODES);
+ return qn;
+}
+
+/**
+ * Frees space used by a queue node
+ */
+static INLINE void free_qnode(qnode_t *qn) {
+ del_set(qn->conflicts);
+ del_set(qn->changed_nodes);
+ bitset_free(qn->nodes);
+ bitset_free(qn->mis);
+ free(qn);
+}
+
+/**
+ * Determines a maximum independent set with respect to the interference and
+ * conflict edges of all nodes in a qnode.
+ */
+static INLINE void qnode_max_ind_set(qnode_t *qn, const unit_t *ou) {
+ int all_size, curr_size, i, o;
+ int *which;
+ const ir_node **curr, **all = alloca(bitset_popcnt(qn->nodes) * sizeof(*all));
+
+ /* all contains all nodes not removed in this qn */
+ assert(bitset_is_set(qn->nodes, 0) && "root is not element of this queue node");
+ all_size = 0;
+ bitset_foreach(qn->nodes, i)
+ all[all_size++] = ou->nodes[i];
+
+ /* which[i] says which element to take out of all[] and put into curr[i] */
+ which = alloca(all_size*sizeof(*which));
+ for (curr_size=0; curr_size<all_size; ++curr_size)
+ which[curr_size] = curr_size;
+
+ /* stores the currently examined set */
+ curr = alloca(all_size*sizeof(*curr));
+
+ while (1) { /* this loop will terminate because at least a single node'll be a max indep. set */
+ /* build current set */
+ for (i=0; i<curr_size; ++i)
+ curr[i] = all[which[all_size-curr_size+i]];
+
+ /* check current set */
+ for (i=0; i<curr_size; ++i)
+ for (o=i+1; o<curr_size; ++o)
+ if (qnode_are_conflicting(qn, curr[i], curr[o]))
+ goto conflict_found;
+
+ /* We had no conflict. This is the max indep. set */
+ bitset_clear_all(qn->mis);
+ qn->size = curr_size;
+ for (i=0; i<curr_size; ++i)
+ for (o=0; o<ou->node_count; ++o)
+ if (curr[i] == ou->nodes[o])
+ bitset_set(qn->mis, o);
+ return;
+
+conflict_found:
+ /* We had a conflict. Generate next set */
+ if (which[all_size-curr_size+1] == all_size-curr_size+1) {
+ curr_size--;
+ for (i=0; i<curr_size; ++i)
+ which[all_size-curr_size+i] = i;
+ } else {
+ int redo = 1;
+ while (redo) {
+ int pos = all_size;
+ do {
+ pos--;
+ } while (!(which[pos] = (which[pos]+1) % all_size));
+
+ for (i=pos+1; i<all_size; ++i)
+ which[i] = MIN(which[i-1]+1, all_size-1);
+
+ redo = 0;
+ for (i=all_size-curr_size; i<all_size-1; ++i)
+ if (which[i]>=which[i+1]) {
+ redo = 1;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Inserts a qnode in the sorted queue of the outimization unit. Queue is
+ * ordered by field 'size' (the size of the mis) in decreasing order.
+ */
+static INLINE void qnode_insert(qnode_t *qn, unit_t *ou) {
+ struct list_head *lh;
+ /* root node is not in qnode */
+ if (!bitset_is_set(qn->nodes, 0)) {
+ free_qnode(qn);
+ return;
+ }
+
+ qnode_max_ind_set(qn, ou);
+ if (ou->mis_size < qn->size)
+ ou->mis_size = qn->size;
+
+ lh = &ou->queue;
+ while (lh->next != &ou->queue) {
+ qnode_t *curr = list_entry_queue(lh->next);
+ if (curr->size <= qn->size)
+ break;
+ lh = lh->next;
+ }
+ list_add(&qn->queue, lh);
+}
+
+/**
+ * Tries to re-allocate colors of nodes in this opt unit, to achieve a lower
+ * number of copy instructions placed during SSA-destruction and lowering.
+ * Works only for opt units with exactly 1 root node, which is the
+ * case for approximately 80% of all phi classes and all register constrained
+ * nodes. (All other phi classes are reduced to this case.)
+ */
+static void co_heur_opt_unit(const copy_opt_t *co, unit_t *ou) {
+ int i;
+ qnode_t * curr;
+
+ /* init queue */
+ INIT_LIST_HEAD(&ou->queue);
+ for (i=MAX_COLORS-1; i>=0; --i)
+ if (is_possible_color(ou->nodes[0], i))
+ qnode_insert(new_qnode(ou, i), ou);
+
+ /* search best */
+ while (!list_empty(&ou->queue)) {
+ /* get head of queue */
+ curr = list_entry_queue(ou->queue.next);
+ list_del(&curr->queue);
+ /* try */
+ if (qnode_try_color(curr, ou, co))
+ break;
+ /* no success, so re-insert */
+ del_set(curr->changed_nodes);
+ curr->changed_nodes = new_set(set_cmp_node_stat_t, SLOTS_CHANGED_NODES);
+ qnode_insert(curr, ou);
+ }
+
+ /* apply the best found qnode */
+ if (curr->size >= 2) {
+ DBG((dbg, 1, "\tBest color: %d Copies: %d/%d\n", curr->color, ou->interf+ou->node_count-1-curr->size));
+ /* globally pin root and eventually others */
+ pset_insert_ptr(co->pinned_global, ou->nodes[0]);
+ for (i=1; i<ou->node_count; ++i) {
+ const ir_node *irn = ou->nodes[i];
+ int nc = qnode_get_new_color(curr, irn);
+ if (nc != NO_COLOR && nc == qnode_get_new_color(curr, ou->nodes[0]))
+ pset_insert_ptr(co->pinned_global, irn);
+ }
+
+ /* set color of all changed nodes */
+ node_stat_t *ns;
+ for (ns = set_first(curr->changed_nodes); ns; ns = set_next(curr->changed_nodes)) {
+ /* NO_COLOR is possible, if we had an undo */
+ if (ns->new_color != NO_COLOR) {
+ DBG((dbg, 1, "\t color(%n) := %d\n", ns->irn, ns->new_color));
+ set_irn_color(ns->irn, ns->new_color);
+ }
+ }
+ }
+
+ /* free best qnode (curr) and queue */
+ free_qnode(curr);
+ list_for_each_entry(qnode_t, curr, &ou->queue, queue)
+ free_qnode(curr);
+}
+
+void co_heur_opt(copy_opt_t *co) {
+ unit_t *curr;
+ dbg = firm_dbg_register("ir.be.copyoptheur");
+ firm_dbg_set_mask(dbg, DEBUG_LVL);
+
+ co->pinned_global = pset_new_ptr(SLOTS_PINNED_GLOBAL);
+
+ list_for_each_entry(unit_t, curr, &co->units, units)
+ co_heur_opt_unit(co, curr);
+
+ del_pset(co->pinned_global);
+}
--- /dev/null
+/**
+ * Minimizing copies with an exact algorithm using mixed integer programming (MIP).
+ * Problem statement as a 'quadratic 0-1 program with linear constraints' with
+ * n binary variables. Constraints are knapsack (enforce color for each node) and
+ * cliques of ifg (interference constraints).
+ * Transformation into a 'mixed integer program' with n binary variables and
+ * additional 2n real variables. Constraints are the above the transformed
+ * objective function and 'complementary conditions' for two var classes.
+ * @author Daniel Grund
+ *
+ * NOTE: Unfortunately no good solver is available locally (or even for linking)
+ * We use CPLEX 9.0 which runs on a machine residing at the Rechenzentrum.
+ * @date 12.04.2005
+ */
+
+#include "becopyopt.h"
+
+#define DUMP_MPS /**< dumps the problem in "CPLEX"-MPS format. NOT fixed-column-MPS. */
+#define USE_SOS /**< uses Special Ordered Sets when using MPS */
+#define DO_SOLVE /**< solve the MPS output with CPLEX */
+#define DUMP_MATRICES /**< dumps all matrices completely. only recommended for small problems */
+#define DUMP_LP /**< dumps the problem in LP format. 'human-readable' equations etc... */
+#define DELETE_FILES /**< deletes all dumped files after use */
+#define EXPECT_FILENAME "runme" /** name of the expect-script */
+
+/* CPLEX-account related stuff */
+#define SSH_USER_HOST_PATH "kb61@sp-smp.rz.uni-karlsruhe.de"
+#define SSH_PASSWD "!cplex90"
+
+#define DEBUG_LVL SET_LEVEL_1
+static firm_dbg_module_t *dbg = NULL;
+
+#define SLOTS_NUM2POS 256
+#define SLOTS_LIVING 32
+
+/**
+ * A type storing names of the x variables in the form x[NUMBER]_[COLOR]
+ */
+typedef struct _x_name_t {
+ int n, c;
+} x_name_t;
+
+/**
+ * For each node taking part in the opt-problem its position in the
+ * x-variable-vector is stored in a set. This set maps the node-nr (given by
+ * benumb) to the position in the vector.
+ */
+typedef struct _num2pos_t {
+ int num, pos;
+} num2pos_t;
+
+/**
+ * A type storing the unmodified '0-1 quadratic program' of the form
+ * min f = xQx
+ * udN: Ax = e
+ * Bx <= e
+ * x \in {0, 1}
+ *
+ * This problem is called the original problem
+ */
+typedef struct _problem_instance_t {
+ ir_graph* irg;
+ const char *name;
+ int x_dim, A_dim, B_dim; /**< number of: x variables, rows in A, rows in B */
+ x_name_t *x; /**< stores the names of the x variables. all possible colors for a node are ordered and occupy consecutive entries. lives in obstack ob. */
+ set *num2pos; /**< maps node numbers to positions in x. */
+ sp_matrix_t *Q, *A, *B; /**< the (sparse) matrices of this problem */
+
+ /* needed only for linearizations */
+ int bigM, maxQij, minQij;
+
+ /* overhead needed to build this */
+ struct obstack ob;
+ int curr_color;
+ int curr_row;
+} problem_instance_t;
+
+/* Nodes have consecutive numbers so this hash shoud be fine */
+#define HASH_NUM(num) num
+
+static int set_cmp_num2pos(const void *x, const void *y, size_t size) {
+ return ((num2pos_t *)x)->num != ((num2pos_t *)y)->num;
+}
+
+/**
+ * Sets the first position of node with number num to pos.
+ * See x_name_t *x in _problem_instance_t.
+ */
+static INLINE void pi_set_first_pos(problem_instance_t *pi, int num, int pos) {
+ num2pos_t find;
+ find.num = num;
+ find.pos = pos;
+ set_insert(pi->num2pos, &find, sizeof(find), HASH_NUM(num));
+}
+
+/**
+ * Get position by number. (First possible color)
+ * returns -1 if not found.
+ */
+static INLINE int pi_get_first_pos(problem_instance_t *pi, int num) {
+ num2pos_t find, *found;
+ find.num = num;
+ found = set_find(pi->num2pos, &find, sizeof(find), HASH_NUM(num));
+ if (found) {
+ assert(pi->x[found->pos].n == num && (found->pos == 0 || pi->x[found->pos-1].n != num) && "pi->num2pos is broken!");
+ return found->pos;
+ } else
+ return -1;
+}
+
+/**
+ * Get position by number and color.
+ * returns -1 if not found.
+ */
+static INLINE int pi_get_pos(problem_instance_t *pi, int num, int col) {
+ num2pos_t find, *found;
+ find.num = num;
+ int pos;
+ found = set_find(pi->num2pos, &find, sizeof(find), HASH_NUM(num));
+ if (!found)
+ return -1;
+ pos = found->pos;
+ while (pos < pi->x_dim && pi->x[pos].n == num && pi->x[pos].c < col)
+ pos++;
+
+ if (pi->x[pos].n == num && pi->x[pos].c == col)
+ return pos;
+ else
+ return -1;
+}
+
+static INLINE FILE *ffopen(const char *base, const char *ext, const char *mode) {
+ FILE *out;
+ char buf[1024];
+
+ snprintf(buf, sizeof(buf), "%s.%s", base, ext);
+ if (! (out = fopen(buf, mode))) {
+ fprintf(stderr, "Cannot open file %s in mode %s\n", buf, mode);
+ assert(0);
+ }
+ return out;
+}
+
+#ifdef DUMP_MATRICES
+/**
+ * Dump the raw matrices of the problem to a file for debugging.
+ */
+static void pi_dump_matrices(problem_instance_t *pi) {
+ int i;
+ FILE *out = ffopen(pi->name, "matrix", "wt");
+
+ DBG((dbg, LEVEL_1, "Dumping raw...\n"));
+ fprintf(out, "\n\nx-names =\n");
+ for (i=0; i<pi->x_dim; ++i)
+ fprintf(out, "%5d %2d\n", pi->x[i].n, pi->x[i].c);
+
+ fprintf(out, "\n\n-Q =\n");
+ matrix_dump(pi->Q, out, -1);
+
+ fprintf(out, "\n\nA =\n");
+ matrix_dump(pi->A, out, 1);
+
+ fprintf(out, "\n\nB =\n");
+ matrix_dump(pi->B, out, 1);
+
+ fclose(out);
+}
+#endif
+
+#ifdef DUMP_LP
+/**
+ * Dumps the problem instance as a MILP. The original problem is transformed into:
+ * min f = es - Mex
+ * udN: Qx -y -s +Me = 0
+ * Ax = e
+ * Bx <= e
+ * y <= 2M(e-x)
+ * x \in N y, s >= 0
+ *
+ * with M >= max sum Q'ij * x_j
+ * i j
+ */
+static void pi_dump_lp(problem_instance_t *pi) {
+ int i, max_abs_Qij;
+ matrix_elem_t *e;
+ FILE *out = ffopen(pi->name, "lpo", "wt");
+
+ DBG((dbg, LEVEL_1, "Dumping lp_org...\n"));
+ /* calc the big M for Q */
+ max_abs_Qij = pi->maxQij;
+ if (-pi->minQij > max_abs_Qij)
+ max_abs_Qij = -pi->minQij;
+ pi->bigM = pi->A_dim * max_abs_Qij;
+ DBG((dbg, LEVEL_2, "BigM = %d\n", pi->bigM));
+
+ /* generate objective function */
+ fprintf(out, "min: ");
+ for (i=0; i<pi->x_dim; ++i)
+ fprintf(out, "+s%d_%d -%dx%d_%d ", pi->x[i].n, pi->x[i].c, pi->bigM, pi->x[i].n, pi->x[i].c);
+ fprintf(out, ";\n\n");
+
+ /* constraints for former objective function */
+ for (i=0; i<pi->x_dim; ++i) {
+ matrix_foreach_in_row(pi->Q, i, e) {
+ int Qio = e->val;
+ if (Qio == 1)
+ fprintf(out, "+x%d_%d ", pi->x[e->col].n, pi->x[e->col].c);
+ else if(Qio == -1)
+ fprintf(out, "-x%d_%d ", pi->x[e->col].n, pi->x[e->col].c);
+ else
+ fprintf(out, "%+dx%d_%d ", Qio, pi->x[e->col].n, pi->x[e->col].c);
+ }
+ fprintf(out, "-y%d_%d -s%d_%d +%d= 0;\n", pi->x[i].n, pi->x[i].c, pi->x[i].n, pi->x[i].c, pi->bigM);
+ }
+ fprintf(out, "\n\n");
+
+ /* constraints for (special) complementary condition */
+ for (i=0; i<pi->x_dim; ++i)
+ fprintf(out, "y%d_%d <= %d - %dx%d_%d;\n", pi->x[i].n, pi->x[i].c, 2*pi->bigM, 2*pi->bigM, pi->x[i].n, pi->x[i].c);
+ fprintf(out, "\n\n");
+
+ /* knapsack constraints */
+ for (i=0; i<pi->A_dim; ++i) {
+ matrix_foreach_in_row(pi->Q, i, e)
+ fprintf(out, "+x%d_%d ", pi->x[e->col].n, pi->x[e->col].c);
+ fprintf(out, " = 1;\n");
+ }
+ fprintf(out, "\n\n");
+
+ /* interference graph constraints */
+ for (i=0; i<pi->B_dim; ++i) {
+ matrix_foreach_in_row(pi->Q, i, e)
+ fprintf(out, "+x%d_%d ", pi->x[e->col].n, pi->x[e->col].c);
+ fprintf(out, " <= 1;\n");
+ }
+ fprintf(out, "\n\n");
+
+ /* integer constraints */
+ fprintf(out, "int x%d_%d", pi->x[0].n, pi->x[0].c);
+ for (i=1; i<pi->x_dim; ++i)
+ fprintf(out, ", x%d_%d", pi->x[i].n, pi->x[i].c);
+ fprintf(out, ";\n");
+
+ fclose(out);
+}
+#endif
+
+#ifdef DUMP_MPS
+/**
+ * Dumps an mps file representing the problem. This is NOT the old-style,
+ * fixed-column format. Some white spaces are important, in general spaces
+ * are separators, MARKER-lines are used in COLUMN section to define binaries.
+ */
+//BETTER use last 2 fields in COLUMNS section
+static void pi_dump_mps(problem_instance_t *pi) {
+ int i, max_abs_Qij;
+ matrix_elem_t *e;
+ FILE *out = ffopen(pi->name, "mps", "wt");
+
+ DBG((dbg, LEVEL_1, "Dumping mps...\n"));
+ max_abs_Qij = pi->maxQij;
+ if (-pi->minQij > max_abs_Qij)
+ max_abs_Qij = -pi->minQij;
+ pi->bigM = pi->A_dim * max_abs_Qij;
+ DBG((dbg, LEVEL_2, "BigM = %d\n", pi->bigM));
+
+ fprintf(out, "NAME %s\n", pi->name);
+
+ fprintf(out, "ROWS\n");
+ fprintf(out, " N obj\n");
+ for (i=0; i<pi->x_dim; ++i)
+ fprintf(out, " E cQ%d\n", i);
+ for (i=0; i<pi->A_dim; ++i)
+ fprintf(out, " E cA%d\n", i);
+ for (i=0; i<pi->B_dim; ++i)
+ fprintf(out, " L cB%d\n", i);
+ for (i=0; i<pi->x_dim; ++i)
+ fprintf(out, " L cy%d\n", i);
+
+ fprintf(out, "COLUMNS\n");
+ /* the x vars come first */
+ /* mark them as binaries */
+ fprintf(out, " MARKI0\t'MARKER'\t'INTORG'\n");
+#ifdef USE_SOS
+ int sos_cnt = 0;
+ fprintf(out, " S1 SOS_%d\t'MARKER'\t'SOSORG'\n", sos_cnt++);
+#endif
+ for (i=0; i<pi->x_dim; ++i) {
+#ifdef USE_SOS
+ if (i>0 && pi->x[i].n != pi->x[i-1].n) {
+ fprintf(out, " SOS_%d\t'MARKER'\t'SOSEND'\n", sos_cnt++);
+ fprintf(out, " S1 SOS_%d\t'MARKER'\t'SOSORG'\n", sos_cnt++);
+ }
+#endif
+ /* participation in objective */
+ fprintf(out, " x%d_%d\tobj\t%d\n", pi->x[i].n, pi->x[i].c, -pi->bigM);
+ /* in Q */
+ matrix_foreach_in_col(pi->Q, i, e)
+ fprintf(out, " x%d_%d\tcQ%d\t%d\n", pi->x[i].n, pi->x[i].c, e->row, e->val);
+ /* in A */
+ matrix_foreach_in_col(pi->A, i, e)
+ fprintf(out, " x%d_%d\tcA%d\t%d\n", pi->x[i].n, pi->x[i].c, e->row, e->val);
+ /* in B */
+ matrix_foreach_in_col(pi->B, i, e)
+ fprintf(out, " x%d_%d\tcB%d\t%d\n", pi->x[i].n, pi->x[i].c, e->row, e->val);
+ /* in y */
+ fprintf(out, " x%d_%d\tcy%d\t%d\n", pi->x[i].n, pi->x[i].c, i, 2*pi->bigM);
+ }
+
+#ifdef USE_SOS
+ fprintf(out, " SOS_%d\t'MARKER'\t'SOSEND'\n", sos_cnt++);
+#endif
+ fprintf(out, " MARKI1\t'MARKER'\t'INTEND'\n"); /* end of marking */
+
+ /* next the s vars */
+ for (i=0; i<pi->x_dim; ++i) {
+ /* participation in objective */
+ fprintf(out, " s%d_%d\tobj\t%d\n", pi->x[i].n, pi->x[i].c, 1);
+ /* in Q */
+ fprintf(out, " s%d_%d\tcQ%d\t%d\n", pi->x[i].n, pi->x[i].c, i, -1);
+ }
+
+ /* next the y vars */
+ for (i=0; i<pi->x_dim; ++i) {
+ /* in Q */
+ fprintf(out, " y%d_%d\tcQ%d\t%d\n", pi->x[i].n, pi->x[i].c, i, -1);
+ /* in y */
+ fprintf(out, " y%d_%d\tcy%d\t%d\n", pi->x[i].n, pi->x[i].c, i, 1);
+ }
+
+ fprintf(out, "RHS\n");
+ for (i=0; i<pi->x_dim; ++i)
+ fprintf(out, " rhs\tcQ%d\t%d\n", i, -pi->bigM);
+ for (i=0; i<pi->A_dim; ++i)
+ fprintf(out, " rhs\tcA%d\t%d\n", i, 1);
+ for (i=0; i<pi->B_dim; ++i)
+ fprintf(out, " rhs\tcB%d\t%d\n", i, 1);
+ for (i=0; i<pi->x_dim; ++i)
+ fprintf(out, " rhs\tcy%d\t%d\n", i, 2*pi->bigM);
+
+ fprintf(out, "ENDATA\n");
+ fclose(out);
+
+ out = ffopen(pi->name, "mst", "wt");
+ fprintf(out, "NAME\n");
+ for (i=0; i<pi->x_dim; ++i) {
+ int val, n, c;
+ n = pi->x[i].n;
+ c = pi->x[i].c;
+ if (get_irn_color(get_irn_for_graph_nr(pi->irg, n)) == c)
+ val = 1;
+ else
+ val = 0;
+ fprintf(out, " x%d_%d\t%d\n", n, c, val);
+ }
+ fprintf(out, "ENDATA\n");
+ fclose(out);
+}
+#endif
+
+#ifdef DO_SOLVE
+/**
+ * Invoke an external solver
+ */
+static void pi_solve_ilp(problem_instance_t *pi) {
+ FILE *out;
+
+ /* write command file for CPLEX */
+ out = ffopen(pi->name, "cmd", "wt");
+ fprintf(out, "read %s.mps\n", pi->name);
+ fprintf(out, "read %s.mst\n", pi->name);
+ fprintf(out, "set mip strategy mipstart 1\n");
+ fprintf(out, "optimize\n");
+ fprintf(out, "set logfile %s.sol\n", pi->name);
+ fprintf(out, "display solution variables 1-%d\n", pi->x_dim);
+ fprintf(out, "set logfile cplex.log\n");
+ fprintf(out, "quit\n");
+ fclose(out);
+
+ /* write expect-file for copying problem to RZ */
+ out = ffopen(EXPECT_FILENAME, "exp", "wt");
+ fprintf(out, "#! /usr/bin/expect\n");
+ fprintf(out, "spawn scp %s.mps %s.mst %s.cmd %s:\n", pi->name, pi->name, pi->name, SSH_USER_HOST_PATH);
+ fprintf(out, "expect \":\"\n");
+ fprintf(out, "send \"%s\\n\"\n", SSH_PASSWD);
+ fprintf(out, "interact\n");
+
+ fprintf(out, "spawn ssh %s \"./cplex90 < %s.cmd\"\n", SSH_USER_HOST_PATH, pi->name);
+ fprintf(out, "expect \":\"\n");
+ fprintf(out, "send \"%s\\n\"\n", SSH_PASSWD);
+ fprintf(out, "interact\n");
+
+ fprintf(out, "spawn scp %s:%s.sol .\n", SSH_USER_HOST_PATH, pi->name);
+ fprintf(out, "expect \":\"\n");
+ fprintf(out, "send \"%s\\n\"\n", SSH_PASSWD);
+ fprintf(out, "interact\n");
+ fclose(out);
+
+ /* call the expect script */
+ chmod(EXPECT_FILENAME ".exp", 0700);
+ system(EXPECT_FILENAME ".exp");
+}
+
+/**
+ * Sets the colors of irns according to the values of variables found in the
+ * output file of the solver.
+ */
+static void pi_apply_solution(problem_instance_t *pi) {
+ FILE *in = ffopen(pi->name, "sol", "rt");
+
+ if (!in)
+ return;
+ DBG((dbg, LEVEL_1, "Applying solution...\n"));
+ while (!feof(in)) {
+ char buf[1024];
+ int num = -1, col = -1, val = -1;
+ if (fscanf(in, "x%d_%d %d.%s\n", &num, &col, &val, buf) != 3) {
+ while(fscanf(in, "%1020s\n", buf) != 1);
+ continue;
+ }
+ if (val == 1) {
+ DBG((dbg, LEVEL_1, "x%d_%d = %d\n", num, col, val));
+ set_irn_color(get_irn_for_graph_nr(pi->irg, num), col);
+ }
+ }
+ fclose(in);
+}
+#endif /* DO_SOLVE */
+
+#ifdef DELETE_FILES
+static void pi_delete_files(problem_instance_t *pi) {
+ char buf[1024];
+ int end = snprintf(buf, sizeof(buf), "%s", pi->name);
+#ifdef DUMP_MATRICES
+ snprintf(buf+end, sizeof(buf)-end, ".matrix");
+ remove(buf);
+#endif
+#ifdef DUMP_MPS
+ snprintf(buf+end, sizeof(buf)-end, ".mps");
+ remove(buf);
+ snprintf(buf+end, sizeof(buf)-end, ".mst");
+ remove(buf);
+ snprintf(buf+end, sizeof(buf)-end, ".cmd");
+ remove(buf);
+ remove(EXPECT_FILENAME ".exp");
+#endif
+#ifdef DUMP_LP
+ snprintf(buf+end, sizeof(buf)-end, ".lp");
+ remove(buf);
+#endif
+}
+#endif
+
+/**
+ * Collects all irns in currently processed register class
+ */
+static void pi_collect_x_names(ir_node *block, void *env) {
+ problem_instance_t *pi = env;
+ struct list_head *head = &get_ra_block_info(block)->border_head;
+ border_t *curr;
+
+ list_for_each_entry_reverse(border_t, curr, head, list)
+ if (curr->is_def && curr->is_real) {
+ x_name_t xx;
+ pi->A_dim++; /* one knapsack constraint for each node */
+
+ xx.n = get_irn_graph_nr(curr->irn);
+ pi_set_first_pos(pi, xx.n, pi->x_dim);
+ //TODO iterate over all possible colors !!MUST BE IN ORDER!!
+ for (xx.c=0; xx.c<MAX_COLORS; ++xx.c) {
+ if (!is_possible_color(irn, xx.c))
+ continue;
+ DBG((dbg, LEVEL_2, "Adding %n %d\n", curr->irn, xx.c));
+ obstack_grow(&pi->ob, &xx, sizeof(xx));
+ pi->x_dim++; /* one x variable for each node and color */
+ }
+ }
+}
+
+/**
+ * Checks if all nodes in living are live_out in block block.
+ */
+static INLINE int all_live_out(ir_node *block, pset *living) {
+ ir_node *n;
+ for (n = pset_first(living); n; n = pset_next(living))
+ if (!is_live_out(block, n)) {
+ pset_break(living);
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * Finds cliques in the interference graph, considering only nodes
+ * for which the color pi->curr_color is possible. Finds only 'maximal-cliques',
+ * viz cliques which are not conatained in another one.
+ * This is used for the matrix B.
+ */
+static void pi_clique_finder(ir_node *block, void *env) {
+ problem_instance_t *pi = env;
+ enum phase_t {growing, shrinking} phase = growing;
+ struct list_head *head = &get_ra_block_info(block)->border_head;
+ border_t *b;
+ pset *living = pset_new_ptr(SLOTS_LIVING);
+
+ list_for_each_entry_reverse(border_t, b, head, list) {
+ const ir_node *irn = b->irn;
+ if (!is_possible_color(n, pi->curr_col))
+ continue;
+
+ if (b->is_def) {
+ DBG((dbg, LEVEL_2, "Def %n\n", irn));
+ pset_insert_ptr(living, irn);
+ phase = growing;
+ } else { /* is_use */
+ DBG((dbg, LEVEL_2, "Use %n\n", irn));
+
+ /* before shrinking the set, store the current 'maximum' clique;
+ * do NOT if clique is a single node
+ * do NOT if all values are live_out */
+ if (phase == growing && pset_count(living) >= 2 && !all_live_out(block, living)) {
+ ir_node *n;
+ for (n = pset_first(living); n; n = pset_next(living)) {
+ int pos = pi_get_pos(pi, get_irn_graph_nr(n), pi->curr_color);
+ matrix_set(pi->B, pi->curr_row, pos, 1);
+ DBG((dbg, LEVEL_2, "B[%d, %d] := %d\n", pi->curr_row, pos, 1));
+ }
+ pi->curr_row++;
+ }
+ pset_remove_ptr(living, irn);
+ phase = shrinking;
+ }
+ }
+
+ del_pset(living);
+}
+
+/**
+ * Generate the initial problem matrices and vectors.
+ */
+static problem_instance_t *new_pi(const copy_opt_t *co) {
+ DBG((dbg, LEVEL_1, "Generating new instance...\n"));
+ problem_instance_t *pi = calloc(1, sizeof(*pi));
+ pi->irg = co->irg;
+ pi->name = get_entity_name(get_irg_entity(co->irg));
+ pi->num2pos = new_set(set_cmp_num2pos, SLOTS_NUM2POS);
+ pi->bigM = 1;
+
+ /* Vector x
+ * one entry per node and possible color */
+ obstack_init(&pi->ob);
+ dom_tree_walk_irg(co->irg, pi_collect_x_names, NULL, &pi->ob);
+ pi->x = obstack_finish(&pi->ob);
+
+ /* Matrix Q
+ * weights for the 'same-color-optimization' target */
+ {
+ unit_t *curr;
+ pi->Q = new_matrix(pi->x_dim, pi->x_dim);
+
+ list_for_each_entry(unit_t, curr, &co->units, units) {
+ const ir_node *root, *arg;
+ int rootnr, argnr;
+ unsigned rootpos, argpos;
+ int i;
+
+ root = curr->nodes[0];
+ rootnr = get_irn_graph_nr(root);
+ rootpos = pi_get_first_pos(pi, rootnr);
+ for (i = 1; i < curr->node_count; ++i) {
+ int weight = -get_weight(root, arg);
+ arg = curr->nodes[i];
+ argnr = get_irn_graph_nr(arg);
+ argpos = pi_get_first_pos(pi, argnr);
+
+ DBG((dbg, LEVEL_2, "Q[%n, %n] := %d\n", root, arg, weight));
+ /* for all colors root and arg have in common, set the weight for
+ * this pair in the objective function matrix Q */
+ while (rootpos < pi->x_dim && argpos < pi->x_dim &&
+ pi->x[rootpos].n == rootnr && pi->x[argpos].n == argnr) {
+ if (pi->x[rootpos].c < pi->x[argpos].c)
+ ++rootpos;
+ else if (pi->x[rootpos].c > pi->x[argpos].c)
+ ++argpos;
+ else {
+ matrix_set(pi->Q, rootpos++, argpos++, weight);
+
+ if (weight < pi->minQij) {
+ DBG((dbg, LEVEL_2, "minQij = %d\n", weight));
+ pi->minQij = weight;
+ }
+ if (weight > pi->maxQij) {
+ DBG((dbg, LEVEL_2, "maxQij = %d\n", weight));
+ pi->maxQij = weight;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Matrix A
+ * knapsack constraint for each node */
+ {
+ int row = 0, col = 0;
+ pi->A = new_matrix(pi->A_dim, pi->x_dim);
+ while (col < pi->x_dim) {
+ int curr_n = pi->x[col].n;
+ while (col < pi->x_dim && pi->x[col].n == curr_n) {
+ DBG((dbg, LEVEL_2, "A[%d, %d] := %d\n", row, col, 1));
+ matrix_set(pi->A, row, col++, 1);
+ }
+ ++row;
+ }
+ assert(row == pi->A_dim);
+ }
+
+ /* Matrix B
+ * interference constraints using exactly those cliques not contained in others. */
+ {
+ int color, expected_clipques = pi->A_dim/3 * MAX_COLORS;
+ pi->B = new_matrix(expected_clipques, pi->x_dim);
+ for (color = 0; color < MAX_COLORS; ++color) {
+ pi->curr_color = color;
+ dom_tree_walk_irg(pi->irg, pi_clique_finder, NULL, pi);
+ }
+ pi->B_dim = matrix_get_rowcount(pi->B);
+ }
+
+ return pi;
+}
+
+/**
+ * clean the problem instance
+ */
+static void free_pi(problem_instance_t *pi) {
+ del_matrix(pi->Q);
+ del_matrix(pi->A);
+ del_matrix(pi->B);
+ del_set(pi->num2pos);
+ obstack_free(&pi->ob, NULL);
+ free(pi);
+}
+
+void co_ilp_opt(copy_opt_t *co) {
+ dbg = firm_dbg_register("ir.be.copyoptilp");
+ firm_dbg_set_mask(dbg, DEBUG_LVL);
+
+ problem_instance_t *pi = new_pi(co);
+
+#ifdef DUMP_MATRICES
+ pi_dump_matrices(pi);
+#endif
+
+#ifdef DUMP_LP
+ pi_dump_lp(pi);
+#endif
+
+#ifdef DUMP_MPS
+ pi_dump_mps(pi);
+#endif
+
+#ifdef DO_SOLVE
+ pi_solve_ilp(pi);
+ pi_apply_solution(pi);
+#endif
+
+#ifdef DELETE_FILES
+ pi_delete_files(pi);
+#endif
+
+ free_pi(pi);
+}
--- /dev/null
+/**
+ * @author Daniel Grund
+ * @date 12.04.2005
+ */
+
+#include "becopyopt.h"
+
+#define DEBUG_LVL SET_LEVEL_1
+static firm_dbg_module_t *dbg = NULL;
+
+//TODO
+#define is_optimizable(irn) (is_Phi(irn) || 0)
+
+/**
+ * Builds an optimization unit for a given optimizable irn (root).
+ * This opt-unit is inserted in the main structure co.
+ * If an arg of root itself is optimizable process this arg before with a
+ * recursive call. For handling this situation and loops co->root is used
+ * to remember all roots.
+ */
+static void co_append_unit(copy_opt_t *co, const ir_node *root) {
+ int i, arity;
+ unit_t *unit;
+ DBG((dbg, LEVEL_1, "Root: %n\n", root));
+ /* check if we encountered this root earlier */
+ if (pset_find_ptr(co->roots, root))
+ return;
+ pset_insert_ptr(co->roots, root);
+
+ /* init unit */
+ arity = get_irn_arity(root);
+ unit = malloc(sizeof(*unit));
+ unit->interf = 0;
+ unit->node_count = 1;
+ unit->nodes = malloc((arity+1) * sizeof(*unit->nodes));
+ unit->nodes[0] = root;
+ INIT_LIST_HEAD(&unit->queue);
+
+ /* check all args */
+ for (i=0; i<arity; ++i) {
+ ir_node *arg = get_irn_n(root, i);
+ if (!values_interfere(root, arg)) {
+ if (arg != root) {
+ DBG((dbg, LEVEL_1, "Member: %n\n", arg));
+ if (is_optimizable(arg))
+ co_append_unit(co, arg);
+ unit->nodes[unit->node_count++] = arg;
+ }
+ } else
+ unit->interf++;
+ }
+
+ if (unit->node_count > 1) {
+ unit->nodes = realloc(unit->nodes, unit->node_count * sizeof(*unit->nodes));
+ list_add_tail(&unit->units, &co->units);
+ } else {
+ free(unit->nodes);
+ free(unit);
+ }
+}
+
+static void co_collect_in_block(ir_node *block, void *env) {
+ copy_opt_t *co = env;
+ struct list_head *head = &get_ra_block_info(block)->border_head;
+ border_t *curr;
+
+ list_for_each_entry_reverse(border_t, curr, head, list)
+ if (curr->is_def && curr->is_real && is_optimizable(curr->irn))
+ co_append_unit(co, curr->irn);
+}
+
+static void co_collect_units(copy_opt_t *co) {
+ co->roots = pset_new_ptr(64);
+ dom_tree_walk_irg(co->irg, co_collect_in_block, NULL, co);
+ del_pset(co->roots);
+}
+
+copy_opt_t *new_copy_opt(ir_graph *irg) {
+ dbg = firm_dbg_register("ir.be.copyopt");
+ firm_dbg_set_mask(dbg, DEBUG_LVL);
+
+ copy_opt_t *co = calloc(1, sizeof(*co));
+ co->irg = irg;
+ INIT_LIST_HEAD(&co->units);
+ co_collect_units(co);
+ return co;
+}
+
+void free_copy_opt(copy_opt_t *co) {
+ unit_t *curr;
+ list_for_each_entry(unit_t, curr, &co->units, units) {
+ free(curr->nodes);
+ free(curr);
+ }
+}
+
+int co_get_lower_bound(copy_opt_t *co) {
+ //TODO Think if copy counting is this easy!
+ int res = 0;
+ unit_t *curr;
+ list_for_each_entry(unit_t, curr, &co->units, units)
+ res += curr->interf + curr->node_count - curr->mis_size;
+ return res;
+}
+
+int co_get_interferer_count(copy_opt_t *co) {
+ int res = 0;
+ unit_t *curr;
+ list_for_each_entry(unit_t, curr, &co->units, units)
+ res += curr->interf;
+ return res;
+}
--- /dev/null
+/**
+ * Header for copy optimization problem. Analysis and set up of the problem.
+ * @author Daniel Grund
+ * @date 12.04.2005
+ */
+
+#ifndef _BECOPYOPT_H
+#define _BECOPYOPT_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <alloca.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "debug.h"
+#include "obst.h"
+#include "list.h"
+#include "set.h"
+#include "pset.h"
+#include "bitset.h"
+#include "sp_matrix.h"
+
+#include "irgraph.h"
+#include "irgwalk.h"
+#include "irnode.h"
+#include "irdom.h"
+#include "irouts.h"
+
+#include "benumb_t.h"
+#include "belive_t.h"
+#include "bera_t.h"
+#include "bechordal_t.h"
+
+/**
+ * TODO THIS EXTERNAL THINGS
+ * define get_weight to sth representing the _gain_ if node n and m
+ * have the same color. Must return values MIN_WEIGHT <= . <= MAX_WEIGHT.
+ */
+#define get_weight(n,m) 1
+#define is_possible_color(irn, col) 1
+#define MAX_COLORS 32
+
+/**
+ * A single unit of optimization. Lots of these form a copy-opt problem
+ */
+typedef struct _unit_t {
+ struct list_head units; /**< chain for all units */
+ int interf; /**< number of nodes dropped due to interference */
+ int node_count; /**< size of the nodes array */
+ const ir_node **nodes; /**< [0] is the root-node, others are non interfering args of it. */
+
+ /* for heuristic */
+ int mis_size; /**< size of a mis considering only ifg (not coloring conflicts) */
+ struct list_head queue; /**< list of (mis/color) sorted by size of mis */
+} unit_t;
+
+/**
+ * Data representing the problem of copy minimization.
+ */
+typedef struct _copy_opt_t {
+ ir_graph *irg; /**< the irg which is processed */
+ struct list_head units; /**< all units to optimize in right oreder */
+ pset *roots; /**< used only temporary for detecting multiple appends */
+
+ /* for heuristic */
+ pset *pinned_global; /**< optimized nodes should not be altered any more */
+} copy_opt_t;
+
+
+/**
+ * Generate the problem. Collect all infos and optimizable nodes.
+ */
+copy_opt_t *new_copy_opt(ir_graph *irg);
+
+/**
+ * Free the space...
+ */
+void free_copy_opt(copy_opt_t *co);
+
+/**
+ * Returns a lower bound for the number of copies needed based on interfering
+ * arguments and the size of a max indep. set (only ifg-edges) of the other args.
+ */
+int co_get_lower_bound(copy_opt_t *co);
+
+/**
+ * Returns the number of arguments interfering with their root node. This also
+ * is a (worse) lower bound for the number of copies needed.
+ */
+int co_get_interferer_count(copy_opt_t *co);
+
+/**
+ * Solves the problem using a heuristic approach
+ */
+void co_heur_opt(copy_opt_t *co);
+
+/**
+ * Solves the problem using mixed integer programming
+ */
+void co_ilp_opt(copy_opt_t *co);
+
+#endif
--- /dev/null
+/**
+ * Main file for the optimization reducing the copies needed for:
+ * - phi coalescing
+ * - register-constrained nodes
+ *
+ * Contains a simple checker for this optimization.
+ * By request some statistics are collected too.
+ *
+ * @author Daniel Grund
+ * @date 11.04.2005
+ */
+
+#include "debug.h"
+#include "list.h"
+#include "obst.h"
+#include "irgraph.h"
+#include "irnode.h"
+#include "irgwalk.h"
+
+#include "bera_t.h"
+#include "becopyoptmain.h"
+#include "becopyopt.h"
+#include "becopystat.h"
+
+#define DO_HEUR
+#define DO_ILP
+#undef DO_STAT
+
+#define DEBUG_LVL SET_LEVEL_1
+static firm_dbg_module_t *dbg = NULL;
+
+/**
+ * Needed for result checking
+ */
+static void allocatable_collector(ir_node *node, void *env) {
+ struct obstack *obst = env;
+ if (!is_Block(node) && is_allocatable_irn(node))
+ obstack_ptr_grow(obst, node);
+}
+
+/**
+ * This O(n^2) checker checks, if two ifg-connected nodes have the same color.
+ */
+static void check_results(ir_graph *irg) {
+ struct obstack ob;
+ ir_node **nodes, *n1, *n2;
+ int i, o;
+
+ obstack_init(&ob);
+ irg_walk_graph(irg, allocatable_collector, NULL, &ob);
+ obstack_ptr_grow(&ob, NULL);
+ nodes = (ir_node **) obstack_finish(&ob);
+ for (i = 0, n1 = nodes[i]; n1; n1 = nodes[++i]) {
+ assert(! (is_allocatable_irn(n1) && get_irn_color(n1) == NO_COLOR));
+ for (o = i+1, n2 = nodes[o]; n2; n2 = nodes[++o])
+ if (phi_ops_interfere(n1, n2) && get_irn_color(n1) == get_irn_color(n2)) {
+ DBG((dbg, 0, "Error: %n in %n and %n in %n\n", n1, get_nodes_block(n1), n2, get_nodes_block(n2)));
+ assert(0 && "Interfering values have the same color!");
+ }
+ }
+ obstack_free(&ob, NULL);
+}
+
+void be_copy_opt_init(void) {
+ dbg = firm_dbg_register("ir.be.copyopt");
+ firm_dbg_set_mask(dbg, DEBUG_LVL);
+}
+
+void be_copy_opt(ir_graph* irg) {
+ copy_opt_t *co;
+
+ check_results(irg);
+ co = new_copy_opt(irg);
+
+#ifdef DO_STAT
+ irg_stat_t *stats = new_irg_stat(co);
+ irg_stat_count(stats, co, 0);
+#endif
+
+#ifdef DO_HEUR
+ co_heur_opt(co);
+ check_results(irg);
+#ifdef DO_STAT
+ irg_stat_count(stats, co, 1);
+#endif
+#endif
+
+#ifdef DO_ILP
+ co_ilp_opt(co);
+ check_results(irg);
+#ifdef DO_STAT
+ irg_stat_count(stats, co, 2);
+#endif
+#endif
+
+#ifdef DO_STAT
+ irg_stat_print(stats);
+ all_stat_dump();
+#endif
+
+ free_copy_opt(co);
+}
+
+void be_copy_opt_done(ir_graph* irg) {
+}
--- /dev/null
+/**
+ * Main header for the optimization reducing the copies needed for:
+ * - phi coalescing
+ * - register-constrained nodes
+ *
+ * Checker included.
+ * By request some statistics are collected too.
+ *
+ * @author Daniel Grund
+ * @date 11.04.2005
+ */
+
+#ifndef _BECOPYOPTMAIN_H
+#define _BECOPYOPTMAIN_H
+
+#include "irgraph.h"
+
+void be_copy_opt_init(void);
+void be_copy_opt(ir_graph* irg);
+void be_copy_opt_done(ir_graph* irg);
+
+#endif
--- /dev/null
+/**
+ * @author Daniel Grund
+ * @date 19.04.2005
+ */
+#include "beutil.h"
+#include "becopystat.h"
+#include "list.h"
+
+struct _irg_stat_t {
+ struct list_head chain;
+ ir_graph *irg;
+ const char *irg_name;
+ int interferers, lb, max;
+ int copies[3];
+};
+
+typedef struct _all_stat_t {
+ char *unit_name;
+ struct list_head irgs;
+} all_stat_t;
+
+static all_stat_t *all_stats = NULL;
+
+#define irg_list_entry(lh) list_entry(lh, irg_stat_t, chain)
+
+irg_stat_t *new_irg_stat(copy_opt_t *co) {
+ irg_stat_t *is, *curr;
+
+ if (!all_stats) {
+ all_stats = calloc(1, sizeof(*all_stats));
+ //TODO all_stats->unit_name = ??? */
+ INIT_LIST_HEAD(&all_stats->irgs);
+ is = calloc(1, sizeof(*is));
+ is->irg_name = "CUMULATIVE";
+ list_add_tail(&is->chain, &all_stats->irgs);
+ }
+
+ /* look if we had this irg already */
+ list_for_each_entry(irg_stat_t, curr, &all_stats->irgs, chain)
+ if (curr->irg == co->irg)
+ return curr;
+
+ /* else create a new entry */
+ is = calloc(1, sizeof(*is));
+ is->irg = co->irg;
+ is->irg_name = get_entity_name(get_irg_entity(co->irg));
+ list_add_tail(&is->chain, &all_stats->irgs);
+ return is;
+}
+
+void irg_stat_count(irg_stat_t *is, copy_opt_t *co, int phase) {
+ unit_t *curr;
+ int max = 0, copies = 0;
+
+ list_for_each_entry(unit_t, curr, &co->units, units) {
+ int i;
+ max += curr->interf + curr->node_count - 1;
+ const ir_node *root = curr->nodes[0];
+ int root_color = get_irn_color(root);
+ copies += curr->interf;
+ for (i=1; i<curr->node_count; ++i) {
+ const ir_node *arg = curr->nodes[i];
+ if (root_color != get_irn_color(arg))
+ copies++;
+ }
+ }
+
+ is->copies[phase] += copies;
+ if (phase == 0)
+ is->max += max;
+ if (phase == 1) {
+ is->interferers += co_get_interferer_count(co);
+ is->lb += co_get_lower_bound(co);
+ }
+}
+
+void irg_stat_print(irg_stat_t *is) {
+ printf("Irg %s: %3d %3d %3d %3d %3d %3d", is->irg_name, is->interferers, is->lb, is->copies[0], is->copies[1], is->copies[2], is->max);
+}
+
+void all_stat_dump(void) {
+ FILE *out;
+ irg_stat_t *cuml, *curr;
+ /* Compute cumulative values */
+ cuml = irg_list_entry(all_stats->irgs.next);
+ cuml->interferers = 0;
+ cuml->lb = 0;
+ cuml->max = 0;
+ cuml->copies[0] = 0;
+ cuml->copies[1] = 0;
+ cuml->copies[2] = 0;
+ list_for_each_entry(irg_stat_t, curr, &all_stats->irgs, chain) {
+ int i = 0;
+ cuml->interferers += curr->interferers;
+ cuml->lb += curr->lb;
+ cuml->max += curr->max;
+ for (i=0; i<3; ++i)
+ cuml->copies[i] += curr->copies[i];
+ }
+
+ /* dump to file */
+ out = ffopen(all_stats->unit_name, "stats", "wt");
+ list_for_each_entry(irg_stat_t, curr, &all_stats->irgs, chain)
+ fprintf(out, "%15s %3d %3d %3d %3d %3d %3d", curr->irg_name, curr->interferers, curr->lb, curr->copies[0], curr->copies[1], curr->copies[2], curr->max);
+ fclose(out);
+}
--- /dev/null
+/**
+ * @author Daniel Grund
+ * @date 11.04.2005
+ */
+
+//TODO
+#ifndef _BECOPYSTAT_H
+#define _BECOPYSTAT_H
+
+#include "becopyopt.h"
+
+typedef struct _irg_stat_t irg_stat_t;
+
+irg_stat_t *new_irg_stat(copy_opt_t *co);
+void irg_stat_count(irg_stat_t *is, copy_opt_t *co, int phase);
+void irg_stat_print(irg_stat_t *is);
+void all_stat_dump(void);
+
+#endif
#include "beutil.h"
#include "bechordal.h"
#include "bechordal.h"
-#include "bephiopt.h"
+#include "becopyoptmain.h"
#include "phistat.h"
#include "beasm_dump_globals.h"
be_numbering_init();
be_ra_init();
be_ra_chordal_init();
- be_phi_opt_init();
+ be_copy_opt_init();
}
extern void be_ra_chordal(ir_graph *irg);
#ifdef DUMP_ALLOCATED
dump_allocated_irg(irg, "");
#endif
- be_phi_opt(irg);
+ be_copy_opt(irg);
be_ra_chordal_done(irg);
be_numbering_done(irg);
+++ /dev/null
-/**
- * @author Daniel Grund
- * @date 04.01.2005
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-
-#include "obst.h"
-#include "set.h"
-#include "pset.h"
-#include "bitset.h"
-#include "debug.h"
-#include "irouts.h"
-#include "irdom.h"
-
-#include "bechordal.h"
-#include "belive_t.h"
-#include "bera_t.h"
-#include "phiclass_t.h"
-#include "bephicoal_t.h"
-
-#define DEBUG_LVL 0 //SET_LEVEL_2
-#define MAX_COLORS 32
-
-#define INITIAL_SLOTS_PINNED_GLOBAL 256
-#define INITIAL_SLOTS_CHANGED_NODES 32
-
-/* some things for readable code */
-#define CHANGE_SAVE NULL
-#define CHANGE_IMPOSSIBLE (ir_node *)1
-#define CHANGE_NYI (ir_node *)2
-#define is_conflicting_node(n) (((int)n) > 2)
-
-/**
- * Models conflicts between nodes. These may be life range conflicts or
- * pinning conflicts, which may occur while changing colors
- */
-typedef struct _conflict_t {
- ir_node *n1, *n2;
-} conflict_t;
-
-/**
- * If an irn is changed, the changes first get stored in a node_stat_t,
- * to allow undo of changes in case of conflicts.
- */
-typedef struct _node_stat_t {
- ir_node *irn;
- int color;
- int undo_color;
- char status; /**< Bit 0: pinned, Bit 1: removed */
-} node_stat_t;
-
-#define _set_pinned(nodestat) nodestat->status |= 1
-#define _set_removed(nodestat) nodestat->status |= 2
-#define _clear_pinned(nodestat) nodestat->status &= 255 ^ 1
-#define _clear_removed(nodestat) nodestat->status &= 255 ^ 2
-#define _is_pinned(nodestat) (nodestat->status & 1)
-#define _is_removed(nodestat) (nodestat->status & 2)
-
-/**
- * Central data structure. Contains infos needed during coalescing of the
- * corresponding phi class.
- */
-typedef struct _phi_unit_t {
- unsigned char node_count; /**< size of the nodes-array */
- unsigned char conflict_count; /**< size of the conflicts-array */
- unsigned char conflict_count_org; /**< initial size of the conflicts-array */
- ir_node **nodes; /**< [0] is the phi node. [1..node_count-1] the arguments of the phi not interfering with it */
- conflict_t *conflicts; /**< pairs of conflicting ir_nodes. */
- set *changed_nodes; /**< contains node_stat_t's. */
-} phi_unit_t;
-
-static firm_dbg_module_t *dbgphi = NULL;
-
-/**
- * Contains already optimized ir_nodes of phi-units fully processed.
- * So one can perform a check not to switch them twice or more.
- */
-static pset *pinned_global = NULL;
-
-static int set_cmp_node_stat_t(const void *x, const void *y, size_t size) {
- return ((node_stat_t *)x)->irn != ((node_stat_t *)y)->irn;
-}
-
-/**
- * Finds a node status entry of a node if existent.
- */
-static INLINE node_stat_t *pu_find_node(phi_unit_t *pu, ir_node *irn) {
- node_stat_t find;
- find.irn = irn;
- return set_find(pu->changed_nodes, &find, sizeof(find), HASH_PTR(irn));
-}
-
-/**
- * Finds a node status entry of a node if existent. Otherwise it will return
- * an initialized new entry for this node.
- */
-static INLINE node_stat_t *pu_find_or_insert_node(phi_unit_t *pu, ir_node *irn) {
- node_stat_t find;
- find.irn = irn;
- find.color = NO_COLOR;
- find.undo_color = NO_COLOR;
- find.status = 0;
- return set_insert(pu->changed_nodes, &find, sizeof(find), HASH_PTR(irn));
-}
-
-/**
- * @return The virtual color of a node, if set before, else just the real color.
- */
-static INLINE int pu_get_new_color(phi_unit_t *pu, ir_node *irn) {
- node_stat_t *found = pu_find_node(pu, irn);
- if (found)
- return found->color;
- else
- return get_irn_color(irn);
-}
-
-/**
- * Sets the virtual color of a node.
- */
-static INLINE void pu_set_new_color(phi_unit_t *pu, ir_node *irn, int color) {
- node_stat_t *found = pu_find_or_insert_node(pu, irn);
- found->undo_color = found->color;
- found->color = color;
- DBG((dbgphi, LEVEL_4, "%n %d\n", irn, color));
-}
-
-/**
- * Sets the virtual color of a node to the color it had,
- * before the last call to pu_set_new_color
- */
-static INLINE void pu_undo_color(phi_unit_t *pu, ir_node *irn) {
- node_stat_t *ns = pu_find_node(pu, irn);
- assert(ns && "Nodes whose colors are undone must be in pu->changed_nodes");
- ns->color = ns->undo_color;
- DBG((dbgphi, LEVEL_3, "\t\tUndo: col(%n) := %d\n", irn, ns->undo_color));
-}
-
-/**
- * Checks if a node is removed from consideration respectively building
- * a maximum independent set.
- */
-static INLINE int pu_is_node_removed(phi_unit_t *pu, ir_node *irn) {
- node_stat_t *found = pu_find_node(pu, irn);
- if (found)
- return _is_removed(found);
- else
- return 0;
-}
-
-/**
- * Removes a node from the base set, out of which a maximum independet
- * set gets build from.
- */
-static INLINE void pu_remove_node(phi_unit_t *pu, ir_node *irn) {
- node_stat_t *found = pu_find_or_insert_node(pu, irn);
- _set_removed(found);
- DBG((dbgphi, LEVEL_4, "%n\n", irn));
-}
-
-/**
- * Checks if a node is local pinned; i.e. it belongs to the same phi unit and
- * has been optimized before the current processed one.
- */
-static INLINE int pu_is_node_pinned(phi_unit_t *pu, ir_node *irn) {
- node_stat_t *found = pu_find_node(pu, irn);
- if (found)
- return _is_pinned(found);
- else
- return 0;
-}
-
-/**
- * Local-pins a node, so optimizations of further nodes of the same phi unit
- * can handle situations in which a color change would undo prior optimizations.
- */
-static INLINE void pu_pin_node(phi_unit_t *pu, ir_node *irn) {
- node_stat_t *found = pu_find_or_insert_node(pu, irn);
- _set_pinned(found);
- DBG((dbgphi, LEVEL_4, "%n\n", irn));
-}
-
-/**
- * If a local pinned conflict occurs, a new edge in the conflict graph is added.
- * The next maximum independent set build, will regard it.
- */
-static INLINE void pu_add_conflict(phi_unit_t *pu, ir_node *n1, ir_node *n2) {
- int count = pu->conflict_count;
-
- DBG((dbgphi, LEVEL_3, "\t %n -- %n\n", n1, n2));
- assert(count != 255 && "Too much conflicts. Can hold max 255 entries");
- if ((count & 15) == 0)
- pu->conflicts = realloc(pu->conflicts, (count + 16)*sizeof(*pu->conflicts));
-
- if ((int)n1 < (int)n2) {
- pu->conflicts[count].n1 = n1;
- pu->conflicts[count].n2 = n2;
- } else {
- pu->conflicts[count].n1 = n2;
- pu->conflicts[count].n2 = n1;
- }
-
- pu->conflict_count++;
-}
-
-/**
- * Checks if two nodes are in a conflict.
- */
-static INLINE int pu_are_conflicting(phi_unit_t *pu, ir_node *n1, ir_node *n2) {
- const ir_node *o1, *o2;
- int i;
-
- if ((int)n1 < (int)n2) {
- o1 = n1;
- o2 = n2;
- } else {
- o1 = n2;
- o2 = n1;
- }
-
- for (i = 0; i < pu->conflict_count; ++i)
- if (pu->conflicts[i].n1 == o1 && pu->conflicts[i].n2 == o2)
- return 1;
- return 0;
-}
-
-/**
- * Checks if a node is a member of a phi unit.
- * Other nodes should not be pinned global.
- */
-static INLINE int pu_is_global_pinnable(phi_unit_t *pu, ir_node *irn) {
- int i;
- for (i = 0; i < pu->node_count; ++i)
- if (pu->nodes[i] == irn)
- return 1;
- return 0;
-}
-
-/**
- * Determines a maximum independent set with respect to the conflict edges
- * in pu->conflicts and the nodes beeing all non-removed nodes of pu->nodes.
- * TODO: make this 'un-greedy'
- * ATTENTION: be aware that phi nodes find their way into the set. For 1 phi
- * in greedy version this is no prob, cause it comes first at [0].
- */
-static int pu_get_mis(phi_unit_t *pu, struct obstack *res) {
- int i, o, size = 0;
- ir_node **mis;
-
- DBG((dbgphi, LEVEL_2, "\t Max indep set:\n"));
- for (i = 0; i < pu->node_count; ++i) {
- int intf_det = 0;
- if (pu_is_node_removed(pu, pu->nodes[i]))
- continue;
- mis = (ir_node**) obstack_base(res);
- for (o = 0; o < size; ++o)
- if (pu_are_conflicting(pu, pu->nodes[i], mis[o])) {
- intf_det = 1;
- break;
- }
-
- if (!intf_det) {
- DBG((dbgphi, LEVEL_2, "\t\t%n\n", pu->nodes[i]));
- obstack_ptr_grow(res, pu->nodes[i]);
- size++;
- }
- }
- return size;
-}
-
-/**
- * Performs virtual re-coloring of node @p n to color @p col. Virtual colors of
- * other nodes are changed too, as required to preserve correctness. Function is
- * aware of local and global pinning. Recursive.
- * @param irn The node to set the color for
- * @param col The color to set.
- * @param trigger The irn that caused the wish to change the color of the irn
- * @param changed_nodes An obstack on which all ir_nodes get growed on, which are changed
- * @return CHANGE_SAVE iff setting the color is possible, with all transiteve effects.
- * CHANGE_IMPOSSIBLE iff conflicts with reg-constraintsis occured.
- * CHANGE_NYI iff an unhandled situation occurs.
- * Else the first conflicting ir_node encountered is returned.
- *
- * ASSUMPTION: Assumes that a life range of a single value can't be spilt into
- * several smaller intervals where other values can live in between.
- * This should be true in SSA.
- */
-static ir_node *_pu_color_irn(phi_unit_t *pu, ir_node *irn, int col, const ir_node *trigger, struct obstack *changed_nodes) {
- ir_node *res;
- struct obstack confl_ob;
- ir_node **confl, *cn;
- int i, irn_col;
-
- DBG((dbgphi, LEVEL_3, "\t\t%n \tcaused col(%n) \t%2d --> %2d\n", trigger, irn, pu_get_new_color(pu, irn), col));
- obstack_init(&confl_ob);
- irn_col = pu_get_new_color(pu, irn);
-
- if (irn_col == col)
- goto ret_save;
- if (pset_find_ptr(pinned_global, irn) || pu_is_node_pinned(pu, irn)) {
- res = irn;
- goto ret_confl;
- }
-
- /* get all nodes which would conflict with this change */
- {
- struct obstack q;
- int in, out;
- ir_node *irn_bl;
-
- irn_bl = get_nodes_block(irn);
-
- /* first check for a conflicting node which is 'living in' the irns block */
- {
- ir_node *n;
- pset *live_ins = get_live_in(irn_bl);
- for (n = pset_first(live_ins); n; n = pset_next(live_ins))
- if (is_allocatable_irn(n) && n != trigger && pu_get_new_color(pu, n) == col && phi_ops_interfere(irn, n)) {
- DBG((dbgphi, LEVEL_4, "\t\t %n\ttroubles\n", n));
- obstack_ptr_grow(&confl_ob, n);
- pset_break(live_ins);
- break;
- }
- }
-
- /* setup the queue of blocks. */
- obstack_init(&q);
- obstack_ptr_grow(&q, irn_bl);
- in = 1;
- out = 0;
-
- /* process the queue. The code below checks for every block dominated
- * by the irns one, and in which the irn is live, if there are
- * conflicting nodes */
- while (out < in) {
- ir_node *curr_bl, *sub_bl;
- int i, max;
-
- curr_bl = ((ir_node **)obstack_base(&q))[out++];
-
- /* Add to the result all nodes in the block, which have
- * the target color and interfere with the irn */
- for (i = 0, max = get_irn_n_outs(curr_bl); i < max; ++i) {
- ir_node *n = get_irn_out(curr_bl, i);
- if (is_allocatable_irn(n) && n != trigger && pu_get_new_color(pu, n) == col && phi_ops_interfere(irn, n)) {
- DBG((dbgphi, LEVEL_4, "\t\t %n\ttroubles\n", n));
- obstack_ptr_grow(&confl_ob, n);
- }
- }
-
- /* If irn lives out check i-dominated blocks where the irn lives in */
- /* Fill the queue */
- if (is_live_out(curr_bl, irn)) {
- dominates_for_each(curr_bl, sub_bl)
- if (is_live_in(sub_bl, irn)) {
- obstack_ptr_grow(&q, sub_bl);
- in++;
- }
- }
- }
- obstack_free(&q, NULL);
- obstack_ptr_grow(&confl_ob, NULL);
- confl = (ir_node **) obstack_finish(&confl_ob);
- }
-
- /* process all nodes which would conflict with this change */
- for (i = 0, cn = confl[0]; cn; cn = confl[++i]) {
- ir_node *sub_res;
-
- /* try to color the conflicting node cn with the color of the irn itself */
- sub_res = _pu_color_irn(pu, cn, irn_col, irn, changed_nodes);
- if (sub_res != CHANGE_SAVE) {
- res = sub_res;
- goto ret_confl;
- }
- }
- /* if we arrive here all sub changes can be applied, so it's save to change this irn */
-
-ret_save:
- DBG((dbgphi, LEVEL_3, "\t\t%n save\n", irn));
- obstack_free(&confl_ob, NULL);
- pu_set_new_color(pu, irn, col);
- obstack_ptr_grow(changed_nodes, irn);
- return CHANGE_SAVE;
-
-ret_confl:
- DBG((dbgphi, LEVEL_3, "\t\t%n conflicting\n", irn));
- obstack_free(&confl_ob, NULL);
- return res;
-}
-
-static ir_node *pu_color_irn(phi_unit_t *pu, ir_node *irn, int col) {
- ir_node *res;
- struct obstack ob_undo;
-
- obstack_init(&ob_undo);
- res = _pu_color_irn(pu, irn, col, irn, &ob_undo);
-
- if (res != CHANGE_SAVE) { /* undo virtual changes caused by the last call */
- int i;
- ir_node *undo_node, **undo_nodes;
-
- obstack_ptr_grow(&ob_undo, NULL);
- undo_nodes = obstack_finish(&ob_undo);
- for (i = 0, undo_node = undo_nodes[0]; undo_node; undo_node = undo_nodes[++i])
- pu_undo_color(pu, undo_node);
- }
-
- obstack_free(&ob_undo, NULL);
- return res;
-}
-
-/**
- * Tries to set as much members of a phi unit as possible to color @p col.
- * All changes taken together are guaranteed to be conflict free.
- */
-static int pu_try_color(phi_unit_t *pu, int col, int b_size) {
- struct obstack ob_mis;
- int i, redo, mis_size;
- ir_node **mis;
-
- obstack_init(&ob_mis);
- redo = 1;
- while (redo) {
- redo = 0;
- /* get a max independent set regarding current conflicts */
- mis_size = pu_get_mis(pu, &ob_mis);
- mis = obstack_finish(&ob_mis);
-
- /* shortcut: if mis size is worse than best, then mis won't be better. */
- if (mis_size < b_size)
- goto ret;
-
- /* check if its possible to set the color for all members of the maximum set*/
- for (i = 0; i < mis_size; ++i) {
- ir_node *test_node, *confl_node;
-
- test_node = mis[i];
- DBG((dbgphi, LEVEL_2, "\t Testing %n\n", test_node));
- confl_node = pu_color_irn(pu, test_node, col);
-
- if (confl_node == CHANGE_SAVE) {
- DBG((dbgphi, LEVEL_2, "\t Save\n"));
- pu_pin_node(pu, test_node);
- } else if (confl_node == CHANGE_NYI) {
- DBG((dbgphi, 0, "\t NYI\n"));
- } else if (confl_node == CHANGE_IMPOSSIBLE) {
- /* TODO: this may happen due to reg constraints --> remove from set ?? */
- } else {
- DBG((dbgphi, LEVEL_2, "\t Conflicting\n"));
- assert(is_conflicting_node(confl_node));
-
- if (pu_is_node_pinned(pu, confl_node)) {
- /* changing test_node would change back a node of current phi unit */
- pu_add_conflict(pu, confl_node, test_node);
- redo = 1;
- }
- if (pset_find_ptr(pinned_global, confl_node)) {
- /* changing test_node would change back a node of a prior phi unit */
- pu_remove_node(pu, test_node);
- redo = 1;
- }
- }
-
- if (confl_node != CHANGE_SAVE) {
- /* shortcut: color not possible for phi node (phi comes first) ==> exit */
- if (i == 0) {
- mis_size = 0;
- goto ret;
- }
- /* break iteration over current mis, because it will change */
- break;
- }
- }
- obstack_free(&ob_mis, mis);
- }
-
-ret:
- obstack_free(&ob_mis, NULL);
- return mis_size;
-}
-
-/**
- * Tries to re-allocate colors of nodes in this phi unit, to achieve a lower
- * number of copy instructions placed during phi destruction. Optimized version.
- * Works only for phi-classes/phi-units with exactly 1 phi node, which is the
- * case for approximately 80% of all phi classes. All other phi classes are
- * reduced to this case.
- */
-static void pu_coal_1_phi(phi_unit_t *pu) {
- int size, col, b_size, b_color;
- set *b_changes;
-
- /* init best search result */
- b_changes = NULL;
- b_size = 0;
- b_color = NO_COLOR;
-
- /* find optimum of all colors */
- for (col = MAX_COLORS-1; col >= 0; --col) {
- DBG((dbgphi, 1, "\tTrying color %d\n", col));
- size = pu_try_color(pu, col, b_size);
-
- /* did we find a better max ind. set? */
- if (size > b_size) {
- DBG((dbgphi, 1, "\tBetter size: %d\n", size));
- if (b_changes)
- del_set(b_changes);
- b_changes = pu->changed_nodes;
- b_size = size;
- b_color = col;
- } else {
- del_set(pu->changed_nodes);
- }
-
- /* reset the phi unit to original state for next color */
- pu->changed_nodes = new_set(set_cmp_node_stat_t, INITIAL_SLOTS_CHANGED_NODES);
- pu->conflict_count = pu->conflict_count_org;
-
- /* shortcut: if all members can be colored we are (very) happy */
- if (b_size == pu->node_count)
- break;
- }
-
- /* now apply the found optimum */
- if (b_changes) {
- node_stat_t *ns;
- DBG((dbgphi, 1, "\tBest color: %d Copies: %d/%d\n", b_color, pu->node_count-b_size, pu->node_count-1));
- for (ns = set_first(b_changes); ns; ns = set_next(b_changes)) {
- /* NO_COLOR is possible, if we had an undo; so the irn stays in the
- * pu->changed_nodes with new color set to NO_COLOR. */
- if (ns->color != NO_COLOR) {
- DBG((dbgphi, 1, "\t color(%n) := %d\n", ns->irn, ns->color));
- set_irn_color(ns->irn, ns->color);
- if (pu_is_global_pinnable(pu, ns->irn) && ns->color == pu_get_new_color(pu, pu->nodes[0]))
- pset_insert_ptr(pinned_global, ns->irn);
- }
- }
- free(b_changes);
- } else {
- DBG((dbgphi, 1, "\tBest color: none\n"));
- }
-}
-
-
-/**
- * Prepares a phi class for further processing as one or more phi units.
- * Calls the worker-functions for all units.
- * @param pc The phi class to process.
- * @param root_phi In case of recursive call this is the phi node not beeing
- * an argument in the phi1unit.
- * Else this has to be NULL.
- */
-static void coal_phi_class(pset *pc, ir_node *root_phi) {
- int phi_count = 0;
- ir_node *n, *phi = NULL;
-
- /* unfortunately there _can_ be >1 phi nodes in a phi1unit,
- * so we have an if... */
- if (root_phi) {
- phi = root_phi;
- phi_count = 1;
- } else {
- /* get the phi count of this class. May result in phi_count == 1 */
- for (n = pset_first(pc); n; n = pset_next(pc))
- if (is_Phi(n)) {
- phi = n;
- phi_count++;
- }
- }
-
- /* the 'simple' case */
- if (phi_count == 1) {
- phi_unit_t *pu;
- ir_node **tmp;
- struct obstack ob;
- int i, o;
-
- obstack_init(&ob);
-
- DBG((dbgphi, 1, "\tPhi-1 unit:\n"));
- pu = calloc(1, sizeof(*pu));
-
- /* build member set not containing phi interferers */
- DBG((dbgphi, 1, "\t %n\n", phi));
- obstack_ptr_grow(&ob, phi);
- pu->node_count = 1;
-
- for (n = pset_first(pc); n; n = pset_next(pc)) {
- if (n == phi)
- continue;
- if (!phi_ops_interfere(phi, n)) {
- DBG((dbgphi, 1, "\t %n\n", n));
- obstack_ptr_grow(&ob, n);
- pu->node_count++;
- } else {
- DBG((dbgphi, 1, "\t %n \tdropped\n", n));
- }
- }
- tmp = obstack_finish(&ob);
- pu->nodes = malloc(pu->node_count * sizeof(*pu->nodes));
- memcpy(&pu->nodes[0], tmp, pu->node_count * sizeof(*tmp));
- obstack_free(&ob, NULL);
-
- /* init conlict graph to life range interference */
- DBG((dbgphi, 1, "\tInitial conflicts:\n"));
- for (i = 0; i < pu->node_count; ++i)
- for (o = i+1; o < pu->node_count; ++o)
- if (phi_ops_interfere(pu->nodes[i], pu->nodes[o]))
- pu_add_conflict(pu, pu->nodes[i], pu->nodes[o]);
- pu->conflict_count_org = pu->conflict_count;
-
- /* init changed nodes */
- pu->changed_nodes = new_set(set_cmp_node_stat_t, INITIAL_SLOTS_CHANGED_NODES);
-
- pu_coal_1_phi(pu);
-
- free(pu->nodes);
- free(pu->changed_nodes);
- if (pu->conflicts)
- free(pu->conflicts);
- } else { /* the 'not so easy' case */
- DBG((dbgphi, 1, "\tPhi-n unit:\n"));
-
- /* copy pc into big_pc... */
- pset *copy = pset_new_ptr(32);
- for (n = pset_first(pc); n; n = pset_next(pc)) {
- DBG((dbgphi, 1, "\t %n\n", n));
- pset_insert_ptr(copy, n);
- }
-
- /* ... because we want to build small 'connected graphs' and
- * delete their members from the copy */
- while (pset_count(copy) > 0) {
- /* build all connected sets from the copy */
- int last = 0, first = 0;
- ir_node **queue = calloc(pset_count(copy), sizeof(*queue));
-
- /* pick some node out of copy, place into queue */
- n = pset_first(copy);
- pset_break(copy);
- pset_remove_ptr(copy, n);
- queue[last++] = n;
-
- DBG((dbgphi, 1, "\tConnected:\n"));
- pset *connected = pset_new_ptr(8);
- while (first < last) {
- /* pick n out of the queue into connected set */
- n = queue[first++];
- pset_insert_ptr(connected, n);
- DBG((dbgphi, 1, "\t %n\n", n));
-
-
- /* check if pre/successors are 'connected' with n */
- {
- ir_node *other;
- int i;
- /* insert all args of n, which are in the phi class to the queue */
- for(i=0; i < get_irn_arity(n); ++i) {
- other = get_irn_n(n, i);
- if (pset_find_ptr(copy, other) && !values_interfere(n, other)) {
- queue[last++] = other;
- pset_remove_ptr(copy, other);
- }
- }
- /* same for outs of n */
- for(i=0; i < get_irn_n_outs(n); ++i) {
- other = get_irn_out(n, i);
- if (pset_find_ptr(copy, other) && !values_interfere(n, other)) {
- queue[last++] = other;
- pset_remove_ptr(copy, other);
- }
- }
- }
- }
-
- /* Now we have a "connected graph" build from copy==pc.
- * Remove 1-phi-units from the connected set for
- * passing to optimizer */
- while (pset_count(connected) > 0) {
- pset *phi1unit;
- ir_node *phi = NULL;
- int i;
- /* search a phi node */
- for (n = pset_first(connected); n; n = pset_next(connected))
- if (is_Phi(n)) {
- phi = n;
- break;
- }
- pset_break(connected);
-
- /* if there are only non-phi nodes left quit */
- if (!phi)
- break;
-
- /* Build a 1-phi-unit with this phi */
- DBG((dbgphi, 1, "\t Phi-1-unit:\n"));
- phi1unit = pset_new_ptr(8);
- pset_insert_ptr(phi1unit, phi);
- pset_remove_ptr(connected, phi);
- DBG((dbgphi, 1, "\t\t%n\n", phi));
- /* insert all arguments of phi, which are in the connected set
- * to the 1-phi-unit */
- for(i=0; i < get_irn_arity(phi); ++i) {
- ir_node *arg = get_irn_n(phi, i);
- if (pset_find_ptr(connected, arg)) {
- DBG((dbgphi, 1, "\t\t%n\n", arg));
- pset_insert_ptr(phi1unit, arg);
- pset_remove_ptr(connected, arg);
- }
- }
-
- /* finally the call for coalescing the 1-phi-unit */
- if (pset_count(phi1unit) > 1) /* ==1 can happen if the connected set contains only a single phi node */
- coal_phi_class(phi1unit, phi);
-
- del_pset(phi1unit);
- }
- del_pset(connected);
- free(queue);
- }
- del_pset(copy);
- }
-}
-
-
-void be_phi_coalesce(pset *all_phi_classes) {
- pset *pc;
-
- pinned_global = pset_new_ptr(INITIAL_SLOTS_PINNED_GLOBAL);
-
- for (pc = pset_first(all_phi_classes); pc; pc = pset_next(all_phi_classes))
- coal_phi_class(pc, NULL);
-
- del_pset(pinned_global);
-}
-
-
-void be_phi_coal_init(void) {
- dbgphi = firm_dbg_register("ir.be.phicoal");
- firm_dbg_set_mask(dbgphi, DEBUG_LVL);
-}
+++ /dev/null
-/**
- * @author Daniel Grund
- * @date 04.01.2005
- */
-
-#ifndef _BEPHICOAL_T_H
-#define _BEPHICOAL_T_H
-
-#include "pset.h"
-
-void be_phi_coal_init(void);
-void be_phi_coalesce(pset *all_phi_classes);
-
-#endif
+++ /dev/null
-/**
- * @author Daniel Grund
- * @date 10.03.2005
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#define __USE_BSD
-#include <string.h>
-
-#include "obst.h"
-#include "set.h"
-#include "pset.h"
-#include "list.h"
-#include "debug.h"
-
-#include "irdom.h"
-#include "irouts.h"
-#include "bephicoalilp_t.h"
-#include "benumb_t.h"
-#include "bera_t.h"
-#include "belive_t.h"
-#include "bechordal_t.h"
-
-
-#define MAX_COLORS 32
-
-/**
- * define get_weight to sth representing the _gain_ if node n and m
- * have the same color. Must return values MIN_WEIGHT <= . <= MAX_WEIGHT.
- */
-#define get_weight(n,m) 1
-#define MAX_WEIGHT 127
-#define MIN_WEIGHT 0
-
-/** define this to sth which returns 0 iff c is NOT a possible color for node n */
-#define is_possible_color(n,c) 1
-
-/** define this to sth which returns 1 iff not all colors can be assigned to node n */
-#define is_constrained(n) 0
-
-#undef DUMP_MATRICES
-#define DUMP_MPS
-#undef DUMP_LPO
-#undef DUMP_LPP
-#define DO_SOLVE
-#define DELETE_FILES
-#undef USE_SOS
-#define SSH_USER_HOST "kb61@sp-smp.rz.uni-karlsruhe.de"
-
-/* The overhead stuff */
-#define DEBUG_LVL SET_LEVEL_1
-#define SET_LIVING_INIT 32
-#define MAX_Q_INIT 0
-#define MIN_Q_INIT 0
-
-static firm_dbg_module_t *dbgphi = NULL;
-
-static INLINE FILE *ffopen(const char *base, const char *ext, const char *mode) {
- FILE *out;
- char buf[1024];
-
- snprintf(buf, sizeof(buf), "%s.%s", base, ext);
- if (! (out = fopen(buf, mode))) {
- fprintf(stderr, "Cannot open file %s in mode %s\n", buf, mode);
- return NULL;
- }
- return out;
-}
-
-/** A type storing names of the x variables in the form x[NUMBER]_[COLOR] */
-typedef struct _x_vec_t {
- int n, c;
-} x_vec_t;
-
-/**
- * A type storing the unmodified '0-1 quadratic program' of the form
- * min f = xQx
- * udN: Ax = e
- * Bx <= e
- * x \in {0, 1}
- *
- * This problem is called the original problem
- */
-typedef struct _problem_instance_t {
- ir_graph* irg;
- const char *name;
- int x_dim, A_dim, B_dim;
- char *Q, *A, *B;
- x_vec_t *x; /**< stores the names of the x variables. Sorted first by node-num then by color. */
-
- /* needed only for linearizations */
- int bigM, maxQij, minQij, correction;
-
- /* overhead needed to build this */
- set *num2pos;
- struct obstack ob;
- int curr_col;
- int curr_row;
-} problem_instance_t;
-
-/**
- * For each node taking part in the opt-problem its position in the
- * x-variable-vector is stored in a set. This set maps the node-nr (given by
- * benumb) to the position in the vector.
- */
-typedef struct _num2pos_t {
- int num, pos;
-} num2pos_t;
-
-/* Nodes have consecutive numbers so... */
-#define HASH_NUM(num) num
-
-static int pi_num2pos_cmp(const void *x, const void *y, size_t size) {
- return ((num2pos_t *)x)->num != ((num2pos_t *)y)->num;
-}
-
-/**
- * Sets the first position of node with number num to pos.
- * See x_vec_t *x in _problem_instance_t.
- */
-static INLINE void pi_set_first_pos(problem_instance_t *pi, int num, int pos) {
- num2pos_t find;
- find.num = num;
- find.pos = pos;
- set_insert(pi->num2pos, &find, sizeof(find), HASH_NUM(num));
-}
-
-/**
- * Get position by number. (First possible color)
- * returns -1 if not found.
- */
-static INLINE int pi_get_first_pos(problem_instance_t *pi, int num) {
- num2pos_t find, *found;
- find.num = num;
- found = set_find(pi->num2pos, &find, sizeof(find), HASH_NUM(num));
- if (found) {
- assert(pi->x[found->pos].n == num && (found->pos == 0 || pi->x[found->pos-1].n != num) && "pi->num2pos is broken!");
- return found->pos;
- } else
- return -1;
-}
-
-/**
- * Get position by number and color.
- * returns -1 if not found.
- */
-static INLINE int pi_get_pos(problem_instance_t *pi, int num, int col) {
- num2pos_t find, *found;
- find.num = num;
- int pos;
- found = set_find(pi->num2pos, &find, sizeof(find), HASH_NUM(num));
- if (!found)
- return -1;
- pos = found->pos;
- while (pos < pi->x_dim && pi->x[pos].n == num && pi->x[pos].c < col)
- pos++;
-
- if (pi->x[pos].n == num && pi->x[pos].c == col)
- return pos;
- else
- return -1;
-}
-
-/**
- * Checks if all nodes in living are live_out in block block.
- */
-static INLINE int all_live_out(ir_node *block, pset *living) {
- ir_node *n;
- for (n = pset_first(living); n; n = pset_next(living))
- if (!is_live_out(block, n)) {
- pset_break(living);
- return 0;
- }
- return 1;
-}
-
-/**
- * Finds all cliques in the interference graph, which are not conatained in
- * another one (or at least an approximation of that).
- * This is used for the matrix B.
- */
-static void pi_clique_finder(ir_node *block, void *env) {
- enum phase_t {growing, shrinking} phase = growing;
- problem_instance_t *pi = env;
- struct list_head *head = &get_ra_block_info(block)->border_head;
- border_t *b;
- pset *living = pset_new_ptr(SET_LIVING_INIT);
-
- list_for_each_entry_reverse(border_t, b, head, list) {
- const ir_node *irn = b->irn;
- if (!is_possible_color(n, pi->curr_col))
- continue;
-
- if (b->is_def) {
- DBG((dbgphi, LEVEL_2, "Def %n\n", irn));
- pset_insert_ptr(living, irn);
- phase = growing;
- } else { /* is_use */
- DBG((dbgphi, LEVEL_2, "Use %n\n", irn));
-
- /* before shrinking the set store the current 'maximum' clique;
- * do NOT if clique is a single node
- * do NOT if all values are live_out */
- if (phase == growing && pset_count(living) >= 2 && !all_live_out(block, living)) {
- ir_node *n;
- for (n = pset_first(living); n; n = pset_next(living)) {
- int pos = pi_get_pos(pi, get_irn_graph_nr(n), pi->curr_col);
- pi->B[pi->curr_row*pi->x_dim + pos] = 1;
- DBG((dbgphi, LEVEL_2, "B[%d, %d] := %d\n", pi->curr_row, pos, 1));
- }
- pi->curr_row++;
- }
- pset_remove_ptr(living, irn);
- phase = shrinking;
- }
- }
-
- del_pset(living);
-}
-
-#ifdef DUMP_MATRICES
-/**
- * Dump the raw matrices of the problem to a file for debugging.
- */
-static void pi_dump_matrices(problem_instance_t *pi) {
- int i, o;
- FILE *out = ffopen(pi->name, "matrix", "wt");
-
- DBG((dbgphi, LEVEL_1, "Dumping raw...\n"));
- fprintf(out, "\n\nx-names =\n");
- for (i=0; i<pi->x_dim; ++i)
- fprintf(out, "%5d %2d\n", pi->x[i].n, pi->x[i].c);
-
- fprintf(out, "\n\n-Q =\n");
- for (i=0; i<pi->x_dim; ++i) {
- for (o=0; o<pi->x_dim; ++o)
- fprintf(out, "%d", -pi->Q[i*pi->x_dim + o]);
- fprintf(out, "\n");
- }
-
- fprintf(out, "\n\nA =\n");
- for (i=0; i<pi->A_dim; ++i) {
- for (o=0; o<pi->x_dim; ++o)
- fprintf(out, "%d", pi->A[i*pi->x_dim + o]);
- fprintf(out, "\n");
- }
-
- fprintf(out, "\n\nB =\n");
- for (i=0; i<pi->B_dim; ++i) {
- for (o=0; o<pi->x_dim; ++o)
- fprintf(out, "%d", pi->B[i*pi->x_dim + o]);
- fprintf(out, "\n");
- }
- fclose(out);
-}
-#endif
-
-#ifdef DUMP_MPS
-/**
- * Dumps an mps file representing the problem. This is NOT the old-style,
- * fixed-column format. Spaces are separators, MARKER-lines are used in
- * COLUMN section to define binaries.
- */
-static void pi_dump_mps(problem_instance_t *pi) {
- int i, o, max_abs_Qij;
- FILE *out = ffopen(pi->name, "mps", "wt");
-
- DBG((dbgphi, LEVEL_1, "Dumping mps...\n"));
- max_abs_Qij = pi->maxQij;
- if (-pi->minQij > max_abs_Qij)
- max_abs_Qij = -pi->minQij;
- pi->bigM = pi->A_dim * max_abs_Qij;
- DBG((dbgphi, LEVEL_2, "BigM = %d\n", pi->bigM));
-
- fprintf(out, "NAME %s\n", pi->name);
-
- fprintf(out, "ROWS\n");
- fprintf(out, " N obj\n");
- for (i=0; i<pi->x_dim; ++i)
- fprintf(out, " E cQ%d\n", i);
- for (i=0; i<pi->A_dim; ++i)
- fprintf(out, " E cA%d\n", i);
- for (i=0; i<pi->B_dim; ++i)
- fprintf(out, " L cB%d\n", i);
- for (i=0; i<pi->x_dim; ++i)
- fprintf(out, " L cy%d\n", i);
-
- fprintf(out, "COLUMNS\n");
- /* the x vars come first */
- /* mark them as binaries */
- fprintf(out, " MARKI0\t'MARKER'\t'INTORG'\n");
-#ifdef USE_SOS
- int sos_cnt = 0;
- fprintf(out, " S1 SOS_%d\t'MARKER'\t'SOSORG'\n", sos_cnt++);
-#endif
- for (i=0; i<pi->x_dim; ++i) {
-#ifdef USE_SOS
- if (i>0 && pi->x[i].n != pi->x[i-1].n) {
- fprintf(out, " SOS_%d\t'MARKER'\t'SOSEND'\n", sos_cnt++);
- fprintf(out, " S1 SOS_%d\t'MARKER'\t'SOSORG'\n", sos_cnt++);
- }
-#endif
- /* participation in objective */
- fprintf(out, " x%d_%d\tobj\t%d\n", pi->x[i].n, pi->x[i].c, -pi->bigM);
- /* in Q */
- for (o=0; o<pi->x_dim; ++o) {
- int Qoi = pi->Q[o*pi->x_dim + i];
- if (Qoi)
- fprintf(out, " x%d_%d\tcQ%d\t%d\n", pi->x[i].n, pi->x[i].c, o, Qoi);
- }
- /* in A */
- for (o=0; o<pi->A_dim; ++o) {
- int Aoi = pi->A[o*pi->x_dim + i];
- if (Aoi)
- fprintf(out, " x%d_%d\tcA%d\t%d\n", pi->x[i].n, pi->x[i].c, o, Aoi);
- }
- /* in B */
- for (o=0; o<pi->B_dim; ++o) {
- int Boi = pi->B[o*pi->x_dim + i];
- if (Boi)
- fprintf(out, " x%d_%d\tcB%d\t%d\n", pi->x[i].n, pi->x[i].c, o, Boi);
- }
- /* in y */
- fprintf(out, " x%d_%d\tcy%d\t%d\n", pi->x[i].n, pi->x[i].c, i, 2*pi->bigM);
- }
-#ifdef USE_SOS
- fprintf(out, " SOS_%d\t'MARKER'\t'SOSEND'\n", sos_cnt++);
-#endif
- fprintf(out, " MARKI1\t'MARKER'\t'INTEND'\n"); /* end of marking */
-
- /* next the s vars */
- for (i=0; i<pi->x_dim; ++i) {
- /* participation in objective */
- fprintf(out, " s%d_%d\tobj\t%d\n", pi->x[i].n, pi->x[i].c, 1);
- /* in Q */
- fprintf(out, " s%d_%d\tcQ%d\t%d\n", pi->x[i].n, pi->x[i].c, i, -1);
- }
-
- /* next the y vars */
- for (i=0; i<pi->x_dim; ++i) {
- /* in Q */
- fprintf(out, " y%d_%d\tcQ%d\t%d\n", pi->x[i].n, pi->x[i].c, i, -1);
- /* in y */
- fprintf(out, " y%d_%d\tcy%d\t%d\n", pi->x[i].n, pi->x[i].c, i, 1);
- }
-
- fprintf(out, "RHS\n");
- for (i=0; i<pi->x_dim; ++i)
- fprintf(out, " rhs\tcQ%d\t%d\n", i, -pi->bigM);
- for (i=0; i<pi->A_dim; ++i)
- fprintf(out, " rhs\tcA%d\t%d\n", i, 1);
- for (i=0; i<pi->B_dim; ++i)
- fprintf(out, " rhs\tcB%d\t%d\n", i, 1);
- for (i=0; i<pi->x_dim; ++i)
- fprintf(out, " rhs\tcy%d\t%d\n", i, 2*pi->bigM);
-
- fprintf(out, "ENDATA\n");
- fclose(out);
-
- out = ffopen(pi->name, "mst", "wt");
- fprintf(out, "NAME\n");
- for (i=0; i<pi->x_dim; ++i) {
- int val, n, c;
- n = pi->x[i].n;
- c = pi->x[i].c;
- if (get_irn_color(get_irn_for_graph_nr(pi->irg, n)) == c)
- val = 1;
- else
- val = 0;
- fprintf(out, " x%d_%d\t%d\n", n, c, val);
- }
- fprintf(out, "ENDATA\n");
- fclose(out);
-}
-#endif
-
-#if defined(DUMP_LPO) || defined(DUMP_LPP)
-/**
- * Dumps constraints used by both linearizations
- */
-static void pi_dump_lp_common_constraints(problem_instance_t *pi, FILE *out) {
- int i, o;
- /* knapsack constraints */
- for (i=0; i<pi->A_dim; ++i) {
- for (o=0; o<pi->x_dim; ++o)
- if (pi->A[i*pi->x_dim + o])
- fprintf(out, "+x%d_%d ", pi->x[o].n, pi->x[o].c);
- fprintf(out, " = 1;\n");
- }
- fprintf(out, "\n\n");
-
- /* interference graph constraints */
- for (i=0; i<pi->B_dim; ++i) {
- for (o=0; o<pi->x_dim; ++o)
- if (pi->B[i*pi->x_dim + o])
- fprintf(out, "+x%d_%d ", pi->x[o].n, pi->x[o].c);
- fprintf(out, " <= 1;\n");
- }
- fprintf(out, "\n\n");
-
- /* integer constraints */
- fprintf(out, "int x%d_%d", pi->x[0].n, pi->x[0].c);
- for (i=1; i<pi->x_dim; ++i)
- fprintf(out, ", x%d_%d", pi->x[i].n, pi->x[i].c);
- fprintf(out, ";\n");
-}
-#endif
-
-#ifdef DUMP_LPO
-/**
- * Dumps the problem instance as a MILP. The original problem is transformed into:
- * min f = es - Mex
- * udN: Qx -y -s +Me = 0
- * Ax = e
- * Bx <= e
- * y <= 2M(e-x)
- * x \in N y, s >= 0
- *
- * with M >= max sum Q'ij * x_j
- * i j
- */
-static void pi_dump_lp_org(problem_instance_t *pi) {
- int i, o, max_abs_Qij;
- FILE *out = ffopen(pi->name, "lpo", "wt");
-
- DBG((dbgphi, LEVEL_1, "Dumping lp_org...\n"));
- /* calc the big M for Q */
- max_abs_Qij = pi->maxQij;
- if (-pi->minQij > max_abs_Qij)
- max_abs_Qij = -pi->minQij;
- pi->bigM = pi->A_dim * max_abs_Qij;
- DBG((dbgphi, LEVEL_2, "BigM = %d\n", pi->bigM));
-
- /* generate objective function */
- fprintf(out, "min: ");
- for (i=0; i<pi->x_dim; ++i)
- fprintf(out, "+s%d_%d -%dx%d_%d ", pi->x[i].n, pi->x[i].c, pi->bigM, pi->x[i].n, pi->x[i].c);
- fprintf(out, ";\n\n");
-
- /* constraints for former objective function */
- for (i=0; i<pi->x_dim; ++i) {
- for (o=0; o<pi->x_dim; ++o) {
- int Qio = pi->Q[i*pi->x_dim + o];
- if (Qio) {
- if (Qio == 1)
- fprintf(out, "+x%d_%d ", pi->x[o].n, pi->x[o].c);
- else if(Qio == -1)
- fprintf(out, "-x%d_%d ", pi->x[o].n, pi->x[o].c);
- else
- fprintf(out, "%+dx%d_%d ", Qio, pi->x[o].n, pi->x[o].c);
- }
- }
- fprintf(out, "-y%d_%d -s%d_%d +%d= 0;\n", pi->x[i].n, pi->x[i].c, pi->x[i].n, pi->x[i].c, pi->bigM);
- }
- fprintf(out, "\n\n");
-
- /* constraints for (special) complementary condition */
- for (i=0; i<pi->x_dim; ++i)
- fprintf(out, "y%d_%d <= %d - %dx%d_%d;\n", pi->x[i].n, pi->x[i].c, 2*pi->bigM, 2*pi->bigM, pi->x[i].n, pi->x[i].c);
- fprintf(out, "\n\n");
-
- pi_dump_lp_common_constraints(pi, out);
- fclose(out);
-}
-#endif
-
-#ifdef DUMP_LPP
-/**
- * Dumps the problem instance as a MILP. The original problem is transformed into:
- * min f = es
- * udN: Q'x -y -s = 0
- * Ax = e
- * Bx <= e
- * y <= M(e-x)
- * x \in N y, s >= 0
- *
- * with Q' = (q'_ij) := q_ij - minQij
- * and M >= max sum Q'ij * x_j
- * i j
- */
-static void pi_dump_lp_pos(problem_instance_t *pi) {
- int i, o;
- FILE *out = ffopen(pi->name, "lpp", "wt");
-
- DBG((dbgphi, LEVEL_1, "Dumping lp_pos...\n"));
- /* Norm the Matrix: Qij >=0 and \exists i,j Qij=0 */
- for (i=0; i<pi->x_dim; ++i)
- for (o=0; o<pi->x_dim; ++o)
- pi->Q[i*pi->x_dim + o] -= pi->minQij;
- /* now Q' is stored in Q */
-
- /* calc the big M for Q'
- * maxQ'ij = maxQij-minQij
- * #nodes = A_dim
- * So max sum Q'ij * x_j <= A_dim * maxQ'ij
- * i j
- */
- pi->bigM = pi->A_dim * (pi->maxQij - pi->minQij);
- DBG((dbgphi, LEVEL_2, "BigM = %d\n", pi->bigM));
-
- /* clac the correction term for the obj func
- * xQx = xQ'x + minQij * k^2
- * where k, in general, is the knapsack size of wx = k.
- * Here w=1 and so 1x = #nodes = A_dim
- */
- pi->correction = pi->minQij * pi->A_dim * pi->A_dim;
- DBG((dbgphi, LEVEL_2, "Correction = %d\n", pi->correction));
-
- /* generate objective function */
- fprintf(out, "min: ");
- for (i=0; i<pi->x_dim; ++i)
- fprintf(out, "+s%d_%d ", pi->x[i].n, pi->x[i].c);
- fprintf(out, "+ correction\n");
- fprintf(out, "correction = %d ", pi->correction);
- fprintf(out, ";\n\n");
-
- /* constraints for former objective function */
- for (i=0; i<pi->x_dim; ++i) {
- for (o=0; o<pi->x_dim; ++o) {
- int Qio = pi->Q[i*pi->x_dim + o];
- if (Qio) {
- if (Qio != 1)
- fprintf(out, "+%d", Qio);
- fprintf(out, "+x%d_%d ", pi->x[o].n, pi->x[o].c);
- }
- }
- fprintf(out, "-y%d_%d -s%d_%d = 0;\n", pi->x[i].n, pi->x[i].c, pi->x[i].n, pi->x[i].c);
- }
- fprintf(out, "\n\n");
-
- /* constraints for (special) complementary condition */
- for (i=0; i<pi->x_dim; ++i)
- fprintf(out, "y%d_%d<=%d-%dx%d_%d;\n", pi->x[i].n, pi->x[i].c, pi->bigM, pi->bigM, pi->x[i].n, pi->x[i].c);
- fprintf(out, "\n\n");
-
- pi_dump_lp_common_constraints(pi, out);
- fclose(out);
-}
-#endif
-
-#ifdef DO_SOLVE
-/**
- * Invoke an external solver
- */
-static void pi_solve_ilp(problem_instance_t *pi) {
- FILE *out;
- char buf[1024];
-
- /* write command file for CPLEX */
- out = ffopen(pi->name, "cmd", "wt");
- fprintf(out, "read %s.mps\n", pi->name);
- fprintf(out, "read %s.mst\n", pi->name);
- fprintf(out, "set mip strategy mipstart 1\n");
- fprintf(out, "optimize\n");
- fprintf(out, "set logfile %s.sol\n", pi->name);
- fprintf(out, "display solution variables 1-%d\n", pi->x_dim);
- fprintf(out, "set logfile cplex.log\n");
- fprintf(out, "quit\n");
- fclose(out);
-
- snprintf(buf, sizeof(buf), "scp %s.mps %s.mst %s.cmd %s:", pi->name, pi->name, pi->name, SSH_USER_HOST);
- system(buf);
- snprintf(buf, sizeof(buf), "ssh %s \"./cplex90 < %s.cmd\"", SSH_USER_HOST, pi->name);
- system(buf);
- snprintf(buf, sizeof(buf), "scp %s:%s.sol .", SSH_USER_HOST, pi->name);
- system(buf);
-}
-
-/**
- * Sets the colors of irns according to the values of variables found in the
- * output file of the solver.
- */
-static void pi_apply_solution(problem_instance_t *pi) {
- FILE *in = ffopen(pi->name, "sol", "rt");
-
- DBG((dbgphi, LEVEL_1, "Applying solution...\n"));
- while (!feof(in)) {
- char buf[1024];
- int num = -1, col = -1, val = -1;
- if (fscanf(in, "x%d_%d %d.%s\n", &num, &col, &val, buf) != 3) {
- while(fscanf(in, "%1020s\n", buf) != 1);
- continue;
- }
- if (val == 1) {
- DBG((dbgphi, LEVEL_1, "x%d_%d = %d\n", num, col, val));
- set_irn_color(get_irn_for_graph_nr(pi->irg, num), col);
- }
- }
- fclose(in);
-}
-#endif /* DO_SOLVE */
-
-#ifdef DELETE_FILES
-static void pi_delete_files(problem_instance_t *pi) {
- char buf[1024];
- int end = snprintf(buf, sizeof(buf), "%s", pi->name);
-#ifdef DUMP_MATRICES
- snprintf(buf+end, sizeof(buf)-end, ".matrix");
- remove(buf);
-#endif
-#ifdef DUMP_MPS
- snprintf(buf+end, sizeof(buf)-end, ".mps");
- remove(buf);
- snprintf(buf+end, sizeof(buf)-end, ".mst");
- remove(buf);
- snprintf(buf+end, sizeof(buf)-end, ".cmd");
- remove(buf);
-#endif
-#ifdef DUMP_LPO
- snprintf(buf+end, sizeof(buf)-end, ".lpo");
- remove(buf);
-#endif
-#ifdef DUMP_LPP
- snprintf(buf+end, sizeof(buf)-end, ".lpp");
- remove(buf);
-#endif
-}
-#endif
-
-/**
- * Let N be minimal so that the copy-minimization-problem resticted to
- * N possible colors has the same result as the original copy-min-prob with
- * MAX_COLORS possible colors.
- * It is assumed (not proven) that this is true, if for each phi and phi-arg
- * an extra register would be available. Constrained registers count an additinal
- * register too.
- * TODO Prove the above.
- *
- * This function returns M in env, where N <= M <= MAX_COLROS
- */
-static void pi_colors_upper_bound(ir_node *block, void *env) {
- int *res = env;
- int i, max, max_pressure, special_cnt;
- if (*res == MAX_COLORS)
- return;
-
- /* get maximal register pressure */
- {
- struct list_head *head = &get_ra_block_info(block)->border_head;
- border_t *b;
- max_pressure = 0;
- list_for_each_entry(border_t, b, head, list)
- if (b->pressure > max_pressure) {
- max_pressure = b->pressure;
- }
- }
-
- /* count special nodes */
- special_cnt = 0;
- for (i = 0, max = get_irn_n_outs(block); i < max; ++i) {
- ir_node *n = get_irn_out(block, i);
- if (get_nodes_block(n) != block)
- continue;
- if (is_Phi(n) || is_phi_operand(n) || is_constrained(n))
- special_cnt++;
- }
-
- /* new max? */
- if (*res < max_pressure + special_cnt)
- *res = max_pressure + special_cnt;
- if (*res > MAX_COLORS)
- *res = MAX_COLORS;
-}
-
-/**
- * Generate the initial problem matrices and vectors.
- */
-static problem_instance_t *new_pi(ir_graph *irg, pset *all_phi_nodes) {
- int max_needed_cols;
- problem_instance_t *pi = calloc(1, sizeof(problem_instance_t));
- pi->irg = irg;
- pi->name = get_entity_name(get_irg_entity(irg));
- pi->bigM = 1;
- pi->minQij = MIN_Q_INIT;
- pi->maxQij = MAX_Q_INIT;
- obstack_init(&pi->ob);
-
- DBG((dbgphi, LEVEL_1, "Generating new instance...\n"));
- pi->num2pos = new_set(pi_num2pos_cmp, 128);
-
- //TODO move pi_colors_upper_bound in "super-class" to fix issue with
- //invalid mst-values
- /* get max_needed_cols */
- max_needed_cols = 0;
- dom_tree_walk_irg(irg, pi_colors_upper_bound, NULL, &max_needed_cols);
- //TODO remove
- max_needed_cols = MAX_COLORS;
- DBG((dbgphi, LEVEL_1, "max_needed_cols: %d\n", max_needed_cols));
-
- /* Vector x
- * one entry per node and possible color */
- {
- x_vec_t xx;
- for (xx.n=0; xx.n<get_graph_node_count(irg); ++xx.n) {
- ir_node *irn = get_irn_for_graph_nr(irg, xx.n);
-
- if (!is_allocatable_irn(irn))
- continue;
- DBG((dbgphi, LEVEL_2, "pi->num2pos %4d --> %4d\n", xx.n, pi->x_dim));
- pi_set_first_pos(pi, xx.n, pi->x_dim);
-
- pi->A_dim++; /* one knapsack constraint for each node */
- for (xx.c=0; xx.c<max_needed_cols; ++xx.c) {
- if (!is_possible_color(irn, xx.c))
- continue;
- DBG((dbgphi, LEVEL_2, "Adding %n %d\n", irn, xx.c));
- obstack_grow(&pi->ob, &xx, sizeof(xx));
- pi->x_dim++; /* one x variable for each node and color */
- }
- }
- pi->x = obstack_finish(&pi->ob);
- }
-
- /* Matrix Q
- * weights for the 'same-color-optimization' target */
- {
- ir_node *phi, *arg;
- pi->Q = calloc(pi->x_dim*pi->x_dim, sizeof(pi->Q[0]));
- for (phi = pset_first(all_phi_nodes); phi; phi = pset_next(all_phi_nodes)) {
- unsigned phipos, argpos;
- int phinr, argnr;
- int i, max;
-
- for (i = 0, max = get_irn_arity(phi); i < max; ++i) {
- int weight;
- arg = get_irn_n(phi, i);
- if (phi_ops_interfere(phi, arg))
- continue;
- phinr = get_irn_graph_nr(phi);
- argnr = get_irn_graph_nr(arg);
- phipos = pi_get_first_pos(pi, phinr);
- argpos = pi_get_first_pos(pi, argnr);
- weight = -get_weight(phi, arg);
-
- DBG((dbgphi, LEVEL_2, "Q[%n, %n] := %d\n", phi, arg, weight));
- /* for all colors phi and arg have in common, set the weight for
- * this pair in the objective function matrix Q */
- while (phipos < pi->x_dim && argpos < pi->x_dim &&
- pi->x[phipos].n == phinr && pi->x[argpos].n == argnr) {
- if (pi->x[phipos].c < pi->x[argpos].c)
- ++phipos;
- else if (pi->x[phipos].c > pi->x[argpos].c)
- ++argpos;
- else {
- pi->Q[(phipos++)*pi->x_dim + argpos++] = weight;
-
- if (weight < pi->minQij) {
- DBG((dbgphi, LEVEL_2, "minQij = %d\n", weight));
- pi->minQij = weight;
- }
- if (weight > pi->maxQij) {
- DBG((dbgphi, LEVEL_2, "maxQij = %d\n", weight));
- pi->maxQij = weight;
- }
- }
- }
- }
- }
- }
-
- /* Matrix A
- * knapsack constraint for each node */
- {
- int row = 0, col = 0;
- pi->A = calloc(pi->A_dim*pi->x_dim, sizeof(pi->A[0]));
- while (col < pi->x_dim) {
- int curr_n = pi->x[col].n;
- while (col < pi->x_dim && pi->x[col].n == curr_n) {
- DBG((dbgphi, LEVEL_2, "A[%d, %d] := %d\n", row, col, 1));
- pi->A[row*pi->x_dim + col++] = 1;
- }
- ++row;
- }
- assert(row == pi->A_dim);
- }
-
- /* Matrix B
- * interference constraints using exactly those cliques not contained in others. */
- {
- int col;
- pi->B_dim = set_count(be_ra_get_ifg(irg))*max_needed_cols; /* this is an upper bound, see realloc below */
- pi->B = calloc(pi->B_dim*pi->x_dim, sizeof(pi->B[0]));
-
- for (col = 0; col < max_needed_cols; ++col) {
- pi->curr_col = col;
- dom_tree_walk_irg(irg, pi_clique_finder, NULL, pi);
- }
-
- pi->B_dim = pi->curr_row;
- pi->B = realloc(pi->B, pi->B_dim*pi->x_dim*sizeof(pi->B[0]));
- }
-
- return pi;
-}
-
-/**
- * clean the problem instance
- */
-static void free_pi(problem_instance_t *pi) {
- free(pi->Q);
- free(pi->A);
- free(pi->B);
- del_set(pi->num2pos);
- obstack_free(&pi->ob, NULL);
- free(pi);
-}
-
-void be_phi_coalesce_ilp(ir_graph *irg, pset *all_phi_nodes) {
- problem_instance_t *pi = new_pi(irg, all_phi_nodes);
-
-#ifdef DUMP_MATRICES
- pi_dump_matrices(pi);
-#endif
-
-#ifdef DUMP_MPS
- pi_dump_mps(pi);
-#endif
-
-#ifdef DUMP_LPO
- pi_dump_lp_org(pi);
-#endif
-
-#ifdef DUMP_LPP
- pi_dump_lp_pos(pi);
-#endif
-
-#ifdef DO_SOLVE
- pi_solve_ilp(pi);
- pi_apply_solution(pi);
-#endif
-
-#ifdef DELETE_FILES
- pi_delete_files(pi);
-#endif
-
- free_pi(pi);
-}
-
-void be_phi_coal_ilp_init(void) {
- dbgphi = firm_dbg_register("ir.be.phicoalilp");
- firm_dbg_set_mask(dbgphi, DEBUG_LVL);
-}
+++ /dev/null
-/**
- * @author Daniel Grund
- * @date 11.03.2005
- */
-
-#ifndef _BEPHICOALILP_T_H
-#define _BEPHICOALILP_T_H
-
-#include "irgraph.h"
-#include "pset.h"
-
-void be_phi_coal_ilp_init(void);
-void be_phi_coalesce_ilp(ir_graph *irg, pset *all_phi_nodes);
-
-#endif
+++ /dev/null
-/**
- * @author Daniel Grund
- * @date 04.01.2005
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "pset.h"
-#include "obst.h"
-#include "irgraph.h"
-#include "irnode.h"
-#include "irgwalk.h"
-#include "irouts.h"
-#include "irdom.h"
-
-#include "beutil.h"
-#include "benumb_t.h"
-#include "bera_t.h"
-#include "bephiopt.h"
-#include "phiclass_t.h"
-#include "bephicoal_t.h"
-#include "bephicoalilp_t.h"
-#include "phistat.h"
-
-#define DO_HEURISTIC
-#undef DO_OPTIMAL
-
-#define DEBUG_LVL SET_LEVEL_1
-
-/** checks if two interfering nodes have the same color */
-#define CHECK_RESULTS
-/** counts the copies needed before and after optimization */
-#define COUNT_COPY_SAVINGS
-/** dumps 2 allocated graphs; before and after opt. */
-#undef DUMP_OPT_DIFF
-
-#undef DO_PHI_STATISTICS
-#define DUMP_IRG_PHI_STAT
-#define DUMP_DIR_PHI_STAT
-#define DUMP_ALL_PHI_STAT
-
-#define PHI_STAT_FILE "dir.phistat"
-#define ENV_PHI_STAT "PHI_STAT"
-
-static firm_dbg_module_t *dbgphi = NULL;
-
-typedef struct _copies_t {
- int lb, ub;
- int count[3]; /* before, after heuristics, after optimality */
-} copies_t;
-
-
-static void phi_node_walker(ir_node *node, void *env) {
- if (is_Phi(node) && mode_is_datab(get_irn_mode(node)))
- pset_insert_ptr((pset *)env, node);
-}
-
-
-static void node_collector(ir_node *node, void *env) {
- struct obstack *obst = env;
- if (!is_Block(node) && is_allocatable_irn(node))
- obstack_ptr_grow(obst, node);
-}
-
-
-static void check_result(ir_graph *irg) {
- struct obstack ob;
- ir_node **nodes, *n1, *n2;
- int i, o;
-
- obstack_init(&ob);
- irg_walk_graph(irg, node_collector, NULL, &ob);
- obstack_ptr_grow(&ob, NULL);
- nodes = (ir_node **) obstack_finish(&ob);
- for (i = 0, n1 = nodes[i]; n1; n1 = nodes[++i]) {
- assert(! (is_allocatable_irn(n1) && get_irn_color(n1) == NO_COLOR));
- for (o = i+1, n2 = nodes[o]; n2; n2 = nodes[++o])
- if (phi_ops_interfere(n1, n2) && get_irn_color(n1) == get_irn_color(n2)) {
- DBG((dbgphi, 1, "Ouch!\n %n[%d]in %n\n %n[%d] in %n\n", n1, get_irn_graph_nr(n1), get_nodes_block(n1), n2, get_irn_graph_nr(n2), get_nodes_block(n2)));
- assert(0 && "Interfering values have the same color!");
- }
- }
-
- obstack_free(&ob, NULL);
-}
-
-
-/**
- * Init the copies struct lower and upper bound
- */
-static void init_copies(copies_t *c, pset *all_phi_nodes) {
- ir_node *phi;
-
- c->count[0] = c->count[1] = c->count[2] = -1;
- c->ub = c->lb = 0;
-
- for (phi = pset_first(all_phi_nodes); phi; phi = pset_next(all_phi_nodes)) {
- /* upper bound: each argument of a phi node is a potential copy */
- int i, max = get_irn_arity(phi);
- c->ub += max;
- /* lower bound: at least all interfering pairs */
- for (i = 0; i < max; ++i) {
- ir_node *arg = get_irn_n(phi, i);
- if (phi_ops_interfere(phi, arg))
- c->lb++;
- }
- }
-}
-
-
-/**
- * Count the copies needed with current coloring
- */
-static void count_copies(copies_t *c, pset *all_phi_nodes, int stage) {
- int i, max, phi_color;
- ir_node *phi;
-
- c->count[stage] = 0;
-
- for (phi = pset_first(all_phi_nodes); phi; phi = pset_next(all_phi_nodes)) {
- phi_color = get_irn_color(phi);
- for (i = 0, max = get_irn_arity(phi); i < max; ++i) {
- ir_node *arg = get_irn_n(phi, i);
- if (phi_color != get_irn_color(arg)) {
- c->count[stage]++;
- DBG((dbgphi, LEVEL_2, "Copy: %n %n\n", phi, arg));
- }
- }
- }
-}
-
-
-void be_phi_opt(ir_graph* irg) {
- pset *all_phi_nodes, *all_phi_classes;
- copies_t *copies;
-
- DBG((dbgphi, 1, "\n\n=======================> IRG: %s\n\n", get_entity_name(get_irg_entity(irg))));
-
-
- /* get all phi nodes */
- DBG((dbgphi, 1, "-----------------------> Collecting phi nodes <-----------------------\n"));
- all_phi_nodes = pset_new_ptr(64);
- irg_walk_graph(irg, phi_node_walker, NULL, all_phi_nodes);
-
-
- /* get all phi congruence classes */
- DBG((dbgphi, 1, "-----------------------> Collecting phi classes <---------------------\n"));
- all_phi_classes = phi_class_compute_by_phis(all_phi_nodes);
-
-
- /* do some statistics */
-#ifdef DO_PHI_STATISTICS
- DBG((dbgphi, 1, "-----------------------> Collecting phi stats <-----------------------\n"));
- phi_stat_reset();
- phi_stat_collect(irg, all_phi_nodes, all_phi_classes);
-#ifdef DUMP_IRG_PHI_STAT
- char buf[1024];
- snprintf(buf, sizeof(buf), "%s.phistat", get_entity_name(get_irg_entity(irg)));
- /*phi_stat_dump(buf);*/
- phi_stat_dump_pretty(buf);
-#endif
-#ifdef DUMP_DIR_PHI_STAT
- phi_stat_update(PHI_STAT_FILE);
-#endif
-#ifdef DUMP_ALL_PHI_STAT
- phi_stat_update(getenv(ENV_PHI_STAT));
-#endif
-#endif
-
-
- /* try to coalesce the colors of each phi class */
- DBG((dbgphi, 1, "-----------------------> Coalescing <---------------------------------\n"));
- compute_outs(irg);
- compute_doms(irg);
-
-
-#ifdef DUMP_OPT_DIFF
- dump_allocated_irg(irg, "-before");
-#endif
-#ifdef CHECK_RESULTS
- check_result(irg);
-#endif
-#ifdef COUNT_COPY_SAVINGS
- copies = malloc(sizeof(*copies));
- init_copies(copies, all_phi_nodes);
- DBG((dbgphi, 0, "Copy bounds : %3d < . < %3d\n", copies->lb, copies->ub));
- count_copies(copies, all_phi_nodes, 0);
-#endif
-
-
-
-#ifdef DO_HEURISTIC
- be_phi_coalesce(all_phi_classes);
-#ifdef DUMP_OPT_DIFF
- dump_allocated_irg(irg, "-heur");
-#endif
-#ifdef CHECK_RESULTS
- check_result(irg);
-#endif
-#ifdef COUNT_COPY_SAVINGS
- count_copies(copies, all_phi_nodes, 1);
-#endif
-#endif /* DO_HEURISTIC */
-
-
- if (copies->count[1] == -1 || copies->count[1] > copies->lb) {
-#ifdef DO_OPTIMAL
- be_phi_coalesce_ilp(irg, all_phi_nodes);
-#ifdef DUMP_OPT_DIFF
- dump_allocated_irg(irg, "-opt");
-#endif
-#ifdef CHECK_RESULTS
- check_result(irg);
-#endif
-#ifdef COUNT_COPY_SAVINGS
- count_copies(copies, all_phi_nodes, 2);
-#endif
-#endif /* DO_OPTIMAL */
- }
-#ifdef COUNT_COPY_SAVINGS
- DBG((dbgphi, 0, "Copies before/heur/opt: %3d / %3d / %3d\n", copies->count[0], copies->count[1], copies->count[2]));
-#endif
- free_dom_and_peace(irg);
-}
-
-
-void be_phi_opt_init(void) {
- dbgphi = firm_dbg_register("ir.be.phiopt");
- firm_dbg_set_mask(dbgphi, DEBUG_LVL);
-
- phi_class_init();
-#ifdef DO_HEURISTIC
- be_phi_coal_init();
-#endif
-#ifdef DO_OPTIMAL
- be_phi_coal_ilp_init();
-#endif
-}
+++ /dev/null
-/**
- * @author Daniel Grund
- * @date 04.01.2005
- */
-
-#ifndef _BEPHIOPT_H
-#define _BEPHIOPT_H
-
-#include "debug.h"
-#include "irgraph.h"
-
-void be_phi_opt_init(void);
-void be_phi_opt(ir_graph* irg);
-
-#endif