merge kaps
authorAndreas Zwinkau <zwinkau@kit.edu>
Fri, 8 Apr 2011 12:10:06 +0000 (14:10 +0200)
committerAndreas Zwinkau <zwinkau@kit.edu>
Fri, 8 Apr 2011 12:10:06 +0000 (14:10 +0200)
30 files changed:
ir/kaps/brute_force.c [new file with mode: 0644]
ir/kaps/brute_force.h [new file with mode: 0644]
ir/kaps/bucket.c [new file with mode: 0644]
ir/kaps/bucket.h [new file with mode: 0644]
ir/kaps/bucket_t.h [new file with mode: 0644]
ir/kaps/heuristical.c [new file with mode: 0644]
ir/kaps/heuristical.h [new file with mode: 0644]
ir/kaps/heuristical_co.c [new file with mode: 0644]
ir/kaps/heuristical_co.h [new file with mode: 0644]
ir/kaps/heuristical_co_ld.c [new file with mode: 0644]
ir/kaps/heuristical_co_ld.h [new file with mode: 0644]
ir/kaps/html_dumper.c [new file with mode: 0644]
ir/kaps/html_dumper.h [new file with mode: 0644]
ir/kaps/kaps.c [new file with mode: 0644]
ir/kaps/kaps.h [new file with mode: 0644]
ir/kaps/matrix.c [new file with mode: 0644]
ir/kaps/matrix.h [new file with mode: 0644]
ir/kaps/matrix_t.h [new file with mode: 0644]
ir/kaps/optimal.c [new file with mode: 0644]
ir/kaps/optimal.h [new file with mode: 0644]
ir/kaps/pbqp_edge.c [new file with mode: 0644]
ir/kaps/pbqp_edge.h [new file with mode: 0644]
ir/kaps/pbqp_edge_t.h [new file with mode: 0644]
ir/kaps/pbqp_node.c [new file with mode: 0644]
ir/kaps/pbqp_node.h [new file with mode: 0644]
ir/kaps/pbqp_node_t.h [new file with mode: 0644]
ir/kaps/pbqp_t.h [new file with mode: 0644]
ir/kaps/vector.c [new file with mode: 0644]
ir/kaps/vector.h [new file with mode: 0644]
ir/kaps/vector_t.h [new file with mode: 0644]

