Adapt to latest libfirm.
[libfirm] / optimal.c
index e5c6a65..01c8fe1 100644 (file)
--- a/optimal.c
+++ b/optimal.c
 #include "timing.h"
 
 pbqp_edge **edge_bucket;
+pbqp_edge **rm_bucket;
 pbqp_node **node_buckets[4];
 pbqp_node **reduced_bucket = NULL;
 static int         buckets_filled = 0;
 
-#if KAPS_STATISTIC
-static int dump = 0;
-#endif
-
 static void insert_into_edge_bucket(pbqp_edge *edge)
 {
        if (edge_bucket_contains(edge_bucket, edge)) {
@@ -65,11 +62,22 @@ static void insert_into_edge_bucket(pbqp_edge *edge)
        edge_bucket_insert(&edge_bucket, edge);
 }
 
+static void insert_into_rm_bucket(pbqp_edge *edge)
+{
+       if (edge_bucket_contains(rm_bucket, edge)) {
+               /* Edge is already inserted. */
+               return;
+       }
+
+       edge_bucket_insert(&rm_bucket, edge);
+}
+
 static void init_buckets(void)
 {
        int i;
 
        edge_bucket_init(&edge_bucket);
+       edge_bucket_init(&rm_bucket);
        node_bucket_init(&reduced_bucket);
 
        for (i = 0; i < 4; ++i) {
@@ -86,6 +94,7 @@ void free_buckets(void)
        }
 
        edge_bucket_free(&edge_bucket);
+       edge_bucket_free(&rm_bucket);
        node_bucket_free(&reduced_bucket);
 
        buckets_filled = 0;
@@ -100,8 +109,8 @@ void fill_node_buckets(pbqp *pbqp)
        node_len = pbqp->num_nodes;
 
        #if KAPS_TIMING
-               ir_timer_t *t_fill_buckets = ir_timer_register("be_pbqp_fill_buckets", "PBQP Fill Nodes into buckets");
-               ir_timer_reset_and_start(t_fill_buckets);
+               ir_timer_t *t_fill_buckets = ir_timer_new();
+               ir_timer_start(t_fill_buckets);
        #endif
 
        for (node_index = 0; node_index < node_len; ++node_index) {
@@ -124,11 +133,11 @@ void fill_node_buckets(pbqp *pbqp)
 
        #if KAPS_TIMING
                ir_timer_stop(t_fill_buckets);
-               printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_fill_buckets), (double)ir_timer_elapsed_usec(t_fill_buckets) / 1000.0);
+               printf("PBQP Fill Nodes into buckets: %8.3lf msec\n", (double)ir_timer_elapsed_usec(t_fill_buckets) / 1000.0);
        #endif
 }
 
-static void normalize_towards_source(pbqp *pbqp, pbqp_edge *edge)
+static void normalize_towards_source(pbqp_edge *edge)
 {
        pbqp_matrix    *mat;
        pbqp_node      *src_node;
@@ -139,7 +148,6 @@ static void normalize_towards_source(pbqp *pbqp, pbqp_edge *edge)
        int             tgt_len;
        int             src_index;
 
-       assert(pbqp);
        assert(edge);
 
        src_node = edge->src;
@@ -188,7 +196,7 @@ static void normalize_towards_source(pbqp *pbqp, pbqp_edge *edge)
        }
 }
 
-static void normalize_towards_target(pbqp *pbqp, pbqp_edge *edge)
+static void normalize_towards_target(pbqp_edge *edge)
 {
        pbqp_matrix    *mat;
        pbqp_node      *src_node;
@@ -199,7 +207,6 @@ static void normalize_towards_target(pbqp *pbqp, pbqp_edge *edge)
        int             tgt_len;
        int             tgt_index;
 
-       assert(pbqp);
        assert(edge);
 
        src_node = edge->src;
@@ -247,42 +254,184 @@ static void normalize_towards_target(pbqp *pbqp, pbqp_edge *edge)
        }
 }
 
