xref: /llvm-project/polly/lib/External/isl/isl_tarjan.c (revision a7f1e0403116136f3ab9aa71eff5b92b28fd417f)
152a25237STobias Grosser /*
252a25237STobias Grosser  * Copyright 2010-2011 INRIA Saclay
352a25237STobias Grosser  * Copyright 2012      Ecole Normale Superieure
452a25237STobias Grosser  *
552a25237STobias Grosser  * Use of this software is governed by the MIT license
652a25237STobias Grosser  *
752a25237STobias Grosser  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
852a25237STobias Grosser  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
952a25237STobias Grosser  * 91893 Orsay, France
1052a25237STobias Grosser  * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
1152a25237STobias Grosser  */
1252a25237STobias Grosser 
1352a25237STobias Grosser #include <stdlib.h>
1452a25237STobias Grosser #include <isl/ctx.h>
1552a25237STobias Grosser #include <isl_tarjan.h>
1652a25237STobias Grosser 
isl_tarjan_graph_free(struct isl_tarjan_graph * g)17*a7f1e040STobias Grosser struct isl_tarjan_graph *isl_tarjan_graph_free(struct isl_tarjan_graph *g)
1852a25237STobias Grosser {
1952a25237STobias Grosser 	if (!g)
20*a7f1e040STobias Grosser 		return NULL;
2152a25237STobias Grosser 	free(g->node);
2252a25237STobias Grosser 	free(g->stack);
2352a25237STobias Grosser 	free(g->order);
2452a25237STobias Grosser 	free(g);
25*a7f1e040STobias Grosser 	return NULL;
2652a25237STobias Grosser }
2752a25237STobias Grosser 
isl_tarjan_graph_alloc(isl_ctx * ctx,int len)2852a25237STobias Grosser static struct isl_tarjan_graph *isl_tarjan_graph_alloc(isl_ctx *ctx, int len)
2952a25237STobias Grosser {
3052a25237STobias Grosser 	struct isl_tarjan_graph *g;
3152a25237STobias Grosser 	int i;
3252a25237STobias Grosser 
3352a25237STobias Grosser 	g = isl_calloc_type(ctx, struct isl_tarjan_graph);
3452a25237STobias Grosser 	if (!g)
3552a25237STobias Grosser 		return NULL;
3652a25237STobias Grosser 	g->len = len;
3752a25237STobias Grosser 	g->node = isl_alloc_array(ctx, struct isl_tarjan_node, len);
3852a25237STobias Grosser 	if (len && !g->node)
3952a25237STobias Grosser 		goto error;
4052a25237STobias Grosser 	for (i = 0; i < len; ++i)
4152a25237STobias Grosser 		g->node[i].index = -1;
4252a25237STobias Grosser 	g->stack = isl_alloc_array(ctx, int, len);
4352a25237STobias Grosser 	if (len && !g->stack)
4452a25237STobias Grosser 		goto error;
4552a25237STobias Grosser 	g->order = isl_alloc_array(ctx, int, 2 * len);
4652a25237STobias Grosser 	if (len && !g->order)
4752a25237STobias Grosser 		goto error;
4852a25237STobias Grosser 
4952a25237STobias Grosser 	g->sp = 0;
5052a25237STobias Grosser 	g->index = 0;
5152a25237STobias Grosser 	g->op = 0;
5252a25237STobias Grosser 
5352a25237STobias Grosser 	return g;
5452a25237STobias Grosser error:
5552a25237STobias Grosser 	isl_tarjan_graph_free(g);
5652a25237STobias Grosser 	return NULL;
5752a25237STobias Grosser }
5852a25237STobias Grosser 
5952a25237STobias Grosser /* Perform Tarjan's algorithm for computing the strongly connected components
6052a25237STobias Grosser  * in the graph with g->len nodes and with edges defined by "follows".
6152a25237STobias Grosser  */
isl_tarjan_components(struct isl_tarjan_graph * g,int i,isl_bool (* follows)(int i,int j,void * user),void * user)62b2f39926STobias Grosser static isl_stat isl_tarjan_components(struct isl_tarjan_graph *g, int i,
63b2f39926STobias Grosser 	isl_bool (*follows)(int i, int j, void *user), void *user)
6452a25237STobias Grosser {
6552a25237STobias Grosser 	int j;
6652a25237STobias Grosser 
6752a25237STobias Grosser 	g->node[i].index = g->index;
6852a25237STobias Grosser 	g->node[i].min_index = g->index;
6952a25237STobias Grosser 	g->node[i].on_stack = 1;
7052a25237STobias Grosser 	g->index++;
7152a25237STobias Grosser 	g->stack[g->sp++] = i;
7252a25237STobias Grosser 
7352a25237STobias Grosser 	for (j = g->len - 1; j >= 0; --j) {
74b2f39926STobias Grosser 		isl_bool f;
7552a25237STobias Grosser 
7652a25237STobias Grosser 		if (j == i)
7752a25237STobias Grosser 			continue;
7852a25237STobias Grosser 		if (g->node[j].index >= 0 &&
7952a25237STobias Grosser 			(!g->node[j].on_stack ||
8052a25237STobias Grosser 			 g->node[j].index > g->node[i].min_index))
8152a25237STobias Grosser 			continue;
8252a25237STobias Grosser 
8352a25237STobias Grosser 		f = follows(i, j, user);
8452a25237STobias Grosser 		if (f < 0)
85b2f39926STobias Grosser 			return isl_stat_error;
8652a25237STobias Grosser 		if (!f)
8752a25237STobias Grosser 			continue;
8852a25237STobias Grosser 
8952a25237STobias Grosser 		if (g->node[j].index < 0) {
9052a25237STobias Grosser 			isl_tarjan_components(g, j, follows, user);
9152a25237STobias Grosser 			if (g->node[j].min_index < g->node[i].min_index)
9252a25237STobias Grosser 				g->node[i].min_index = g->node[j].min_index;
9352a25237STobias Grosser 		} else if (g->node[j].index < g->node[i].min_index)
9452a25237STobias Grosser 			g->node[i].min_index = g->node[j].index;
9552a25237STobias Grosser 	}
9652a25237STobias Grosser 
9752a25237STobias Grosser 	if (g->node[i].index != g->node[i].min_index)
98b2f39926STobias Grosser 		return isl_stat_ok;
9952a25237STobias Grosser 
10052a25237STobias Grosser 	do {
10152a25237STobias Grosser 		j = g->stack[--g->sp];
10252a25237STobias Grosser 		g->node[j].on_stack = 0;
10352a25237STobias Grosser 		g->order[g->op++] = j;
10452a25237STobias Grosser 	} while (j != i);
10552a25237STobias Grosser 	g->order[g->op++] = -1;
10652a25237STobias Grosser 
107b2f39926STobias Grosser 	return isl_stat_ok;
10852a25237STobias Grosser }
10952a25237STobias Grosser 
11052a25237STobias Grosser /* Decompose the graph with "len" nodes and edges defined by "follows"
11152a25237STobias Grosser  * into strongly connected components (SCCs).
11252a25237STobias Grosser  * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
11352a25237STobias Grosser  * It should return -1 on error.
11452a25237STobias Grosser  *
11552a25237STobias Grosser  * If SCC a contains a node i that follows a node j in another SCC b
11652a25237STobias Grosser  * (i.e., follows(i, j, user) returns 1), then SCC a will appear after SCC b
11752a25237STobias Grosser  * in the result.
11852a25237STobias Grosser  */
isl_tarjan_graph_init(isl_ctx * ctx,int len,isl_bool (* follows)(int i,int j,void * user),void * user)11952a25237STobias Grosser struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len,
120b2f39926STobias Grosser 	isl_bool (*follows)(int i, int j, void *user), void *user)
12152a25237STobias Grosser {
12252a25237STobias Grosser 	int i;
12352a25237STobias Grosser 	struct isl_tarjan_graph *g = NULL;
12452a25237STobias Grosser 
12552a25237STobias Grosser 	g = isl_tarjan_graph_alloc(ctx, len);
12652a25237STobias Grosser 	if (!g)
12752a25237STobias Grosser 		return NULL;
12852a25237STobias Grosser 	for (i = len - 1; i >= 0; --i) {
12952a25237STobias Grosser 		if (g->node[i].index >= 0)
13052a25237STobias Grosser 			continue;
13152a25237STobias Grosser 		if (isl_tarjan_components(g, i, follows, user) < 0)
132*a7f1e040STobias Grosser 			return isl_tarjan_graph_free(g);
13352a25237STobias Grosser 	}
13452a25237STobias Grosser 
13552a25237STobias Grosser 	return g;
136*a7f1e040STobias Grosser }
137*a7f1e040STobias Grosser 
138*a7f1e040STobias Grosser /* Decompose the graph with "len" nodes and edges defined by "follows"
139*a7f1e040STobias Grosser  * into the strongly connected component (SCC) that contains "node"
140*a7f1e040STobias Grosser  * as well as all SCCs that are followed by this SCC.
141*a7f1e040STobias Grosser  * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
142*a7f1e040STobias Grosser  * It should return -1 on error.
143*a7f1e040STobias Grosser  *
144*a7f1e040STobias Grosser  * The SCC containing "node" will appear as the last component
145*a7f1e040STobias Grosser  * in g->order.
146*a7f1e040STobias Grosser  */
isl_tarjan_graph_component(isl_ctx * ctx,int len,int node,isl_bool (* follows)(int i,int j,void * user),void * user)147*a7f1e040STobias Grosser struct isl_tarjan_graph *isl_tarjan_graph_component(isl_ctx *ctx, int len,
148*a7f1e040STobias Grosser 	int node, isl_bool (*follows)(int i, int j, void *user), void *user)
149*a7f1e040STobias Grosser {
150*a7f1e040STobias Grosser 	struct isl_tarjan_graph *g;
151*a7f1e040STobias Grosser 
152*a7f1e040STobias Grosser 	g = isl_tarjan_graph_alloc(ctx, len);
153*a7f1e040STobias Grosser 	if (!g)
15452a25237STobias Grosser 		return NULL;
155*a7f1e040STobias Grosser 	if (isl_tarjan_components(g, node, follows, user) < 0)
156*a7f1e040STobias Grosser 		return isl_tarjan_graph_free(g);
157*a7f1e040STobias Grosser 
158*a7f1e040STobias Grosser 	return g;
15952a25237STobias Grosser }
160