PIPS
control.c
Go to the documentation of this file.
1 /*
2 
3  $Id: control.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 /* Some utilities to deal with the control graph.
28  It is mainly used by my unspaghettify and the controlizer.
29 
30  Ronan Keryell.
31 */
32 
33 #ifndef lint
34 char vcid_ri_util_control[] = "$Id: control.c 23065 2016-03-02 09:05:50Z coelho $";
35 #endif /* lint */
36 
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40 
41 #include "linear.h"
42 
43 #include "genC.h"
44 #include "ri.h"
45 #include "ri-util.h"
46 #include "misc.h"
47 
48 /* \defgroup control Control and unstructured methods
49 
50  Here are most of the functions that deals with control graph in PIPS
51  that are encapsulated in what is called an "unstructured" in the RI.
52 
53  @{
54  */
55 
56 
57 /* \defgroup control_visitors Control node visitors */
58 
59 /* @{ */
60 
61 /* Build recursively the list of all controls reachable from a control of
62  an unstructured.
63 
64  It is usually called from the CONTROL_MAP macro, with the entry node of
65  an unstructured as initial argument. It uses both successors and
66  predecessors to define reachability, i.e. the graph arcs are
67  considered edges.
68 
69  @param c is a control node to start with
70 
71  @param l is a list used to stored the visited nodes. It must be
72  initialized to the list of nodes to skip. To visit all the nodes from
73  c, just give a list variable initialized to NIL
74 */
76 {
77  MAPL( cs,
78  {if( CONTROL( CAR( cs )) == c ) return ;},
79  *l ) ;
80  *l = CONS( CONTROL, c, *l ) ;
81  MAPL( cs,
82  {control_map_get_blocs( CONTROL( CAR( cs )), l );},
83  control_successors( c )) ;
84  MAPL( ps, {control_map_get_blocs( CONTROL( CAR( ps )), l );},
85  control_predecessors( c )) ;
86 }
87 
88 /* Build recursively a control path from b to e
89 
90  It is used for debugging purposes
91 
92  @param b is a control node to begin with
93 
94  @param e is a control node to end with
95 
96  @param pp is a pointer to the list used to stored the path from b
97  to e. It includes both b and e.
98 
99  @param vp is a pointer to the list used to stored the visited nodes. It must be
100  initialized to the list of nodes to skip if any. To visit all the nodes from
101  c, just give a list variable initialized to NIL. It usually must be
102  by the caller.
103 
104  @param dir request a forward path is strictly positive, a backward
105  path is stricly negative and an undirected path if zero.
106 */
107 void find_a_control_path(control b, control e, list * pp, list * vp, int dir)
108 {
109  if(b==e) {
110  *pp = CONS(CONTROL, b, NIL);
111  return;
112  }
113 
114  if(ENDP(*pp) && !gen_in_list_p(b, *vp)) {
115  *vp = CONS(CONTROL, b, *vp);
116  if(dir>=0) {
118  find_a_control_path(s, e, pp, vp, dir);
119  if(!ENDP(*pp)) {
120  pips_assert("e is the last element of *pp",
121  e==CONTROL(CAR(gen_last(*pp))));
122  *pp = CONS(CONTROL, s, *pp);
123  return;
124  }
125  }
126  }
127  if(dir<=0) {
129  find_a_control_path(p, e, pp, vp, dir);
130  if(!ENDP(*pp)) {
131  pips_assert("e is the last element of *pp",
132  e==CONTROL(CAR(gen_last(*pp))));
133  *pp = CONS(CONTROL, p, *pp);
134  return;
135  }
136  }
137  }
138  }
139  pips_assert("*pp is empty", ENDP(*pp));
140  return;
141 }
142 
143 /* Build recursively the list of all controls backward-reachable from a
144  control of an unstructured.
145 
146  It is usually called from the BACKWARD_CONTROL_MAP macro, with the
147  entry node of an unstructured as initial argument. It uses predecessors
148  to define reachability.
149 
150  @param c is a control node to start with
151 
152  @param l is a list used to stored the visited nodes. It must be
153  initialized to the list of nodes to skip. To visit all the nodes from
154  c, just give a list variable initialized to NIL
155 */
156 void
158 control c ;
159 cons **l ;
160 {
161  MAPL( cs, {if( CONTROL( CAR( cs )) == c ) return ;}, *l ) ;
162  *l = CONS( CONTROL, c, *l ) ;
163  MAPL( cs,
164  {backward_control_map_get_blocs( CONTROL( CAR( cs )), l );},
165  control_predecessors( c )) ;
166 }
167 
168 
169 /* Transitive closure of c's predecessors, but for control f.
170 
171  It is like backward_control_map_get_blocs() but avoid visiting a
172  control node. It is used to visit subgraphs begining at c and ending at
173  f (excluded).
174 
175  @param c is a control node to start with
176 
177  @param f is a control node not to visit
178 
179  @param l is a list used to stored the visited nodes. It must be
180  initialized to the list of nodes to skip. To visit all the nodes from
181  c, just give a list variable initialized to NIL
182 */
183 void
185 {
186  if(gen_in_list_p(c, *l) || c == f) return;
187  *l = CONS( CONTROL, c, *l ) ;
188  MAPL( cs, {
190  }, control_predecessors( c )) ;
191 }
192 
193 
194 /* Build recursively the list of all controls forward-reachable from a
195  control of an unstructured.
196 
197  It is usually called from the FORWARD_CONTROL_MAP macro, with the entry
198  node of an unstructured as initial argument. It uses successors to
199  define reachability.
200 
201  @param c is a control node to start with
202 
203  @param l is a list used to stored the visited nodes. It must be
204  initialized to the list of nodes to skip. To visit all the nodes from
205  c, just give a list variable initialized to NIL
206 */
207 void
209 control c ;
210 cons **l ;
211 {
212  MAPL( cs, {if( CONTROL( CAR( cs )) == c ) return ;}, *l ) ;
213  *l = CONS( CONTROL, c, *l ) ;
214  MAPL( cs,
215  {forward_control_map_get_blocs( CONTROL( CAR( cs )), l );},
216  control_successors( c )) ;
217 }
218 
219 /* Transitive closure of c's successors, but for control f.
220 
221  It is like forward_control_map_get_blocs() but avoid visiting a
222  control node. It is used to visit subgraphs begining at c and ending at
223  f (excluded).
224 
225  @param c is a control node to start with
226 
227  @param f is a control node not to visit
228 
229  @param l is a list used to stored the visited nodes. It must be
230  initialized to the list of nodes to skip. To visit all the nodes from
231  c, just give a list variable initialized to NIL
232 */
233 void
235 {
236  if(gen_in_list_p(c, *l) || c == f) return;
237  *l = CONS( CONTROL, c, *l ) ;
238  MAPL( cs, {
240  }, control_successors( c )) ;
241 }
242 
243 
244 /* Same as above, but follows successors by minimal path lengths. It is OK
245  if there is only one path length when computing transformers and/or
246  preconditions. However, if a node is reached by several paths, the node
247  with the minimal maximal path length should come first.
248 
249  This last condition assumes infinite path length for nodes in cycles
250  (?). It is not implemented. */
251 void
253 control c ;
254 cons **l ;
255 {
256  list nodes = NIL;
257  list frontier = CONS( CONTROL, c, NIL );
258  list new_frontier = NIL;
259 
260  while(!ENDP(frontier)) {
261  MAP(CONTROL,c ,{
262  MAP(CONTROL, cp, {
263  if(!is_control_in_list_p(cp, nodes)
264  && !is_control_in_list_p(cp, frontier)
265  && !is_control_in_list_p(cp, new_frontier))
266  new_frontier = CONS(CONTROL, cp, new_frontier);
267  }, control_successors(c));
268  }, frontier);
269  nodes = gen_append(nodes, frontier);
270  frontier = new_frontier;
271  new_frontier = NIL;
272  }
273 
274  *l = nodes;
275 }
276 /* @} */
277 
278 
279 /* \defgroup control_methods Functions to manage control the graph and
280  unstructured
281 
282  @{
283 */
284 
285 
286 
287 /* Test if a control node is in a list of control nodes
288 
289  FI: is this different from gen_in_list_p(), but for the c type and
290  the qualifiers?
291 
292  @param c control node to look for
293 
294  @param cs is the list of control to search through
295 
296  @return true if the control node is in the list
297 */
298 bool
300  list cs)
301 {
302  MAP(CONTROL, cc, {
303  if (cc == c)
304  return true;
305  }, cs);
306  return false;
307 }
308 
309 /* Count the number of occurences of a control node in a list of control
310  nodes
311 
312  @param c control node to look for
313 
314  @param cs is the list of control to count through
315 
316  @return the number of occurences
317  */
318 int
320  list cs)
321 {
322  return gen_occurences((gen_chunk *) c, cs);
323 }
324 
325 
326 /* Replace in a list of control nodes all the instance of a control node
327  by another one
328 
329  @param l is the list of control nodes
330 
331  @param c_old is the control node to remove
332 
333  @param c_new is the control node to put instead
334  */
335 void
337  control c_old,
338  control c_new)
339 {
340  gen_list_patch(l, (gen_chunk *) c_old, (gen_chunk *) c_new);
341 }
342 
343 
344 /* Transfer a control node as a predecessor from one node to another one
345 
346  It disconnected a node @p c that was pointing to (was a predecessor of)
347  @p old_node and reconnect it to @p new_node that becomes its new
348  successor instead.
349 
350  @param old_node the control node that was a successor of @p c
351 
352  @param new_node the control node that will be a successor of @p c
353 
354  @param c the control node that is disconnected of @p old_node and
355  connected to @p new_node
356  */
357 void
359  control new_node,
360  control c)
361 {
363  if (predecessor == c)
364  /* Add c as a predecessor of new_node: */
365  control_predecessors(new_node) =
367  CONS(CONTROL, c, NIL));
368  }, control_predecessors(old_node));
369  /* Remove c as a predecessor of old_node: */
370  gen_remove(&control_predecessors(old_node), c);
371  /* Correct the reverse link c->old_node to c->new_node: */
372  control_list_patch(control_successors(c), old_node, new_node);
373 }
374 
375 
376 /* Transfer a control node as a successor of one node to another one
377 
378  It disconnected a node @p c that was coming from (was a successor of)
379  @p old_node and reconnect it to @p new_node that becomes its new
380  predecessor instead.
381 
382  @param old_node the control node that was a predecessor of @p c
383 
384  @param new_node the control node that will be a predecessor of @p c
385 
386  @param c the control node that is disconnected of @p old_node and
387  connected to @p new_node
388 */
389 void
391  control new_node,
392  control c)
393 {
394  MAP(CONTROL, successor, {
395  if (successor == c)
396  /* Add c as a predecessor of new_node: */
397  control_successors(new_node) =
398  gen_nconc(control_successors(new_node),
399  CONS(CONTROL, c, NIL));
400  }, control_successors(old_node));
401  /* Remove c as a successor of old_node: */
402  gen_remove(&control_successors(old_node), c);
403  /* Correct the reverse link c->old_node to c->new_node: */
404  control_list_patch(control_predecessors(c), old_node, new_node);
405 }
406 
407 
408 /* Replace all the references to a control node by a new one in the
409  successors & predecessors of a list of controls
410 
411  @param old_node is the control node to replace
412 
413  @param new_node is the control node to replace
414 
415  @param controls is a list of controls we want to disconnect from @p
416  old_node and reconnect to @p new_node instead
417  */
418 void
420  control new_node,
421  list controls)
422 {
423  /* Need a intermediate list since we cannot iterate on
424  control_successors(old_node) for example and modifying it...*/
425  list controls_to_change = NIL;
426  /* Since we need to keep successors order (to avoid for example
427  IF/THEN/ELSE transformed in IF/ELSE/THEN), iterate directly on
428  the links of old_node instead of on controls: */
429  /* First transfer the successors in controls from old_node to
430  new_node: */
431  MAP(CONTROL, c, {
432  if (gen_in_list_p(c, controls))
433  /* Use gen_nconc to keep test order: */
434  controls_to_change = gen_nconc(controls_to_change,
435  CONS(CONTROL, c, NIL));
436  }, control_successors(old_node));
437  /* And then do the modification: */
438  MAP(CONTROL, c, {
439  pips_debug(8, "Transfer old node %p to new node %p in successor %p\n", old_node, new_node, c);
440  if (c != old_node)
441  transfer_control_successor(old_node, new_node, c);
442  else {
443  /* Hmmm... We need to transfer a loop around old_node to a
444  loop around new_node: */
445  /* Create the new loop around new_node: */
446  control_successors(new_node) =
447  gen_nconc(control_successors(new_node),
448  CONS(CONTROL, new_node, NIL));
449  control_predecessors(new_node) =
451  CONS(CONTROL, new_node, NIL));
452  /* Delete the old one. Use gen_remove_once() instead of
453  gen_remove() to deal with double loops around a node
454  (See hierarchy02.f in validation): */
455  gen_remove_once(&control_successors(old_node), (gen_chunk *) old_node);
456  gen_remove_once(&control_predecessors(old_node), (gen_chunk *) old_node);
457  }
458  }, controls_to_change);
459  gen_free_list(controls_to_change);
460 
461  /* And then transfer the predecessors in controls from old_node to
462  new_node (the previous double loops have disappeared here): */
463  controls_to_change = NIL;
464  MAP(CONTROL, c, {
465  if (gen_in_list_p(c, controls))
466  /* Use gen_nconc to keep test order: */
467  controls_to_change = gen_nconc(controls_to_change,
468  CONS(CONTROL, c, NIL));
469  }, control_predecessors(old_node));
470  /* And then do the modification: */
471  MAP(CONTROL, c, {
472  pips_debug(8, "Transfer old node %p to new node %p in predecessor %p\n", old_node, new_node, c);
473  transfer_control_predecessor(old_node, new_node, c);
474  }, controls_to_change);
475  gen_free_list(controls_to_change);
476 }
477 
478 
479 /* Test the coherency of a control node network from a control node.
480 
481  Do not verify the fact that nodes could appear twice in the case of
482  unstructured tests.
483 
484  @param c is the control node we want to start the verification from
485  */
486 void
488 {
489  list blocs = NIL;
490  int i1, i2;
491  set stmts = set_make(set_pointer);
492 
494 
495  CONTROL_MAP(ctl, {
496 
497  /* Test the coherency of the successors */
498  MAP(CONTROL, cc, {
499  /* if (!is_control_in_list_p(ctl, control_predecessors(cc))) { */
502  if(i1==0) {
503  pips_debug(0, "Control node %p not in the predecessor list of %p\n", ctl, cc);
504  }
505  else {
506  pips_debug(0, "Control %p occurs %d times in the predecessor list of %p"
507  " while control %p occurs %d times in the successor list of %p\n",
508  ctl, i1, cc, cc, i2, ctl);
509  }
510  ifdebug(8)
511  pips_assert("Control is correct", false);
512  }
513  }, control_successors(ctl));
514 
515  /* Test the coherency of the predecessors */
516  MAP(CONTROL, cc, {
517  /* if (!is_control_in_list_p(ctl, control_successors(cc))) { */
520  bool consistent_p = false;
521  if(i1==0) {
522  pips_debug(0, "Control node %p not in the successor list of %p\n", ctl, cc);
523  }
524  else {
525  if(statement_test_p(control_statement(cc)) && i1>=2 && i2==1) {
526  consistent_p = true;
527  }
528  else {
529  pips_debug(0, "Control %p occurs %d times in the successor list of %p"
530  " while control %p occurs %d times in the predecessor list of %p\n",
531  ctl, i1, cc, cc, i2, ctl);
532  }
533  }
534  ifdebug(8) {
535  if(!consistent_p) {
536  pips_debug(8, "control %p is not correct\n", cc);
537  pips_assert("Control is correct", consistent_p);
538  }
539  }
540  }
541  }, control_predecessors(ctl));
542 
543  /* Check that the statement are consistent */
545 
546  /* Check that two nodes do not point towards the same
547  statement as this makes label resolution ambiguous */
548  if(set_belong_p(stmts, control_statement(ctl))) {
549  fprintf(stderr, "Statement %p is pointed by two different control nodes\n", control_statement(ctl));
550  pips_assert("each statement appears in at most one control node", false);
551  }
552  else
553  stmts = set_add_element(stmts, stmts, (void *) control_statement(ctl));
554  }, c, blocs);
555 
556  set_free(stmts);
557  gen_free_list(blocs);
558 }
559 
560 
561 // FI: as commented, needed for debugging purposes
562 // #if 0
563 /*
564  Prettyprinting of control nodes for debugging purposes
565 */
567 {
568  fprintf(stderr,
569  "ctr %p, %zd preds, %zd succs: %s",
570  c,
574  fprintf(stderr,"\tsuccessors:\n");
575  MAP(CONTROL, s, {
576  fprintf(stderr, "\t\t%p %s", s,
578  }, control_successors(c));
579  fprintf(stderr,"\tpredecessors:\n");
580  MAP(CONTROL, p, {
581  fprintf(stderr, "\t\t%p %s", p,
583  }, control_predecessors(c));
584  fprintf(stderr, "\n");
585 }
586 
587 
588 /* Display identification of a list of control nodes */
590 {
591  if(ENDP(l)) {
592  fprintf(stderr, "empty control list");
593  }
594  else {
595  MAP(CONTROL, c, {
596  fprintf(stderr, "%p, %s", c,
598  // The version used in control/bourdoncle.c also had this check
599  // (void) check_control_statement(c);
600  }, l);
601  }
602  fprintf(stderr, "\n");
603 }
604 //#endif
605 
606 
607 /* Display the adresses a list of control nodes
608 
609  @param cs is the control node list
610 */
611 void
613 {
614  MAP(CONTROL, cc,
615  {
616  fprintf(stderr, "%p,", cc);
617  }, cs);
618 }
619 
620 
621 /* Display all the control nodes reached or reachable from c for debugging
622  purpose
623 
624  Display also the statement of each control node if the debug level is
625  high enough
626 
627  @param c is the control node we start the visit from
628 */
630 {
631  list blocs = NIL;
632  set stmts = set_make(set_pointer);
633 
634  CONTROL_MAP(ctl, {
635  fprintf(stderr, "%p (pred (#%zd)=", ctl,
638  fprintf(stderr, " succ (#%zd)=", gen_length(control_successors(ctl)));
640  fprintf(stderr, "), ");
641  ifdebug(8) {
642  fprintf(stderr, "\n");
643  pips_debug(8, "Statement %p of control %p:\n", control_statement(ctl), ctl);
644  // FI: no cycle with prettyprint
645  /* safe_print_statement(control_statement(ctl)); */
646  }
647  if(set_belong_p(stmts, control_statement(ctl))) {
648  fprintf(stderr, "Statement %p is pointed by two different control nodes\n",
649  control_statement(ctl));
650  }
651  else
652  stmts = set_add_element(stmts, stmts, (void *) control_statement(ctl));
653  }, c, blocs);
654  gen_free_list(blocs);
655  set_free(stmts);
656 
657  fprintf(stderr, "---\n");
658 }
659 
660 
661 /* Remove all the control nodes (with their statements) from @p c in the
662  successor tree of @p c up to the nodes with more than 1 predecessor,
663  that is when it reach another flow.
664 
665  The entry node of the unstructured is given to avoid removing it
666  when there is an unreachable sequence pointing on it.
667 
668  If a control node contains a FORMAT, assume that it is useful and
669  stop removing.
670 
671  The @param do_not_delete_node is expected to be the entry or the exit node
672  for example in order not to delete them.
673 
674  @param c is the control we start the deletion from.
675 
676  @param do_not_delete_node is a control node we stop at when encountered
677 
678  @param do_not_delete_node_either is another control node we stop at
679  when encountered
680  */
681 void
683  control do_not_delete_node,
684  control do_not_delete_node_either)
685 {
686  list the_successors;
687 
688  /* If this is the do_not_delete_node nodes: stop deleting: */
689  if (c == do_not_delete_node || c == do_not_delete_node_either)
690  return;
691  /* If this is not or no more the begin of a sequence, stop deleting: */
692  if (control_predecessors(c) != NIL)
693  return;
694  /* If there is a FORMAT inside a control node, just stop deleting
695  the control nodes since we cannot decide locally if the FORMAT
696  is useful or not: */
698  return;
699 
700  /* Save the successor list since we iterate o it and discard it at
701  the same time: */
702  the_successors = gen_copy_seq(control_successors(c));
703  /* Ok, we can delete. For each successor of c: */
704  MAP(CONTROL, a_successor, {
705  /* Remove any predecessor reference of itself in this
706  successor: */
707  unlink_2_control_nodes(c, a_successor);
709  do_not_delete_node,
710  do_not_delete_node_either);
711  }, the_successors);
712  gen_free_list(the_successors);
713 
714  /* Discard the control node itself: */
715  pips_debug(7, "Discarding control node %p.\n", c);
716  ifdebug(7) {
718  }
719  free_control(c);
720 }
721 
722 
723 /* Remove all the control sequences that are unreachable and that
724  begin with a node without any predecessor. It is an old version and
725  a normal user should use
726  remove_all_unreachable_controls_of_an_unstructured() instead.
727 
728  It is still buggy on Validation/Syntax/asgoto.f... */
729 void
731 {
732  list blocs = NIL;
733  list control_remove_list = NIL;
734 
735  /* The entry point of the unstructured: */
736  control entry_node = unstructured_control(u);
737  control exit_node = unstructured_exit(u);
738  bool exit_node_has_been_seen = false;
739  pips_debug(7, "From control %p, exit %p.\n", entry_node, exit_node);
740  ifdebug(7) {
741  display_linked_control_nodes(entry_node);
742  }
743 
744  CONTROL_MAP(c,
745  {
746  if (c != entry_node)
747  /* Well, the entry node is guessed as
748  reachable... :-) */
749  if (control_predecessors(c) == NIL) {
750  /* A control without predecessor is
751  unreachable, so it is dead code: */
752  pips_debug(7, "Want to discard control %p.\n", c);
753  control_remove_list = CONS(CONTROL,
754  c,
755  control_remove_list);
756  }
757  if (c == exit_node)
758  /* Note that we could have entry_node ==
759  exit_node... */
760  exit_node_has_been_seen = true;
761  },
762  entry_node,
763  blocs);
764  gen_free_list(blocs);
765 
766  /* Now remove all the marqued sequences from the entry_node: */
767  MAP(CONTROL, c,
768  {
769  remove_unreachable_following_control(c, entry_node, exit_node);
770  },
771  control_remove_list);
772  gen_free_list(control_remove_list);
773 
774  if (!exit_node_has_been_seen) {
775  /* Do not forget the unreachable exit part if it is not connex
776  to the entry_node: */
777  blocs = NIL;
778  control_remove_list = NIL;
779  CONTROL_MAP(c,
780  {
781  if (c != exit_node)
782  /* Do not remove the exit_node... */
783  if (control_predecessors(c) == NIL) {
784  /* A control without predecessor is
785  unreachable, so it is dead code: */
786  control_remove_list = CONS(CONTROL,
787  c,
788  control_remove_list);
789  }
790  },
791  exit_node,
792  blocs);
793  gen_free_list(blocs);
794  /* Now remove all the marqued sequences from the entry_node: */
795  MAP(CONTROL, c,
796  {
797  remove_unreachable_following_control(c, entry_node, exit_node);
798  },
799  control_remove_list);
800  gen_free_list(control_remove_list);
801  }
802 }
803 
804 
805 /* Remove all control nodes that are not forward reachable from the
806  entry node. Warning: useful FORMAT that are unreachable are also
807  discarded, so...
808 
809  @param u is the unstructured to clean
810 */
811 void
813 {
814  list blocs = NIL;
815 
816  set useful_controls = set_make(set_pointer);
817  set unreachable_controls = set_make(set_pointer);
818 
819  /* The entry point of the unstructured: */
820  control entry_node = unstructured_control(u);
821  control exit_node = unstructured_exit(u);
822  pips_debug(7, "From control %p, exit %p.\n", entry_node, exit_node);
823  ifdebug(7) {
824  display_linked_control_nodes(entry_node);
825  }
826 
827  /* Mark all the forward-reachable nodes: */
829  pips_debug(5, "Forward visiting control node %p.\n", c);
830  set_add_element(useful_controls,
831  useful_controls,
832  (char *) c);
833  },
834  entry_node,
835  blocs);
836  gen_free_list(blocs);
837  blocs = NIL;
838 
839  /* Now build the remove list from all the non-marked nodes: */
840  CONTROL_MAP(c, {
841  pips_debug(5, "Testing control node %p.\n", c);
842  if (! set_belong_p(useful_controls, (char *) c)) {
843  pips_debug(5, "Adding to the removing list control node %p.\n", c);
844  set_add_element(unreachable_controls,
845  unreachable_controls,
846  (char *) c);
847  }
848  },
849  entry_node,
850  blocs);
851  gen_free_list(blocs);
852  blocs = NIL;
853 
854  /* The same thing from the exit node that may be not reachable
855  from the entry node: */
856  CONTROL_MAP(c, {
857  pips_debug(5, "Testing from exit control node %p.\n", c);
858  if (! set_belong_p(useful_controls, (char *) c)) {
859  pips_debug(5, "From exit node: Adding to the removing list control node %p.\n", c);
860  set_add_element(unreachable_controls,
861  unreachable_controls,
862  (char *) c);
863  }
864  },
865  exit_node,
866  blocs);
867  gen_free_list(blocs);
868 
869  /* And delete them: */
870  SET_MAP(cc, {
871  control c = (control) cc;
872  if (c == exit_node) {
873  pips_debug(5, "Skipping discarding exit control node %p.\n", c);
874  }
875  else {
876  pips_debug(5, "Discarding control node %p.\n", c);
878  pips_user_warning("Discarding an unreachable FORMAT that may be "
879  "usefull. "
880  "Try to use the GATHER_FORMATS_AT_BEGINNING "
881  "property.\n");
883  }
884  },
885  unreachable_controls);
886  set_free(useful_controls);
887  set_free(unreachable_controls);
888 }
889 
890 
891 /* Replace each occurence of c in a_source_control_list_of_c with a
892  a_dest_control_list_of_c:
893 
894  @param c is the control node to unlink. It is not freed
895 
896  @param a_source_control_list_of_c is the list of control nodes to be
897  linked to the @p a_dest_control_list_of_c list of control nodes
898 
899  @param a_dest_control_list_of_c is the list of control nodes to be
900  linked from the @p a_source_control_list_of_c list of control nodes
901 
902  @param which_way precise if we deal with successors or predecessors:
903 
904  - if it is source_is_predecessor_and_dest_is_successor: @p
905  a_source_control_list_of_c is considered as predecessors of @p c and @p
906  a_dest_control_list_of_c is considered as successors of @p c
907 
908  -if it is source_is_successor_and_dest_is_predecessor: @p
909  a_source_control_list_of_c is considered as successors of @p c and @p
910  a_dest_control_list_of_c is considered as predecessors of @p c
911  */
912 void
914  list a_source_control_list_of_c,
915  list a_dest_control_list_of_c,
917 {
918  MAPL(a_control_list,
919  {
920  list *the_dest_of_a_source_list = NULL;
921  list the_position_of_c = NIL;
922  list the_position_before_c = NIL;
923  list l = NIL;
924 
925  control a_dest_of_a_source = CONTROL(CAR(a_control_list));
926  /* Now, find the corresponding dest in the source list
927  with the same value as c: */
928  switch(which_way) {
930  the_dest_of_a_source_list = &control_successors(a_dest_of_a_source);
931  break;
933  the_dest_of_a_source_list = &control_predecessors(a_dest_of_a_source);
934  break;
935  default:
936  pips_assert("remove_a_control_from_a_list_and_relink with not a good \"which_way\".\n", false);
937  }
938 
939  /* Find the reference to c in the the_dest_of_a_source_list: */
940  the_position_before_c = NIL;
941  MAPL(a_list,
942  {
943  /* l is local to the MAPL... */
944  if (CONTROL(CAR(the_position_of_c = a_list)) == c)
945  break;
946  the_position_before_c = the_position_of_c;
947  },
948  *the_dest_of_a_source_list);
949 
950  /* And add the a_dest_control_list_of_c instead of c: */
951  /* First concatenate (with copy) a_dest_control_list_of_c
952  before what follow c in the list: */
953  l = gen_append(a_dest_control_list_of_c, CDR(the_position_of_c));
954 
955  /* Then place this list instead of c in
956  *the_dest_of_a_source_list: */
957  if (the_position_before_c == NIL)
958  /* Modify the begin of the list: */
959  *the_dest_of_a_source_list = l;
960  else
961  CDR(the_position_before_c) = l;
962 
963  /* Deallocate the cons that point to c: */
964  CDR(the_position_of_c) = NIL;
965  gen_free_list(the_position_of_c);
966  },
967  a_source_control_list_of_c);
968 
969  /* c is now in the memory nowhere: */
971  control_successors(c) = NIL;
972 }
973 
974 
975 /* Remove a control node from a control graph
976 
977  The control node is freed and its predecessors are relinked to its
978  successor and relink the successor and the predecessor.
979 
980  If you want to preserve the control statement, do a
981  control_statement(c) = statement_undefined
982  before calling this function.
983 
984  @param[in,out] c is the control node to unlink and to free
985 
986  Assume that it cannot have more than 1 successor (so no test node)
987 
988  If the graph is in an unstructured and @p c is either the entry or
989  exit node, do not forget to update the entry or exit node.
990 */
991 void
993 {
994  list the_predecessors = control_predecessors(c);
995  list the_successors = control_successors(c);
996 
997  int number_of_successors = gen_length(the_successors);
998 
999  /* Unlink from the predecessor. Note that a node may have more than
1000  one predecessor. Since we cannot discard an IF this way, we have
1001  at most 1 successor: */
1002  pips_assert("remove_a_control_from_an_unstructured:"
1003  " no more than one successor",
1004  number_of_successors <= 1);
1006  the_predecessors,
1007  the_successors,
1009 
1010  /* Unlink from the successor: */
1012  the_successors,
1013  the_predecessors,
1015 
1016  /* Remove the control node: */
1017  free_control(c);
1018 }
1019 
1020 
1021 /* It removes a control node from its successor and predecessor.
1022 
1023  It can be applied to an unstructured "IF".
1024 
1025  @param c is the control node to unlink and to free
1026 
1027  If the graph is in an unstructured and @param c is either the entry or
1028  exit node, do not forget to update the entry or exit node.
1029 */
1030 void
1032 {
1033  /* Use a copy since we iterate and discard at the same time: */
1034  list the_predecessors = gen_copy_seq(control_predecessors(c));
1035  list the_successors = gen_copy_seq(control_successors(c));
1036 
1037  MAP(CONTROL, a_predecessor, {
1038  unlink_2_control_nodes(a_predecessor, c);
1039  }, the_predecessors);
1040  gen_free_list(the_predecessors);
1041 
1042  MAP(CONTROL, a_successor, {
1043  unlink_2_control_nodes(c, a_successor);
1044  }, the_successors);
1045  gen_free_list(the_successors);
1046 
1047  pips_assert("The control node should not have any connection here,",
1049  /* Remove the control node itself: */
1050  free_control(c);
1051 }
1052 
1053 
1054 /* Used to discard an unstructured without touching its
1055  statements.
1056 
1057  The statements are assumed to be referenced in another
1058  way.
1059 
1060  @param he unstructured to free
1061 */
1062 void
1064 {
1065  list blocs = NIL;
1066 
1067  /* Protect the statements by unlinking them: */
1068  CONTROL_MAP(c,
1069  {
1071  },
1073  blocs);
1074  gen_free_list(blocs);
1075 
1076  /* And then free the discard the unstructured: */
1077  free_unstructured(u);
1078 }
1079 
1080 
1081 /* Remove a control node without touching its statement, its predecessors
1082  and successors, if any.
1083 
1084  @param c is the control node to free
1085  */
1086 void
1088  /* Protect the statement: */
1091  control_successors(c) = NIL;
1094 
1095  free_control(c);
1096 }
1097 
1098 
1099 /* Remove a control sequence without touching its statements.
1100 
1101  It also removes the reference to the sequence from the predecessors or
1102  the successors.
1103 
1104  @param begin is the control node we start from
1105 
1106  @param end is the control node to stop at
1107 
1108  Of course, there should be a unique path from @p begin to @p end.
1109 */
1110 void
1112  control end)
1113 {
1114  control c;
1115  list successor_list;
1116 
1117  /* Unlink any extern reference to the control sequence: */
1118  MAP(CONTROL, a_predecessor,
1119  {
1120  gen_remove(&control_successors(a_predecessor),
1121  begin);
1122  },
1123  control_predecessors(begin));
1124 
1125  MAP(CONTROL, a_successor,
1126  {
1127  gen_remove(&control_predecessors(a_successor) ,
1128  end);
1129  },
1131 
1132  for(c = begin; ; c = CONTROL(CAR(successor_list))) {
1133  /* To pass through the free: */
1134  successor_list = control_successors(c);
1135 
1136  pips_assert("discard_a_control_sequence_without_its_statements: not a sequence.", gen_length(successor_list) <= 1);
1137 
1139 
1140  if (c == end)
1141  break;
1142  }
1143 }
1144 
1145 
1146 /* Take a control sequence and return a list of all the statements in
1147  the sequence (in the same order... :-) ).
1148 
1149  @param begin is the control node we start from
1150 
1151  @param end is the control node to stop at
1152 
1153  Of course, there should be a unique path from @p begin to @p end.
1154 */
1155 list
1157  control end)
1158 {
1159  control c;
1160  list the_statements_of_the_sequence = NIL;
1161 
1162  /* Because of the way CONS is working, reversed the walk through
1163  the sequence. */
1164 
1165  for(c = end; ; c = CONTROL(CAR(control_predecessors(c)))) {
1166  int number_of_predecessor = gen_length(control_predecessors(c));
1167  pips_assert("discard_a_control_sequence_without_its_statements: not a sequence.", number_of_predecessor <= 1);
1168 
1169  /* Add the statement to the list: */
1170  the_statements_of_the_sequence = CONS(STATEMENT,
1171  control_statement(c),
1172  the_statements_of_the_sequence);
1173  if (c == begin)
1174  break;
1175  }
1176 
1177  return the_statements_of_the_sequence;
1178 }
1179 
1180 
1181 /* Add an edge between 2 control nodes.
1182 
1183  Assume that this edge does not already exist or the source should be an
1184  unstructured IF. FI: I am still puzzled how this can work when
1185  tests are involved since the semantics of the first and second
1186  successor is not paid attention at at all.
1187 
1188  @param source is the control node the edge starts from
1189 
1190  @param target is the control node the edge ends to
1191  */
1192 void
1194  control target)
1195 {
1196  // FI: should we check here that the statement of "source" is
1197  // defined and if it is defined and that it already has a successor
1198  // then it is a test? Might be better done here than later when
1199  // trying to print out the statements...
1200  // FI: I think this explains why for loops are improperly desugared...
1201 
1202  // FI: this assert is too strong because if statements are
1203  // considered potentially structured and are linked like any other
1204  // statement when processing a statement
1205  //
1206  // pips_assert("source is not a test\n",
1207  // statement_undefined_p(control_statement(source))
1208  // || !statement_test_p(control_statement(source)));
1209 
1210  // FI: to avoid memory leaks and/or inconsistency
1211  //pips_assert("source has no successor\n", ENDP(control_successors(source)));
1212 
1213 #if 0
1214  if(!ENDP(control_successors(source)))
1215  // FI: this should never happen if the graph is properly
1216  // handled...
1217  // I could re-instate the assert and/or just set a breakpoint on
1218  // the gen_free_list()
1220  control_successors(source) = CONS(CONTROL, target, NIL);
1221 #endif
1222 
1223  // FI: assume the callers knows what it is doing when dealing with tests...
1224  control_successors(source) = CONS(CONTROL,
1225  target,
1226  control_successors(source));
1227 
1228  // FI: guess to get for loop properly desugared... but it breaks
1229  // something else...
1230  //control_successors(source) =
1231  // gen_nconc(control_successors(source), CONS(CONTROL, target, NIL));
1232  control_predecessors(target) = CONS(CONTROL,
1233  source,
1234  control_predecessors(target));
1235 }
1236 
1237 /* Add an edge between 2 control nodes.
1238 
1239  Assume that this edge does not already exist or the source should be an
1240  unstructured IF. FI: I am still puzzled how this can work when
1241  tests are involved since the semantics of the first and second
1242  successor is not paid attention at at all.
1243 
1244  @param source is the control node the edge starts from
1245 
1246  @param target is the control node the edge ends to
1247  */
1248 void
1250  control c_then, control c_else)
1251 {
1255  CONS(CONTROL, c_then, CONS(CONTROL, c_else, NIL));
1256 
1257  control_predecessors(c_then) = CONS(CONTROL,
1258  c_test,
1259  control_predecessors(c_then));
1260  control_predecessors(c_else) = CONS(CONTROL,
1261  c_test,
1262  control_predecessors(c_else));
1263 }
1264 
1265 
1266 /* Remove all edged between 2 control nodes.
1267 
1268  Note: if the source is a test, the false branch may be come the
1269  true branch if the true branch is unlinked
1270 
1271  @param source is the control node the edges start from
1272 
1273  @param target is the control node the edges end to
1274 */
1275 void
1277  control target)
1278 {
1279  // FI: no check that the nodes are properly linked before unlinking
1280  gen_remove(&control_successors(source), target);
1281  gen_remove(&control_predecessors(target), source);
1282 }
1283 
1284 
1285 /* Insert a control node between 2 connected control nodes
1286 
1287  @param c is the control node to insert
1288 
1289  @param before is the control node before where @p c is to be inserted
1290 
1291  @param after is the control node after where @p c is to be inserted
1292 
1293  Assume that @p c is not already connected and that @p after is the
1294  successor of @p before.
1295 
1296  Note: statements associated to nodes are not tested in case they
1297  are undefined.
1298 */
1300  // These first two assertions are wrong when "before" is a test whose two
1301  // branches reach "after":
1302  //
1303  // if(c) goto l1; else goto l1; l1: ;
1304  //
1305  // This is unlikely but does happen when macros are used or when
1306  // some code is generated automatically. FI assumes that the two
1307  // substitutions will happen simultaneously thanks to the
1308  // substitutions in the list
1309  pips_assert("c is not already a successor of before",
1311 
1312  // This may be wrong if c has already been inserted in another
1313  //arc. Nevertheless it may be useful to insert it in the "before->after" arc.
1314  //
1315  //pips_assert("c is not a predecessor of after",
1316  // !is_control_in_list_p(c, control_predecessors(after)));
1317 
1318  // Make sure that before and after are properly linked
1319  pips_assert("after is a successor of before",
1320  is_control_in_list_p(after, control_successors(before)));
1321  pips_assert("before is a predecessor of after",
1322  is_control_in_list_p(before, control_predecessors(after)));
1323 
1324  // FI: we might also assert that the statement associated to c is
1325  // not a test... but it is not possible when sequences are
1326  // transformed into a chain of nodes. So, temporarily, you can have
1327  // test control nodes with only one successor. May be definitely if
1328  // they are structured?
1329  //pips_assert("c is not a test: it has only one successor at most",
1330  // !statement_test_p(control_statement(c)));
1331 
1332  // FI: when before is a test, how do you know if c must be in the
1333  // true or in the false branch?
1334  /* If there is no ambiguity about the linking, use Ronan's technique */
1335  if(gen_length(control_successors(before))==1
1336  && gen_length(control_successors(c))==0) {
1337  unlink_2_control_nodes(before, after);
1338  link_2_control_nodes(before, c);
1339  link_2_control_nodes(c, after);
1340  }
1341  else if(gen_length(control_successors(c))==0) {
1342  /* Let's try to preserve the true and false branch */
1343  bool success1 = gen_replace_in_list(control_successors(before), after, c);
1344  bool success2 = gen_replace_in_list(control_predecessors(after), before, c);
1345  // The order is meaning less, but it is easier to debug if the
1346  // order is preserved
1348  = gen_nconc(control_predecessors(c), CONS(CONTROL, before, NIL));
1349  //control_predecessors(c) = CONS(CONTROL, before, NIL);
1350  control_successors(c) = CONS(CONTROL, after, NIL);
1351 
1352  pips_assert("after and before were linked", success1 && success2);
1353  pips_debug(8, "control %p inserted between before=%p and after=%p\n",
1354  c, before, after);
1355  }
1356  else if(gen_length(control_successors(c))==1
1357  && CONTROL(CAR(control_successors(c)))==after) {
1358  // We may handle the case outlined above?
1359  // The two substitutions should have occured simultaneously?
1360  // No, simply the more general case:
1361  // precondition: x -> c && c -> after && before -> after
1362  // postcondition x -> c && before -> c && c -> after
1363  // pips_internal_error("Should not happen\n");
1364  // Preserve the branch positions for tests
1365  bool success = gen_replace_in_list(control_successors(before), after, c);
1366  gen_remove(&control_predecessors(after), before);
1368  = gen_nconc(control_predecessors(c), CONS(CONTROL, before, NIL));
1369  pips_assert("after and before were linked", success);
1370  }
1371  else
1372  pips_internal_error("No semantics, no implementation...\n");
1373 }
1374 
1375 /* Fuse a 2 control nodes
1376 
1377  It adds the statement of the second one to the statement of the first
1378  one. Assumes that the second node is the only successor of the first
1379  one.
1380 
1381  The second control node is freed.
1382 
1383  It does not update the entry or exit field of the unstructured.
1384 
1385  @param first is the first control node
1386 
1387  @param second is the control node to fuse in the first one. It is
1388  precised because it is possible that there are not connected.
1389  */
1390 void
1392  control second)
1393 {
1394  if (gen_length(control_successors(second)) == 2) {
1395  /* If the second node has 2 successors, it is a test node. The
1396  fused node has 2 successors and must be a test too. So, the
1397  only thing I can do is to remove the first statement, just
1398  keeping its comments. And how about the label? It might be
1399  useful for syntactic reasons and only reachable via END=nnn
1400  after prettyprinting (see Validation/redlec2.f) */
1401  string first_comment =
1403  entity first_label = statement_to_label(control_statement(first));
1404 
1405  if(!entity_empty_label_p(first_label)) {
1406  entity second_label = statement_to_label(control_statement(second));
1407  pips_user_warning("Useless label %s\n",
1408  entity_name(first_label));
1409  if(!entity_empty_label_p(second_label)) {
1410  /* A return might be OK?!? What does the caller expect? The
1411  first label must be useless and is dropped. */
1412  /* pips_user_warning("Useless label %s\n",
1413  entity_name(first_label)); */
1414  /* pips_internal_error("Two labels for one control node"); */
1415  ;
1416  }
1417  else {
1418  statement_label(control_statement(second)) = first_label;
1419  ;
1420  }
1421  }
1423  first_comment);
1424  control_statement(first) = control_statement(second);
1425  }
1426  else {
1427  /* If not, build a block with the two statements: */
1429  statement_instruction(st) =
1431  control_statement(first),
1432  CONS(STATEMENT,
1433  control_statement(second), NIL)));
1434  /* Reconnect the new statement to the node to fuse: */
1435  control_statement(first) = st;
1436  }
1438 
1439  /* Unlink the second node from the first one: */
1441  gen_remove(&control_predecessors(second), first);
1442 
1443  /* Link the first node with the successors of the second one in
1444  the forward direction: */
1445  control_successors(first) =
1446  control_successors(second);
1447  /* Update all the predecessors of the successors: */
1448  MAP(CONTROL, c,
1449  {
1450  MAPL(cp,
1451  {
1452  if (CONTROL(CAR(cp)) == second)
1453  CONTROL_(CAR(cp)) = first;
1454  }, control_predecessors(c));
1455  }, control_successors(first));
1456 
1457  /* Transfer the predecessors of the second node to the first one.
1458  Note that the original second -> first predecessor link has
1459  already been removed. But a loop from second to second appear
1460  at this point as a link from first to second. Nasty bug... */
1461  MAP(CONTROL, c,
1462  {
1464  c,
1465  control_predecessors(first));
1466  MAPL(cp,
1467  {
1468  if (CONTROL(CAR(cp)) == second) {
1469  CONTROL_(CAR(cp)) = first;
1470  }
1471  }, control_successors(c));
1472  }, control_predecessors(second));
1473 
1474  /* Now we remove the useless intermediate node "second": */
1475  /* Do not gen_free_list(control_successors(second)) since it is
1476  used as control_successors(first) now: */
1477  control_successors(second) = NIL;
1479  control_predecessors(second) = NIL;
1480  free_control(second);
1481 }
1482 
1483 /*
1484  @}
1485 */
void free_control(control p)
Definition: ri.c:490
bool statement_consistent_p(statement p)
Definition: ri.c:2195
void free_unstructured(unstructured p)
Definition: ri.c:2745
bool control_consistent_p(control p)
Definition: ri.c:496
static string c_test(test t, bool breakable)
bool success
Definition: gpips-local.h:59
void remove_some_unreachable_controls_of_an_unstructured(unstructured u)
Remove all the control sequences that are unreachable and that begin with a node without any predeces...
Definition: control.c:730
void insert_control_in_arc(control c, control before, control after)
Insert a control node between 2 connected control nodes.
Definition: control.c:1299
void unlink_2_control_nodes(control source, control target)
Remove all edged between 2 control nodes.
Definition: control.c:1276
void remove_all_unreachable_controls_of_an_unstructured(unstructured u)
Remove all control nodes that are not forward reachable from the entry node.
Definition: control.c:812
void display_linked_control_nodes(control c)
Display all the control nodes reached or reachable from c for debugging purpose.
Definition: control.c:629
void transfer_control_successor(control old_node, control new_node, control c)
Transfer a control node as a successor of one node to another one.
Definition: control.c:390
void display_address_of_control_nodes(list cs)
Display the adresses a list of control nodes.
Definition: control.c:612
void remove_a_control_from_a_list_and_relink(control c, list a_source_control_list_of_c, list a_dest_control_list_of_c, remove_a_control_from_a_list_and_relink_direction which_way)
Replace each occurence of c in a_source_control_list_of_c with a a_dest_control_list_of_c:
Definition: control.c:913
void remove_unreachable_following_control(control c, control do_not_delete_node, control do_not_delete_node_either)
Remove all the control nodes (with their statements) from c in the successor tree of c up to the node...
Definition: control.c:682
void link_3_control_nodes(control c_test, control c_then, control c_else)
Add an edge between 2 control nodes.
Definition: control.c:1249
void link_2_control_nodes(control source, control target)
Add an edge between 2 control nodes.
Definition: control.c:1193
void print_control_node(control c)
Definition: control.c:566
void remove_a_control_from_an_unstructured_without_relinking(control c)
It removes a control node from its successor and predecessor.
Definition: control.c:1031
void transfer_control_predecessor(control old_node, control new_node, control c)
Transfer a control node as a predecessor from one node to another one.
Definition: control.c:358
void discard_an_unstructured_without_its_statements(unstructured u)
Used to discard an unstructured without touching its statements.
Definition: control.c:1063
void replace_control_related_to_a_list(control old_node, control new_node, list controls)
Replace all the references to a control node by a new one in the successors & predecessors of a list ...
Definition: control.c:419
bool is_control_in_list_p(control c, list cs)
Test if a control node is in a list of control nodes.
Definition: control.c:299
void free_a_control_without_its_statement(control c)
Remove a control node without touching its statement, its predecessors and successors,...
Definition: control.c:1087
void remove_a_control_from_an_unstructured(control c)
Remove a control node from a control graph.
Definition: control.c:992
void control_list_patch(list l, control c_old, control c_new)
Replace in a list of control nodes all the instance of a control node by another one.
Definition: control.c:336
void discard_a_control_sequence_without_its_statements(control begin, control end)
Remove a control sequence without touching its statements.
Definition: control.c:1111
void print_control_nodes(list l)
Display identification of a list of control nodes.
Definition: control.c:589
void fuse_2_control_nodes(control first, control second)
Fuse a 2 control nodes.
Definition: control.c:1391
void check_control_coherency(control c)
Test the coherency of a control node network from a control node.
Definition: control.c:487
list generate_a_statement_list_from_a_control_sequence(control begin, control end)
Take a control sequence and return a list of all the statements in the sequence (in the same order....
Definition: control.c:1156
int occurences_in_control_list(control c, list cs)
Count the number of occurences of a control node in a list of control nodes.
Definition: control.c:319
#define CONTROL_MAP(ctl, code, c, list)
Macro to walk through all the controls reachable from a given control node of an unstructured.
void forward_control_map_get_blocs(c, l)
Build recursively the list of all controls forward-reachable from a control of an unstructured.
Definition: control.c:208
void backward_control_map_get_blocs_but(control c, control f, list *l)
Transitive closure of c's predecessors, but for control f.
Definition: control.c:184
void control_map_get_blocs(control c, list *l)
Build recursively the list of all controls reachable from a control of an unstructured.
Definition: control.c:75
void forward_control_map_get_blocs_but(control c, control f, list *l)
Transitive closure of c's successors, but for control f.
Definition: control.c:234
#define FORWARD_CONTROL_MAP(ctl, code, c, list)
Walk through all the controls forward-reachable from a given control node of an unstructured.
void find_a_control_path(control b, control e, list *pp, list *vp, int dir)
Build recursively a control path from b to e.
Definition: control.c:107
void backward_control_map_get_blocs(c, l)
Build recursively the list of all controls backward-reachable from a control of an unstructured.
Definition: control.c:157
void wide_forward_control_map_get_blocs(c, l)
Same as above, but follows successors by minimal path lengths.
Definition: control.c:252
instruction make_instruction_block(list statements)
Build an instruction block from a list of statements.
Definition: instruction.c:106
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
void gen_remove(list *cpp, const void *o)
remove all occurences of item o from list *cpp, which is thus modified.
Definition: list.c:685
void gen_remove_once(list *pl, const void *o)
Remove the first occurence of o in list pl:
Definition: list.c:691
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
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
list gen_last(list l)
Return the last element of a list.
Definition: list.c:578
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
#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
list gen_append(list l1, const list l2)
Definition: list.c:471
int gen_occurences(const void *vo, const list l)
count occurences of vo in l
Definition: list.c:746
void gen_list_patch(list l, const void *x, const void *y)
Replace all the reference to x in list l by a reference to y:
Definition: list.c:985
#define MAP(_map_CASTER, _map_item, _map_code, _map_list)
Apply/map an instruction block on all the elements of a list (old fashioned)
Definition: newgen_list.h:226
bool gen_replace_in_list(list l, const void *s, const void *t)
substitute all item s by t in list l
Definition: list.c:634
bool statement_test_p(statement)
Definition: statement.c:343
entity statement_to_label(statement)
See if statement s is labelled and can be reached by a GO TO.
Definition: statement.c:2090
void insert_comments_to_statement(statement, const char *)
Insert a comment string (if non empty) at the beginning of the comments of a statement.
Definition: statement.c:1916
string safe_statement_identification(statement)
Definition: statement.c:1726
string gather_all_comments_of_a_statement(statement)
Gather all the comments recursively found in the given statement and return them in a strduped string...
Definition: statement.c:1760
bool format_inside_statement_p(statement)
Definition: statement.c:2360
char end
Definition: gtk_status.c:82
struct _newgen_struct_control_ * control
#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_user_warning
Definition: misc-local.h:146
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define pips_internal_error
Definition: misc-local.h:149
#define SET_MAP(element, code, the_set)
Definition: newgen_set.h:54
void set_free(set)
Definition: set.c:332
bool set_belong_p(const set, const void *)
Definition: set.c:194
@ set_pointer
Definition: newgen_set.h:44
set set_make(set_type)
Create an empty set of any type but hash_private.
Definition: set.c:102
set set_add_element(set, const set, const void *)
Definition: set.c:152
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
remove_a_control_from_a_list_and_relink_direction
For the control graph modifiers:
@ source_is_predecessor_and_dest_is_successor
Put some strange number to avoid random clash as much as possible...
@ source_is_successor_and_dest_is_predecessor
#define unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
#define make_empty_statement
An alias for make_empty_block_statement.
char vcid_ri_util_control[]
Some utilities to deal with the control graph.
Definition: control.c:34
bool entity_empty_label_p(entity e)
Definition: entity.c:666
#define CONTROL_(x)
Definition: ri.h:913
#define control_predecessors(x)
Definition: ri.h:943
#define CONTROL(x)
CONTROL.
Definition: ri.h:910
#define statement_label(x)
Definition: ri.h:2450
#define entity_name(x)
Definition: ri.h:2790
#define control_successors(x)
Definition: ri.h:945
#define unstructured_exit(x)
Definition: ri.h:3006
#define statement_instruction(x)
Definition: ri.h:2458
#define control_statement(x)
Definition: ri.h:941
#define statement_undefined
Definition: ri.h:2419
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
Pvecteur cp
pointeur sur l'egalite ou l'inegalite courante
Definition: sc_read.c:87
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
#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
A gen_chunk is used to store every object.
Definition: genC.h:58