-static void reorder_node(pbqp_node *node)
+/**
+ * Tries to apply RM for the source node of the given edge.
+ *
+ * Checks whether the source node of edge can be merged into the target node of
+ * edge, and performs the merge, if possible.
+ */
+static void merge_source_into_target(pbqp *pbqp, pbqp_edge *edge)
 {
-       unsigned    degree     = pbqp_node_get_degree(node);
-       /* Assume node lost one incident edge. */
-       unsigned    old_degree = degree + 1;
+       pbqp_matrix    *mat;
+       pbqp_node      *src_node;
+       pbqp_node      *tgt_node;
+       vector         *src_vec;
+       vector         *tgt_vec;
+       unsigned       *mapping;
+       unsigned        src_len;
+       unsigned        tgt_len;
+       unsigned        src_index;
+       unsigned        tgt_index;
+       unsigned        edge_index;
+       unsigned        edge_len;
 
-       if (!buckets_filled) return;
+       assert(pbqp);
+       assert(edge);
 
-       /* Same bucket as before */
-       if (degree > 2) return;
+       src_node = edge->src;
+       tgt_node = edge->tgt;
+       assert(src_node);
+       assert(tgt_node);
 
-       if (!node_bucket_contains(node_buckets[old_degree], node)) {
-               /* Old arity is new arity, so we have nothing to do. */
-               assert(node_bucket_contains(node_buckets[degree], node));
-               return;
+       src_vec = src_node->costs;
+       tgt_vec = tgt_node->costs;
+       assert(src_vec);
+       assert(tgt_vec);
+
+       src_len = src_vec->len;
+       tgt_len = tgt_vec->len;
+
+       /* Matrizes are normalized. */
+       assert(src_len > 1);
+       assert(tgt_len > 1);
+
+       mat = edge->costs;
+       assert(mat);
+
+       mapping = NEW_ARR_F(unsigned, tgt_len);
+
+       /* Check that each column has at most one zero entry. */
+       for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+               unsigned onlyOneZero = 0;
+
+               if (tgt_vec->entries[tgt_index].data == INF_COSTS)
+                       continue;
+
+               for (src_index = 0; src_index < src_len; ++src_index) {
+                       if (src_vec->entries[src_index].data == INF_COSTS)
+                               continue;
+
+                       if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS)
+                               continue;
+
+                       /* Matrix entry is finite. */
+                       if (onlyOneZero) {
+                               DEL_ARR_F(mapping);
+                               return;
+                       }
+
+                       onlyOneZero = 1;
+                       mapping[tgt_index] = src_index;
+               }
        }
 
-       /* Delete node from old bucket... */
-       node_bucket_remove(&node_buckets[old_degree], node);
+       /* We know that we can merge the source node into the target node. */
+       edge_len = pbqp_node_get_degree(src_node);
 
