Added ILP module. Integrated it. Some old TODOs in heuristic.
authorDaniel Grund <grund@cs.uni-saarland.de>
Thu, 31 Mar 2005 11:22:04 +0000 (11:22 +0000)
committerDaniel Grund <grund@cs.uni-saarland.de>
Thu, 31 Mar 2005 11:22:04 +0000 (11:22 +0000)
ir/be/Makefile.in
ir/be/bemain.c
ir/be/bephicoal.c
ir/be/bephicoalilp.c [new file with mode: 0644]
ir/be/bephicoalilp_t.h [new file with mode: 0644]
ir/be/bephiopt.c

index 3de14ab..bc68ce9 100644 (file)
@@ -22,7 +22,7 @@ SOURCES = $(INSTALL_HEADERS)
 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 bera.h bechordalspill.c \
+       bephiopt.c bephicoal.c bephicoalilp.c bera.h bechordalspill.c \
        beasm_dump_globals.c beasm_asm_gnu.c bearch.h bearch.c
 
 include $(topdir)/MakeRules
index 079785d..372e695 100644 (file)
@@ -31,7 +31,7 @@
 #include "beasm_dump_globals.h"
 #include "beasm_asm_gnu.h"
 
-#define DUMP_ALLOCATED
+#undef DUMP_ALLOCATED
 #undef DUMP_LOCALIZED
 
 #define N_PHASES 256
@@ -128,7 +128,7 @@ static void be_main_loop(void)
 #ifdef DUMP_ALLOCATED
                dump_allocated_irg(irg, "");
 #endif
-               //be_phi_opt(irg);
+               be_phi_opt(irg);
 
                be_ra_chordal_done(irg);
                be_numbering_done(irg);
index b956d6c..a596553 100644 (file)
 #include "phiclass_t.h"
 #include "bephicoal_t.h"
 
-#define DEBUG_LVL 0
-//SET_LEVEL_1
-#define MAX_COLORS 16
+#define DEBUG_LVL 0 //SET_LEVEL_2
+#define MAX_COLORS 32
 
 #define INITIAL_SLOTS_PINNED_GLOBAL 256
-//#define INITIAL_SLOTS_FREE_NODES    128
 #define INITIAL_SLOTS_CHANGED_NODES 32
 
 /* some things for readable code */
