PIPS
cfg.c
Go to the documentation of this file.
1 /*
2 
3  $Id: cfg.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 /* Basic functions about control flow graphs (CFG), aka unstructured data structure
28  *
29  * Francois Irigoin, 1997.
30  */
31 
32 #include <stdlib.h>
33 #include <stdio.h>
34 
35 #include "linear.h"
36 
37 #include "genC.h"
38 #include "misc.h"
39 #include "ri.h"
40 #include "ri-util.h"
41 #include "control.h"
42 
43 /* Check some nice properties expected to be true after a powerful
44  * enough controlizer phase.
45  *
46  * The calls to pips_assert could be replaced by calls to user_warning,
47  * the control graph could be printed out before core dumping,...
48  *
49  * See also check_control_coherency().
50  */
51 bool
53 {
54  control entry_node = unstructured_control(u);
55  control exit_node = unstructured_exit(u);
56  bool consistency_p = true;
57  list nodes = NIL;
58 
59  forward_control_map_get_blocs(entry_node, &nodes);
60 
61  /* the exit and entry nodes must be different or the
62  * unstructured would have been reduced to one structured statement
63  */
64  if(exit_node==entry_node) {
65  consistency_p = false;
66  if(assert_p) pips_assert("Entry and exit nodes are different", false);
67  }
68 
69  /* The entry node must have at least one predecessor:
70  * else it should have been moved out of the unstructured.
71  * Note that it has in fact TWO predecessors since it is the
72  * unstructured entry point.
73  */
74  if(consistency_p && ENDP(control_predecessors(entry_node))) {
75  consistency_p = false;
76  if(assert_p) pips_assert("Entry node has at least one predecessor", false);
77  }
78 
79  /* The exit node should have no successors: its real successor
80  * is the statement following the unstructured
81  */
82  if(consistency_p && !ENDP(control_successors(exit_node))) {
83  consistency_p = false;
84  if(assert_p) pips_assert("Exit node has no successor", false);
85  }
86 
87  /* The exit node should not be a test:
88  * else one of its successors should be control_undefined
89  * since it would be outside of the unstructured, or the
90  * exit condition would be unknown.
91  */
92  if(consistency_p) {
93  statement exit_s = control_statement(exit_node);
94  if(statement_test_p(exit_s)) {
95  consistency_p = false;
96  if(assert_p) pips_assert("Exit node is not a test", false);
97  }
98  }
99 
100  /* The exit node may have no predecessor because an infinite loop
101  * appears in the code. Or it is a successor of the entry node.
102  */
103  if(consistency_p && !ENDP(control_predecessors(exit_node))) {
104  if(gen_find_eq(exit_node, nodes)!=exit_node) {
105  consistency_p = false;
106  if(assert_p) pips_assert("Exit node has predecessors but is unreachable", false);
107  }
108  }
109 
110  /* RK: ??? If the exit node is unreachable, it should be a CONTINUE
111  * Since a CONTINUE has no effects, it does not perturb analyses even
112  * if they do not check reachability.
113  * RK: The NOP might be the empty sequence instead of a CONTINUE?
114  */
115  if(consistency_p && ENDP(control_predecessors(exit_node))) {
116  statement exit_s = control_statement(exit_node);
117 
118  if(!continue_statement_p(exit_s)) {
119  consistency_p = false;
120  if(assert_p) pips_assert("Unreachable exit node is a CONTINUE statement", false);
121  }
122  }
123 
124  /* If the exit node has only one predecessor, it should
125  * be a test or the exit node would have been moved outside of
126  * the unstructured.
127  */
128  if(consistency_p && gen_length(control_predecessors(exit_node))==1) {
129  control c = CONTROL(CAR(control_predecessors(exit_node)));
131 
132  if(!statement_test_p(s)) {
133  consistency_p = false;
134  if(assert_p) pips_assert("Unique predecessor of exit node is a test", false);
135  }
136  }
137 
138  /* Since sequences are merged into a unique node, if a node c1 has only one
139  * successor c2, and if c2 has only one predecessor c3, c3 must be c1
140  * and either c1 is the exit node which is impossible because there
141  * would be no exit condition and the exit node would have a
142  * successor, c2, or c2 is the entry node. So c2 must be the entry node.
143  *
144  * Well, this is not true because only tests can have two successors.
145  * hence, a test node cannot be merged.
146  */
147  MAP(CONTROL, c1, {
148  if(gen_length(control_successors(c1))==1) {
150  statement s2 = control_statement(c2);
151 
152  if(gen_length(control_predecessors(c2))==1) {
154  if(c1!=c3) {
155  consistency_p = false;
156  if(assert_p) {
157  (void) fprintf(stderr,
158  "\nEntry node: %p\nExit node: %p\n"
159  "c1 node: %p\nc2 node: %p\nc3 node: %p\n",
160  entry_node, exit_node, c1, c2, c3);
161  display_linked_control_nodes(entry_node);
162  pips_assert("c3, the unique predecessor of the unique successor of c1, is c1",
163  false);
164  }
165  }
166  else if(c2!=entry_node && !statement_test_p(s2)) {
167  consistency_p = false;
168  if(assert_p) {
169  (void) fprintf(stderr,
170  "\nEntry node: %p\nExit node: %p\nc1 node: %p\nc2 node: %p\n\n",
171  entry_node, exit_node, c1, c2);
172  display_linked_control_nodes(entry_node);
173  pips_assert("c2 is the unique successor of c1. "
174  "c2 has c1 as unique predecessor. c2 must be the entry node",
175  false);
176  }
177  }
178  }
179 
180  }
181  }, nodes)
182 
183  gen_free_list(nodes);
184 
185  return consistency_p;
186 }
187 
188 
189 /* Test if an unstructured is found to be like a structured while-loop */
190 bool
192 {
193  control entry_node = unstructured_control(u);
194  control exit_node = unstructured_exit(u);
195  bool while_p = false;
196 
197  ifdebug(5) {
198  debug(5, "unstructured_while_p", "Begin with graph\n");
199  (void) fprintf(stderr,
200  "\nEntry node: %p\nExit node: %p\n\n",
201  entry_node, exit_node);
202  display_linked_control_nodes(entry_node);
203  }
204 
205  /* Make sure that the unstructured has been "normalized" */
206  /* while_p = unstructured_consistency_p(u, true); */
207  while_p = unstructured_consistency_p(u, false);
208 
209  /* An unstructured is a while loop if and only if the exit node
210  * has only one predecessor and if the entry node is a successor
211  * of the predecessor of the exit node.
212  *
213  * A loop with two exit conditions is not recognized as a while loop.
214  *
215  * A loop with an exit test on entry, a final exit test (do...while) or
216  * an exit test anywhere is recognized as a while loop.
217  */
218 
219  if(while_p && gen_length(control_predecessors(exit_node))==1) {
220  control pred = CONTROL(CAR(control_predecessors(exit_node)));
221  list succs = NIL;
222 
223  forward_control_map_get_blocs(pred, &succs);
224 
225  if(gen_find_eq(entry_node, succs)==entry_node) {
226  while_p = true;
227  }
228  gen_free_list(succs);
229  }
230  else {
231  while_p = false;
232  }
233 
234  debug(5, "unstructured_while_p", "End with while_p=%s\n", bool_to_string(while_p));
235 
236  return while_p;
237 }
bool unstructured_consistency_p(unstructured u, bool assert_p)
Basic functions about control flow graphs (CFG), aka unstructured data structure.
Definition: cfg.c:52
bool unstructured_while_p(unstructured u)
Test if an unstructured is found to be like a structured while-loop.
Definition: cfg.c:191
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 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
#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 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
void * gen_find_eq(const void *item, const list seq)
Definition: list.c:422
#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 statement_test_p(statement)
Definition: statement.c:343
bool continue_statement_p(statement)
Test if a statement is a CONTINUE, that is the FORTRAN nop, the ";" in C or the "pass" in Python....
Definition: statement.c:203
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
void debug(const int the_expected_debug_level, const char *calling_function_name, const char *a_message_format,...)
ARARGS0.
Definition: debug.c:189
string bool_to_string(bool)
Definition: string.c:243
#define unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
#define control_predecessors(x)
Definition: ri.h:943
#define CONTROL(x)
CONTROL.
Definition: ri.h:910
#define control_successors(x)
Definition: ri.h:945
#define unstructured_exit(x)
Definition: ri.h:3006
#define control_statement(x)
Definition: ri.h:941
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
#define ifdebug(n)
Definition: sg.c:47
The structure used to build lists in NewGen.
Definition: newgen_list.h:41