-       /* ..and add to new one. */
-       node_bucket_insert(&node_buckets[degree], node);
+#if KAPS_STATISTIC
+       pbqp->num_rm++;
+#endif
+
+       /* Reconnect the source's edges with the target node. */
+       for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+               pbqp_edge   *old_edge = src_node->edges[edge_index];
+               pbqp_edge   *new_edge;
+               pbqp_matrix *old_matrix;
+               pbqp_matrix *new_matrix;
+               pbqp_node   *other_node;
+               vector      *other_vec;
+               unsigned     other_len;
+               unsigned     other_index;
+               unsigned     tgt_index;
+
+               assert(old_edge);
+
+               if (old_edge == edge)
+                       continue;
+
+               old_matrix = old_edge->costs;
+               assert(old_matrix);
+
+               if (old_edge->tgt == src_node) {
+                       other_node = old_edge->src;
+                       other_len  = old_matrix->rows;
+               }
+               else {
+                       other_node = old_edge->tgt;
+                       other_len = old_matrix->cols;
+               }
+               assert(other_node);
+               other_vec = other_node->costs;
+
+               new_matrix = pbqp_matrix_alloc(pbqp, tgt_len, other_len);
+
+               /* Source node selects the column of the old_matrix. */
+               if (old_edge->tgt == src_node) {
+                       for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+                               unsigned src_index = mapping[tgt_index];
+
+                               if (tgt_vec->entries[tgt_index].data == INF_COSTS)
+                                       continue;
+
+                               for (other_index = 0; other_index < other_len; ++other_index) {
+                                       if (other_vec->entries[other_index].data == INF_COSTS)
+                                               continue;
+
+                                       new_matrix->entries[tgt_index*other_len+other_index] = old_matrix->entries[other_index*src_len+src_index];
+                               }
+                       }
+               }
+               /* Source node selects the row of the old_matrix. */
+               else {
+                       for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+                               unsigned src_index = mapping[tgt_index];
+
+                               if (tgt_vec->entries[tgt_index].data == INF_COSTS)
+                                       continue;
+
+                               for (other_index = 0; other_index < other_len; ++other_index) {
+                                       if (other_vec->entries[other_index].data == INF_COSTS)
+                                               continue;
+
+                                       new_matrix->entries[tgt_index*other_len+other_index] = old_matrix->entries[src_index*other_len+other_index];
+                               }
+                       }
+               }
+
+               add_edge_costs(pbqp, tgt_node->index, other_node->index, new_matrix);
+
+               delete_edge(old_edge);
+               reorder_node(src_node);
+               reorder_node(other_node);
+
+               new_edge = get_edge(pbqp, tgt_node->index, other_node->index);
+               insert_into_rm_bucket(new_edge);
+       }
+
+       /* Reduce the remaining source node via RI. */
+       apply_RI(pbqp);
 }
 
-#if 0
-static void check_melting_possibility(pbqp *pbqp, pbqp_edge *edge)
+/**
+ * Tries to apply RM for the target node of the given edge.
+ *
+ * Checks whether the target node of edge can be merged into the source node of
+ * edge, and performs the merge, if possible.
+ */
+static void merge_target_into_source(pbqp *pbqp, pbqp_edge *edge)
 {
        pbqp_matrix    *mat;
        pbqp_node      *src_node;
        pbqp_node      *tgt_node;
        vector         *src_vec;
        vector         *tgt_vec;
-       int             src_len;
-       int             tgt_len;
-       int             src_index;
-       int             tgt_index;
+       unsigned       *mapping;
+       unsigned        src_len;
+       unsigned        tgt_len;
+       unsigned        src_index;
+       unsigned        tgt_index;
+       unsigned        edge_index;
+       unsigned        edge_len;
 
        assert(pbqp);
        assert(edge);
@@ -299,77 +448,185 @@ static void check_melting_possibility(pbqp *pbqp, pbqp_edge *edge)
 
        src_len = src_vec->len;
        tgt_len = tgt_vec->len;
-       assert(src_len > 0);
-       assert(tgt_len > 0);
+
+       /* Matrizes are normalized. */
+       assert(src_len > 1);
+       assert(tgt_len > 1);
 
        mat = edge->costs;
        assert(mat);
 
-       if (src_len == 1 && tgt_len == 1) {
-               //panic("Something is wrong");
-       }
+       mapping = NEW_ARR_F(unsigned, src_len);
 
-       int allRowsOk = 1;
+       /* Check that each row has at most one zero entry. */
        for (src_index = 0; src_index < src_len; ++src_index) {
-               int onlyOneZero = 0;
-               if (src_vec->entries[src_index].data == INF_COSTS) {
+               unsigned onlyOneZero = 0;
+
+               if (src_vec->entries[src_index].data == INF_COSTS)
                        continue;
-               }
+
                for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
-                       if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
+                       if (tgt_vec->entries[tgt_index].data == INF_COSTS)
                                continue;
-                       }
-                       if (mat->entries[src_index * tgt_len + tgt_index] == 0) {
-                               if (onlyOneZero) {
-                                       onlyOneZero = 0;
-                                       break;
-                               } else {
-                                       onlyOneZero = 1;
-                                       continue;
-                               }
-                       }
-                       if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS) {
+
+                       if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS)
                                continue;
+
+                       /* Matrix entry is finite. */
+                       if (onlyOneZero) {
+                               DEL_ARR_F(mapping);
+                               return;
                        }