diff --git a/ir/kaps/brute_force.c b/ir/kaps/brute_force.c
new file mode 100644 (file)
index 0000000..94111ce
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Brute force PBQP solver.
+ * @date    02.12.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "assert.h"
+#include "error.h"
+
+#include "bucket.h"
+#include "brute_force.h"
+#include "optimal.h"
+#if    KAPS_DUMP
+#include "html_dumper.h"
+#endif
+#include "kaps.h"
+#include "matrix.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+#if KAPS_STATISTIC
+static int dump = 0;
+#endif
+
+/* Forward declarations. */
+static void apply_Brute_Force(pbqp_t *pbqp);
+
+static void apply_brute_force_reductions(pbqp_t *pbqp)
+{
+       for (;;) {
+               if (edge_bucket_get_length(edge_bucket) > 0) {
+                       apply_edge(pbqp);
+               } else if (node_bucket_get_length(node_buckets[1]) > 0) {
+                       apply_RI(pbqp);
+               } else if (node_bucket_get_length(node_buckets[2]) > 0) {
+                       apply_RII(pbqp);
+               } else if (node_bucket_get_length(node_buckets[3]) > 0) {
+                       apply_Brute_Force(pbqp);
+               } else {
+                       return;
+               }
+       }
+}
+
+static unsigned get_minimal_alternative(pbqp_t *pbqp, pbqp_node_t *node)
+{
+       vector_t *node_vec;
+       unsigned  node_index;
+       unsigned  node_len;
+       unsigned  min_index    = 0;
+       num       min          = INF_COSTS;
+       unsigned  bucket_index;
+
+       assert(pbqp);
+       assert(node);
+       node_vec     = node->costs;
+       node_len     = node_vec->len;
+       bucket_index = node->bucket_index;
+
+       for (node_index = 0; node_index < node_len; ++node_index) {
+               pbqp_node_bucket_t bucket_deg3;
+               num                value;
+               unsigned           bucket_0_length;
+               unsigned           bucket_red_length;
+
+               char *tmp = (char*)obstack_finish(&pbqp->obstack);
+
+               node_bucket_init(&bucket_deg3);
+
+               /* Some node buckets and the edge bucket should be empty. */
+               assert(node_bucket_get_length(node_buckets[1]) == 0);
+               assert(node_bucket_get_length(node_buckets[2]) == 0);
+               assert(edge_bucket_get_length(edge_bucket)     == 0);
+
+               /* char *tmp = obstack_finish(&pbqp->obstack); */
+
+               /* Save current PBQP state. */
+               node_bucket_copy(&bucket_deg3, node_buckets[3]);
+               node_bucket_shrink(&node_buckets[3], 0);
+               node_bucket_deep_copy(pbqp, &node_buckets[3], bucket_deg3);
+               node_bucket_update(pbqp, node_buckets[3]);
+               bucket_0_length   = node_bucket_get_length(node_buckets[0]);
+               bucket_red_length = node_bucket_get_length(reduced_bucket);
+
+               /* Select alternative and solve PBQP recursively. */
+               select_alternative(node_buckets[3][bucket_index], node_index);
+               apply_brute_force_reductions(pbqp);
+
+               value = determine_solution(pbqp);
+
+               if (value < min) {
+                       min = value;
+                       min_index = node_index;
+               }
+
+               /* Some node buckets and the edge bucket should still be empty. */
+               assert(node_bucket_get_length(node_buckets[1]) == 0);
+               assert(node_bucket_get_length(node_buckets[2]) == 0);
+               assert(edge_bucket_get_length(edge_bucket)     == 0);
+
+               /* Clear modified buckets... */
+               node_bucket_shrink(&node_buckets[3], 0);
+
+               /* ... and restore old PBQP state. */
+               node_bucket_shrink(&node_buckets[0], bucket_0_length);
+               node_bucket_shrink(&reduced_bucket, bucket_red_length);
+               node_bucket_copy(&node_buckets[3], bucket_deg3);
+               node_bucket_update(pbqp, node_buckets[3]);
+
+               /* Free copies. */
+               /* obstack_free(&pbqp->obstack, tmp); */
+               node_bucket_free(&bucket_deg3);
+
+               obstack_free(&pbqp->obstack, tmp);
+       }
+
+       return min_index;
+}
+
+static void apply_Brute_Force(pbqp_t *pbqp)
+{
+       pbqp_node_t *node         = NULL;
+       unsigned     min_index    = 0;
+
+       assert(pbqp);
+
+       /* We want to reduce a node with maximum degree. */
+       node = get_node_with_max_degree();
+       assert(node);
+       assert(pbqp_node_get_degree(node) > 2);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               char     txt[100];
+               sprintf(txt, "BF-Reduction of Node n%d", node->index);
+               dump_section(pbqp->dump_file, 2, txt);
+               pbqp_dump_graph(pbqp);
+       }
+#endif
+
+#if KAPS_STATISTIC
+       dump++;
+#endif
+
+       min_index = get_minimal_alternative(pbqp, node);
+       node = pbqp->nodes[node->index];
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
+                                       node->index, min_index);
+       }
+#endif
+
+#if KAPS_STATISTIC
+       dump--;
+       if (dump == 0) {
+               FILE *fh = fopen("solutions.pb", "a");
+               fprintf(fh, "[%u]", min_index);
+               fclose(fh);
+               pbqp->num_bf++;
+       }
+#endif
+
+       /* Now that we found the minimum set all other costs to infinity. */
+       select_alternative(node, min_index);
+}
+
+
+
+static void back_propagate_RI(pbqp_t *pbqp, pbqp_node_t *node)
+{
+       pbqp_edge_t   *edge;
+       pbqp_node_t   *other;
+       pbqp_matrix_t *mat;
+       vector_t      *vec;
+       int            is_src;
+
+       assert(pbqp);
+       assert(node);
+
+       edge = node->edges[0];
+       mat = edge->costs;
+       is_src = edge->src == node;
+       vec = node->costs;
+
+       if (is_src) {
+               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);
+       }
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+       }
+#endif
+}
+
+static void back_propagate_RII(pbqp_t *pbqp, pbqp_node_t *node)
+{
+       pbqp_edge_t   *src_edge   = node->edges[0];
+       pbqp_edge_t   *tgt_edge   = node->edges[1];
+       int            src_is_src = src_edge->src == node;
+       int            tgt_is_src = tgt_edge->src == node;
+       pbqp_matrix_t *src_mat;
+       pbqp_matrix_t *tgt_mat;
+       pbqp_node_t   *src_node;
+       pbqp_node_t   *tgt_node;
+       vector_t      *vec;
+       vector_t      *node_vec;
+       unsigned       col_index;
+       unsigned       row_index;
+
+       assert(pbqp);
+
+       if (src_is_src) {
+               src_node = src_edge->tgt;
+       } else {
+               src_node = src_edge->src;
+       }
+
+       if (tgt_is_src) {
+               tgt_node = tgt_edge->tgt;
+       } else {
+               tgt_node = tgt_edge->src;
+       }
+
+       /* Swap nodes if necessary. */
+       if (tgt_node->index < src_node->index) {
+               pbqp_node_t *tmp_node;
+               pbqp_edge_t *tmp_edge;
+
+               tmp_node = src_node;
+               src_node = tgt_node;
+               tgt_node = tmp_node;
+
+               tmp_edge = src_edge;
+               src_edge = tgt_edge;
+               tgt_edge = tmp_edge;
+
+               src_is_src = src_edge->src == 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;
+
+       node_vec = node->costs;
+
+       row_index = src_node->solution;
+       col_index = tgt_node->solution;
+
+       vec = vector_copy(pbqp, node_vec);
+
+       if (src_is_src) {
+               vector_add_matrix_col(vec, src_mat, row_index);
+       } else {
+               vector_add_matrix_row(vec, src_mat, row_index);
+       }
+
+       if (tgt_is_src) {
+               vector_add_matrix_col(vec, tgt_mat, col_index);
+       } else {
+               vector_add_matrix_row(vec, tgt_mat, col_index);
+       }
+
+       node->solution = vector_get_min_index(vec);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+       }
+#endif
+
+       obstack_free(&pbqp->obstack, vec);
+}
+
+static void back_propagate_brute_force(pbqp_t *pbqp)
+{
+       unsigned node_index;
+       unsigned node_len = node_bucket_get_length(reduced_bucket);
+
+       assert(pbqp);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               dump_section(pbqp->dump_file, 2, "Back Propagation");
+       }
+#endif
+
+       for (node_index = node_len; node_index > 0; --node_index) {
+               pbqp_node_t *node = reduced_bucket[node_index - 1];
+
+               switch (pbqp_node_get_degree(node)) {
+                       case 1:
+                               back_propagate_RI(pbqp, node);
+                               break;
+                       case 2:
+                               back_propagate_RII(pbqp, node);
+                               break;
+                       default:
+                               panic("Only nodes with degree one or two should be in this bucket");
+                               break;
+               }
+       }
+}
+
+void solve_pbqp_brute_force(pbqp_t *pbqp)
+{
+       /* Reduce nodes degree ... */
+       initial_simplify_edges(pbqp);
+
+       /* ... and put node into bucket representing their degree. */
+       fill_node_buckets(pbqp);
+
+#if KAPS_STATISTIC
+       FILE *fh = fopen("solutions.pb", "a");
+       fprintf(fh, "Solution");
+       fclose(fh);
+#endif
+
+       apply_brute_force_reductions(pbqp);
+
+       pbqp->solution = determine_solution(pbqp);
+
+#if KAPS_STATISTIC
+       fh = fopen("solutions.pb", "a");
+       #if KAPS_USE_UNSIGNED
+               fprintf(fh, ": %u RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+                               pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+                               pbqp->num_rm, pbqp->num_rn);
+       #else
+               fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+                               pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+                               pbqp->num_rm, pbqp->num_bf);
+       #endif
+       fclose(fh);
+#endif
+
+       /* Solve reduced nodes. */
+       back_propagate_brute_force(pbqp);
+
+       free_buckets();
+}
diff --git a/ir/kaps/brute_force.h b/ir/kaps/brute_force.h
new file mode 100644 (file)
index 0000000..696dccc
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Brute force PBQP solver.
+ * @date    02.12.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_BRUTE_FORCE_H
+#define KAPS_BRUTE_FORCE_H
+
+#include "pbqp_t.h"
+
+void solve_pbqp_brute_force(pbqp_t *pbqp);
+
+#endif /* KAPS_BRUTE_FORCE_H */
diff --git a/ir/kaps/bucket.c b/ir/kaps/bucket.c
new file mode 100644 (file)
index 0000000..77e8599
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Buckets for nodes and edges.
+ * @date    30.11.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+
+#include "bucket.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+
+int edge_bucket_contains(pbqp_edge_bucket_t bucket, pbqp_edge_t *edge)
+{
+       assert(edge);
+
+       return edge->bucket_index < edge_bucket_get_length(bucket)
+                       && bucket[edge->bucket_index] == edge;
+}
+
+void edge_bucket_free(pbqp_edge_bucket_t *bucket)
+{
+       DEL_ARR_F(*bucket);
+       *bucket = NULL;
+}
+
+unsigned edge_bucket_get_length(pbqp_edge_bucket_t bucket)
+{
+       return ARR_LEN(bucket);
+}
+
+void edge_bucket_init(pbqp_edge_bucket_t *bucket)
+{
+       *bucket = NEW_ARR_F(pbqp_edge_t *, 0);
+}
+
+void edge_bucket_insert(pbqp_edge_bucket_t *bucket, pbqp_edge_t *edge)
+{
+       edge->bucket_index = edge_bucket_get_length(*bucket);
+       ARR_APP1(pbqp_edge_t *, *bucket, edge);
+}
+
+pbqp_edge_t *edge_bucket_pop(pbqp_edge_bucket_t *bucket)
+{
+       unsigned     bucket_len = edge_bucket_get_length(*bucket);
+       pbqp_edge_t *edge;
+
+       assert(bucket_len > 0);
+
+       edge = (*bucket)[bucket_len - 1];
+
+       ARR_SHRINKLEN(*bucket, (int)bucket_len - 1);
+       edge->bucket_index = UINT_MAX;
+
+       return edge;
+}
+
+void node_bucket_shrink(pbqp_node_bucket_t *bucket, unsigned len)
+{
+       ARR_SHRINKLEN(*bucket, (int)len);
+}
+
+int node_bucket_contains(pbqp_node_bucket_t bucket, pbqp_node_t *node)
+{
+       assert(node);
+
+       return node->bucket_index < node_bucket_get_length(bucket)
+                       && bucket[node->bucket_index] == node;
+}
+
+void node_bucket_copy(pbqp_node_bucket_t *dst, pbqp_node_bucket_t src)
+{
+       unsigned src_index;
+       unsigned src_length = node_bucket_get_length(src);
+
+       for (src_index = 0; src_index < src_length; ++src_index) {
+               node_bucket_insert(dst, src[src_index]);
+       }
+}
+
+void node_bucket_update(pbqp_t *pbqp, pbqp_node_bucket_t bucket)
+{
+       unsigned index;
+       unsigned length = node_bucket_get_length(bucket);
+
+       for (index = 0; index < length; ++index) {
+               pbqp->nodes[bucket[index]->index] = bucket[index];
+       }
+}
+
+void node_bucket_free(pbqp_node_bucket_t *bucket)
+{
+       DEL_ARR_F(*bucket);
+       *bucket = NULL;
+}
+
+unsigned node_bucket_get_length(pbqp_node_bucket_t bucket)
+{
+       return ARR_LEN(bucket);
+}
+
+void node_bucket_init(pbqp_node_bucket_t *bucket)
+{
+       *bucket = NEW_ARR_F(pbqp_node_t*, 0);
+}
+
+void node_bucket_insert(pbqp_node_bucket_t *bucket, pbqp_node_t *node)
+{
+       node->bucket_index = node_bucket_get_length(*bucket);
+       ARR_APP1(pbqp_node_t *, *bucket, node);
+}
+
+pbqp_node_t *node_bucket_pop(pbqp_node_bucket_t *bucket)
+{
+       unsigned     bucket_len = node_bucket_get_length(*bucket);
+       pbqp_node_t *node;
+
+       assert(bucket_len > 0);
+
+       node = (*bucket)[bucket_len - 1];
+       assert(node);
+
+       ARR_SHRINKLEN(*bucket, (int)bucket_len - 1);
+       node->bucket_index = UINT_MAX;
+
+       return node;
+}
+
+void node_bucket_remove(pbqp_node_bucket_t *bucket, pbqp_node_t *node)
+{
+       unsigned     bucket_len = node_bucket_get_length(*bucket);
+       unsigned     node_index;
+       pbqp_node_t *other;
+
+       assert(node);
+       assert(node_bucket_contains(*bucket, node));
+       assert(bucket_len > 0);
+
+       node_index            = node->bucket_index;
+       other                 = (*bucket)[bucket_len - 1];
+       other->bucket_index   = node_index;
+       (*bucket)[node_index] = other;
+
+       ARR_SHRINKLEN(*bucket, (int)bucket_len - 1);
+       node->bucket_index = UINT_MAX;
+}
+
+void node_bucket_deep_copy(pbqp_t *pbqp, pbqp_node_bucket_t *dst,
+                           pbqp_node_bucket_t src)
+{
+       unsigned bucket_index;
+       unsigned bucket_length;
+
+       bucket_length = node_bucket_get_length(src);
+
+       for (bucket_index = 0; bucket_index < bucket_length; ++bucket_index) {
+               node_bucket_insert(dst, pbqp_node_deep_copy(pbqp, *dst, src[bucket_index]));
+       }
+}
diff --git a/ir/kaps/bucket.h b/ir/kaps/bucket.h
new file mode 100644 (file)
index 0000000..fd0d92e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Buckets for nodes and edges.
+ * @date    30.11.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_BUCKET_H
+#define KAPS_BUCKET_H
+
+#include "bucket_t.h"
+
+int edge_bucket_contains(pbqp_edge_bucket_t bucket, pbqp_edge_t *edge);
+void edge_bucket_free(pbqp_edge_bucket_t *bucket);
+unsigned edge_bucket_get_length(pbqp_edge_bucket_t bucket);
+void edge_bucket_init(pbqp_edge_bucket_t *bucket);
+void edge_bucket_insert(pbqp_edge_bucket_t *bucket, pbqp_edge_t *edge);
+pbqp_edge_t *edge_bucket_pop(pbqp_edge_bucket_t *bucket);
+
+int node_bucket_contains(pbqp_node_bucket_t bucket, pbqp_node_t *node);
+void node_bucket_copy(pbqp_node_bucket_t *dst, pbqp_node_bucket_t src);
+void node_bucket_deep_copy(pbqp_t *pbqp, pbqp_node_bucket_t *dst, pbqp_node_bucket_t src);
+void node_bucket_free(pbqp_node_bucket_t *bucket);
+unsigned node_bucket_get_length(pbqp_node_bucket_t bucket);
+void node_bucket_init(pbqp_node_bucket_t *bucket);
+void node_bucket_insert(pbqp_node_bucket_t *bucket, pbqp_node_t *node);
+pbqp_node_t *node_bucket_pop(pbqp_node_bucket_t *bucket);
+void node_bucket_remove(pbqp_node_bucket_t *bucket, pbqp_node_t *node);
+void node_bucket_shrink(pbqp_node_bucket_t *bucket, unsigned len);
+void node_bucket_update(pbqp_t *pbqp, pbqp_node_bucket_t bucket);
+
+#endif /* KAPS_BUCKET_H */
diff --git a/ir/kaps/bucket_t.h b/ir/kaps/bucket_t.h
new file mode 100644 (file)
index 0000000..df9cce5
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Node/edge bucket data types.
+ * @date    30.11.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_BUCKET_T_H
+#define KAPS_BUCKET_T_H
+
+#include "pbqp_t.h"
+
+typedef pbqp_node_t** pbqp_node_bucket_t;
+typedef pbqp_edge_t** pbqp_edge_bucket_t;
+
+#endif /* KAPS_BUCKET_T_H */
diff --git a/ir/kaps/heuristical.c b/ir/kaps/heuristical.c
new file mode 100644 (file)
index 0000000..c078f5d
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Heuristic PBQP solver.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+#include "error.h"
+
+#include "bucket.h"
+#include "heuristical.h"
+#include "optimal.h"
+#if    KAPS_DUMP
+#include "html_dumper.h"
+#endif
+#include "kaps.h"
+#include "matrix.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+#include "timing.h"
+
+static void apply_RN(pbqp_t *pbqp)
+{
+       pbqp_node_t *node      = NULL;
+       unsigned     min_index = 0;
+
+       assert(pbqp);
+
+       /* We want to reduce a node with maximum degree. */
+       node = get_node_with_max_degree();
+       assert(node);
+       assert(pbqp_node_get_degree(node) > 2);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               char     txt[100];
+               sprintf(txt, "RN-Reduction of Node n%d", node->index);
+               dump_section(pbqp->dump_file, 2, txt);
+               pbqp_dump_graph(pbqp);
+       }
+#endif
+
+       min_index = get_local_minimal_alternative(pbqp, node);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
+                                       node->index, min_index);
+       }
+#endif
+
+#if KAPS_STATISTIC
+       FILE *fh = fopen("solutions.pb", "a");
+       fprintf(fh, "[%u]", min_index);
+       fclose(fh);
+       pbqp->num_rn++;
+#endif
+
+       /* Now that we found the local minimum set all other costs to infinity. */
+       select_alternative(node, min_index);
+}
+
+static void apply_heuristic_reductions(pbqp_t *pbqp)
+{
+       for (;;) {
+               if (edge_bucket_get_length(edge_bucket) > 0) {
+                       apply_edge(pbqp);
+               } else if (node_bucket_get_length(node_buckets[1]) > 0) {
+                       apply_RI(pbqp);
+               } else if (node_bucket_get_length(node_buckets[2]) > 0) {
+                       apply_RII(pbqp);
+               } else if (node_bucket_get_length(node_buckets[3]) > 0) {
+                       apply_RN(pbqp);
+               } else {
+                       return;
+               }
+       }
+}
+
+void solve_pbqp_heuristical(pbqp_t *pbqp)
+{
+       /* Reduce nodes degree ... */
+       initial_simplify_edges(pbqp);
+
+       /* ... and put node into bucket representing their degree. */
+       fill_node_buckets(pbqp);
+
+#if KAPS_STATISTIC
+       FILE *fh = fopen("solutions.pb", "a");
+       fprintf(fh, "Solution");
+       fclose(fh);
+#endif
+
+       apply_heuristic_reductions(pbqp);
+
+       pbqp->solution = determine_solution(pbqp);
+
+#if KAPS_STATISTIC
+       fh = fopen("solutions.pb", "a");
+       #if KAPS_USE_UNSIGNED
+               fprintf(fh, ": %u RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+                               pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+                               pbqp->num_rm, pbqp->num_rn);
+       #else
+               fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+                               pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+                               pbqp->num_rm, pbqp->num_rn);
+       #endif
+       fclose(fh);
+#endif
+
+       /* Solve reduced nodes. */
+       back_propagate(pbqp);
+
+       free_buckets();
+}
diff --git a/ir/kaps/heuristical.h b/ir/kaps/heuristical.h
new file mode 100644 (file)
index 0000000..688b2bf
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Heuristic PBQP solver.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_HEURISTICAL_CO_H
+#define KAPS_HEURISTICAL_CO_H
+
+#include "pbqp_t.h"
+
+void solve_pbqp_heuristical(pbqp_t *pbqp);
+
+#endif /* KAPS_HEURISTICAL_CO_H */
diff --git a/ir/kaps/heuristical_co.c b/ir/kaps/heuristical_co.c
new file mode 100644 (file)
index 0000000..aa30729
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Heuristic PBQP solver for SSA-based register allocation.
+ * @date    18.09.2009
+ * @author  Thomas Bersch
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+#include "error.h"
+
+#include "bucket.h"
+#include "heuristical_co.h"
+#include "optimal.h"
+#if    KAPS_DUMP
+#include "html_dumper.h"
+#endif
+#include "kaps.h"
+#include "matrix.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+#include "plist.h"
+#include "timing.h"
+
+static void merge_into_RN_node(pbqp_t *pbqp, plist_t *rpeo)
+{
+       pbqp_node_t *node = NULL;
+
+       assert(pbqp);
+
+       /* We want to reduce the first node in reverse perfect elimination order. */
+       do {
+               /* get first element from reverse perfect elimination order */
+               node = (pbqp_node_t*)plist_first(rpeo)->data;
+               /* remove element from reverse perfect elimination order */
+               plist_erase(rpeo, plist_first(rpeo));
+               /* insert node at the end of rpeo so the rpeo already exits after pbqp solving */
+               plist_insert_back(rpeo, node);
+       } while(node_is_reduced(node));
+
+       assert(node);
+       assert(pbqp_node_get_degree(node) > 2);
+
+       /* Check whether we can merge a neighbor into the current node. */
+       apply_RM(pbqp, node);
+}
+
+static void apply_RN_co(pbqp_t *pbqp)
+{
+       pbqp_node_t *node;
+       unsigned     min_index;
+
+       assert(pbqp);
+
+       node        = merged_node;
+       merged_node = NULL;
+       assert(node);
+
+       if (node_is_reduced(node))
+               return;
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               char     txt[100];
+               sprintf(txt, "RN-Reduction of Node n%d", node->index);
+               dump_section(pbqp->dump_file, 2, txt);
+               pbqp_dump_graph(pbqp);
+       }
+#endif
+
+       min_index = get_local_minimal_alternative(pbqp, node);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
+                                       node->index, min_index);
+       }
+#endif
+
+#if KAPS_STATISTIC
+               FILE *fh = fopen("solutions.pb", "a");
+               fprintf(fh, "[%u]", min_index);
+               fclose(fh);
+               pbqp->num_rn++;
+#endif
+
+       /* Now that we found the local minimum set all other costs to infinity. */
+       select_alternative(node, min_index);
+}
+
+static void apply_heuristic_reductions_co(pbqp_t *pbqp, plist_t *rpeo)
+{
+       #if KAPS_TIMING
+               /* create timers */
+               ir_timer_t *t_edge = ir_timer_new();
+               ir_timer_t *t_r1   = ir_timer_new();
+               ir_timer_t *t_r2   = ir_timer_new();
+               ir_timer_t *t_rn   = ir_timer_new();
+       #endif
+
+       for (;;) {
+               if (edge_bucket_get_length(edge_bucket) > 0) {
+                       #if KAPS_TIMING
+                               ir_timer_start(t_edge);
+                       #endif
+
+                       apply_edge(pbqp);
+
+                       #if KAPS_TIMING
+                               ir_timer_stop(t_edge);
+                       #endif
+               } else if (node_bucket_get_length(node_buckets[1]) > 0) {
+                       #if KAPS_TIMING
+                               ir_timer_start(t_r1);
+                       #endif
+
+                       apply_RI(pbqp);
+
+                       #if KAPS_TIMING
+                               ir_timer_stop(t_r1);
+                       #endif
+               } else if (node_bucket_get_length(node_buckets[2]) > 0) {
+                       #if KAPS_TIMING
+                               ir_timer_start(t_r2);
+                       #endif
+
+                       apply_RII(pbqp);
+
+                       #if KAPS_TIMING
+                               ir_timer_stop(t_r2);
+                       #endif
+               } else if (merged_node != NULL) {
+                       #if KAPS_TIMING
+                               ir_timer_start(t_rn);
+                       #endif
+
+                       apply_RN_co(pbqp);
+
+                       #if KAPS_TIMING
+                               ir_timer_stop(t_rn);
+                       #endif
+               } else if (node_bucket_get_length(node_buckets[3]) > 0) {
+                       #if KAPS_TIMING
+                               ir_timer_start(t_rn);
+                       #endif
+
+                       merge_into_RN_node(pbqp, rpeo);
+
+                       #if KAPS_TIMING
+                               ir_timer_stop(t_rn);
+                       #endif
+               } else {
+                       #if KAPS_TIMING
+                               printf("PBQP RE reductions:           %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_edge) / 1000.0);
+                               printf("PBQP R1 reductions:           %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_r1) / 1000.0);
+                               printf("PBQP R2 reductions:           %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_r2) / 1000.0);
+                               printf("PBQP RN reductions:           %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_rn) / 1000.0);
+                       #endif
+
+                       return;
+               }
+       }
+}
+
+void solve_pbqp_heuristical_co(pbqp_t *pbqp, plist_t *rpeo)
+{
+       /* Reduce nodes degree ... */
+       initial_simplify_edges(pbqp);
+
+       /* ... and put node into bucket representing their degree. */
+       fill_node_buckets(pbqp);
+
+       #if KAPS_STATISTIC
+               FILE *fh = fopen("solutions.pb", "a");
+               fprintf(fh, "Solution");
+               fclose(fh);
+       #endif
+
+       apply_heuristic_reductions_co(pbqp, rpeo);
+
+       pbqp->solution = determine_solution(pbqp);
+
+       #if KAPS_STATISTIC
+               fh = fopen("solutions.pb", "a");
+               #if KAPS_USE_UNSIGNED
+                       fprintf(fh, ": %u RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+                                       pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+                                       pbqp->num_rm, pbqp->num_rn);
+               #else
+                       fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+                                       pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+               #endif
+               fclose(fh);
+       #endif
+
+       /* Solve reduced nodes. */
+       back_propagate(pbqp);
+
+       free_buckets();
+}
diff --git a/ir/kaps/heuristical_co.h b/ir/kaps/heuristical_co.h
new file mode 100644 (file)
index 0000000..2872edc
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Heuristic PBQP solver for SSA-based register allocation.
+ * @date    18.09.2009
+ * @author  Thomas Bersch
+ * @version $Id$
+ */
+#ifndef KAPS_HEURISTICAL_H
+#define KAPS_HEURISTICAL_H
+
+#include "pbqp_t.h"
+
+#include "plist.h"
+
+void solve_pbqp_heuristical_co(pbqp_t *pbqp, plist_t *rpeo);
+
+#endif /* KAPS_HEURISTICAL_H */
diff --git a/ir/kaps/heuristical_co_ld.c b/ir/kaps/heuristical_co_ld.c
new file mode 100644 (file)
index 0000000..ba694f9
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * heuristical_co_ld.c
+ *
+ *  Created on: 06.05.2010
+ *      Author: berschth
+ */
+
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+#include "error.h"
+
+#include "bucket.h"
+#include "heuristical_co_ld.h"
+#include "optimal.h"
+#if    KAPS_DUMP
+#include "html_dumper.h"
+#endif
+#include "kaps.h"
+#include "matrix.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+#include "plist.h"
+#include "timing.h"
+
+static void back_propagate_RI(pbqp_t *pbqp, pbqp_node_t *node)
+{
+       pbqp_edge_t   *edge;
+       pbqp_node_t   *other;
+       pbqp_matrix_t *mat;
+       vector_t      *vec;
+       int            is_src;
+
+       assert(pbqp);
+       assert(node);
+
+       (void) pbqp;
+
+       edge = node->edges[0];
+       mat = edge->costs;
+       is_src = edge->src == node;
+       vec = node->costs;
+
+       if (is_src) {
+               other = edge->tgt;
+               assert(other);
+
+               node->solution = pbqp_matrix_get_col_min_index(mat, other->solution, vec);
+       } else {
+               other = edge->src;
+               assert(other);
+
+               node->solution = pbqp_matrix_get_row_min_index(mat, other->solution, vec);
+       }
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+       }
+#endif
+}
+
+static void back_propagate_RII(pbqp_t *pbqp, pbqp_node_t *node)
+{
+       pbqp_edge_t   *src_edge   = node->edges[0];
+       pbqp_edge_t   *tgt_edge   = node->edges[1];
+       int            src_is_src = src_edge->src == node;
+       int            tgt_is_src = tgt_edge->src == node;
+       pbqp_matrix_t *src_mat;
+       pbqp_matrix_t *tgt_mat;
+       pbqp_node_t   *src_node;
+       pbqp_node_t   *tgt_node;
+       vector_t      *vec;
+       vector_t      *node_vec;
+       unsigned       col_index;
+       unsigned       row_index;
+
+       assert(pbqp);
+
+       if (src_is_src) {
+               src_node = src_edge->tgt;
+       } else {
+               src_node = src_edge->src;
+       }
+
+       if (tgt_is_src) {
+               tgt_node = tgt_edge->tgt;
+       } else {
+               tgt_node = tgt_edge->src;
+       }
+
+       /* Swap nodes if necessary. */
+       if (tgt_node->index < src_node->index) {
+               pbqp_node_t *tmp_node;
+               pbqp_edge_t *tmp_edge;
+
+               tmp_node = src_node;
+               src_node = tgt_node;
+               tgt_node = tmp_node;
+
+               tmp_edge = src_edge;
+               src_edge = tgt_edge;
+               tgt_edge = tmp_edge;
+
+               src_is_src = src_edge->src == node;
+               tgt_is_src = tgt_edge->src == node;
+       }
+
+       src_mat = src_edge->costs;
+       tgt_mat = tgt_edge->costs;
+
+       node_vec = node->costs;
+
+       row_index = src_node->solution;
+       col_index = tgt_node->solution;
+
+       vec = vector_copy(pbqp, node_vec);
+
+       if (src_is_src) {
+               vector_add_matrix_col(vec, src_mat, row_index);
+       } else {
+               vector_add_matrix_row(vec, src_mat, row_index);
+       }
+
+       if (tgt_is_src) {
+               vector_add_matrix_col(vec, tgt_mat, col_index);
+       } else {
+               vector_add_matrix_row(vec, tgt_mat, col_index);
+       }
+
+       node->solution = vector_get_min_index(vec);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+       }
+#endif
+
+       obstack_free(&pbqp->obstack, vec);
+}
+
+static void back_propagate_RN(pbqp_t *pbqp, pbqp_node_t *node)
+{
+       vector_t    *vec        = NULL;
+       pbqp_node_t *neighbor   = NULL;
+       pbqp_edge_t *edge       = NULL;
+       unsigned     edge_index = 0;
+
+       assert(pbqp);
+
+       vec = vector_copy(pbqp, node->costs);
+
+       for(edge_index = 0; edge_index < pbqp_node_get_degree(node); edge_index++) {
+               /* get neighbor node */
+               edge = node->edges[edge_index];
+               neighbor = edge->src == node ? edge->tgt : edge->src;
+
+               /* node is edge src node */
+               if(edge->src == node)
+                       vector_add_matrix_col(vec, edge->costs, neighbor->solution);
+               /* node is edge tgt node */
+               else
+                       vector_add_matrix_row(vec, edge->costs, neighbor->solution);
+       }
+
+       assert(vector_get_min(vec) != INF_COSTS);
+       node->solution = vector_get_min_index(vec);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+       }
+#endif
+
+       obstack_free(&pbqp->obstack, vec);
+}
+
+static void back_propagate_ld(pbqp_t *pbqp)
+{
+       unsigned node_index;
+       unsigned node_len   = node_bucket_get_length(reduced_bucket);
+
+       assert(pbqp);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               dump_section(pbqp->dump_file, 2, "Back Propagation");
+       }
+#endif
+
+       for (node_index = node_len; node_index > 0; --node_index) {
+               pbqp_node_t *node = reduced_bucket[node_index - 1];
+
+               switch (pbqp_node_get_degree(node)) {
+                       case 1:
+                               back_propagate_RI(pbqp, node);
+                               break;
+                       case 2:
+                               back_propagate_RII(pbqp, node);
+                               break;
+                       default:
+                               back_propagate_RN(pbqp, node);
+                               break;
+               }
+       }
+}
+
+static void merge_into_RN_node(pbqp_t *pbqp, plist_t *rpeo)
+{
+       pbqp_node_t *node = NULL;
+
+       assert(pbqp);
+
+       do {
+               /* get last element from reverse perfect elimination order */
+               node = (pbqp_node_t*)plist_last(rpeo)->data;
+               /* remove element from reverse perfect elimination order */
+               plist_erase(rpeo, plist_last(rpeo));
+               /* insert node at the beginning of rpeo so the rpeo already exits after pbqp solving */
+               plist_insert_front(rpeo, node);
+       } while(node_is_reduced(node));
+
+       assert(node);
+       assert(pbqp_node_get_degree(node) > 2);
+
+       /* Check whether we can merge a neighbor into the current node. */
+       apply_RM(pbqp, node);
+}
+
+static void apply_RN_co_without_selection(pbqp_t *pbqp)
+{
+       pbqp_node_t *node;
+       unsigned     edge_index;
+
+       assert(pbqp);
+
+       node        = merged_node;
+       merged_node = NULL;
+       assert(node);
+
+       if (node_is_reduced(node))
+               return;
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               char     txt[100];
+               sprintf(txt, "RN-Reduction of Node n%d", node->index);
+               dump_section(pbqp->dump_file, 2, txt);
+               pbqp_dump_graph(pbqp);
+       }
+#endif
+
+       /* Disconnect neighbor nodes */
+       for(edge_index = 0; edge_index < pbqp_node_get_degree(node); edge_index++) {
+               pbqp_edge_t *edge;
+               pbqp_node_t *neighbor;
+
+               /* get neighbor node */
+               edge = node->edges[edge_index];
+               assert(edge);
+
+               neighbor = edge->src == node ? edge->tgt : edge->src;
+               assert(neighbor);
+
+               assert(neighbor != node);
+
+               if(!is_connected(neighbor, edge))
+                       continue;
+
+               disconnect_edge(neighbor, edge);
+               reorder_node_after_edge_deletion(neighbor);
+       }
+
+       /* Remove node from old bucket */
+       node_bucket_remove(&node_buckets[3], node);
+
+       /* Add node to back propagation list. */
+       node_bucket_insert(&reduced_bucket, node);
+}
+
+static void apply_heuristic_reductions_co(pbqp_t *pbqp, plist_t *rpeo)
+{
+       #if KAPS_TIMING
+               /* create timers */
+               ir_timer_t *t_edge = ir_timer_new();
+               ir_timer_t *t_r1   = ir_timer_new();
+               ir_timer_t *t_r2   = ir_timer_new();
+               ir_timer_t *t_rn   = ir_timer_new();
+       #endif
+
+       for (;;) {
+               if (edge_bucket_get_length(edge_bucket) > 0) {
+                       #if KAPS_TIMING
+                               ir_timer_start(t_edge);
+                       #endif
+
+                       apply_edge(pbqp);
+
+                       #if KAPS_TIMING
+                               ir_timer_stop(t_edge);
+                       #endif
+               } else if (node_bucket_get_length(node_buckets[1]) > 0) {
+                       #if KAPS_TIMING
+                               ir_timer_start(t_r1);
+                       #endif
+
+                       apply_RI(pbqp);
+
+                       #if KAPS_TIMING
+                               ir_timer_stop(t_r1);
+                       #endif
+               } else if (node_bucket_get_length(node_buckets[2]) > 0) {
+                       #if KAPS_TIMING
+                               ir_timer_start(t_r2);
+                       #endif
+
+                       apply_RII(pbqp);
+
+                       #if KAPS_TIMING
+                               ir_timer_stop(t_r2);
+                       #endif
+               } else if (merged_node != NULL) {
+                       #if KAPS_TIMING
+                               ir_timer_start(t_rn);
+                       #endif
+
+                       apply_RN_co_without_selection(pbqp);
+
+                       #if KAPS_TIMING
+                               ir_timer_stop(t_rn);
+                       #endif
+               } else if (node_bucket_get_length(node_buckets[3]) > 0) {
+                       #if KAPS_TIMING
+                               ir_timer_start(t_rn);
+                       #endif
+
+                       merge_into_RN_node(pbqp, rpeo);
+
+                       #if KAPS_TIMING
+                               ir_timer_stop(t_rn);
+                       #endif
+               } else {
+                       #if KAPS_TIMING
+                               printf("PBQP RE reductions:           %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_edge) / 1000.0);
+                               printf("PBQP R1 reductions:           %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_r1) / 1000.0);
+                               printf("PBQP R2 reductions:           %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_r2) / 1000.0);
+                               printf("PBQP RN reductions:           %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_rn) / 1000.0);
+                       #endif
+
+                       return;
+               }
+       }
+}
+
+void solve_pbqp_heuristical_co_ld(pbqp_t *pbqp, plist_t *rpeo)
+{
+       /* Reduce nodes degree ... */
+       initial_simplify_edges(pbqp);
+
+       /* ... and put node into bucket representing their degree. */
+       fill_node_buckets(pbqp);
+
+       #if KAPS_STATISTIC
+               FILE *fh = fopen("solutions.pb", "a");
+               fprintf(fh, "Solution");
+               fclose(fh);
+       #endif
+
+       apply_heuristic_reductions_co(pbqp, rpeo);
+
+       pbqp->solution = determine_solution(pbqp);
+
+       #if KAPS_STATISTIC
+               fh = fopen("solutions.pb", "a");
+               #if KAPS_USE_UNSIGNED
+                       fprintf(fh, ": %u RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+                                       pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+                                       pbqp->num_rm, pbqp->num_rn);
+               #else
+                       fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+                                       pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+                                       pbqp->num_rm, pbqp->num_rn);
+               #endif
+               fclose(fh);
+       #endif
+
+       /* Solve reduced nodes. */
+       back_propagate_ld(pbqp);
+
+       free_buckets();
+}
diff --git a/ir/kaps/heuristical_co_ld.h b/ir/kaps/heuristical_co_ld.h
new file mode 100644 (file)
index 0000000..097fe3b
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * heuristical_co_ld.h
+ *
+ *  Created on: 06.05.2010
+ *      Author: berschth
+ */
+
+#ifndef HEURISTICAL_CO_LD_H_
+#define HEURISTICAL_CO_LD_H_
+
+#include "pbqp_t.h"
+#include "plist.h"
+
+void solve_pbqp_heuristical_co_ld(pbqp_t *pbqp, plist_t *rpeo);
+
+#endif /* HEURISTICAL_CO_LD_H_ */
diff --git a/ir/kaps/html_dumper.c b/ir/kaps/html_dumper.c
new file mode 100644 (file)
index 0000000..93d0fd1
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   HTML dumper for PBQP.
+ * @date    03.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+
+#include "pbqp_edge_t.h"
+#include "pbqp_node_t.h"
+#include "optimal.h"
+#include "html_dumper.h"
+#include "kaps.h"
+
+/* Caution: Due to static buffer use only once per statement */
+static const char *cost2a(num const cost)
+{
+       static char buf[10];
+
+       if (cost == INF_COSTS) return "inf";
+#if KAPS_USE_UNSIGNED
+       sprintf(buf, "%u", cost);
+#else
+       sprintf(buf, "%10lld", cost);
+#endif
+       return buf;
+}
+
+/* print vector */
+static void dump_vector(FILE *f, vector_t *vec)
+{
+       unsigned index;
+       assert(vec);
+
+       fprintf(f, "<span class=\"vector\">( ");
+       unsigned len = vec->len;
+       assert(len > 0);
+       for (index = 0; index < len; ++index) {
+#if KAPS_ENABLE_VECTOR_NAMES
+               fprintf(f, "<span title=\"%s\">%s</span> ",
+                               vec->entries[index].name, cost2a(vec->entries[index].data));
+#else
+               fprintf(f, "%s ", cost2a(vec->entries[index].data));
+#endif
+       }
+       fprintf(f, " )</span>\n");
+}
+
+static void dump_matrix(FILE *f, pbqp_matrix_t *mat)
+{
+       unsigned row, col;
+       assert(mat);
+       num *p = mat->entries;
+
+       assert(mat->cols> 0);
+       assert(mat->rows> 0);
+       fprintf(f, "\t\\begin{pmatrix}\n");
+       for (row = 0; row < mat->rows; ++row) {
+               fprintf(f, "\t %s", cost2a(*p++));
+
+               for (col = 1; col < mat->cols; ++col) {
+                       fprintf(f, "& %s", cost2a(*p++));
+               }
+               fprintf(f, "\\\\\n");
+       }
+       fprintf(f, "\t\\end{pmatrix}\n");
+}
+
+void dump_edge(FILE *file, pbqp_edge_t *edge)
+{
+       fputs("<tex>\n", file);
+       fprintf(file, "\t\\overline\n{C}_{%d,%d}=\n",
+                       edge->src->index, edge->tgt->index);
+       dump_matrix(file, edge->costs);
+       fputs("</tex><br>", file);
+}
+
+static void dump_edge_costs(pbqp_t *pbqp)
+{
+       unsigned src_index;
+
+       assert(pbqp);
+       assert(pbqp->dump_file);
+
+       fputs("<p>", pbqp->dump_file);
+       for (src_index = 0; src_index < pbqp->num_nodes; ++src_index) {
+               pbqp_node_t *src_node = get_node(pbqp, src_index);
+
+               if (!src_node)
+                       continue;
+
+               unsigned edge_index;
+               unsigned len = ARR_LEN(src_node->edges);
+               for (edge_index = 0; edge_index < len; ++edge_index) {
+                       pbqp_edge_t *edge      = src_node->edges[edge_index];
+                       unsigned     tgt_index = edge->tgt->index;
+                       if (src_index < tgt_index) {
+                               dump_edge(pbqp->dump_file, edge);
+                       }
+               }
+       }
+       fputs("</p>", pbqp->dump_file);
+}
+
+void dump_node(FILE *file, pbqp_node_t *node)
+{
+       assert(file);
+
+       if (node) {
+               fprintf(file, "\tc<sub>%d</sub> = ", node->index);
+               dump_vector(file, node->costs);
+               fputs("<br>\n", file);
+       }
+}
+
+static void dump_node_costs(pbqp_t *pbqp)
+{
+       unsigned index;
+
+       assert(pbqp);
+       assert(pbqp->dump_file);
+
+       /* dump node costs */
+       fputs("<p>", pbqp->dump_file);
+       for (index = 0; index < pbqp->num_nodes; ++index) {
+               dump_node(pbqp->dump_file, get_node(pbqp, index));
+       }
+       fputs("</p>", pbqp->dump_file);
+}
+
+void dump_section(FILE *f, int level, const char *txt)
+{
+       assert(f);
+
+       fprintf(f, "<h%d>%s</h%d>\n", level, txt, level);
+}
+
+void pbqp_dump_graph(pbqp_t *pbqp)
+{
+       unsigned src_index;
+
+       assert(pbqp);
+       assert(pbqp->dump_file);
+
+       fputs("<p>\n<graph>\n\tgraph input {\n", pbqp->dump_file);
+       for (src_index = 0; src_index < pbqp->num_nodes; ++src_index) {
+               pbqp_node_t *node = get_node(pbqp, src_index);
+               if (node && !node_is_reduced(node)) {
+                       fprintf(pbqp->dump_file, "\t n%d;\n", src_index);
+               }
+       }
+
+       for (src_index = 0; src_index < pbqp->num_nodes; ++src_index) {
+               pbqp_node_t *node = get_node(pbqp, src_index);
+
+               if (!node)
+                       continue;
+
+               if (node_is_reduced(node))
+                       continue;
+
+               unsigned len = ARR_LEN(node->edges);
+               unsigned edge_index;
+               for (edge_index = 0; edge_index < len; ++edge_index) {
+                       pbqp_node_t *tgt_node  = node->edges[edge_index]->tgt;
+                       unsigned     tgt_index = tgt_node->index;
+
+                       if (node_is_reduced(tgt_node))
+                               continue;
+
+                       if (src_index < tgt_index) {
+                               fprintf(pbqp->dump_file, "\t n%d -- n%d;\n", src_index,
+                                               tgt_index);
+                       }
+               }
+       }
+       fputs("\t}\n</graph>\n</p>\n", pbqp->dump_file);
+}
+
+void pbqp_dump_input(pbqp_t *pbqp)
+{
+       assert(pbqp);
+       assert(pbqp->dump_file);
+
+       dump_section(pbqp->dump_file, 1, "1. PBQP Problem");
+       dump_section(pbqp->dump_file, 2, "1.1 Topology");
+       pbqp_dump_graph(pbqp);
+       dump_section(pbqp->dump_file, 2, "1.2 Cost Vectors");
+       dump_node_costs(pbqp);
+       dump_section(pbqp->dump_file, 2, "1.3 Cost Matrices");
+       dump_edge_costs(pbqp);
+}
+
+void dump_simplifyedge(pbqp_t *pbqp, pbqp_edge_t *edge)
+{
+       assert(pbqp);
+       assert(pbqp->dump_file);
+
+       dump_node(pbqp->dump_file, edge->src);
+       dump_edge(pbqp->dump_file, edge);
+       dump_node(pbqp->dump_file, edge->tgt);
+}
diff --git a/ir/kaps/html_dumper.h b/ir/kaps/html_dumper.h
new file mode 100644 (file)
index 0000000..7f0ac06
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   HTML dumper for PBQP.
+ * @date    03.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_HTML_DUMPER_H
+#define KAPS_HTML_DUMPER_H
+
+#include "pbqp_t.h"
+
+void pbqp_dump_input(pbqp_t *pbqp);
+
+void pbqp_dump_graph(pbqp_t *pbqp);
+
+void dump_simplifyedge(pbqp_t *pbqp, pbqp_edge_t *edge);
+
+void dump_section(FILE *f, int level, const char *txt);
+
+void dump_node(FILE *file, pbqp_node_t *node);
+void dump_edge(FILE *file, pbqp_edge_t *edge);
+
+#endif /* KAPS_HTML_DUMPER_H */
diff --git a/ir/kaps/kaps.c b/ir/kaps/kaps.c
new file mode 100644 (file)
index 0000000..8bbbd93
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Partitioned Boolean Quadratic Problem (PBQP) solver.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "adt/xmalloc.h"
+
+#include "kaps.h"
+#include "matrix.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+pbqp_node_t *get_node(pbqp_t *pbqp, unsigned index)
+{
+       return pbqp->nodes[index];
+}
+
+pbqp_edge_t *get_edge(pbqp_t *pbqp, unsigned src_index, unsigned tgt_index)
+{
+       int i;
+       int len;
+
+       if (tgt_index < src_index) {
+               unsigned tmp = src_index;
+               src_index    = tgt_index;
+               tgt_index    = tmp;
+       }
+
+       pbqp_node_t *src_node = get_node(pbqp, src_index);
+       pbqp_node_t *tgt_node = get_node(pbqp, tgt_index);
+       assert(src_node);
+       assert(tgt_node);
+
+       len = ARR_LEN(src_node->edges);
+
+       for (i = 0; i < len; ++i) {
+               pbqp_edge_t *cur_edge = src_node->edges[i];
+               if (cur_edge->tgt == tgt_node) {
+                       return cur_edge;
+               }
+       }
+
+       return NULL;
+}
+
+pbqp_t *alloc_pbqp(unsigned number_nodes)
+{
+       pbqp_t *pbqp = XMALLOC(pbqp_t);
+
+       obstack_init(&pbqp->obstack);
+
+       pbqp->solution = 0;
+       pbqp->num_nodes = number_nodes;
+#if    KAPS_DUMP
+       pbqp->dump_file = NULL;
+#endif
+       pbqp->nodes = OALLOCNZ(&pbqp->obstack, pbqp_node_t*, number_nodes);
+#if KAPS_STATISTIC
+       pbqp->num_bf = 0;
+       pbqp->num_edges = 0;
+       pbqp->num_r0 = 0;
+       pbqp->num_r1 = 0;
+       pbqp->num_r2 = 0;
+       pbqp->num_rm = 0;
+       pbqp->num_rn = 0;
+#endif
+
+       return pbqp;
+}
+
+void free_pbqp(pbqp_t *pbqp)
+{
+       obstack_free(&pbqp->obstack, NULL);
+       xfree(pbqp);
+}
+
+void add_node_costs(pbqp_t *pbqp, unsigned node_index, vector_t *costs)
+{
+       pbqp_node_t *node = get_node(pbqp, node_index);
+
+       if (node == NULL) {
+               node = alloc_node(pbqp, node_index, costs);
+               pbqp->nodes[node_index] = node;
+       } else {
+               vector_add(node->costs, costs);
+       }
+}
+
+void add_edge_costs(pbqp_t *pbqp, unsigned src_index, unsigned tgt_index,
+                    pbqp_matrix_t *costs)
+{
+       pbqp_edge_t *edge = get_edge(pbqp, src_index, tgt_index);
+
+       if (tgt_index < src_index) {
+               pbqp_matrix_transpose(pbqp, costs);
+               add_edge_costs(pbqp, tgt_index, src_index, costs);
+               return;
+       }
+
+       if (edge == NULL) {
+               edge = alloc_edge(pbqp, src_index, tgt_index, costs);
+       } else {
+               pbqp_matrix_add(edge->costs, costs);
+       }
+}
+
+num get_node_solution(pbqp_t *pbqp, unsigned node_index)
+{
+       pbqp_node_t *node = get_node(pbqp, node_index);
+       assert(node);
+
+       return node->solution;
+}
+
+num get_solution(pbqp_t *pbqp)
+{
+       return pbqp->solution;
+}
+
+#if    KAPS_DUMP
+void set_dumpfile(pbqp *pbqp, FILE *f)
+{
+       assert(pbqp);
+       pbqp->dump_file = f;
+}
+#endif
diff --git a/ir/kaps/kaps.h b/ir/kaps/kaps.h
new file mode 100644 (file)
index 0000000..c9097aa
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Partitioned Boolean Quadratic Problem (PBQP) solver.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_KAPS_H
+#define KAPS_KAPS_H
+
+#include "pbqp_t.h"
+
+/**
+ * Create an empty PBQP instance with the given number of nodes.
+ */
+pbqp_t* alloc_pbqp(unsigned number_nodes);
+
+/**
+ * Free the given PBQP.
+ */
+void free_pbqp(pbqp_t *pbqp);
+
+/**
+ * Add costs vector to given node.
+ */
+void add_node_costs(pbqp_t *pbqp, unsigned node_index, vector_t *costs);
+
+/**
+ * Add costs matrix between given nodes.
+ */
+void add_edge_costs(pbqp_t *pbqp, unsigned src_index, unsigned tgt_index,
+                    pbqp_matrix_t *costs);
+
+pbqp_edge_t *get_edge(pbqp_t *pbqp, unsigned src_index, unsigned tgt_index);
+pbqp_node_t *get_node(pbqp_t *pbqp, unsigned index);
+
+num get_node_solution(pbqp_t *pbqp, unsigned node_index);
+num get_solution(pbqp_t *pbqp);
+
+void set_dumpfile(pbqp_t *pbqp, FILE *f);
+
+#endif /* KAPS_KAPS_H */
diff --git a/ir/kaps/matrix.c b/ir/kaps/matrix.c
new file mode 100644 (file)
index 0000000..8608057
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP matrix.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "pbqp_t.h"
+#include "vector.h"
+#include "matrix.h"
+
+pbqp_matrix_t *pbqp_matrix_alloc(pbqp_t *pbqp, unsigned rows, unsigned cols)
+{
+       assert(cols> 0);
+       assert(rows> 0);
+
+       unsigned length = rows * cols;
+
+       pbqp_matrix_t *mat = (pbqp_matrix_t*)obstack_alloc(&pbqp->obstack, sizeof(*mat) + sizeof(*mat->entries) * length);
+       assert(mat);
+
+       mat->cols = cols;
+       mat->rows = rows;
+       memset(mat->entries, 0, sizeof(*mat->entries) * length);
+
+       return mat;
+}
+
+pbqp_matrix_t *pbqp_matrix_copy(pbqp_t *pbqp, pbqp_matrix_t *m)
+{
+       unsigned       len  = m->rows * m->cols;
+       pbqp_matrix_t *copy = (pbqp_matrix_t*)obstack_copy(&pbqp->obstack, m, sizeof(*copy) + sizeof(*copy->entries) * len);
+       assert(copy);
+
+       return copy;
+}
+
+pbqp_matrix_t *pbqp_matrix_copy_and_transpose(pbqp_t *pbqp, pbqp_matrix_t *m)
+{
+       unsigned       i;
+       unsigned       j;
+       unsigned       cols = m->cols;
+       unsigned       rows = m->rows;
+       unsigned       len  = rows * cols;
+       pbqp_matrix_t *copy = (pbqp_matrix_t*)obstack_alloc(&pbqp->obstack, sizeof(*copy) + sizeof(*copy->entries) * len);
+       assert(copy);
+
+       for (i = 0; i < rows; ++i) {
+               for (j = 0; j < cols; ++j) {
+                       copy->entries[j*rows+i] = m->entries[i*cols+j];
+               }
+       }
+
+       copy->cols = rows;
+       copy->rows = cols;
+
+       return copy;
+}
+
+void pbqp_matrix_transpose(pbqp_t *pbqp, pbqp_matrix_t *mat)
+{
+       unsigned len;
+
+       assert(mat);
+       len = mat->rows * mat->cols;
+
+       pbqp_matrix_t *tmp = pbqp_matrix_copy_and_transpose(pbqp, mat);
+
+       memcpy(mat, tmp, sizeof(*mat) + sizeof(*mat->entries) * len);
+
+       obstack_free(&pbqp->obstack, tmp);
+}
+
+void pbqp_matrix_add(pbqp_matrix_t *sum, pbqp_matrix_t *summand)
+{
+       int i;
+       int len;
+
+       assert(sum);
+       assert(summand);
+       assert(sum->cols == summand->cols);
+       assert(sum->rows == summand->rows);
+
+       len = sum->rows * sum->cols;
+
+       for (i = 0; i < len; ++i) {
+               sum->entries[i] = pbqp_add(sum->entries[i], summand->entries[i]);
+       }
+}
+
+void pbqp_matrix_set_col_value(pbqp_matrix_t *mat, unsigned col, num value)
+{
+       unsigned row_index;
+       unsigned row_len;
+
+       assert(mat);
+       assert(col < mat->cols);
+
+       row_len = mat->rows;
+
+       for (row_index = 0; row_index < row_len; ++row_index) {
+               mat->entries[row_index * mat->cols + col] = value;
+       }
+}
+
+void pbqp_matrix_set_row_value(pbqp_matrix_t *mat, unsigned row, num value)
+{
+       unsigned col_index;
+       unsigned col_len;
+
+       assert(mat);
+       assert(row < mat->rows);
+
+       col_len = mat->cols;
+
+       for (col_index = 0; col_index < col_len; ++col_index) {
+               mat->entries[row * mat->cols + col_index] = value;
+       }
+}
+
+void pbqp_matrix_set(pbqp_matrix_t *mat, unsigned row, unsigned col, num value)
+{
+       assert(mat);
+       assert(col < mat->cols);
+       assert(row < mat->rows);
+
+       mat->entries[row * mat->cols + col] = value;
+}
+
+num pbqp_matrix_get_col_min(pbqp_matrix_t *matrix, unsigned col_index, vector_t *flags)
+{
+       unsigned row_index;
+       num min = INF_COSTS;
+
+       assert(matrix);
+       assert(flags);
+       assert(matrix->rows == flags->len);
+
+       unsigned col_len = matrix->cols;
+       unsigned row_len = matrix->rows;
+
+       for (row_index = 0; row_index < row_len; ++row_index) {
+               /* Ignore virtual deleted columns. */
+               if (flags->entries[row_index].data == INF_COSTS) continue;
+
+               num elem = matrix->entries[row_index * col_len + col_index];
+
+               if (elem < min) {
+                       min = elem;
+               }
+       }
+
+       return min;
+}
+
+unsigned pbqp_matrix_get_col_min_index(pbqp_matrix_t *matrix, unsigned col_index, vector_t *flags)
+{
+       unsigned row_index;
+       unsigned min_index = 0;
+       num      min       = INF_COSTS;
+
+       assert(matrix);
+       assert(flags);
+       assert(matrix->rows == flags->len);
+
+       unsigned col_len = matrix->cols;
+       unsigned row_len = matrix->rows;
+
+       for (row_index = 0; row_index < row_len; ++row_index) {
+               /* Ignore virtual deleted columns. */
+               if (flags->entries[row_index].data == INF_COSTS) continue;
+
+               num elem = matrix->entries[row_index * col_len + col_index];
+
+               if (elem < min) {
+                       min = elem;
+                       min_index = row_index;
+               }
+       }
+
+       return min_index;
+}
+
+void pbqp_matrix_sub_col_value(pbqp_matrix_t *matrix, unsigned col_index,
+               vector_t *flags, num value)
+{
+       unsigned col_len;
+       unsigned row_index;
+       unsigned row_len;
+
+       assert(matrix);
+       assert(flags);
+       assert(matrix->rows == flags->len);
+
+       col_len = matrix->cols;
+       row_len = matrix->rows;
+
+       for (row_index = 0; row_index < row_len; ++row_index) {
+               if (flags->entries[row_index].data == INF_COSTS) {
+                       matrix->entries[row_index * col_len + col_index] = 0;
+                       continue;
+               }
+               /* inf - x = inf if x < inf */
+               if (matrix->entries[row_index * col_len + col_index] == INF_COSTS && value
+                               != INF_COSTS)
+                       continue;
+               matrix->entries[row_index * col_len + col_index] -= value;
+       }
+}
+
+num pbqp_matrix_get_row_min(pbqp_matrix_t *matrix, unsigned row_index, vector_t *flags)
+{
+       unsigned col_index;
+       num min = INF_COSTS;
+
+       assert(matrix);
+       assert(flags);
+       assert(matrix->cols == flags->len);
+
+       unsigned len = flags->len;
+
+       for (col_index = 0; col_index < len; ++col_index) {
+               /* Ignore virtual deleted columns. */
+               if (flags->entries[col_index].data == INF_COSTS) continue;
+
+               num elem = matrix->entries[row_index * len + col_index];
+
+               if (elem < min) {
+                       min = elem;
+               }
+       }
+
+       return min;
+}
+
+unsigned pbqp_matrix_get_row_min_index(pbqp_matrix_t *matrix, unsigned row_index, vector_t *flags)
+{
+       unsigned col_index;
+       unsigned min_index = 0;
+       num      min       = INF_COSTS;
+
+       assert(matrix);
+       assert(flags);
+       assert(matrix->cols == flags->len);
+
+       unsigned len = flags->len;
+
+       for (col_index = 0; col_index < len; ++col_index) {
+               /* Ignore virtual deleted columns. */
+               if (flags->entries[col_index].data == INF_COSTS) continue;
+
+               num elem = matrix->entries[row_index * len + col_index];
+
+               if (elem < min) {
+                       min = elem;
+                       min_index = col_index;
+               }
+       }
+
+       return min_index;
+}
+
+void pbqp_matrix_sub_row_value(pbqp_matrix_t *matrix, unsigned row_index,
+               vector_t *flags, num value)
+{
+       unsigned col_index;
+       unsigned col_len;
+
+       assert(matrix);
+       assert(flags);
+       assert(matrix->cols == flags->len);
+
+       col_len = matrix->cols;
+
+       for (col_index = 0; col_index < col_len; ++col_index) {
+               if (flags->entries[col_index].data == INF_COSTS) {
+                       matrix->entries[row_index * col_len + col_index] = 0;
+                       continue;
+               }
+               /* inf - x = inf if x < inf */
+               if (matrix->entries[row_index * col_len + col_index] == INF_COSTS && value
+                               != INF_COSTS)
+                       continue;
+               matrix->entries[row_index * col_len + col_index] -= value;
+       }
+}
+
+int pbqp_matrix_is_zero(pbqp_matrix_t *mat, vector_t *src_vec, vector_t *tgt_vec)
+{
+       unsigned col_index;
+       unsigned col_len;
+       unsigned row_index;
+       unsigned row_len;
+
+       assert(mat);
+       assert(src_vec);
+       assert(tgt_vec);
+       assert(mat->cols = tgt_vec->len);
+       assert(mat->rows = src_vec->len);
+
+       col_len = mat->cols;
+       row_len = mat->rows;
+
+       for (row_index = 0; row_index < row_len; ++row_index) {
+               if (src_vec->entries[row_index].data == INF_COSTS) continue;
+               for (col_index = 0; col_index < col_len; ++col_index) {
+                       if (tgt_vec->entries[col_index].data == INF_COSTS) continue;
+
+                       if (mat->entries[row_index * col_len + col_index] != 0) {
+                               return 0;
+                       }
+               }
+       }
+
+       return 1;
+}
+
+void pbqp_matrix_add_to_all_cols(pbqp_matrix_t *mat, vector_t *vec)
+{
+       unsigned col_index;
+       unsigned col_len;
+       unsigned row_index;
+       unsigned row_len;
+
+       assert(mat);
+       assert(vec);
+       assert(mat->rows == vec->len);
+
+       col_len = mat->cols;
+       row_len = mat->rows;
+
+       for (row_index = 0; row_index < row_len; ++row_index) {
+               num value = vec->entries[row_index].data;
+               for (col_index = 0; col_index < col_len; ++col_index) {
+                       mat->entries[row_index * col_len + col_index] = pbqp_add(
+                                       mat->entries[row_index * col_len + col_index], value);
+               }
+       }
+}
+
+void pbqp_matrix_add_to_all_rows(pbqp_matrix_t *mat, vector_t *vec)
+{
+       unsigned col_index;
+       unsigned col_len;
+       unsigned row_index;
+       unsigned row_len;
+
+       assert(mat);
+       assert(vec);
+       assert(mat->cols == vec->len);
+
+       col_len = mat->cols;
+       row_len = mat->rows;
+
+       for (row_index = 0; row_index < row_len; ++row_index) {
+               for (col_index = 0; col_index < col_len; ++col_index) {
+                       num value = vec->entries[col_index].data;
+
+                       mat->entries[row_index * col_len + col_index] = pbqp_add(mat->entries[row_index * col_len + col_index], value);
+               }
+       }
+}
diff --git a/ir/kaps/matrix.h b/ir/kaps/matrix.h
new file mode 100644 (file)
index 0000000..c87f777
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP matrix.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_MATRIX_H
+#define KAPS_MATRIX_H
+
+#include "matrix_t.h"
+
+pbqp_matrix_t *pbqp_matrix_alloc(pbqp_t *pbqp, unsigned rows, unsigned cols);
+
+/* Copy the given matrix. */
+pbqp_matrix_t *pbqp_matrix_copy(pbqp_t *pbqp, pbqp_matrix_t *m);
+
+pbqp_matrix_t *pbqp_matrix_copy_and_transpose(pbqp_t *pbqp, pbqp_matrix_t *m);
+
+void pbqp_matrix_transpose(pbqp_t *pbqp, pbqp_matrix_t *mat);
+
+/* sum += summand */
+void pbqp_matrix_add(pbqp_matrix_t *sum, pbqp_matrix_t *summand);
+
+void pbqp_matrix_set(pbqp_matrix_t *mat, unsigned row, unsigned col, num value);
+
+num pbqp_matrix_get_col_min(pbqp_matrix_t *matrix, unsigned col_index, vector_t *flags);
+num pbqp_matrix_get_row_min(pbqp_matrix_t *matrix, unsigned row_index, vector_t *flags);
+
+unsigned pbqp_matrix_get_col_min_index(pbqp_matrix_t *matrix, unsigned col_index, vector_t *flags);
+unsigned pbqp_matrix_get_row_min_index(pbqp_matrix_t *matrix, unsigned row_index, vector_t *flags);
+
+void pbqp_matrix_set_col_value(pbqp_matrix_t *mat, unsigned col, num value);
+void pbqp_matrix_set_row_value(pbqp_matrix_t *mat, unsigned row, num value);
+
+void pbqp_matrix_sub_col_value(pbqp_matrix_t *matrix, unsigned col_index,
+                               vector_t *flags, num value);
+void pbqp_matrix_sub_row_value(pbqp_matrix_t *matrix, unsigned row_index,
+                               vector_t *flags, num value);
+
+int pbqp_matrix_is_zero(pbqp_matrix_t *mat, vector_t *src_vec, vector_t *tgt_vec);
+
+void pbqp_matrix_add_to_all_cols(pbqp_matrix_t *mat, vector_t *vec);
+void pbqp_matrix_add_to_all_rows(pbqp_matrix_t *mat, vector_t *vec);
+
+#endif /* KAPS_MATRIX_H */
diff --git a/ir/kaps/matrix_t.h b/ir/kaps/matrix_t.h
new file mode 100644 (file)
index 0000000..f1458c1
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP matrix data types.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_MATRIX_T_H
+#define KAPS_MATRIX_T_H
+
+#include "pbqp_t.h"
+
+typedef struct pbqp_matrix_t pbqp_matrix_t;
+
+struct pbqp_matrix_t {
+       unsigned rows;
+       unsigned cols;
+       num entries[];
+};
+
+#endif /* KAPS_MATRIX_T_H */
diff --git a/ir/kaps/optimal.c b/ir/kaps/optimal.c
new file mode 100644 (file)
index 0000000..fe82844
--- /dev/null
@@ -0,0 +1,1465 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Optimal reductions and helper functions.
+ * @date    28.12.2009
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+#include "error.h"
+
+#include "bucket.h"
+#if    KAPS_DUMP
+#include "html_dumper.h"
+#endif
+#include "kaps.h"
+#include "matrix.h"
+#include "optimal.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+#include "plist.h"
+#include "timing.h"
+
+pbqp_edge_t **edge_bucket;
+pbqp_edge_t **rm_bucket;
+pbqp_node_t **node_buckets[4];
+pbqp_node_t **reduced_bucket = NULL;
+pbqp_node_t  *merged_node = NULL;
+static int  buckets_filled = 0;
+
+static void insert_into_edge_bucket(pbqp_edge_t *edge)
+{
+       if (edge_bucket_contains(edge_bucket, edge)) {
+               /* Edge is already inserted. */
+               return;
+       }
+
+       edge_bucket_insert(&edge_bucket, edge);
+}
+
+static void insert_into_rm_bucket(pbqp_edge_t *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) {
+               node_bucket_init(&node_buckets[i]);
+       }
+}
+
+void free_buckets(void)
+{
+       int i;
+
+       for (i = 0; i < 4; ++i) {
+               node_bucket_free(&node_buckets[i]);
+       }
+
+       edge_bucket_free(&edge_bucket);
+       edge_bucket_free(&rm_bucket);
+       node_bucket_free(&reduced_bucket);
+
+       buckets_filled = 0;
+}
+
+void fill_node_buckets(pbqp_t *pbqp)
+{
+       unsigned node_index;
+       unsigned node_len;
+
+       assert(pbqp);
+       node_len = pbqp->num_nodes;
+
+       #if KAPS_TIMING
+               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) {
+               unsigned     degree;
+               pbqp_node_t *node = get_node(pbqp, node_index);
+
+               if (!node) continue;
+
+               degree = pbqp_node_get_degree(node);
+
+               /* We have only one bucket for nodes with arity >= 3. */
+               if (degree > 3) {
+                       degree = 3;
+               }
+
+               node_bucket_insert(&node_buckets[degree], node);
+       }
+
+       buckets_filled = 1;
+
+       #if KAPS_TIMING
+               ir_timer_stop(t_fill_buckets);
+               printf("PBQP Fill Nodes into buckets: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_fill_buckets) / 1000.0);
+       #endif
+}
+
+static void normalize_towards_source(pbqp_edge_t *edge)
+{
+       pbqp_matrix_t  *mat;
+       pbqp_node_t    *src_node;
+       pbqp_node_t    *tgt_node;
+       vector_t       *src_vec;
+       vector_t       *tgt_vec;
+       unsigned        src_len;
+       unsigned        tgt_len;
+       unsigned        src_index;
+       unsigned        new_infinity = 0;
+
+       assert(edge);
+
+       src_node = edge->src;
+       tgt_node = edge->tgt;
+       assert(src_node);
+       assert(tgt_node);
+
+       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;
+       assert(src_len > 0);
+       assert(tgt_len > 0);
+
+       mat = edge->costs;
+       assert(mat);
+
+       /* Normalize towards source node. */
+       for (src_index = 0; src_index < src_len; ++src_index) {
+               num min = pbqp_matrix_get_row_min(mat, src_index, tgt_vec);
+
+               if (min != 0) {
+                       if (src_vec->entries[src_index].data == INF_COSTS) {
+                               pbqp_matrix_set_row_value(mat, src_index, 0);
+                               continue;
+                       }
+
+                       pbqp_matrix_sub_row_value(mat, src_index, tgt_vec, min);
+                       src_vec->entries[src_index].data = pbqp_add(
+                                       src_vec->entries[src_index].data, min);
+
+                       if (min == INF_COSTS) {
+                               new_infinity = 1;
+                       }
+               }
+       }
+
+       if (new_infinity) {
+               unsigned edge_index;
+               unsigned edge_len = pbqp_node_get_degree(src_node);
+
+               for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+                       pbqp_edge_t *edge_candidate = src_node->edges[edge_index];
+
+                       if (edge_candidate != edge) {
+                               insert_into_edge_bucket(edge_candidate);
+                       }
+               }
+       }
+}
+
+static void normalize_towards_target(pbqp_edge_t *edge)
+{
+       pbqp_matrix_t  *mat;
+       pbqp_node_t    *src_node;
+       pbqp_node_t    *tgt_node;
+       vector_t       *src_vec;
+       vector_t       *tgt_vec;
+       unsigned        src_len;
+       unsigned        tgt_len;
+       unsigned        tgt_index;
+       unsigned        new_infinity = 0;
+
+       assert(edge);
+
+       src_node = edge->src;
+       tgt_node = edge->tgt;
+       assert(src_node);
+       assert(tgt_node);
+
+       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;
+       assert(src_len > 0);
+       assert(tgt_len > 0);
+
+       mat = edge->costs;
+       assert(mat);
+
+       /* Normalize towards target node. */
+       for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+               num min = pbqp_matrix_get_col_min(mat, tgt_index, src_vec);
+
+               if (min != 0) {
+                       if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
+                               pbqp_matrix_set_col_value(mat, tgt_index, 0);
+                               continue;
+                       }
+
+                       pbqp_matrix_sub_col_value(mat, tgt_index, src_vec, min);
+                       tgt_vec->entries[tgt_index].data = pbqp_add(
+                                       tgt_vec->entries[tgt_index].data, min);
+
+                       if (min == INF_COSTS) {
+                               new_infinity = 1;
+                       }
+               }
+       }
+
+       if (new_infinity) {
+               unsigned edge_index;
+               unsigned edge_len = pbqp_node_get_degree(tgt_node);
+
+               for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+                       pbqp_edge_t *edge_candidate = tgt_node->edges[edge_index];
+
+                       if (edge_candidate != edge) {
+                               insert_into_edge_bucket(edge_candidate);
+                       }
+               }
+       }
+}
+
+/**
+ * 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_t *pbqp, pbqp_edge_t *edge)
+{
+       pbqp_matrix_t  *mat;
+       pbqp_node_t    *src_node;
+       pbqp_node_t    *tgt_node;
+       vector_t       *src_vec;
+       vector_t       *tgt_vec;
+       unsigned       *mapping;
+       unsigned        src_len;
+       unsigned        tgt_len;
+       unsigned        src_index;
+       unsigned        tgt_index;
+       unsigned        edge_index;
+       unsigned        edge_len;
+
+       assert(pbqp);
+       assert(edge);
+
+       src_node = edge->src;
+       tgt_node = edge->tgt;
+       assert(src_node);
+       assert(tgt_node);
+
+       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;
+               }
+       }
+
+       /* We know that we can merge the source node into the target node. */
+       edge_len = pbqp_node_get_degree(src_node);
+
+#if KAPS_STATISTIC
+       pbqp->num_rm++;
+#endif
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               char txt[100];
+               sprintf(txt, "Merging n%d into n%d", src_node->index, tgt_node->index);
+               dump_section(pbqp->dump_file, 3, txt);
+       }
+#endif
+
+       /* Reconnect the source's edges with the target node. */
+       for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+               pbqp_edge_t   *old_edge = src_node->edges[edge_index];
+               pbqp_edge_t   *new_edge;
+               pbqp_matrix_t *old_matrix;
+               pbqp_matrix_t *new_matrix;
+               pbqp_node_t   *other_node;
+               vector_t      *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];
+                               }
+                       }
+               }
+
+               new_edge = get_edge(pbqp, tgt_node->index, other_node->index);
+
+               add_edge_costs(pbqp, tgt_node->index, other_node->index, new_matrix);
+
+               if (new_edge == NULL) {
+                       reorder_node_after_edge_insertion(tgt_node);
+                       reorder_node_after_edge_insertion(other_node);
+               }
+
+               delete_edge(old_edge);
+
+               new_edge = get_edge(pbqp, tgt_node->index, other_node->index);
+               simplify_edge(pbqp, new_edge);
+
+               insert_into_rm_bucket(new_edge);
+       }
+
+#if KAPS_STATISTIC
+       pbqp->num_r1--;
+#endif
+}
+
+/**
+ * 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_t *pbqp, pbqp_edge_t *edge)
+{
+       pbqp_matrix_t  *mat;
+       pbqp_node_t    *src_node;
+       pbqp_node_t    *tgt_node;
+       vector_t       *src_vec;
+       vector_t       *tgt_vec;
+       unsigned       *mapping;
+       unsigned        src_len;
+       unsigned        tgt_len;
+       unsigned        src_index;
+       unsigned        tgt_index;
+       unsigned        edge_index;
+       unsigned        edge_len;
+
+       assert(pbqp);
+       assert(edge);
+
+       src_node = edge->src;
+       tgt_node = edge->tgt;
+       assert(src_node);
+       assert(tgt_node);
+
+       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, src_len);
+
+       /* Check that each row has at most one zero entry. */
+       for (src_index = 0; src_index < src_len; ++src_index) {
+               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)
+                               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[src_index] = tgt_index;
+               }
+       }
+
+       /* 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
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               char txt[100];
+               sprintf(txt, "Merging n%d into n%d", tgt_node->index, src_node->index);
+               dump_section(pbqp->dump_file, 3, txt);
+       }
+#endif
+
+       /* Reconnect the target's edges with the source node. */
+       for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+               pbqp_edge_t   *old_edge = tgt_node->edges[edge_index];
+               pbqp_edge_t   *new_edge;
+               pbqp_matrix_t *old_matrix;
+               pbqp_matrix_t *new_matrix;
+               pbqp_node_t   *other_node;
+               vector_t      *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;
+               }
+               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];
+                               }
+                       }
+               }
+               /* 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];
+                               }
+                       }
+               }
+
+               new_edge = get_edge(pbqp, src_node->index, other_node->index);
+
+               add_edge_costs(pbqp, src_node->index, other_node->index, new_matrix);
+
+               if (new_edge == NULL) {
+                       reorder_node_after_edge_insertion(src_node);
+                       reorder_node_after_edge_insertion(other_node);
+               }
+
+               delete_edge(old_edge);
+
+               new_edge = get_edge(pbqp, src_node->index, other_node->index);
+               simplify_edge(pbqp, new_edge);
+
+               insert_into_rm_bucket(new_edge);
+       }
+
+#if KAPS_STATISTIC
+       pbqp->num_r1--;
+#endif
+}
+
+/**
+ * Merge neighbors into the given node.
+ */
+void apply_RM(pbqp_t *pbqp, pbqp_node_t *node)
+{
+       pbqp_edge_t **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_t *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_t *edge = edge_bucket_pop(&rm_bucket);
+               assert(edge);
+
+               /* If the edge is not deleted: Try a merge. */
+               if (edge->src == node)
+                       merge_target_into_source(pbqp, edge);
+               else if (edge->tgt == node)
+                       merge_source_into_target(pbqp, edge);
+       }
+
+       merged_node = node;
+}
+
+void reorder_node_after_edge_deletion(pbqp_node_t *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;
+
+       /* 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 reorder_node_after_edge_insertion(pbqp_node_t *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 (old_degree > 2) 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_t *pbqp, pbqp_edge_t *edge)
+{
+       pbqp_matrix_t *mat;
+       pbqp_node_t   *src_node;
+       pbqp_node_t   *tgt_node;
+       vector_t      *src_vec;
+       vector_t      *tgt_vec;
+       int            src_len;
+       int            tgt_len;
+
+       assert(pbqp);
+       assert(edge);
+
+       (void) pbqp;
+
+       src_node = edge->src;
+       tgt_node = edge->tgt;
+       assert(src_node);
+       assert(tgt_node);
+
+       /* If edge are already deleted, we have nothing to do. */
+       if (is_deleted(edge))
+               return;
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               char txt[100];
+               sprintf(txt, "Simplification of Edge n%d-n%d", src_node->index, tgt_node->index);
+               dump_section(pbqp->dump_file, 3, txt);
+       }
+#endif
+
+       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;
+       assert(src_len > 0);
+       assert(tgt_len > 0);
+
+       mat = edge->costs;
+       assert(mat);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fputs("Input:<br>\n", pbqp->dump_file);
+               dump_simplifyedge(pbqp, edge);
+       }
+#endif
+
+       normalize_towards_source(edge);
+       normalize_towards_target(edge);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fputs("<br>\nOutput:<br>\n", pbqp->dump_file);
+               dump_simplifyedge(pbqp, edge);
+       }
+#endif
+
+       if (pbqp_matrix_is_zero(mat, src_vec, tgt_vec)) {
+#if    KAPS_DUMP
+               if (pbqp->dump_file) {
+                       fputs("edge has been eliminated<br>\n", pbqp->dump_file);
+               }
+#endif
+
+#if KAPS_STATISTIC
+               pbqp->num_edges++;
+#endif
+
+               delete_edge(edge);
+       }
+}
+
+void initial_simplify_edges(pbqp_t *pbqp)
+{
+       unsigned node_index;
+       unsigned node_len;
+
+       assert(pbqp);
+
+       #if KAPS_TIMING
+               ir_timer_t *t_int_simpl = ir_timer_new();
+               ir_timer_start(t_int_simpl);
+       #endif
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               pbqp_dump_input(pbqp);
+               dump_section(pbqp->dump_file, 1, "2. Simplification of Cost Matrices");
+       }
+#endif
+
+       node_len = pbqp->num_nodes;
+
+       init_buckets();
+
+       /* First simplify all edges. */
+       for (node_index = 0; node_index < node_len; ++node_index) {
+               unsigned      edge_index;
+               pbqp_node_t  *node = get_node(pbqp, node_index);
+               pbqp_edge_t **edges;
+               unsigned      edge_len;
+
+               if (!node) continue;
+
+               edges = node->edges;
+               edge_len = pbqp_node_get_degree(node);
+
+               for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+                       pbqp_edge_t *edge = edges[edge_index];
+
+                       /* Simplify only once per edge. */
+                       if (node != edge->src) continue;
+
+                       simplify_edge(pbqp, edge);
+               }
+       }
+
+       #if KAPS_TIMING
+               ir_timer_stop(t_int_simpl);
+               printf("PBQP Initial simplify edges:  %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_int_simpl) / 1000.0);
+       #endif
+}
+
+num determine_solution(pbqp_t *pbqp)
+{
+       unsigned node_index;
+       unsigned node_len;
+       num      solution   = 0;
+
+       #if KAPS_TIMING
+               ir_timer_t *t_det_solution = ir_timer_new();
+               ir_timer_reset_and_start(t_det_solution);
+       #endif
+
+#if    KAPS_DUMP
+       FILE     *file;
+#endif
+
+       assert(pbqp);
+
+       (void) pbqp;
+
+#if    KAPS_DUMP
+       file = pbqp->dump_file;
+
+       if (file) {
+               dump_section(file, 1, "4. Determine Solution/Minimum");
+               dump_section(file, 2, "4.1. Trivial Solution");
+       }
+#endif
+
+       /* Solve trivial nodes and calculate solution. */
+       node_len = node_bucket_get_length(node_buckets[0]);
+
+#if KAPS_STATISTIC
+       pbqp->num_r0 = node_len;
+#endif
+
+       for (node_index = 0; node_index < node_len; ++node_index) {
+               pbqp_node_t *node = node_buckets[0][node_index];
+               assert(node);
+
+               node->solution = vector_get_min_index(node->costs);
+               solution       = pbqp_add(solution,
+                               node->costs->entries[node->solution].data);
+
+#if    KAPS_DUMP
+               if (file) {
+                       fprintf(file, "node n%d is set to %d<br>\n", node->index, node->solution);
+                       dump_node(file, node);
+               }
+#endif
+       }
+
+#if    KAPS_DUMP
+       if (file) {
+               dump_section(file, 2, "Minimum");
+#if KAPS_USE_UNSIGNED
+               fprintf(file, "Minimum is equal to %u.", solution);
+#else
+               fprintf(file, "Minimum is equal to %lld.", solution);
+#endif
+       }
+#endif
+
+       #if KAPS_TIMING
+               ir_timer_stop(t_det_solution);
+               printf("PBQP Determine Solution:      %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_det_solution) / 1000.0);
+       #endif
+
+       return solution;
+}
+
+static void back_propagate_RI(pbqp_t *pbqp, pbqp_node_t *node)
+{
+       pbqp_edge_t   *edge;
+       pbqp_node_t   *other;
+       pbqp_matrix_t *mat;
+       vector_t      *vec;
+       int            is_src;
+
+       assert(pbqp);
+       assert(node);
+
+       (void) pbqp;
+
+       edge = node->edges[0];
+       mat = edge->costs;
+       is_src = edge->src == node;
+       vec = node->costs;
+
+       if (is_src) {
+               other = edge->tgt;
+               assert(other);
+
+               node->solution = pbqp_matrix_get_col_min_index(mat, other->solution, vec);
+       } else {
+               other = edge->src;
+               assert(other);
+
+               node->solution = pbqp_matrix_get_row_min_index(mat, other->solution, vec);
+       }
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+       }
+#endif
+}
+
+static void back_propagate_RII(pbqp_t *pbqp, pbqp_node_t *node)
+{
+       pbqp_edge_t   *src_edge   = node->edges[0];
+       pbqp_edge_t   *tgt_edge   = node->edges[1];
+       int            src_is_src = src_edge->src == node;
+       int            tgt_is_src = tgt_edge->src == node;
+       pbqp_matrix_t *src_mat;
+       pbqp_matrix_t *tgt_mat;
+       pbqp_node_t   *src_node;
+       pbqp_node_t   *tgt_node;
+       vector_t      *vec;
+       vector_t      *node_vec;
+       unsigned       col_index;
+       unsigned       row_index;
+
+       assert(pbqp);
+
+       if (src_is_src) {
+               src_node = src_edge->tgt;
+       } else {
+               src_node = src_edge->src;
+       }
+
+       if (tgt_is_src) {
+               tgt_node = tgt_edge->tgt;
+       } else {
+               tgt_node = tgt_edge->src;
+       }
+
+       /* Swap nodes if necessary. */
+       if (tgt_node->index < src_node->index) {
+               pbqp_node_t *tmp_node;
+               pbqp_edge_t *tmp_edge;
+
+               tmp_node = src_node;
+               src_node = tgt_node;
+               tgt_node = tmp_node;
+
+               tmp_edge = src_edge;
+               src_edge = tgt_edge;
+               tgt_edge = tmp_edge;
+
+               src_is_src = src_edge->src == node;
+               tgt_is_src = tgt_edge->src == node;
+       }
+
+       src_mat = src_edge->costs;
+       tgt_mat = tgt_edge->costs;
+
+       node_vec = node->costs;
+
+       row_index = src_node->solution;
+       col_index = tgt_node->solution;
+
+       vec = vector_copy(pbqp, node_vec);
+
+       if (src_is_src) {
+               vector_add_matrix_col(vec, src_mat, row_index);
+       } else {
+               vector_add_matrix_row(vec, src_mat, row_index);
+       }
+
+       if (tgt_is_src) {
+               vector_add_matrix_col(vec, tgt_mat, col_index);
+       } else {
+               vector_add_matrix_row(vec, tgt_mat, col_index);
+       }
+
+       node->solution = vector_get_min_index(vec);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+       }
+#endif
+
+       obstack_free(&pbqp->obstack, vec);
+}
+
+void back_propagate(pbqp_t *pbqp)
+{
+       unsigned node_index;
+       unsigned node_len   = node_bucket_get_length(reduced_bucket);
+
+       assert(pbqp);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               dump_section(pbqp->dump_file, 2, "Back Propagation");
+       }
+#endif
+
+       for (node_index = node_len; node_index > 0; --node_index) {
+               pbqp_node_t *node = reduced_bucket[node_index - 1];
+
+               switch (pbqp_node_get_degree(node)) {
+                       case 1:
+                               back_propagate_RI(pbqp, node);
+                               break;
+                       case 2:
+                               back_propagate_RII(pbqp, node);
+                               break;
+                       default:
+                               panic("Only nodes with degree one or two should be in this bucket");
+                               break;
+               }
+       }
+}
+
+void apply_edge(pbqp_t *pbqp)
+{
+       pbqp_edge_t *edge = edge_bucket_pop(&edge_bucket);
+
+       simplify_edge(pbqp, edge);
+}
+
+void apply_RI(pbqp_t *pbqp)
+{
+       pbqp_node_t   *node   = node_bucket_pop(&node_buckets[1]);
+       pbqp_edge_t   *edge   = node->edges[0];
+       pbqp_matrix_t *mat    = edge->costs;
+       int            is_src = edge->src == node;
+       pbqp_node_t   *other_node;
+
+       (void ) pbqp;
+       assert(pbqp_node_get_degree(node) == 1);
+
+       if (is_src) {
+               other_node = edge->tgt;
+       } else {
+               other_node = edge->src;
+       }
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               char     txt[100];
+               sprintf(txt, "RI-Reduction of Node n%d", node->index);
+               dump_section(pbqp->dump_file, 2, txt);
+               pbqp_dump_graph(pbqp);
+               fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
+               dump_node(pbqp->dump_file, node);
+               dump_node(pbqp->dump_file, other_node);
+               dump_edge(pbqp->dump_file, edge);
+       }
+#endif
+
+       if (is_src) {
+               pbqp_matrix_add_to_all_cols(mat, node->costs);
+               normalize_towards_target(edge);
+       } else {
+               pbqp_matrix_add_to_all_rows(mat, node->costs);
+               normalize_towards_source(edge);
+       }
+       disconnect_edge(other_node, edge);
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
+               dump_node(pbqp->dump_file, other_node);
+       }
+#endif
+
+       reorder_node_after_edge_deletion(other_node);
+
+#if KAPS_STATISTIC
+       pbqp->num_r1++;
+#endif
+
+       /* Add node to back propagation list. */
+       node_bucket_insert(&reduced_bucket, node);
+}
+
+void apply_RII(pbqp_t *pbqp)
+{
+       pbqp_node_t   *node       = node_bucket_pop(&node_buckets[2]);
+       pbqp_edge_t   *src_edge   = node->edges[0];
+       pbqp_edge_t   *tgt_edge   = node->edges[1];
+       int            src_is_src = src_edge->src == node;
+       int            tgt_is_src = tgt_edge->src == node;
+       pbqp_matrix_t *src_mat;
+       pbqp_matrix_t *tgt_mat;
+       pbqp_node_t   *src_node;
+       pbqp_node_t   *tgt_node;
+       pbqp_matrix_t *mat;
+       vector_t      *vec;
+       vector_t      *node_vec;
+       vector_t      *src_vec;
+       vector_t      *tgt_vec;
+       unsigned       col_index;
+       unsigned       col_len;
+       unsigned       row_index;
+       unsigned       row_len;
+       unsigned       node_len;
+
+       assert(pbqp);
+       assert(pbqp_node_get_degree(node) == 2);
+
+       if (src_is_src) {
+               src_node = src_edge->tgt;
+       } else {
+               src_node = src_edge->src;
+       }
+
+       if (tgt_is_src) {
+               tgt_node = tgt_edge->tgt;
+       } else {
+               tgt_node = tgt_edge->src;
+       }
+
+       /* Swap nodes if necessary. */
+       if (tgt_node->index < src_node->index) {
+               pbqp_node_t *tmp_node;
+               pbqp_edge_t *tmp_edge;
+
+               tmp_node = src_node;
+               src_node = tgt_node;
+               tgt_node = tmp_node;
+
+               tmp_edge = src_edge;
+               src_edge = tgt_edge;
+               tgt_edge = tmp_edge;
+
+               src_is_src = src_edge->src == node;
+               tgt_is_src = tgt_edge->src == node;
+       }
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               char     txt[100];
+               sprintf(txt, "RII-Reduction of Node n%d", node->index);
+               dump_section(pbqp->dump_file, 2, txt);
+               pbqp_dump_graph(pbqp);
+               fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
+               dump_node(pbqp->dump_file, src_node);
+               dump_edge(pbqp->dump_file, src_edge);
+               dump_node(pbqp->dump_file, node);
+               dump_edge(pbqp->dump_file, tgt_edge);
+               dump_node(pbqp->dump_file, tgt_node);
+       }
+#endif
+
+       src_mat = src_edge->costs;
+       tgt_mat = tgt_edge->costs;
+
+       src_vec  = src_node->costs;
+       tgt_vec  = tgt_node->costs;
+       node_vec = node->costs;
+
+       row_len  = src_vec->len;
+       col_len  = tgt_vec->len;
+       node_len = node_vec->len;
+
+       mat = pbqp_matrix_alloc(pbqp, row_len, col_len);
+
+       for (row_index = 0; row_index < row_len; ++row_index) {
+               for (col_index = 0; col_index < col_len; ++col_index) {
+                       vec = vector_copy(pbqp, node_vec);
+
+                       if (src_is_src) {
+                               vector_add_matrix_col(vec, src_mat, row_index);
+                       } else {
+                               vector_add_matrix_row(vec, src_mat, row_index);
+                       }
+
+                       if (tgt_is_src) {
+                               vector_add_matrix_col(vec, tgt_mat, col_index);
+                       } else {
+                               vector_add_matrix_row(vec, tgt_mat, col_index);
+                       }
+
+                       mat->entries[row_index * col_len + col_index] = vector_get_min(vec);
+
+                       obstack_free(&pbqp->obstack, vec);
+               }
+       }
+
+       pbqp_edge_t *edge = get_edge(pbqp, src_node->index, tgt_node->index);
+
+       /* Disconnect node. */
+       disconnect_edge(src_node, src_edge);
+       disconnect_edge(tgt_node, tgt_edge);
+
+#if KAPS_STATISTIC
+       pbqp->num_r2++;
+#endif
+
+       /* Add node to back propagation list. */
+       node_bucket_insert(&reduced_bucket, node);
+
+       if (edge == NULL) {
+               edge = alloc_edge(pbqp, src_node->index, tgt_node->index, mat);
+       } else {
+               // matrix
+               pbqp_matrix_add(edge->costs, mat);
+
+               /* Free local matrix. */
+               obstack_free(&pbqp->obstack, mat);
+
+               reorder_node_after_edge_deletion(src_node);
+               reorder_node_after_edge_deletion(tgt_node);
+       }
+
+#if    KAPS_DUMP
+       if (pbqp->dump_file) {
+               fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
+               dump_edge(pbqp->dump_file, edge);
+       }
+#endif
+
+       /* Edge has changed so we simplify it. */
+       simplify_edge(pbqp, edge);
+}
+
+static void select_column(pbqp_edge_t *edge, unsigned col_index)
+{
+       pbqp_matrix_t  *mat;
+       pbqp_node_t    *src_node;
+       pbqp_node_t    *tgt_node;
+       vector_t       *src_vec;
+       vector_t       *tgt_vec;
+       unsigned        src_len;
+       unsigned        tgt_len;
+       unsigned        src_index;
+       unsigned        new_infinity = 0;
+
+       assert(edge);
+
+       src_node = edge->src;
+       tgt_node = edge->tgt;
+       assert(src_node);
+       assert(tgt_node);
+
+       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;
+       assert(src_len > 0);
+       assert(tgt_len > 0);
+
+       mat = edge->costs;
+       assert(mat);
+
+       for (src_index = 0; src_index < src_len; ++src_index) {
+               num elem = mat->entries[src_index * tgt_len + col_index];
+
+               if (elem != 0) {
+                       if (elem == INF_COSTS && src_vec->entries[src_index].data != INF_COSTS)
+                               new_infinity = 1;
+
+                       src_vec->entries[src_index].data = pbqp_add(
+                                       src_vec->entries[src_index].data, elem);
+               }
+       }
+
+       if (new_infinity) {
+               unsigned edge_index;
+               unsigned edge_len = pbqp_node_get_degree(src_node);
+
+               for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+                       pbqp_edge_t *edge_candidate = src_node->edges[edge_index];
+
+                       if (edge_candidate != edge) {
+                               insert_into_edge_bucket(edge_candidate);
+                       }
+               }
+       }
+
+       delete_edge(edge);
+}
+
+static void select_row(pbqp_edge_t *edge, unsigned row_index)
+{
+       pbqp_matrix_t  *mat;
+       pbqp_node_t    *src_node;
+       pbqp_node_t    *tgt_node;
+       vector_t       *tgt_vec;
+       unsigned        tgt_len;
+       unsigned        tgt_index;
+       unsigned        new_infinity = 0;
+
+       assert(edge);
+
+       src_node = edge->src;
+       tgt_node = edge->tgt;
+       assert(tgt_node);
+
+       tgt_vec = tgt_node->costs;
+       assert(tgt_vec);
+
+       tgt_len = tgt_vec->len;
+       assert(tgt_len > 0);
+
+       mat = edge->costs;
+       assert(mat);
+
+       for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+               num elem = mat->entries[row_index * tgt_len + tgt_index];
+
+               if (elem != 0) {
+                       if (elem == INF_COSTS && tgt_vec->entries[tgt_index].data != INF_COSTS)
+                               new_infinity = 1;
+
+                       tgt_vec->entries[tgt_index].data = pbqp_add(
+                                       tgt_vec->entries[tgt_index].data, elem);
+               }
+       }
+
+       if (new_infinity) {
+               unsigned edge_index;
+               unsigned edge_len = pbqp_node_get_degree(tgt_node);
+
+               for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+                       pbqp_edge_t *edge_candidate = tgt_node->edges[edge_index];
+
+                       if (edge_candidate != edge) {
+                               insert_into_edge_bucket(edge_candidate);
+                       }
+               }
+       }
+
+       delete_edge(edge);
+}
+
+void select_alternative(pbqp_node_t *node, unsigned selected_index)
+{
+       unsigned  edge_index;
+       unsigned  node_index;
+       unsigned  node_len;
+       vector_t *node_vec;
+       unsigned  max_degree = pbqp_node_get_degree(node);
+
+       assert(node);
+       node->solution = selected_index;
+       node_vec = node->costs;
+       node_len = node_vec->len;
+       assert(selected_index < node_len);
+
+       /* Set all other costs to infinity. */
+       for (node_index = 0; node_index < node_len; ++node_index) {
+               if (node_index != selected_index) {
+                       node_vec->entries[node_index].data = INF_COSTS;
+               }
+       }
+
+       /* Select corresponding row/column for incident edges. */
+       for (edge_index = 0; edge_index < max_degree; ++edge_index) {
+               pbqp_edge_t *edge = node->edges[edge_index];
+
+               if (edge->src == node)
+                       select_row(edge, selected_index);
+               else
+                       select_column(edge, selected_index);
+       }
+}
+
+pbqp_node_t *get_node_with_max_degree(void)
+{
+       pbqp_node_t **bucket       = node_buckets[3];
+       unsigned      bucket_len   = node_bucket_get_length(bucket);
+       unsigned      bucket_index;
+       unsigned      max_degree   = 0;
+       pbqp_node_t  *result       = NULL;
+
+       for (bucket_index = 0; bucket_index < bucket_len; ++bucket_index) {
+               pbqp_node_t *candidate = bucket[bucket_index];
+               unsigned     degree    = pbqp_node_get_degree(candidate);
+
+               if (degree > max_degree) {
+                       result = candidate;
+                       max_degree = degree;
+               }
+       }
+
+       return result;
+}
+
+unsigned get_local_minimal_alternative(pbqp_t *pbqp, pbqp_node_t *node)
+{
+       pbqp_edge_t   *edge;
+       vector_t      *node_vec;
+       vector_t      *vec;
+       pbqp_matrix_t *mat;
+       unsigned       edge_index;
+       unsigned       max_degree;
+       unsigned       node_index;
+       unsigned       node_len;
+       unsigned       min_index    = 0;
+       num            min          = INF_COSTS;
+       int            is_src;
+
+       assert(pbqp);
+       assert(node);
+       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;
+
+               for (edge_index = 0; edge_index < max_degree; ++edge_index) {
+                       edge   = node->edges[edge_index];
+                       mat    = edge->costs;
+                       is_src = edge->src == node;
+
+                       if (is_src) {
+                               vec = vector_copy(pbqp, edge->tgt->costs);
+                               vector_add_matrix_row(vec, mat, node_index);
+                       } else {
+                               vec = vector_copy(pbqp, edge->src->costs);
+                               vector_add_matrix_col(vec, mat, node_index);
+                       }
+
+                       value = pbqp_add(value, vector_get_min(vec));
+
+                       obstack_free(&pbqp->obstack, vec);
+               }
+
+               if (value < min) {
+                       min = value;
+                       min_index = node_index;
+               }
+       }
+
+       return min_index;
+}
+
+int node_is_reduced(pbqp_node_t *node)
+{
+       if (!reduced_bucket) return 0;
+
+       if (pbqp_node_get_degree(node) == 0) return 1;
+
+       return node_bucket_contains(reduced_bucket, node);
+}
diff --git a/ir/kaps/optimal.h b/ir/kaps/optimal.h
new file mode 100644 (file)
index 0000000..ec7b026
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   Heuristic PBQP solver.
+ * @date    28.12.2009
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_OPTIMAL_H
+#define KAPS_OPTIMAL_H
+
+#include "pbqp_t.h"
+
+extern pbqp_edge_t **edge_bucket;
+extern pbqp_node_t **node_buckets[4];
+extern pbqp_node_t **reduced_bucket;
+extern pbqp_node_t  *merged_node;
+
+void apply_edge(pbqp_t *pbqp);
+
+void apply_RI(pbqp_t *pbqp);
+void apply_RII(pbqp_t *pbqp);
+void apply_RM(pbqp_t *pbqp, pbqp_node_t *node);
+
+void back_propagate(pbqp_t *pbqp);
+num determine_solution(pbqp_t *pbqp);
+void fill_node_buckets(pbqp_t *pbqp);
+void free_buckets(void);
+unsigned get_local_minimal_alternative(pbqp_t *pbqp, pbqp_node_t *node);
+pbqp_node_t *get_node_with_max_degree(void);
+void initial_simplify_edges(pbqp_t *pbqp);
+void select_alternative(pbqp_node_t *node, unsigned selected_index);
+void simplify_edge(pbqp_t *pbqp, pbqp_edge_t *edge);
+void reorder_node_after_edge_deletion(pbqp_node_t *node);
+void reorder_node_after_edge_insertion(pbqp_node_t *node);
+
+int node_is_reduced(pbqp_node_t *node);
+
+#endif /* KAPS_OPTIMAL_H */
diff --git a/ir/kaps/pbqp_edge.c b/ir/kaps/pbqp_edge.c
new file mode 100644 (file)
index 0000000..8a1d0c4
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP edges.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+
+#include "kaps.h"
+#include "matrix.h"
+#include "optimal.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "pbqp_t.h"
+
+pbqp_edge_t *alloc_edge(pbqp_t *pbqp, int src_index, int tgt_index,
+                        pbqp_matrix_t *costs)
+{
+       int transpose = 0;
+
+       if (tgt_index < src_index) {
+               int tmp = src_index;
+               src_index = tgt_index;
+               tgt_index = tmp;
+
+               transpose = 1;
+       }
+
+       pbqp_edge_t *edge = OALLOC(&pbqp->obstack, pbqp_edge_t);
+       assert(edge);
+
+       pbqp_node_t *src_node = get_node(pbqp, src_index);
+       assert(src_node);
+
+       pbqp_node_t *tgt_node = get_node(pbqp, tgt_index);
+       assert(tgt_node);
+
+       if (transpose) {
+               edge->costs = pbqp_matrix_copy_and_transpose(pbqp, costs);
+       } else {
+               edge->costs = pbqp_matrix_copy(pbqp, costs);
+       }
+
+       /*
+        * Connect edge with incident nodes. Since the edge is allocated, we know
+        * that it don't appear in the edge lists of the nodes.
+        */
+       ARR_APP1(pbqp_edge_t *, src_node->edges, edge);
+       edge->src = src_node;
+       ARR_APP1(pbqp_edge_t *, tgt_node->edges, edge);
+       edge->tgt = tgt_node;
+       edge->bucket_index = UINT_MAX;
+
+       return edge;
+}
+
+void delete_edge(pbqp_edge_t *edge)
+{
+       pbqp_node_t  *src_node;
+       pbqp_node_t  *tgt_node;
+
+       assert(edge);
+
+       src_node = edge->src;
+       tgt_node = edge->tgt;
+       assert(src_node);
+       assert(tgt_node);
+
+       disconnect_edge(src_node, edge);
+       disconnect_edge(tgt_node, edge);
+
+       edge->src = NULL;
+       edge->tgt = NULL;
+
+       reorder_node_after_edge_deletion(src_node);
+       reorder_node_after_edge_deletion(tgt_node);
+}
+
+unsigned is_deleted(pbqp_edge_t *edge)
+{
+       unsigned deleted;
+
+       assert(edge);
+
+       deleted = (edge->src == NULL) && (edge-> tgt == NULL);
+
+       return deleted;
+}
+
+pbqp_edge_t *pbqp_edge_deep_copy(pbqp_t *pbqp, pbqp_edge_t *edge,
+                                 pbqp_node_t *src_node, pbqp_node_t *tgt_node)
+{
+       pbqp_edge_t *copy = OALLOC(&pbqp->obstack, pbqp_edge_t);
+       assert(src_node);
+       assert(tgt_node);
+
+       copy->costs = pbqp_matrix_copy(pbqp, edge->costs);
+
+       /* Connect edge with incident nodes. */
+       copy->src = src_node;
+       copy->tgt = tgt_node;
+       copy->bucket_index = UINT_MAX;
+
+       return copy;
+}
diff --git a/ir/kaps/pbqp_edge.h b/ir/kaps/pbqp_edge.h
new file mode 100644 (file)
index 0000000..1e649a2
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP edges.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_PBQP_EDGE_H
+#define KAPS_PBQP_EDGE_H
+
+#include "pbqp_t.h"
+
+pbqp_edge_t *alloc_edge(pbqp_t *pbqp, int src_index, int tgt_index,
+                        pbqp_matrix_t *costs);
+
+pbqp_edge_t *pbqp_edge_deep_copy(pbqp_t *pbqp, pbqp_edge_t *edge,
+                                 pbqp_node_t *src_node, pbqp_node_t *tgt_node);
+
+void delete_edge(pbqp_edge_t *edge);
+unsigned is_deleted(pbqp_edge_t *edge);
+
+#endif /* KAPS_PBQP_EDGE_H */
diff --git a/ir/kaps/pbqp_edge_t.h b/ir/kaps/pbqp_edge_t.h
new file mode 100644 (file)
index 0000000..02f0248
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP edge data types.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_PBQP_EDGE_T_H
+#define KAPS_PBQP_EDGE_T_H
+
+#include "pbqp_t.h"
+
+struct pbqp_edge_t {
+       pbqp_node_t   *src;                  /* Source index. */
+       pbqp_node_t   *tgt;                  /* Target index. */
+       pbqp_matrix_t *costs;                /* Cost matrix. */
+       unsigned       bucket_index;         /* Index of edge bucket. */
+};
+
+#endif /* KAPS_PBQP_EDGE_T_H */
diff --git a/ir/kaps/pbqp_node.c b/ir/kaps/pbqp_node.c
new file mode 100644 (file)
index 0000000..bb8a352
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP nodes.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+
+#include "assert.h"
+
+#include "bucket.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+pbqp_node_t *alloc_node(pbqp_t *pbqp, unsigned node_index, vector_t *costs)
+{
+       pbqp_node_t *node = OALLOC(&pbqp->obstack, pbqp_node_t);
+       assert(node);
+
+       node->edges = NEW_ARR_F(pbqp_edge_t *, 0);
+       node->costs = vector_copy(pbqp, costs);
+       node->bucket_index = UINT_MAX;
+       node->solution = UINT_MAX;
+       node->index = node_index;
+
+       return node;
+}
+
+int is_connected(pbqp_node_t *node, pbqp_edge_t *edge)
+{
+       pbqp_edge_t **edges;
+       unsigned      edge_index;
+       unsigned      edge_len;
+
+       assert(node);
+       assert(edge);
+
+       if (edge->src != node && edge->tgt != node) return 0;
+
+       edges = node->edges;
+       edge_len = ARR_LEN(edges);
+
+       for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+               pbqp_edge_t *edge_candidate = edges[edge_index];
+               if (edge_candidate == edge) {
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+void disconnect_edge(pbqp_node_t *node, pbqp_edge_t *edge)
+{
+       pbqp_edge_t **edges;
+       unsigned      edge_index;
+       unsigned      edge_len;
+
+       edges = node->edges;
+       edge_len = ARR_LEN(edges);
+
+       for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+               pbqp_edge_t *edge_candidate = edges[edge_index];
+               if (edge_candidate == edge) {
+                       edges[edge_index] = edges[edge_len - 1];
+                       ARR_SHRINKLEN(edges, (int)edge_len - 1);
+                       break;
+               }
+       }
+}
+
+unsigned pbqp_node_get_degree(pbqp_node_t *node)
+{
+       assert(node);
+       return ARR_LEN(node->edges);
+}
+
+pbqp_node_t *pbqp_node_deep_copy(pbqp_t *pbqp, pbqp_node_bucket_t new_bucket,
+                                 pbqp_node_t *node)
+{
+       unsigned     edge_index;
+       unsigned     edge_length = pbqp_node_get_degree(node);
+       pbqp_node_t *copy        = OALLOC(&pbqp->obstack, pbqp_node_t);
+
+       assert(copy);
+
+       copy->edges        = NEW_ARR_F(pbqp_edge_t *, 0);
+       for (edge_index = 0; edge_index < edge_length; ++edge_index) {
+               pbqp_edge_t *edge_copy = NULL;
+               pbqp_edge_t *edge      = node->edges[edge_index];
+               int          is_src    = edge->src == node;
+
+               if (is_src) {
+                       unsigned other_index = edge->tgt->bucket_index;
+                       unsigned is_copied   = other_index < node->bucket_index;
+
+                       if (is_copied) {
+                               pbqp_node_t *other_copy = new_bucket[other_index];
+                               unsigned     degree     = pbqp_node_get_degree(other_copy);
+                               unsigned     index;
+
+                               for (index = 0; index < degree; ++index) {
+                                       if (other_copy->edges[index]->src == node) {
+                                               edge_copy      = other_copy->edges[index];
+                                               edge_copy->src = copy;
+                                               break;
+                                       }
+                               }
+                       } else {
+                               edge_copy = pbqp_edge_deep_copy(pbqp, edge, copy, edge->tgt);
+                       }
+               } else {
+                       unsigned other_index = edge->src->bucket_index;
+                       unsigned is_copied   = other_index < node->bucket_index;
+
+                       if (is_copied) {
+                               pbqp_node_t *other_copy = new_bucket[other_index];
+                               unsigned     degree     = pbqp_node_get_degree(other_copy);
+                               unsigned     index;
+
+                               for (index = 0; index < degree; ++index) {
+                                       if (other_copy->edges[index]->tgt == node) {
+                                               edge_copy      = other_copy->edges[index];
+                                               edge_copy->tgt = copy;
+                                               break;
+                                       }
+                               }
+                       } else {
+                               edge_copy = pbqp_edge_deep_copy(pbqp, edge, edge->src, copy);
+                       }
+               }
+               ARR_APP1(pbqp_edge_t *, copy->edges, edge_copy);
+       }
+       copy->costs        = vector_copy(pbqp, node->costs);
+       copy->bucket_index = node->bucket_index;
+       copy->solution     = node->solution;
+       copy->index   = node->index;
+
+       return copy;
+}
diff --git a/ir/kaps/pbqp_node.h b/ir/kaps/pbqp_node.h
new file mode 100644 (file)
index 0000000..a543907
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP nodes.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_PBQP_NODE_H
+#define KAPS_PBQP_NODE_H
+
+#include "bucket_t.h"
+#include "pbqp_t.h"
+
+pbqp_node_t *alloc_node(pbqp_t *pbqp, unsigned node_index, vector_t *costs);
+
+void disconnect_edge(pbqp_node_t *node, pbqp_edge_t *edge);
+
+int is_connected(pbqp_node_t *node, pbqp_edge_t *edge);
+
+unsigned pbqp_node_get_degree(pbqp_node_t *node);
+
+pbqp_node_t *pbqp_node_deep_copy(pbqp_t *pbqp, pbqp_node_bucket_t new_bucket,
+                                 pbqp_node_t *node);
+
+#endif /* KAPS_PBQP_NODE_H */
diff --git a/ir/kaps/pbqp_node_t.h b/ir/kaps/pbqp_node_t.h
new file mode 100644 (file)
index 0000000..4cd06fa
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP node data types.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_PBQP_NODE_T_H
+#define KAPS_PBQP_NODE_T_H
+
+#include "pbqp_t.h"
+
+struct pbqp_node_t {
+       pbqp_edge_t **edges;
+       vector_t     *costs;
+       unsigned      bucket_index;
+       unsigned      solution;
+       unsigned      index;
+};
+
+#endif /* KAPS_PBQP_NODE_T_H */
diff --git a/ir/kaps/pbqp_t.h b/ir/kaps/pbqp_t.h
new file mode 100644 (file)
index 0000000..11cb51c
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP data types.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_PBQP_T_H
+#define KAPS_PBQP_T_H
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "adt/obstack.h"
+
+#define KAPS_DUMP 0
+#define KAPS_ENABLE_VECTOR_NAMES 0
+#define KAPS_STATISTIC 0
+#define KAPS_TIMING 0
+#define KAPS_USE_UNSIGNED 1
+
+#if KAPS_USE_UNSIGNED
+       typedef unsigned num;
+       static const num INF_COSTS = UINT_MAX;
+#else
+       typedef intmax_t num;
+       static const num INF_COSTS = INTMAX_MAX;
+#endif
+
+#include "matrix_t.h"
+#include "vector_t.h"
+
+typedef struct pbqp_edge_t pbqp_edge_t;
+typedef struct pbqp_node_t pbqp_node_t;
+typedef struct pbqp_t      pbqp_t;
+
+struct pbqp_t {
+       struct obstack obstack;            /* Obstack. */
+       num            solution;           /* Computed solution. */
+       size_t         num_nodes;          /* Number of PBQP nodes. */
+       pbqp_node_t  **nodes;              /* Nodes of PBQP. */
+       FILE          *dump_file;          /* File to dump in. */
+#if KAPS_STATISTIC
+       unsigned       num_bf;             /* Number of brute force reductions. */
+       unsigned       num_edges;          /* Number of independent edges. */
+       unsigned       num_r0;             /* Number of trivial solved nodes. */
+       unsigned       num_r1;             /* Number of R1 reductions. */
+       unsigned       num_r2;             /* Number of R2 reductions. */
+       unsigned       num_rm;             /* Number of RM reductions. */
+       unsigned       num_rn;             /* Number of RN reductions. */
+#endif
+};
+
+#endif /* KAPS_PBQP_T_H */
diff --git a/ir/kaps/vector.c b/ir/kaps/vector.c
new file mode 100644 (file)
index 0000000..04d58e6
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP vector.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include <string.h>
+
+#include "adt/array.h"
+
+#include "vector.h"
+
+num pbqp_add(num x, num y)
+{
+       if (x == INF_COSTS || y == INF_COSTS) return INF_COSTS;
+
+       num res = x + y;
+
+#if !KAPS_USE_UNSIGNED
+       /* No positive overflow. */
+       assert(x < 0 || y < 0 || res >= x);
+       assert(x < 0 || y < 0 || res >= y);
+#endif
+
+       /* No negative overflow. */
+       assert(x > 0 || y > 0 || res <= x);
+       assert(x > 0 || y > 0 || res <= y);
+
+       /* Result is not infinity.*/
+       assert(res < INF_COSTS);
+
+       return res;
+}
+
+vector_t *vector_alloc(pbqp_t *pbqp, unsigned length)
+{
+       assert(length > 0);
+       vector_t *vec = (vector_t*)obstack_alloc(&pbqp->obstack, sizeof(*vec) + sizeof(*vec->entries) * length);
+       assert(vec);
+
+       vec->len = length;
+       memset(vec->entries, 0, sizeof(*vec->entries) * length);
+
+       return vec;
+}
+
+vector_t *vector_copy(pbqp_t *pbqp, vector_t *v)
+{
+       unsigned  len  = v->len;
+       vector_t *copy = (vector_t*)obstack_copy(&pbqp->obstack, v, sizeof(*copy) + sizeof(*copy->entries) * len);
+       assert(copy);
+
+       return copy;
+}
+
+void vector_add(vector_t *sum, vector_t *summand)
+{
+       int i;
+       int len;
+
+       assert(sum);
+       assert(summand);
+       assert(sum->len == summand->len);
+
+       len = sum->len;
+
+       for (i = 0; i < len; ++i) {
+               sum->entries[i].data = pbqp_add(sum->entries[i].data,
+                               summand->entries[i].data);
+       }
+}
+
+void vector_set(vector_t *vec, unsigned index, num value)
+{
+       assert(index < vec->len);
+       vec->entries[index].data = value;
+}
+
+#if KAPS_ENABLE_VECTOR_NAMES
+void vector_set_description(vector_t *vec, unsigned index, const char *name)
+{
+       assert(index < vec->len);
+       vec->entries[index].name = name;
+}
+#endif
+
+void vector_add_value(vector_t *vec, num value)
+{
+       unsigned index;
+       unsigned len;
+
+       assert(vec);
+
+       len = vec->len;
+
+       for (index = 0; index < len; ++index) {
+               vec->entries[index].data = pbqp_add(vec->entries[index].data, value);
+       }
+}
+
+void vector_add_matrix_col(vector_t *vec, pbqp_matrix_t *mat, unsigned col_index)
+{
+       unsigned index;
+       unsigned len;
+
+       assert(vec);
+       assert(mat);
+       assert(vec->len == mat->rows);
+       assert(col_index < mat->cols);
+
+       len = vec->len;
+
+       for (index = 0; index < len; ++index) {
+               vec->entries[index].data = pbqp_add(vec->entries[index].data, mat->entries[index * mat->cols + col_index]);
+       }
+}
+
+void vector_add_matrix_row(vector_t *vec, pbqp_matrix_t *mat, unsigned row_index)
+{
+       unsigned index;
+       unsigned len;
+
+       assert(vec);
+       assert(mat);
+       assert(vec->len == mat->cols);
+       assert(row_index < mat->rows);
+
+       len = vec->len;
+
+       for (index = 0; index < len; ++index) {
+               vec->entries[index].data = pbqp_add(vec->entries[index].data,
+                               mat->entries[row_index * mat->cols + index]);
+       }
+}
+
+num vector_get_min(vector_t *vec)
+{
+       unsigned index;
+       unsigned len;
+       num      min = INF_COSTS;
+
+       assert(vec);
+
+       len = vec->len;
+       assert(len > 0);
+
+       for (index = 0; index < len; ++index) {
+               num elem = vec->entries[index].data;
+
+               if (elem < min) {
+                       min = elem;
+               }
+       }
+
+       return min;
+}
+
+unsigned vector_get_min_index(vector_t *vec)
+{
+       unsigned index;
+       unsigned len;
+       unsigned min_index = 0;
+       num      min       = INF_COSTS;
+
+       assert(vec);
+
+       len = vec->len;
+       assert(len > 0);
+
+       for (index = 0; index < len; ++index) {
+               num elem = vec->entries[index].data;
+
+               if (elem < min) {
+                       min = elem;
+                       min_index = index;
+               }
+       }
+
+       return min_index;
+}
diff --git a/ir/kaps/vector.h b/ir/kaps/vector.h
new file mode 100644 (file)
index 0000000..d54aaea
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP vector.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_VECTOR_H
+#define KAPS_VECTOR_H
+
+#include "vector_t.h"
+
+num pbqp_add(num x, num y);
+
+vector_t *vector_alloc(pbqp_t *pbqp, unsigned length);
+
+/* Copy the given vector. */
+vector_t *vector_copy(pbqp_t *pbqp, vector_t *v);
+
+/* sum += summand */
+void vector_add(vector_t *sum, vector_t *summand);
+
+void vector_set(vector_t *vec, unsigned index, num value);
+
+#if KAPS_ENABLE_VECTOR_NAMES
+void vector_set_description(vector_t *vec, unsigned index, const char *name);
+#endif
+
+void vector_add_value(vector_t *vec, num value);
+
+void vector_add_matrix_col(vector_t *vec, pbqp_matrix_t *mat, unsigned col_index);
+void vector_add_matrix_row(vector_t *vec, pbqp_matrix_t *mat, unsigned row_index);
+
+num vector_get_min(vector_t *vec);
+unsigned vector_get_min_index(vector_t *vec);
+
+#endif /* KAPS_VECTOR_H */
diff --git a/ir/kaps/vector_t.h b/ir/kaps/vector_t.h
new file mode 100644 (file)
index 0000000..03692d1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief   PBQP vector data types.
+ * @date    02.10.2008
+ * @author  Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+#ifndef KAPS_VECTOR_T_H
+#define KAPS_VECTOR_T_H
+
+#include "pbqp_t.h"
+
+typedef struct vec_elem_t vec_elem_t;
+
+struct vec_elem_t {
+       num data;
+#if KAPS_ENABLE_VECTOR_NAMES
+       const char *name;
+#endif
+};
+
+typedef struct vector_t vector_t;
+
+struct vector_t {
+       unsigned   len;
+       vec_elem_t entries[];
+};
+
+#endif /* KAPS_VECTOR_T_H */