#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 */
* 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 */
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;
* 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;
*
* 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;
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) {
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) {
* 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;
/* 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. */
}
}
-/**
- * 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));
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"));
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);
}
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);
}
--- /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);
+}
#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);
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!");
}
}
}
-/* 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));
+ }
}
}
}
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))));
/* 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 */
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);
}
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
}