-                       onlyOneZero = 0;
-                       break;
+
+                       onlyOneZero = 1;
+                       mapping[src_index] = tgt_index;
                }
-               allRowsOk &= onlyOneZero;
        }
 
-       int allColsOk = 1;
-       for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
-               int onlyOneZero = 0;
-               if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
+       /* We know that we can merge the target node into the source node. */
+       edge_len = pbqp_node_get_degree(tgt_node);
+
+#if KAPS_STATISTIC
+       pbqp->num_rm++;
+#endif
+
+       /* Reconnect the target's edges with the source node. */
+       for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+               pbqp_edge   *old_edge = tgt_node->edges[edge_index];
+               pbqp_edge   *new_edge;
+               pbqp_matrix *old_matrix;
+               pbqp_matrix *new_matrix;
+               pbqp_node   *other_node;
+               vector      *other_vec;
+               unsigned     other_len;
+               unsigned     other_index;
+               unsigned     src_index;
+
+               assert(old_edge);
+
+               if (old_edge == edge)
                        continue;
+
+               old_matrix = old_edge->costs;
+               assert(old_matrix);
+
+               if (old_edge->tgt == tgt_node) {
+                       other_node = old_edge->src;
+                       other_len  = old_matrix->rows;
                }
-               for (src_index = 0; src_index < src_len; ++src_index) {
-                       if (src_vec->entries[src_index].data == INF_COSTS) {
-                               continue;
-                       }
-                       if (mat->entries[src_index * tgt_len + tgt_index] == 0) {
-                               if (onlyOneZero) {
-                                       onlyOneZero = 0;
-                                       break;
-                               } else {
-                                       onlyOneZero = 1;
+               else {
+                       other_node = old_edge->tgt;
+                       other_len = old_matrix->cols;
+               }
+               assert(other_node);
+               other_vec = other_node->costs;
+
+               new_matrix = pbqp_matrix_alloc(pbqp, src_len, other_len);
+
+               /* Target node selects the column of the old_matrix. */
+               if (old_edge->tgt == tgt_node) {
+                       for (src_index = 0; src_index < src_len; ++src_index) {
+                               unsigned tgt_index = mapping[src_index];
+
+                               if (src_vec->entries[src_index].data == INF_COSTS)
                                        continue;
+
+                               for (other_index = 0; other_index < other_len; ++other_index) {
+                                       if (other_vec->entries[other_index].data == INF_COSTS)
+                                               continue;
+
+                                       new_matrix->entries[src_index*other_len+other_index] = old_matrix->entries[other_index*tgt_len+tgt_index];
                                }
                        }
-                       if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS) {
-                               continue;
+               }
+               /* Source node selects the row of the old_matrix. */
+               else {
+                       for (src_index = 0; src_index < src_len; ++src_index) {
+                               unsigned tgt_index = mapping[src_index];
+
+                               if (src_vec->entries[src_index].data == INF_COSTS)
+                                       continue;
+
+                               for (other_index = 0; other_index < other_len; ++other_index) {
+                                       if (other_vec->entries[other_index].data == INF_COSTS)
+                                               continue;
+
+                                       new_matrix->entries[src_index*other_len+other_index] = old_matrix->entries[tgt_index*other_len+other_index];
+                               }
                        }
-                       onlyOneZero = 0;
-                       break;
                }
-               allColsOk &= onlyOneZero;
+
+               add_edge_costs(pbqp, src_node->index, other_node->index, new_matrix);
+
+               delete_edge(old_edge);
+               reorder_node(tgt_node);
+               reorder_node(other_node);
+
+               new_edge = get_edge(pbqp, src_node->index, other_node->index);
+               insert_into_rm_bucket(new_edge);
        }
 
-       if (allRowsOk && allColsOk) {
-               panic("Hurray");
+       /* Reduce the remaining source node via RI. */
+       apply_RI(pbqp);
+}
+
+/**
+ * Merge neighbors into the given node.
+ */
+void apply_RM(pbqp *pbqp, pbqp_node *node)
+{
+       pbqp_edge **edges;
+       unsigned    edge_index;
+       unsigned    edge_len;
+
+       assert(node);
+       assert(pbqp);
+
+       edges    = node->edges;
+       edge_len = pbqp_node_get_degree(node);
+
+       /* Check all incident edges. */
+       for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+               pbqp_edge *edge = edges[edge_index];
+
+               insert_into_rm_bucket(edge);
+       }
+
+       /* ALAP: Merge neighbors into given node. */
+       while(edge_bucket_get_length(rm_bucket) > 0) {
+               pbqp_edge *edge = edge_bucket_pop(&rm_bucket);
+               assert(edge);
+
+               if (edge->src == node)
+                       merge_target_into_source(pbqp, edge);
+               else
+                       merge_source_into_target(pbqp, edge);
        }
 }
-#endif
+
+void reorder_node(pbqp_node *node)
+{
+       unsigned    degree     = pbqp_node_get_degree(node);
+       /* Assume node lost one incident edge. */
+       unsigned    old_degree = degree + 1;
+
+       if (!buckets_filled) return;
+
+       /* Same bucket as before */
+       if (degree > 2) return;
+
+       if (!node_bucket_contains(node_buckets[old_degree], node)) {
+               /* Old arity is new arity, so we have nothing to do. */
+               assert(node_bucket_contains(node_buckets[degree], node));
+               return;
+       }
+
+       /* Delete node from old bucket... */
+       node_bucket_remove(&node_buckets[old_degree], node);
+
+       /* ..and add to new one. */
+       node_bucket_insert(&node_buckets[degree], node);
+}
 
 void simplify_edge(pbqp *pbqp, pbqp_edge *edge)
 {
@@ -421,8 +678,8 @@ void simplify_edge(pbqp *pbqp, pbqp_edge *edge)
        }
 #endif
 
-       normalize_towards_source(pbqp, edge);
-       normalize_towards_target(pbqp, edge);
+       normalize_towards_source(edge);
+       normalize_towards_target(edge);
 
 #if    KAPS_DUMP
        if (pbqp->dump_file) {
@@ -439,9 +696,7 @@ void simplify_edge(pbqp *pbqp, pbqp_edge *edge)
 #endif
 
 #if KAPS_STATISTIC
-               if (dump == 0) {
-                       pbqp->num_edges++;
-               }
+               pbqp->num_edges++;
 #endif
 
                delete_edge(edge);
@@ -458,8 +713,8 @@ void initial_simplify_edges(pbqp *pbqp)
        assert(pbqp);
 
        #if KAPS_TIMING
-               ir_timer_t *t_int_simpl = ir_timer_register("be_pbqp_init_simp", "PBQP Initial simplify edges");
-               ir_timer_reset_and_start(t_int_simpl);
+               ir_timer_t *t_int_simpl = ir_timer_new();
+               ir_timer_start(t_int_simpl);
        #endif
 
 #if    KAPS_DUMP
@@ -497,7 +752,7 @@ void initial_simplify_edges(pbqp *pbqp)
 
        #if KAPS_TIMING
                ir_timer_stop(t_int_simpl);
-               printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_int_simpl), (double)ir_timer_elapsed_usec(t_int_simpl) / 1000.0);
+               printf("PBQP Initial simplify edges: %8.3lf msec\n", (double)ir_timer_elapsed_usec(t_int_simpl) / 1000.0);
        #endif
 }
 