@@ -67,8 +65,6 @@ typedef struct _node_stat_t {
  * corresponding phi class.
  */
 typedef struct _phi_unit_t {
-       unsigned char phi_count;                        /**< the number of phi nodes in this unit */
-       /* 1 phi */
        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 */
@@ -80,13 +76,7 @@ typedef struct _phi_unit_t {
 static firm_dbg_module_t *dbgphi = NULL;
 
 /**
- * Contains ir_nodes of phi-classes whose colors may change unlimited times.
- * These nodes are not optimizable, so there is no need to pin their color.
- */
-//static pset *free_nodes = NULL;
-
-/**
- * Contains already optimized ir_nodes of phi-classes fully processed.
+ * 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;
@@ -253,8 +243,8 @@ static INLINE int pu_is_global_pinnable(phi_unit_t *pu, ir_node *irn) {
  * 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'
- * TODO: be aware that phi nodes should find their way in the set.
- *       for 1 phi in greedy version this is no prob, cause is comes first at [0].
+ * 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;
@@ -296,6 +286,7 @@ static int pu_get_mis(phi_unit_t *pu, struct obstack *res) {
  *
  * 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;
@@ -341,7 +332,7 @@ static ir_node *_pu_color_irn(phi_unit_t *pu, ir_node *irn, int col, const ir_no
                in = 1;
                out = 0;
 
-               /* process the queue. The code below looks for every block dominated
+               /* 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) {
@@ -453,8 +444,7 @@ static int pu_try_color(phi_unit_t *pu, int col, int b_size) {
 
                        if (confl_node == CHANGE_SAVE) {
                                DBG((dbgphi, LEVEL_2, "\t    Save\n"));
-                               //if (!pset_find_ptr(free_nodes, test_node))
-                                       pu_pin_node(pu, test_node);
+                               pu_pin_node(pu, test_node);
                        } else if (confl_node == CHANGE_NYI) {
                                DBG((dbgphi, 0, "\t    NYI\n"));
                        } else if (confl_node == CHANGE_IMPOSSIBLE) {
@@ -497,7 +487,8 @@ ret:
  * 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 units.
+ * 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;
@@ -537,7 +528,7 @@ static void pu_coal_1_phi(phi_unit_t *pu) {
        /* now apply the found optimum */
        if (b_changes) {
                node_stat_t *ns;
-               DBG((dbgphi, 0, "\tBest color: %d  Copies: %d/%d\n", b_color, pu->node_count-b_size, pu->node_count-1));
+               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. */
@@ -554,49 +545,52 @@ static void pu_coal_1_phi(phi_unit_t *pu) {
        }
 }
 
-/**
- * Tries to re-allocate colors of nodes in this phi unit, to achieve a lower
- * number of copy instructions placed during phi destruction.
- * General purpose version.
- */
-static void pu_coal_n_phi(phi_unit_t *pu) {
-       /* TODO */
-}
 
 /**
- * Prepares a phi class for further processing as a phi unit.
- * @param pc The phi class to prepare.
- * @return A so called phi unit containing some prepared informations
- *         needed by the following coalescing phase.
+ * 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 phi_unit_t *new_pu(pset *pc) {
-       phi_unit_t *pu;
+static void coal_phi_class(pset *pc, ir_node *root_phi) {
+       int phi_count = 0;
        ir_node *n, *phi = NULL;
 
-       /* get the phi count of this class */
-       pu = calloc(1, sizeof(*pu));
-       for (n = pset_first(pc); n; n = pset_next(pc))
-               if (is_Phi(n)) {
-                       phi = n;
-                       pu->phi_count++;
-               }
+       /* 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++;
+                       }
+       }
 
-       if (pu->phi_count == 1) {
+       /* the 'simple' case */
+       if (phi_count == 1) {
+               phi_unit_t *pu;
                ir_node **tmp;
-               int i, o;
                struct obstack ob;
+               int i, o;
 
                obstack_init(&ob);
 
-               /* build member set not containing phi interferers */
                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 (is_Phi(n))
+                       if (n == phi)
                                continue;
                        if (!phi_ops_interfere(phi, n)) {
                                DBG((dbgphi, 1, "\t    %n\n", n));
@@ -604,13 +598,12 @@ static phi_unit_t *new_pu(pset *pc) {
                                pu->node_count++;
                        } else {
                                DBG((dbgphi, 1, "\t    %n \tdropped\n", n));
-                               /* TODO: What if the irn is only free wrt one phi class? */
-                               //pset_insert_ptr(free_nodes, 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"));
@@ -620,31 +613,117 @@ static phi_unit_t *new_pu(pset *pc) {
                                        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);
 
-               obstack_free(&ob, NULL);
-       } else {
-               DBG((dbgphi, 1, "\tPhi-n unit:\n"));
-               /* TODO */
-       }
+               pu_coal_1_phi(pu);
 
-       return pu;
-}
-
-
-/**
- * Deletes a phi unit
- */
-static void free_pu(phi_unit_t *pu) {
-       if (pu->phi_count == 1) {
                free(pu->nodes);
                free(pu->changed_nodes);
                if (pu->conflicts)
                        free(pu->conflicts);
-       } else {
-               /* TODO */
+       } 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);
        }
-       free(pu);
 }
 
 
@@ -652,18 +731,10 @@ void be_phi_coalesce(pset *all_phi_classes) {
        pset *pc;
 
        pinned_global = pset_new_ptr(INITIAL_SLOTS_PINNED_GLOBAL);
-//     free_nodes = pset_new_ptr(INITIAL_SLOTS_FREE_NODES);
-
-       for (pc = pset_first(all_phi_classes); pc; pc = pset_next(all_phi_classes)) {
-               phi_unit_t *pu = new_pu(pc);
-               if (pu->phi_count == 1)
-                       pu_coal_1_phi(pu);
-               else
-                       pu_coal_n_phi(pu);
-               free_pu(pu);
-       }
 
-//     del_pset(free_nodes);
+       for (pc = pset_first(all_phi_classes); pc; pc = pset_next(all_phi_classes))
+               coal_phi_class(pc, NULL);
+
        del_pset(pinned_global);
 }
 
diff --git a/ir/be/bephicoalilp.c b/ir/be/bephicoalilp.c
new file mode 100644 (file)
index 0000000..9bcba75
--- /dev/null
@@ -0,0 +1,846 @@
+/**
+ * @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);
+}
diff --git a/ir/be/bephicoalilp_t.h b/ir/be/bephicoalilp_t.h
new file mode 100644 (file)
index 0000000..a6567e5
--- /dev/null
@@ -0,0 +1,15 @@
+/**
+ * @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
index f4d4258..8201302 100644 (file)
 #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 DEBUG_LVL 0
-//SET_LEVEL_1
-#define CHECK_RESULTS      1
-#define COUNT_COPY_SAVINGS 1
-#define DUMP_OPT_DIFF      0
+#define DO_HEURISTIC
+#undef DO_OPTIMAL
 
-#define DO_PHI_STATISTICS  0
-#define DUMP_IRG_PHI_STAT  1
-#define DUMP_DIR_PHI_STAT  1
-#define DUMP_ALL_PHI_STAT  1
+#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);
@@ -66,7 +80,7 @@ static void check_result(ir_graph *irg) {
                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 in %n\n   %n in %n\n", n1, get_nodes_block(n1), n2, get_nodes_block(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!");
                        }
        }
@@ -75,19 +89,46 @@ static void check_result(ir_graph *irg) {
 }
 
 
-/* TODO: how to count copies in case of phi swapping */
-static void count_copies(pset *all_phi_nodes, int *copies, int *inevitable) {
+/**
+ * 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))
-                               (*copies)++;
-                       if (phi_ops_interfere(phi, arg))
-                               (*inevitable)++;
+                       if (phi_color != get_irn_color(arg)) {
+                               c->count[stage]++;
+                               DBG((dbgphi, LEVEL_2, "Copy: %n %n\n", phi, arg));
+                       }
                }
        }
 }
@@ -95,7 +136,7 @@ static void count_copies(pset *all_phi_nodes, int *copies, int *inevitable) {
 
 void be_phi_opt(ir_graph* irg) {
        pset *all_phi_nodes, *all_phi_classes;
-       int before, after, inevitable;
+       copies_t *copies;
 
        DBG((dbgphi, 1, "\n\n=======================> IRG: %s\n\n", get_entity_name(get_irg_entity(irg))));
 
@@ -112,21 +153,23 @@ void be_phi_opt(ir_graph* irg) {
 
 
        /* do some statistics */
-       if (DO_PHI_STATISTICS) {
-               DBG((dbgphi, 1, "-----------------------> Collecting phi stats <-----------------------\n"));
-               phi_stat_reset();
-               phi_stat_collect(irg, all_phi_nodes, all_phi_classes);
-               if (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);
-               }
-               if (DUMP_DIR_PHI_STAT)
-                       phi_stat_update(PHI_STAT_FILE);
-               if (DUMP_ALL_PHI_STAT)
-                       phi_stat_update(getenv(ENV_PHI_STAT));
-       }
+#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 */
@@ -134,31 +177,53 @@ void be_phi_opt(ir_graph* irg) {
        compute_outs(irg);
        compute_doms(irg);
 
-       if (COUNT_COPY_SAVINGS) {
-               before = 0;
-               count_copies(all_phi_nodes, &before, &inevitable);
-       }
 
-       if (CHECK_RESULTS)
-               check_result(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
+
 
-       if (DUMP_OPT_DIFF)
-               dump_allocated_irg(irg, "-before");
 
+#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 (DUMP_OPT_DIFF)
-               dump_allocated_irg(irg, "-opt");
 
-       if (CHECK_RESULTS)
+       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);
-
-       if (COUNT_COPY_SAVINGS) {
-               after = 0;
-               inevitable = 0;
-               count_copies(all_phi_nodes, &after, &inevitable);
-               DBG((dbgphi, 0, "Irg: %s. Copies form %d to %d. %d phi-interferers\n", get_entity_name(get_irg_entity(irg)), before, after, inevitable));
+#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);
 }
 
@@ -168,5 +233,10 @@ void be_phi_opt_init(void) {
        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
 }