PIPS
scc.c
Go to the documentation of this file.
1 /*
2 
3  $Id: scc.c 23065 2016-03-02 09:05:50Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23  */
24 #ifdef HAVE_CONFIG_H
25 #include "pips_config.h"
26 #endif
27 
28 #include "local.h"
29 
30 /*
31 
32  this collection of functions implements Tarjan's algorithm to find the
33  strongly connected components of a directed graph.
34 
35  this algorithm is presented in:
36  Types de Donnees et Algorithmes
37  Recherche, Tri, Algorithmes sur les Graphes
38  Marie-Claude Gaudel, Michele Soria, Christine Froidevaux
39  Collection Didactique
40  INRIA
41 
42  the version implemented here has been modified because of Kennedy's
43  algorithm requirements: SCCs are searched for on a sub-graph of graph g
44  defined by:
45 
46  a set of nodes 'region'
47  all arcs of the initial graph whose level is greater than 'level'
48 
49  */
50 
51 /*
52  a set of macros to mark a vertex as 'not visited' or 'visited' and to
53  check if a node has already been visited
54  */
55 /* #define MIN(a,b) ((a)>(b)?(b):(a)) */
56 
57 #define NEW_MARK 1
58 #define OLD_MARK 2
59 #define MARK_OLD(v) \
60  (sccflags_mark(dg_vertex_label_sccflags((dg_vertex_label) \
61  vertex_vertex_label(v))) = OLD_MARK)
62 #define MARK_NEW(v) \
63  (sccflags_mark(dg_vertex_label_sccflags((dg_vertex_label) \
64  vertex_vertex_label(v))) = NEW_MARK)
65 #define MARKED_NEW_P(v) \
66  (sccflags_mark(dg_vertex_label_sccflags((dg_vertex_label) \
67  vertex_vertex_label(v))) == NEW_MARK)
68 
69 /*
70  a set of variables shared by the functions of this package. the stack
71  contains the current SCC, i.e. the SCC currently being built. Components
72  is the result, i.e. a set of scc
73  */
74 static int Count, StackPointer;
75 static vertex *Stack;
76 
77 /*
78  list of drivers functions used bt the SCC module
79  */
80 
83 
84 /*
85  drivers initialisation
86  */
87 
88 void set_sccs_drivers(ignore_this_vertex_fun, ignore_this_successor_fun)
89 bool (*ignore_this_vertex_fun)(set, vertex); bool (*ignore_this_successor_fun)(vertex, set, successor, int);
90 {
91  pips_assert( "ignore_this_vertex_drv is set", ignore_this_vertex_drv == 0 );
92  pips_assert( "ignore_this_successor_drv is set", ignore_this_successor_drv == 0 );
93 
94  ignore_this_vertex_drv = ignore_this_vertex_fun;
95  ignore_this_successor_drv = ignore_this_successor_fun;
96 }
97 
99  pips_assert( "ignore_this_vertex_drv is not set", ignore_this_vertex_drv != 0 );
100  pips_assert( "ignore_this_successor_drv is not set", ignore_this_successor_drv != 0 );
103 }
104 
105 /*
106  LowlinkCompute is the main function. Its behavior is explained in the
107  book mentionned ealier.
108 
109  g is a graph
110 
111  region and level define a sub-graph of g
112 
113  v is the current vertex
114  */
119 
120  pips_debug(7, "vertex is %zd (%zd %zd %zd)\n", statement_number(sv),
122 
123  MARK_OLD(v);
124 
125  sccflags_lowlink(fv) = Count;
126  sccflags_dfnumber(fv) = Count;
127 
128  Count++;
129 
130  Stack[StackPointer++] = v;
132 
133  if(!ignore_this_successor_drv(v, region, su, level)) {
134  vertex s = successor_vertex(su);
135 
136  if(!ignore_this_vertex_drv(region, s)) {
140 
141  pips_debug(7, "successor before is %zd (%zd %zd %zd)\n",
144 
145  if(MARKED_NEW_P(s)) {
147  pips_debug(7, "successor after is %zd (%zd %zd %zd)\n",
151  sccflags_lowlink(fs));
152  } else {
153  if((sccflags_dfnumber(fs) < sccflags_dfnumber(fv)) && IsInStack(s)) {
155  sccflags_lowlink(fv));
156  }
157  }
158  }
159  }
160  }
161 
162  if(sccflags_lowlink(fv) == sccflags_dfnumber(fv)) {
163  scc ns = make_scc(NIL, 0);
164  vertex p;
165  sccflags fp;
166  cons *pv = NIL;
167 
168  do {
169  p = Stack[--StackPointer];
172  sccflags_enclosing_scc(fp) = ns;
173  pv = gen_nconc(pv, CONS(VERTEX, p, NIL));
174  } while(v != p);
175 
176  scc_vertices(ns) = pv;
179  }
180 }
181 
182 /* this function checks if vertex v is in the stack */
184  int i;
185 
186  for (i = 0; i < StackPointer; i++)
187  if(Stack[i] == v)
188  return (true);
189 
190  return (false);
191 }
192 
193 /*
194  FindSccs is the interface function to compute the SCCs of a graph. It
195  marks all nodes as 'not visited' and then apply the main function
196  LowlinkCompute on all vertices.
197 
198  A vertex is processed only if it belongs to region. Later, successors
199  will be processed if they can be reached through arcs whose level is
200  greater or equal to level.
201 
202  g is a graph
203 
204  region and level define a sub-graph of g
205  */
207  list vertices = graph_vertices(g);
209 
210  Count = 1;
211  StackPointer = 0;
212  Stack = (vertex *)malloc(sizeof(vertex) * gen_length(vertices));
214  FOREACH(VERTEX, v, vertices) {
215  if(!ignore_this_vertex_drv(region, v)) {
218  if(fv == sccflags_undefined) {
219  pips_debug (7, "fv has not been set so far");
220  fv = make_sccflags(scc_undefined, 0, 0, 0);
221  dg_vertex_label_sccflags(lv) = fv;
222  }
223  sccflags_mark(fv) = NEW_MARK;
224  }
225  }
226  /* Bug FOREACH */FOREACH(VERTEX, v1, vertices) {
228  if(MARKED_NEW_P(v1)) {
230  }
231  }
232 
233  free(Stack);
234 
235  ifdebug(3) {
236  pips_debug(3, "Strongly connected components:\n");
238  pips_debug(3, "End\n");
239  }
240 
241  return (Components);
242 }
243 
244 void ComputeInDegree(graph g, set region, int l) {
246  {
247  if(!ignore_this_vertex_drv(region, v)) {
248  scc sv = VERTEX_ENCLOSING_SCC(v);
250  {
251  if(!ignore_this_successor_drv(v, region, su, l)) {
252  vertex s = successor_vertex(su);
253  scc ss = VERTEX_ENCLOSING_SCC(s);
254  if(sv != ss)
255  scc_indegree(ss) += 1;
256  }
257  }
258  }
259  }
260 }
261 
263  list lsccs = NIL, elsccs = NIL, no_ins = NIL;
265  if(scc_indegree(s) == 0)
266  no_ins = CONS(SCC, s, no_ins);
267  }
268 
269  while(no_ins != NIL) {
270  list pcs;
271  scc cs;
272 
273  pcs = no_ins;
274  no_ins = CDR(no_ins);
275  INSERT_AT_END(lsccs, elsccs, pcs);
276 
277  pips_debug(3, "updating in degrees ...\n");
278  cs = SCC(CAR(pcs));
279  FOREACH(VERTEX, v, scc_vertices(cs))
280  {
281  scc sv = VERTEX_ENCLOSING_SCC(v);
283  {
284  if(!ignore_this_successor_drv(v, region, su, l)) {
285  vertex s = successor_vertex(su);
286  scc ss = VERTEX_ENCLOSING_SCC(s);
287  if(sv != ss && (scc_indegree(ss) -= 1) == 0
288  && !ignore_this_vertex_drv(region, s)) {
289  no_ins = CONS(SCC, ss, no_ins);
290  }
291  }
292  }
293  }
294  }
295 
296  ifdebug(3) {
297  fprintf(stderr, "[TopSortSccs] topological order:\n");
298  FOREACH(SCC, s, lsccs) {
299  fprintf(stderr, "( ");
300  FOREACH(VERTEX, v, scc_vertices(s)) {
302 
303  fprintf(stderr, "%td ", statement_number(st));
304  }
305  fprintf(stderr, ") --> ");
306  }
307  fprintf(stderr, "\n");
308  }
309 
310  return (lsccs);
311 }
312 
313 /*
314  Don't forget to set the drivers before the call of this function and to
315  reset after!
316  */
318  list lsccs;
320 
321  ifdebug(8) {
322  pips_debug(8, "Dependence graph:\n");
324  }
325 
326  pips_debug(3, "computing sccs ...\n");
327 
328  Components = FindSccs(g, region, l);
329 
330  pips_debug(3, "computing in degrees ...\n");
331 
332  ComputeInDegree(g, region, l);
333 
334  pips_debug(3, "topological sort ...\n");
335 
336  lsccs = TopSortSccs(g, region, l,Components);
337 
338 // free_sccs(Components);
340  free(Components);
341 
342 
343  return (lsccs);
344 }
345 
346 void PrintScc(scc s) {
347  fprintf(stderr, "Scc's statements : ");
348  FOREACH(VERTEX, v, scc_vertices(s)) {
350 
351  fprintf(stderr, "%02td ", statement_number(st));
352  }
353  fprintf(stderr, " - in degree : %td\n", scc_indegree(s));
354 }
355 
356 void PrintSccs(sccs ss) {
357  fprintf(stderr, "Strongly connected components:\n");
358  if(!ENDP(sccs_sccs(ss))) {
359  MAPL(ps, {PrintScc(SCC(CAR(ps)));}, sccs_sccs(ss));
360  } else {
361  fprintf(stderr, "Empty list of scc\n");
362  }
363 }
float a2sf[2] __attribute__((aligned(16)))
USER generates a user error (i.e., non fatal) by printing the given MSG according to the FMT.
Definition: 3dnow.h:3
sccs make_sccs(list a)
Definition: dg.c:264
sccflags make_sccflags(scc a1, intptr_t a2, intptr_t a3, intptr_t a4)
Definition: dg.c:222
scc make_scc(list a1, intptr_t a2)
Definition: dg.c:306
void const char const char const int
#define MIN(x, y)
minimum and maximum if they are defined somewhere else, they are very likely to be defined the same w...
#define sccflags_undefined
Definition: dg.h:247
#define SCC(x)
SCC.
Definition: dg.h:315
#define dg_vertex_label_statement(x)
Definition: dg.h:235
#define sccflags_lowlink(x)
Definition: dg.h:279
#define sccflags_enclosing_scc(x)
Definition: dg.h:273
#define sccflags_mark(x)
Definition: dg.h:275
#define scc_indegree(x)
Definition: dg.h:347
#define dg_vertex_label_sccflags(x)
Definition: dg.h:237
#define scc_vertices(x)
Definition: dg.h:345
#define sccflags_dfnumber(x)
Definition: dg.h:277
struct _newgen_struct_dg_vertex_label_ * dg_vertex_label
Definition: dg.h:68
#define scc_undefined
Definition: dg.h:321
#define sccs_sccs(x)
Definition: dg.h:311
struct _newgen_struct_vertex_ * vertex
Definition: dg.h:28
#define region
simulation of the type region
void * malloc(YYSIZE_T)
void free(void *)
#define successor_vertex(x)
Definition: graph.h:118
#define vertex_vertex_label(x)
Definition: graph.h:152
#define vertex_successors(x)
Definition: graph.h:154
struct _newgen_struct_successor_ * successor
Definition: graph.h:39
#define SUCCESSOR(x)
SUCCESSOR.
Definition: graph.h:86
#define graph_vertices(x)
Definition: graph.h:82
#define VERTEX(x)
VERTEX.
Definition: graph.h:122
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
size_t gen_length(const list l)
Definition: list.c:150
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
#define MAPL(_map_list_cp, _code, _l)
Apply some code on the addresses of all the elements of a list.
Definition: newgen_list.h:203
statement vertex_to_statement(vertex v)
Vertex_to_statement looks for the statement that is pointed to by vertex v.
Definition: util.c:45
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
struct _set_chunk * set
Definition: newgen_set.h:38
int bool
we cannot use an enum or stdbool because we need to be compatible with newgen, thus boolean need to h...
Definition: newgen_types.h:78
statement ordering_to_statement(int o)
Get the statement associated to a given ordering.
Definition: ordering.c:111
#define statement_number(x)
Definition: ri.h:2452
#define statement_undefined
Definition: ri.h:2419
#define VERTEX_ENCLOSING_SCC(v)
macros
Definition: rice-local.h:25
#define INSERT_AT_END(bl, el, c)
a macro to insert an element at the end of a list.
Definition: rice-local.h:34
void prettyprint_dependence_graph(FILE *, statement, graph)
Print all edges and arcs.
Definition: util.c:177
#define level
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
void PrintSccs(sccs ss)
Definition: scc.c:356
void ComputeInDegree(graph g, set region, int l)
Definition: scc.c:244
#define MARKED_NEW_P(v)
Definition: scc.c:65
list FindAndTopSortSccs(graph g, set region, int l)
Definition: scc.c:317
sccs FindSccs(graph g, set region, int level)
FindSccs is the interface function to compute the SCCs of a graph.
Definition: scc.c:206
list TopSortSccs(graph __attribute__((unused)) g, set region, int l, sccs Components)
Definition: scc.c:262
void reset_sccs_drivers()
Definition: scc.c:98
int IsInStack(vertex v)
this function checks if vertex v is in the stack
Definition: scc.c:183
void set_sccs_drivers(bool *ignore_this_vertex_fun, bool *ignore_this_successor_fun)
Definition: scc.c:88
void LowlinkCompute(graph g, set region, vertex v, int level, sccs Components)
Definition: scc.c:115
static vertex * Stack
Definition: scc.c:75
static bool(* ignore_this_successor_drv)(vertex, set, successor, int)=0
Definition: scc.c:82
#define MARK_OLD(v)
Definition: scc.c:59
static int Count
a set of variables shared by the functions of this package.
Definition: scc.c:74
static int StackPointer
Definition: scc.c:74
static bool(* ignore_this_vertex_drv)(set, vertex)=0
Definition: scc.c:81
void PrintScc(scc s)
Definition: scc.c:346
#define NEW_MARK
a set of macros to mark a vertex as 'not visited' or 'visited' and to check if a node has already bee...
Definition: scc.c:57
static sccs Components
Definition: sccdfg.c:126
#define ifdebug(n)
Definition: sg.c:47
FI: I do not understand why the type is duplicated at the set level.
Definition: set.c:59
The structure used to build lists in NewGen.
Definition: newgen_list.h:41