@@ -508,7 +763,7 @@ num determine_solution(pbqp *pbqp)
        num      solution   = 0;
 
        #if KAPS_TIMING
-               ir_timer_t *t_det_solution = ir_timer_register("be_det_solution", "PBQP Determine Solution");
+               ir_timer_t *t_det_solution = ir_timer_new();
                ir_timer_reset_and_start(t_det_solution);
        #endif
 
@@ -531,9 +786,7 @@ num determine_solution(pbqp *pbqp)
        node_len = node_bucket_get_length(node_buckets[0]);
 
 #if KAPS_STATISTIC
-       if (dump == 0) {
-               pbqp->num_r0 = node_len;
-       }
+       pbqp->num_r0 = node_len;
 #endif
 
        for (node_index = 0; node_index < node_len; ++node_index) {
@@ -565,7 +818,7 @@ num determine_solution(pbqp *pbqp)
 
        #if KAPS_TIMING
                ir_timer_stop(t_det_solution);
-               printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_det_solution), (double)ir_timer_elapsed_usec(t_det_solution) / 1000.0);
+               printf("PBQP Determine Solution: %8.3lf msec\n", (double)ir_timer_elapsed_usec(t_det_solution) / 1000.0);
        #endif
 
        return solution;
@@ -591,17 +844,11 @@ static void back_propagate_RI(pbqp *pbqp, pbqp_node *node)
                other = edge->tgt;
                assert(other);
 
