isl_tab.c \
isl_tab.h \
isl_tab_pip.c \
+ isl_tarjan.c \
+ isl_tarjan.h \
isl_transitive_closure.c \
isl_union_map.c \
isl_union_map_private.h \
#include <isl_band_private.h>
#include <isl_list_private.h>
#include <isl_options_private.h>
+#include <isl_tarjan.h>
/*
* The scheduling algorithm implemented in this file was inspired by
* indicating whether the corresponding scheduling dimension results
* in zero dependence distances within its band and with respect
* to the proximity edges.
- *
- * index, min_index and on_stack are used during the SCC detection
- * index represents the order in which nodes are visited.
- * min_index is the index of the root of a (sub)component.
- * on_stack indicates whether the node is currently on the stack.
*/
struct isl_sched_node {
isl_space *dim;
int *band;
int *band_id;
int *zero;
-
- /* scc detection */
- int index;
- int min_index;
- int on_stack;
};
static int node_has_dim(const void *entry, const void *val)
* src_scc and dst_scc are the source and sink SCCs of an edge with
* conflicting constraints
*
- * scc, sp, index and stack are used during the detection of SCCs
- * scc is the number of the next SCC
- * stack contains the nodes on the path from the root to the current node
- * sp is the stack pointer
- * index is the index of the last node visited
+ * scc represents the number of components
*/
struct isl_sched_graph {
isl_hmap_map_basic_set *intra_hmap;
int src_scc;
int dst_scc;
- /* scc detection */
int scc;
- int sp;
- int index;
- int *stack;
};
/* Initialize node_table based on the list of nodes.
graph->node = isl_calloc_array(ctx, struct isl_sched_node, graph->n);
graph->sorted = isl_calloc_array(ctx, int, graph->n);
graph->region = isl_alloc_array(ctx, struct isl_region, graph->n);
- graph->stack = isl_alloc_array(ctx, int, graph->n);
graph->edge = isl_calloc_array(ctx,
struct isl_sched_edge, graph->n_edge);
graph->intra_hmap = isl_hmap_map_basic_set_alloc(ctx, 2 * n_edge);
graph->inter_hmap = isl_hmap_map_basic_set_alloc(ctx, 2 * n_edge);
- if (!graph->node || !graph->region || !graph->stack || !graph->edge ||
- !graph->sorted)
+ if (!graph->node || !graph->region || !graph->edge || !graph->sorted)
return -1;
for(i = 0; i < graph->n; ++i)
isl_map_free(graph->edge[i].map);
free(graph->edge);
free(graph->region);
- free(graph->stack);
for (i = 0; i <= isl_edge_last; ++i)
isl_hash_table_free(ctx, graph->edge_table[i]);
isl_hash_table_free(ctx, graph->node_table);
return graph_edge_table_add(ctx, graph, data->type, edge);
}
-/* Check whether there is a validity dependence from src to dst,
- * forcing dst to follow src (if weak is not set).
- * If weak is set, then check if there is any dependence from src to dst.
+/* Check whether there is any dependence from node[j] to node[i]
+ * or from node[i] to node[j].
*/
-static int node_follows(struct isl_sched_graph *graph,
- struct isl_sched_node *dst, struct isl_sched_node *src, int weak)
+static int node_follows_weak(int i, int j, void *user)
{
- if (weak)
- return graph_has_any_edge(graph, src, dst);
- else
- return graph_has_validity_edge(graph, src, dst);
+ int f;
+ struct isl_sched_graph *graph = user;
+
+ f = graph_has_any_edge(graph, &graph->node[j], &graph->node[i]);
+ if (f < 0 || f)
+ return f;
+ return graph_has_any_edge(graph, &graph->node[i], &graph->node[j]);
+}
+
+/* Check whether there is a validity dependence from node[j] to node[i],
+ * forcing node[i] to follow node[j].
+ */
+static int node_follows_strong(int i, int j, void *user)
+{
+ struct isl_sched_graph *graph = user;
+
+ return graph_has_validity_edge(graph, &graph->node[j], &graph->node[i]);
}
-/* Perform Tarjan's algorithm for computing the strongly connected components
+/* Use Tarjan's algorithm for computing the strongly connected components
* in the dependence graph (only validity edges).
* If weak is set, we consider the graph to be undirected and
* we effectively compute the (weakly) connected components.
* Additionally, we also consider other edges when weak is set.
*/
-static int detect_sccs_tarjan(struct isl_sched_graph *g, int i, int weak)
+static int detect_ccs(isl_ctx *ctx, struct isl_sched_graph *graph, int weak)
{
- int j;
-
- g->node[i].index = g->index;
- g->node[i].min_index = g->index;
- g->node[i].on_stack = 1;
- g->index++;
- g->stack[g->sp++] = i;
+ int i, n;
+ struct isl_tarjan_graph *g = NULL;
- for (j = g->n - 1; j >= 0; --j) {
- int f;
+ g = isl_tarjan_graph_init(ctx, graph->n,
+ weak ? &node_follows_weak : &node_follows_strong, graph);
+ if (!g)
+ return -1;
- if (j == i)
- continue;
- if (g->node[j].index >= 0 &&
- (!g->node[j].on_stack ||
- g->node[j].index > g->node[i].min_index))
- continue;
-
- f = node_follows(g, &g->node[i], &g->node[j], weak);
- if (f < 0)
- return -1;
- if (!f && weak) {
- f = node_follows(g, &g->node[j], &g->node[i], weak);
- if (f < 0)
- return -1;
+ graph->scc = 0;
+ i = 0;
+ n = graph->n;
+ while (n) {
+ while (g->order[i] != -1) {
+ graph->node[g->order[i]].scc = graph->scc;
+ --n;
+ ++i;
}
- if (!f)
- continue;
- if (g->node[j].index < 0) {
- detect_sccs_tarjan(g, j, weak);
- if (g->node[j].min_index < g->node[i].min_index)
- g->node[i].min_index = g->node[j].min_index;
- } else if (g->node[j].index < g->node[i].min_index)
- g->node[i].min_index = g->node[j].index;
+ ++i;
+ graph->scc++;
}
- if (g->node[i].index != g->node[i].min_index)
- return 0;
-
- do {
- j = g->stack[--g->sp];
- g->node[j].on_stack = 0;
- g->node[j].scc = g->scc;
- } while (j != i);
- g->scc++;
-
- return 0;
-}
-
-static int detect_ccs(struct isl_sched_graph *graph, int weak)
-{
- int i;
-
- graph->index = 0;
- graph->sp = 0;
- graph->scc = 0;
- for (i = graph->n - 1; i >= 0; --i)
- graph->node[i].index = -1;
-
- for (i = graph->n - 1; i >= 0; --i) {
- if (graph->node[i].index >= 0)
- continue;
- if (detect_sccs_tarjan(graph, i, weak) < 0)
- return -1;
- }
+ isl_tarjan_graph_free(g);
return 0;
}
/* Apply Tarjan's algorithm to detect the strongly connected components
* in the dependence graph.
*/
-static int detect_sccs(struct isl_sched_graph *graph)
+static int detect_sccs(isl_ctx *ctx, struct isl_sched_graph *graph)
{
- return detect_ccs(graph, 0);
+ return detect_ccs(ctx, graph, 0);
}
/* Apply Tarjan's algorithm to detect the (weakly) connected components
* in the dependence graph.
*/
-static int detect_wccs(struct isl_sched_graph *graph)
+static int detect_wccs(isl_ctx *ctx, struct isl_sched_graph *graph)
{
- return detect_ccs(graph, 1);
+ return detect_ccs(ctx, graph, 1);
}
static int cmp_scc(const void *a, const void *b, void *data)
if (graph->n_edge == 0)
return 0;
- if (detect_sccs(graph) < 0)
+ if (detect_sccs(ctx, graph) < 0)
return -1;
for (i = 0; i < graph->n; ++i) {
{
int force_zero = 0;
- if (detect_sccs(graph) < 0)
+ if (detect_sccs(ctx, graph) < 0)
return -1;
if (sort_sccs(graph) < 0)
return -1;
static int compute_schedule(isl_ctx *ctx, struct isl_sched_graph *graph)
{
if (ctx->opt->schedule_fuse == ISL_SCHEDULE_FUSE_MIN) {
- if (detect_sccs(graph) < 0)
+ if (detect_sccs(ctx, graph) < 0)
return -1;
} else {
- if (detect_wccs(graph) < 0)
+ if (detect_wccs(ctx, graph) < 0)
return -1;
}
--- /dev/null
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ * Copyright 2012 Ecole Normale Superieure
+ *
+ * Use of this software is governed by the GNU LGPLv2.1 license
+ *
+ * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
+ * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
+ * 91893 Orsay, France
+ * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
+ */
+
+#include <stdlib.h>
+#include <isl/ctx.h>
+#include <isl_tarjan.h>
+
+void isl_tarjan_graph_free(struct isl_tarjan_graph *g)
+{
+ if (!g)
+ return;
+ free(g->node);
+ free(g->stack);
+ free(g->order);
+ free(g);
+}
+
+static struct isl_tarjan_graph *isl_tarjan_graph_alloc(isl_ctx *ctx, int len)
+{
+ struct isl_tarjan_graph *g;
+ int i;
+
+ g = isl_calloc_type(ctx, struct isl_tarjan_graph);
+ if (!g)
+ return NULL;
+ g->len = len;
+ g->node = isl_alloc_array(ctx, struct isl_tarjan_node, len);
+ if (!g->node)
+ goto error;
+ for (i = 0; i < len; ++i)
+ g->node[i].index = -1;
+ g->stack = isl_alloc_array(ctx, int, len);
+ if (!g->stack)
+ goto error;
+ g->order = isl_alloc_array(ctx, int, 2 * len);
+ if (!g->order)
+ goto error;
+
+ g->sp = 0;
+ g->index = 0;
+ g->op = 0;
+
+ return g;
+error:
+ isl_tarjan_graph_free(g);
+ return NULL;
+}
+
+/* Perform Tarjan's algorithm for computing the strongly connected components
+ * in the graph with g->len nodes and with edges defined by "follows".
+ */
+static int isl_tarjan_components(struct isl_tarjan_graph *g, int i,
+ int (*follows)(int i, int j, void *user), void *user)
+{
+ int j;
+
+ g->node[i].index = g->index;
+ g->node[i].min_index = g->index;
+ g->node[i].on_stack = 1;
+ g->index++;
+ g->stack[g->sp++] = i;
+
+ for (j = g->len - 1; j >= 0; --j) {
+ int f;
+
+ if (j == i)
+ continue;
+ if (g->node[j].index >= 0 &&
+ (!g->node[j].on_stack ||
+ g->node[j].index > g->node[i].min_index))
+ continue;
+
+ f = follows(i, j, user);
+ if (f < 0)
+ return -1;
+ if (!f)
+ continue;
+
+ if (g->node[j].index < 0) {
+ isl_tarjan_components(g, j, follows, user);
+ if (g->node[j].min_index < g->node[i].min_index)
+ g->node[i].min_index = g->node[j].min_index;
+ } else if (g->node[j].index < g->node[i].min_index)
+ g->node[i].min_index = g->node[j].index;
+ }
+
+ if (g->node[i].index != g->node[i].min_index)
+ return 0;
+
+ do {
+ j = g->stack[--g->sp];
+ g->node[j].on_stack = 0;
+ g->order[g->op++] = j;
+ } while (j != i);
+ g->order[g->op++] = -1;
+
+ return 0;
+}
+
+/* Decompose the graph with "len" nodes and edges defined by "follows"
+ * into strongly connected components.
+ */
+struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len,
+ int (*follows)(int i, int j, void *user), void *user)
+{
+ int i;
+ struct isl_tarjan_graph *g = NULL;
+
+ g = isl_tarjan_graph_alloc(ctx, len);
+ if (!g)
+ return NULL;
+ for (i = len - 1; i >= 0; --i) {
+ if (g->node[i].index >= 0)
+ continue;
+ if (isl_tarjan_components(g, i, follows, user) < 0)
+ goto error;
+ }
+
+ return g;
+error:
+ isl_tarjan_graph_free(g);
+ return NULL;
+}
--- /dev/null
+#ifndef ISL_TARJAN_H
+#define ISL_TARJAN_H
+
+/* Structure for representing the nodes in the graph being traversed
+ * using Tarjan's algorithm.
+ * index represents the order in which nodes are visited.
+ * min_index is the index of the root of a (sub)component.
+ * on_stack indicates whether the node is currently on the stack.
+ */
+struct isl_tarjan_node {
+ int index;
+ int min_index;
+ int on_stack;
+};
+
+/* Structure for representing the graph being traversed
+ * using Tarjan's algorithm.
+ * len is the number of nodes
+ * node is an array of nodes
+ * stack contains the nodes on the path from the root to the current node
+ * sp is the stack pointer
+ * index is the index of the last node visited
+ * order contains the elements of the components separated by -1
+ * op represents the current position in order
+ */
+struct isl_tarjan_graph {
+ int len;
+ struct isl_tarjan_node *node;
+ int *stack;
+ int sp;
+ int index;
+ int *order;
+ int op;
+};
+
+struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len,
+ int (*follows)(int i, int j, void *user), void *user);
+void isl_tarjan_graph_free(struct isl_tarjan_graph *g);
+
+#endif
#include <isl/union_map.h>
#include <isl_mat_private.h>
#include <isl_options_private.h>
+#include <isl_tarjan.h>
int isl_map_is_transitively_closed(__isl_keep isl_map *map)
{
return NULL;
}
-/* Structure for representing the nodes in the graph being traversed
- * using Tarjan's algorithm.
- * index represents the order in which nodes are visited.
- * min_index is the index of the root of a (sub)component.
- * on_stack indicates whether the node is currently on the stack.
- */
-struct basic_map_sort_node {
- int index;
- int min_index;
- int on_stack;
-};
-/* Structure for representing the graph being traversed
- * using Tarjan's algorithm.
- * len is the number of nodes
- * node is an array of nodes
- * stack contains the nodes on the path from the root to the current node
- * sp is the stack pointer
- * index is the index of the last node visited
- * order contains the elements of the components separated by -1
- * op represents the current position in order
+/* Structure for representing the nodes of the graph of which
+ * strongly connected components are being computed.
*
+ * list contains the actual nodes
* check_closed is set if we may have used the fact that
* a pair of basic maps can be interchanged
*/
-struct basic_map_sort {
- int len;
- struct basic_map_sort_node *node;
- int *stack;
- int sp;
- int index;
- int *order;
- int op;
+struct isl_tc_follows_data {
+ isl_basic_map **list;
int check_closed;
};
-static void basic_map_sort_free(struct basic_map_sort *s)
-{
- if (!s)
- return;
- free(s->node);
- free(s->stack);
- free(s->order);
- free(s);
-}
-
-static struct basic_map_sort *basic_map_sort_alloc(struct isl_ctx *ctx, int len)
-{
- struct basic_map_sort *s;
- int i;
-
- s = isl_calloc_type(ctx, struct basic_map_sort);
- if (!s)
- return NULL;
- s->len = len;
- s->node = isl_alloc_array(ctx, struct basic_map_sort_node, len);
- if (!s->node)
- goto error;
- for (i = 0; i < len; ++i)
- s->node[i].index = -1;
- s->stack = isl_alloc_array(ctx, int, len);
- if (!s->stack)
- goto error;
- s->order = isl_alloc_array(ctx, int, 2 * len);
- if (!s->order)
- goto error;
-
- s->sp = 0;
- s->index = 0;
- s->op = 0;
-
- s->check_closed = 0;
-
- return s;
-error:
- basic_map_sort_free(s);
- return NULL;
-}
-
/* Check whether in the computation of the transitive closure
- * "bmap1" (R_1) should follow (or be part of the same component as)
- * "bmap2" (R_2).
+ * "list[i]" (R_1) should follow (or be part of the same component as)
+ * "list[j]" (R_2).
*
* That is check whether
*
* *check_closed is set if the subset relation holds while
* R_1 \circ R_2 is not empty.
*/
-static int basic_map_follows(__isl_keep isl_basic_map *bmap1,
- __isl_keep isl_basic_map *bmap2, int *check_closed)
+static int basic_map_follows(int i, int j, void *user)
{
+ struct isl_tc_follows_data *data = user;
struct isl_map *map12 = NULL;
struct isl_map *map21 = NULL;
int subset;
- if (!isl_space_tuple_match(bmap1->dim, isl_dim_in, bmap2->dim, isl_dim_out))
+ if (!isl_space_tuple_match(data->list[i]->dim, isl_dim_in,
+ data->list[j]->dim, isl_dim_out))
return 0;
map21 = isl_map_from_basic_map(
isl_basic_map_apply_range(
- isl_basic_map_copy(bmap2),
- isl_basic_map_copy(bmap1)));
+ isl_basic_map_copy(data->list[j]),
+ isl_basic_map_copy(data->list[i])));
subset = isl_map_is_empty(map21);
if (subset < 0)
goto error;
return 0;
}
- if (!isl_space_tuple_match(bmap1->dim, isl_dim_in, bmap1->dim, isl_dim_out) ||
- !isl_space_tuple_match(bmap2->dim, isl_dim_in, bmap2->dim, isl_dim_out)) {
+ if (!isl_space_tuple_match(data->list[i]->dim, isl_dim_in,
+ data->list[i]->dim, isl_dim_out) ||
+ !isl_space_tuple_match(data->list[j]->dim, isl_dim_in,
+ data->list[j]->dim, isl_dim_out)) {
isl_map_free(map21);
return 1;
}
map12 = isl_map_from_basic_map(
isl_basic_map_apply_range(
- isl_basic_map_copy(bmap1),
- isl_basic_map_copy(bmap2)));
+ isl_basic_map_copy(data->list[i]),
+ isl_basic_map_copy(data->list[j])));
subset = isl_map_is_subset(map21, map12);
isl_map_free(map21);
if (subset)
- *check_closed = 1;
+ data->check_closed = 1;
return subset < 0 ? -1 : !subset;
error:
return -1;
}
-/* Perform Tarjan's algorithm for computing the strongly connected components
- * in the graph with the disjuncts of "map" as vertices and with an
- * edge between any pair of disjuncts such that the first has
- * to be applied after the second.
- */
-static int power_components_tarjan(struct basic_map_sort *s,
- __isl_keep isl_basic_map **list, int i)
-{
- int j;
-
- s->node[i].index = s->index;
- s->node[i].min_index = s->index;
- s->node[i].on_stack = 1;
- s->index++;
- s->stack[s->sp++] = i;
-
- for (j = s->len - 1; j >= 0; --j) {
- int f;
-
- if (j == i)
- continue;
- if (s->node[j].index >= 0 &&
- (!s->node[j].on_stack ||
- s->node[j].index > s->node[i].min_index))
- continue;
-
- f = basic_map_follows(list[i], list[j], &s->check_closed);
- if (f < 0)
- return -1;
- if (!f)
- continue;
-
- if (s->node[j].index < 0) {
- power_components_tarjan(s, list, j);
- if (s->node[j].min_index < s->node[i].min_index)
- s->node[i].min_index = s->node[j].min_index;
- } else if (s->node[j].index < s->node[i].min_index)
- s->node[i].min_index = s->node[j].index;
- }
-
- if (s->node[i].index != s->node[i].min_index)
- return 0;
-
- do {
- j = s->stack[--s->sp];
- s->node[j].on_stack = 0;
- s->order[s->op++] = j;
- } while (j != i);
- s->order[s->op++] = -1;
-
- return 0;
-}
-
-/* Decompose the "len" basic relations in "list" into strongly connected
- * components.
- */
-static struct basic_map_sort *basic_map_sort_init(isl_ctx *ctx, int len,
- __isl_keep isl_basic_map **list)
-{
- int i;
- struct basic_map_sort *s = NULL;
-
- s = basic_map_sort_alloc(ctx, len);
- if (!s)
- return NULL;
- for (i = len - 1; i >= 0; --i) {
- if (s->node[i].index >= 0)
- continue;
- if (power_components_tarjan(s, list, i) < 0)
- goto error;
- }
-
- return s;
-error:
- basic_map_sort_free(s);
- return NULL;
-}
-
/* Given a union of basic maps R = \cup_i R_i \subseteq D \times D
* and a dimension specification (Z^{n+1} -> Z^{n+1}),
* construct a map that is an overapproximation of the map
{
int i, n, c;
struct isl_map *path = NULL;
- struct basic_map_sort *s = NULL;
+ struct isl_tc_follows_data data;
+ struct isl_tarjan_graph *g = NULL;
int *orig_exact;
int local_exact;
if (map->n <= 1)
return floyd_warshall(dim, map, exact, project);
- s = basic_map_sort_init(map->ctx, map->n, map->p);
- if (!s)
+ data.list = map->p;
+ data.check_closed = 0;
+ g = isl_tarjan_graph_init(map->ctx, map->n, &basic_map_follows, &data);
+ if (!g)
goto error;
orig_exact = exact;
- if (s->check_closed && !exact)
+ if (data.check_closed && !exact)
exact = &local_exact;
c = 0;
struct isl_map *comp;
isl_map *path_comp, *path_comb;
comp = isl_map_alloc_space(isl_map_get_space(map), n, 0);
- while (s->order[i] != -1) {
+ while (g->order[i] != -1) {
comp = isl_map_add_basic_map(comp,
- isl_basic_map_copy(map->p[s->order[i]]));
+ isl_basic_map_copy(map->p[g->order[i]]));
--n;
++i;
}
++c;
}
- if (c > 1 && s->check_closed && !*exact) {
+ if (c > 1 && data.check_closed && !*exact) {
int closed;
closed = isl_map_is_transitively_closed(path);
if (closed < 0)
goto error;
if (!closed) {
- basic_map_sort_free(s);
+ isl_tarjan_graph_free(g);
isl_map_free(path);
return floyd_warshall(dim, map, orig_exact, project);
}
}
- basic_map_sort_free(s);
+ isl_tarjan_graph_free(g);
isl_space_free(dim);
return path;
error:
- basic_map_sort_free(s);
+ isl_tarjan_graph_free(g);
isl_space_free(dim);
isl_map_free(path);
return NULL;
isl_basic_map **list;
isl_basic_map **next;
isl_union_map *path = NULL;
- struct basic_map_sort *s = NULL;
+ struct isl_tc_follows_data data;
+ struct isl_tarjan_graph *g = NULL;
int c, l;
int recheck = 0;
if (isl_union_map_foreach_map(umap, collect_basic_map, &next) < 0)
goto error;
- s = basic_map_sort_init(ctx, n, list);
- if (!s)
+ data.list = list;
+ data.check_closed = 0;
+ g = isl_tarjan_graph_init(ctx, n, &basic_map_follows, &data);
+ if (!g)
goto error;
c = 0;
isl_union_map *comp;
isl_union_map *path_comp, *path_comb;
comp = isl_union_map_empty(isl_union_map_get_space(umap));
- while (s->order[i] != -1) {
+ while (g->order[i] != -1) {
comp = isl_union_map_add_map(comp,
isl_map_from_basic_map(
- isl_basic_map_copy(list[s->order[i]])));
+ isl_basic_map_copy(list[g->order[i]])));
--l;
++i;
}
++c;
}
- if (c > 1 && s->check_closed && !*exact) {
+ if (c > 1 && data.check_closed && !*exact) {
int closed;
closed = isl_union_map_is_transitively_closed(path);
recheck = !closed;
}
- basic_map_sort_free(s);
+ isl_tarjan_graph_free(g);
for (i = 0; i < n; ++i)
isl_basic_map_free(list[i]);
return path;
error:
- basic_map_sort_free(s);
+ isl_tarjan_graph_free(g);
if (list) {
for (i = 0; i < n; ++i)
isl_basic_map_free(list[i]);