-               /* Update pointer for brute force solver. */
-               other = pbqp->nodes[other->index];
-
                node->solution = pbqp_matrix_get_col_min_index(mat, other->solution, vec);
        } else {
                other = edge->src;
                assert(other);
 
-               /* Update pointer for brute force solver. */
-               other = pbqp->nodes[other->index];
-
                node->solution = pbqp_matrix_get_row_min_index(mat, other->solution, vec);
        }
 
@@ -658,10 +905,6 @@ static void back_propagate_RII(pbqp *pbqp, pbqp_node *node)
                tgt_is_src = tgt_edge->src == node;
        }
 
-       /* Update pointer for brute force solver. */
-       src_node = pbqp->nodes[src_node->index];
-       tgt_node = pbqp->nodes[tgt_node->index];
-
        src_mat = src_edge->costs;
        tgt_mat = tgt_edge->costs;
 
@@ -740,6 +983,7 @@ void apply_RI(pbqp *pbqp)
        int          is_src     = edge->src == node;
        pbqp_node   *other_node;
 
+       (void ) pbqp;
        assert(pbqp_node_get_degree(node) == 1);
 
        if (is_src) {
@@ -763,10 +1007,10 @@ void apply_RI(pbqp *pbqp)
 
        if (is_src) {
                pbqp_matrix_add_to_all_cols(mat, node->costs);
-               normalize_towards_target(pbqp, edge);
+               normalize_towards_target(edge);
        } else {
                pbqp_matrix_add_to_all_rows(mat, node->costs);
-               normalize_towards_source(pbqp, edge);
+               normalize_towards_source(edge);
        }
        disconnect_edge(other_node, edge);
 
@@ -780,9 +1024,7 @@ void apply_RI(pbqp *pbqp)
        reorder_node(other_node);
 
 #if KAPS_STATISTIC
-       if (dump == 0) {
-               pbqp->num_r1++;
-       }
+       pbqp->num_r1++;
 #endif
 
        /* Add node to back propagation list. */
@@ -900,9 +1142,7 @@ void apply_RII(pbqp *pbqp)
        disconnect_edge(tgt_node, tgt_edge);
 
 #if KAPS_STATISTIC
-       if (dump == 0) {
-               pbqp->num_r2++;
-       }
+       pbqp->num_r2++;
 #endif
 
        /* Add node to back propagation list. */
@@ -987,7 +1227,7 @@ unsigned get_local_minimal_alternative(pbqp *pbqp, pbqp_node *node)
        vector      *vec;
        pbqp_matrix *mat;
        unsigned     edge_index;
-       unsigned     max_degree   = 0;
+       unsigned     max_degree;
        unsigned     node_index;
        unsigned     node_len;
        unsigned     min_index    = 0;
@@ -996,8 +1236,9 @@ unsigned get_local_minimal_alternative(pbqp *pbqp, pbqp_node *node)
 
        assert(pbqp);
        assert(node);
-       node_vec = node->costs;
-       node_len = node_vec->len;
+       node_vec   = node->costs;
+       node_len   = node_vec->len;
+       max_degree = pbqp_node_get_degree(node);
 
        for (node_index = 0; node_index < node_len; ++node_index) {
                num value = node_vec->entries[node_index].data;