PIPS
ri_to_total_preconditions.c
Go to the documentation of this file.
1 /*
2 
3  $Id: ri_to_total_preconditions.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  /* semantical analysis
28  *
29  * phasis 3: propagate total preconditions from statement to
30  * sub-statement, starting from the module unique return statement. Total
31  * preconditions are over-approximation of the theoretical total
32  * preconditions, i.e. the conditions that must be met by the store
33  * before a statement is executed to reach the end of the module
34  * (intra-procedural) or the end of the program (interprocedural). Since
35  * over-approximations are computed, the end of the module or of the
36  * program cannot be reached if it is not met.
37  *
38  * For (simple) interprocedural analysis, this phasis should be performed
39  * top-down on the call tree.
40  *
41  * Most functions are called xxx_to_total_precondition. They receive a
42  * total postcondition as input and use a transformer to convert it into
43  * a total precondition.
44  *
45  * Total preconditions are *NEVER* shared. Sharing would introduce desastrous
46  * side effects when they are updated as for equivalenced variables and
47  * would make freeing them impossible. Thus on a recursive path from
48  * statement_to_total_precondition() to itself the precondition must have been
49  * reallocated even when its value is not changed as between a block
50  * precondition and the first statement of the block precondition. In the
51  * same way statement_to_total_precondition() should never returned a
52  * total_precondition aliased with its precondition argument. Somewhere
53  * in the recursive call down the data structures towards
54  * call_to_total_precondition() some allocation must take place even if the
55  * statement as no effect on preconditions.
56  *
57  * Ambiguity: the type "transformer" is used to abstract statement effects
58  * as well as effects combined from the beginning of the module to just
59  * before the current statement (precondition) to just after the current
60  * statement (total_precondition). This is because it was not realized that
61  * preconditions could advantageously be seen as transformers of the initial
62  * state when designing the ri.
63  */
64 
65 #include <stdio.h>
66 #include <string.h>
67 /* #include <stdlib.h> */
68 
69 #include "genC.h"
70 #include "linear.h"
71 #include "ri.h"
72 #include "effects.h"
73 #include "ri-util.h"
74 #include "effects-util.h"
75 #include "control.h"
76 #include "effects-generic.h"
77 #include "effects-simple.h"
78 
79 #include "misc.h"
80 
81 #include "properties.h"
82 
83 #include "ray_dte.h"
84 #include "sommet.h"
85 #include "sg.h"
86 #include "polyedre.h"
87 
88 #include "transformer.h"
89 
90 #include "semantics.h"
91 
93 ␌
94 static transformer
96  transformer t_post,
97  list b)
98 {
99  statement s;
102  list ls = b;
103 
104  pips_debug(8,"begin t_post=%p\n", t_post);
105 
106  if(ENDP(ls))
107  t_pre = transformer_dup(t_post);
108  else {
109  list rls = gen_nreverse(ls);
110  list crls = rls;
111 
112  s = STATEMENT(CAR(rls));
113  s_post = statement_to_total_precondition(t_post, s);
114  for (POP(crls) ; !ENDP(crls); POP(crls)) {
115  s = STATEMENT(CAR(crls));
116  t_pre = statement_to_total_precondition(s_post, s);
117  s_post = t_pre;
118  }
119  ls = gen_nreverse(rls);
120 
121  /* t_pre is already associated with a statement */
122  t_pre = transformer_dup(t_pre);
123  }
124 
125  pips_debug(8,"post=%p end\n", t_pre);
126  return t_pre;
127 }
128 ␌
129 static transformer
131  transformer pre,
132  unstructured u,
133  transformer tf)
134 {
135  transformer post;
136  control c;
137 
138  pips_assert("Not implemented yet", false);
139 
140  pips_debug(8,"begin\n");
141 
142  pips_assert("unstructured is defined", u!=unstructured_undefined);
143 
144  c = unstructured_control(u);
145  if(control_predecessors(c) == NIL && control_successors(c) == NIL) {
146  /* there is only one statement in u; no need for a fix-point */
147  pips_debug(8,"unique node\n");
148  /* FI: pre should not be duplicated because
149  * statement_to_total_precondition() means that pre is not
150  * going to be changed, just post produced.
151  */
153  control_statement(c));
154  }
155  else {
156  /* Do not try anything clever! God knows what may happen in
157  unstructured code. Total_Precondition post is not computed recursively
158  from its components but directly derived from u's transformer.
159  Preconditions associated to its components are then computed
160  independently, hence the name unstructured_to_total_preconditionS
161  instead of unstructured_to_total_precondition */
162  /* propagate as precondition an invariant for the whole unstructured u
163  assuming that all nodes in the CFG are fully connected, unless tf
164  is not feasible because the unstructured is never exited or exited
165  thru a direct or indirect call to STOP which invalidates the
166  previous assumption. */
169 
170  pips_debug(8, "complex: based on transformer\n");
171  if(transformer_empty_p(tf)) {
173  }
174  else {
175  tf_u = tf;
176  }
177  pre_u = invariant_wrt_transformer(pre, tf_u);
178  ifdebug(8) {
179  debug(8,"unstructured_to_total_precondition",
180  "filtered precondition pre_u:\n");
181  (void) print_transformer(pre_u) ;
182  }
184  pips_assert("A valid total_precondition is returned",
185  !transformer_undefined_p(post));
186  if(transformer_undefined_p(post)) {
187  post = transformer_apply(transformer_dup(tf), pre);
188  }
189  transformer_free(pre_u);
190  }
191 
192  pips_debug(8,"end\n");
193 
194  return post;
195 }
196 ␌
197 static transformer
199  transformer t_post,
200  test t,
201  transformer tf,
203 {
204 # define DEBUG_TEST_TO_TOTAL_PRECONDITION 7
205  expression c = test_condition(t);
206  statement st = test_true(t);
207  statement sf = test_false(t);
208  transformer t_pre;
209 
211 
213  transformer t_pret = statement_to_total_precondition(t_post, st);
214  transformer t_pref = statement_to_total_precondition(t_post, sf);
215 
216  t_pret = transformer_add_domain_condition(t_pret, c, context,
217  true);
218 /* t_pret = transformer_normalize(t_pret, 4); */
219  t_pret = transformer_normalize(t_pret, 2);
220 
221  t_pref = transformer_add_domain_condition(t_pref, c, context,
222  false);
223 /* transformer_normalize(t_pref, 4); */
224  transformer_normalize(t_pref, 2);
225 
227  pips_debug(DEBUG_TEST_TO_TOTAL_PRECONDITION,"t_pret=%p\n",t_pret);
228  (void) print_transformer(t_pret);
229  pips_debug(DEBUG_TEST_TO_TOTAL_PRECONDITION,"t_pref=%p\n",t_pref);
230  (void) print_transformer(t_pref);
231  }
232 
233  t_pre = transformer_convex_hull(t_pret,t_pref);
234  }
235  else {
236  (void) statement_to_total_precondition(t_post, st);
237  (void) statement_to_total_precondition(t_post, sf);
238  t_pre = transformer_apply(t_post, tf);
239  }
240 
243  (void) print_transformer(t_pre);
244  }
245 
246  return t_pre;
247 }
248 ␌
249 static transformer
251  transformer t_post,
252  call c,
253  transformer tf)
254 {
256  entity e = call_function(c);
257  tag tt;
258 
259  pips_debug(8,"begin\n");
260 
261  switch (tt = value_tag(entity_initial(e))) {
262  case is_value_intrinsic:
263  t_pre = transformer_inverse_apply(tf, t_post);
264  /* memory leak */
265  t_pre = transformer_to_domain(t_pre);
266  break;
267  case is_value_code:
268  t_pre = transformer_inverse_apply(tf, t_post);
269  break;
270  case is_value_symbolic:
271  case is_value_constant:
272  pips_internal_error("call to symbolic or constant %s",
273  entity_name(e));
274  break;
275  case is_value_unknown:
276  pips_internal_error("unknown function %s", entity_name(e));
277  break;
278  default:
279  pips_internal_error("unknown tag %d", tt);
280  }
281 
282  pips_debug(8,"end\n");
283 
284  return t_pre;
285 }
286 ␌
287 static transformer
289  transformer t_post,
290  instruction i,
291  transformer tf,
293 {
295  test t = test_undefined;
296  loop l = loop_undefined;
297  call c = call_undefined;
298 
299  pips_debug(9,"begin t_post=%p tf=%p\n", t_post, tf);
300 
301  switch(instruction_tag(i)) {
304  break;
305  case is_instruction_test:
306  t = instruction_test(i);
307  t_pre = test_to_total_precondition(t_post, t, tf, context);
308  break;
309  case is_instruction_loop:
310  l = instruction_loop(i);
311  t_pre = loop_to_total_precondition(t_post, l, tf, context);
312  break;
316 
317  if(evaluation_before_p(ev)) {
318  t_pre = whileloop_to_total_precondition(t_post, wl, tf, context);
319  }
320  else {
321  pips_user_error("Use property ??? to eliminate C repeat loops, "
322  "which are not handled directly\n");
323  }
324  break;
325  }
327  pips_user_error("Use properties FOR_TO_DO_LOOP_IN_CONTROLIZER and"
328  "FOR_TO_WHILE_LOOP_IN_CONTROLIZER to eliminate C for loops, which are"
329  "not (yet) handled directly\n");
330  //fl = instruction_forloop(i);
331  //t_pre = forloop_to_total_precondition(t_post, fl, tf, context);
332  break;
333  case is_instruction_goto:
334  pips_internal_error("unexpected goto in semantics analysis");
335  /* never reached: post = pre; */
336  break;
337  case is_instruction_call:
338  c = instruction_call(i);
339  t_pre = call_to_total_precondition(t_post, c, tf);
340  break;
343  tf);
344  break ;
345  default:
346  pips_internal_error("unexpected tag %d",
347  instruction_tag(i));
348  }
349  pips_debug(9,"resultat t_pre, %p:\n", t_pre);
350  ifdebug(9) (void) print_transformer(t_pre);
351  return t_pre;
352 }
353 ␌
356  transformer t_post,
357  statement s)
358 {
362  /* Preconditions may be useful to deal with tests and loops and to find
363  out if some control paths do not exist */
364  /* transformer context = transformer_undefined; */
367 
368  pips_debug(1,"begin\n");
369 
370  pips_assert("The statement total postcondition is defined", t_post != transformer_undefined);
371 
372  ifdebug(1) {
373  _int so = statement_ordering(s);
374  (void) fprintf(stderr, "statement %03td (%td,%td), total postcondition %p:\n",
376  ORDERING_STATEMENT(so), t_post);
377  (void) print_transformer(t_post) ;
378  }
379 
380  pips_assert("The statement transformer is defined", tf != transformer_undefined);
381  ifdebug(1) {
382  _int so = statement_ordering(s);
383  pips_debug(9,"statement %03td (%td,%td), transformer %p:\n",
385  ORDERING_STATEMENT(so), tf);
386  (void) print_transformer(tf) ;
387  }
388 
389  if (!statement_reachable_p(s))
390  {
391  /* If the code is not reachable, thanks to STOP or GOTO, which
392  * is a structural information, the total precondition is just empty.
393  */
394 
395  t_pre = transformer_empty();
396  }
397 
399  list non_initial_values = list_undefined;
400 
401  t_pre = instruction_to_total_precondition(t_post, i, tf, context);
402 
403  /* keep only global initial scalar integer values;
404  else, you might end up giving the same xxx#old name to
405  two different local values (?) */
406  non_initial_values =
409 
410  MAPL(cv,
411  {
412  entity v = ENTITY(CAR(cv));
413  ENTITY_(CAR(cv)) = entity_to_old_value(v);
414  },
415  non_initial_values);
416 
417  /* add equivalence equalities */
418  t_pre = tf_equivalence_equalities_add(t_pre);
419 
420 /* t_pre = transformer_normalize(t_pre, 4); */
421  t_pre = transformer_normalize(t_pre, 2);
422 
423  if(!transformer_consistency_p(t_pre)) {
424  _int so = statement_ordering(s);
425  fprintf(stderr, "statement %03td (%td,%td), precondition %p end:\n",
427  ORDERING_STATEMENT(so), t_pre);
428  print_transformer(t_pre);
429  pips_internal_error("Non-consistent precondition after update");
430  }
431 
432  t_pre = transformer_filter(t_pre, non_initial_values);
433 
434  /* store the total precondition in the ri */
436 
437  gen_free_list(non_initial_values);
438  }
439  else {
440  _int so = statement_ordering(s);
441  pips_debug(8, "total precondition already available:\n");
442  (void) print_transformer(t_pre);
443  pips_debug(8, "for statement %03td (%td,%td), total precondition %p end:\n",
446  pips_internal_error("total precondition already computed");
447  }
448 
449  ifdebug(1) {
450  _int so = statement_ordering(s);
451  fprintf(stderr, "statement %03td (%td,%td), total precondition %p end:\n",
455  }
456 
457  ifdebug(1) {
458  _int so = statement_ordering(s);
459  fprintf(stderr, "statement %03td (%td,%td), total_precondition %p:\n",
461  ORDERING_STATEMENT(so), t_pre);
462  print_transformer(t_pre) ;
463  }
464 
466 
467  pips_assert("unexpected sharing",t_post!=t_pre);
468 
469  pips_debug(1,"end\n");
470 
471  return t_pre;
472 }
void free_transformer(transformer p)
Definition: ri.c:2616
cons * arguments_difference(cons *a1, cons *a2)
set difference: a1 - a2 ; similar to set intersection
Definition: arguments.c:233
transformer transformer_dup(transformer t_in)
transformer package - basic routines
Definition: basic.c:49
void transformer_free(transformer t)
Definition: basic.c:68
bool transformer_consistency_p(transformer t)
FI: I do not know if this procedure should always return or fail when an inconsistency is found.
Definition: basic.c:612
transformer transformer_empty()
Allocate an empty transformer.
Definition: basic.c:120
bool statement_reachable_p(statement)
Test if the given statement is reachable from some statements given at init_reachable(start)
Definition: unreachable.c:234
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
#define POP(l)
Modify a list pointer to point on the next element of the list.
Definition: newgen_list.h:59
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
#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 MAPL(_map_list_cp, _code, _l)
Apply some code on the addresses of all the elements of a list.
Definition: newgen_list.h:203
#define list_undefined
Undefined list definition :-)
Definition: newgen_list.h:69
#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
#define pips_internal_error
Definition: misc-local.h:149
#define pips_user_error
Definition: misc-local.h:147
void debug(const int the_expected_debug_level, const char *calling_function_name, const char *a_message_format,...)
ARARGS0.
Definition: debug.c:189
int tag
TAG.
Definition: newgen_types.h:92
intptr_t _int
_INT
Definition: newgen_types.h:53
#define print_transformer(t)
Definition: print.c:357
#define pips_flag_p(p)
for upwards compatibility with Francois's modified version
#define SEMANTICS_FLOW_SENSITIVE
#define ORDERING_NUMBER(o)
#define ORDERING_STATEMENT(o)
#define unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
#define is_instruction_block
soft block->sequence transition
#define instruction_block(i)
#define value_tag(x)
Definition: ri.h:3064
#define transformer_undefined
Definition: ri.h:2847
#define transformer_undefined_p(x)
Definition: ri.h:2848
#define loop_undefined
Definition: ri.h:1612
#define call_function(x)
Definition: ri.h:709
#define control_predecessors(x)
Definition: ri.h:943
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define test_undefined
Definition: ri.h:2808
#define instruction_loop(x)
Definition: ri.h:1520
#define statement_ordering(x)
Definition: ri.h:2454
#define test_false(x)
Definition: ri.h:2837
#define whileloop_evaluation(x)
Definition: ri.h:3166
#define unstructured_undefined
Definition: ri.h:2980
@ is_value_intrinsic
Definition: ri.h:3034
@ is_value_unknown
Definition: ri.h:3035
@ is_value_constant
Definition: ri.h:3033
@ is_value_code
Definition: ri.h:3031
@ is_value_symbolic
Definition: ri.h:3032
@ is_instruction_goto
Definition: ri.h:1473
@ is_instruction_unstructured
Definition: ri.h:1475
@ is_instruction_whileloop
Definition: ri.h:1472
@ is_instruction_test
Definition: ri.h:1470
@ is_instruction_call
Definition: ri.h:1474
@ is_instruction_forloop
Definition: ri.h:1477
@ is_instruction_loop
Definition: ri.h:1471
#define instruction_tag(x)
Definition: ri.h:1511
#define entity_name(x)
Definition: ri.h:2790
#define ENTITY_(x)
Definition: ri.h:2758
#define test_true(x)
Definition: ri.h:2835
#define transformer_arguments(x)
Definition: ri.h:2871
#define control_successors(x)
Definition: ri.h:945
#define test_condition(x)
Definition: ri.h:2833
#define instruction_whileloop(x)
Definition: ri.h:1523
#define statement_instruction(x)
Definition: ri.h:2458
#define instruction_call(x)
Definition: ri.h:1529
#define control_statement(x)
Definition: ri.h:941
#define instruction_test(x)
Definition: ri.h:1517
#define call_undefined
Definition: ri.h:685
#define statement_number(x)
Definition: ri.h:2452
#define evaluation_before_p(x)
Definition: ri.h:1159
#define instruction_unstructured(x)
Definition: ri.h:1532
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
#define entity_initial(x)
Definition: ri.h:2796
list get_module_global_arguments()
ri_to_preconditions.c
static transformer test_to_total_precondition(transformer t_post, test t, transformer tf, transformer context)
static transformer unstructured_to_total_precondition(transformer pre, unstructured u, transformer tf)
transformer statement_to_total_precondition(transformer, statement)
semantical analysis
#define DEBUG_TEST_TO_TOTAL_PRECONDITION
static transformer block_to_total_precondition(transformer t_post, list b)
static transformer call_to_total_precondition(transformer t_post, call c, transformer tf)
static transformer instruction_to_total_precondition(transformer t_post, instruction i, transformer tf, transformer context)
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
transformer transformer_add_domain_condition(transformer tf, expression c, transformer context, bool veracity)
Definition: expression.c:1138
transformer whileloop_to_total_precondition(transformer t_post, whileloop l, transformer tf, transformer context)
Definition: loop.c:3439
transformer loop_to_total_precondition(transformer t_post, loop l, transformer tf, transformer context)
Definition: loop.c:3023
transformer tf_equivalence_equalities_add(transformer tf)
mappings.c
Definition: mappings.c:83
transformer unstructured_to_flow_sensitive_total_preconditions(transformer, transformer, unstructured)
transformer load_statement_precondition(statement)
transformer load_statement_total_precondition(statement)
transformer load_statement_transformer(statement)
transformer unstructured_to_flow_insensitive_transformer(unstructured)
This simple fix-point over-approximates the CFG by a fully connected graph.
void store_statement_total_precondition(statement, transformer)
#define ifdebug(n)
Definition: sg.c:47
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
Definition: delay.c:253
transformer transformer_convex_hull(transformer t1, transformer t2)
transformer transformer_convex_hull(t1, t2): compute convex hull for t1 and t2; t1 and t2 are slightl...
Definition: convex_hull.c:216
transformer transformer_normalize(transformer t, int level)
Eliminate (some) rational or integer redundancy.
Definition: transformer.c:932
transformer transformer_filter(transformer t, list args)
transformer transformer_filter(transformer t, cons * args): projection of t along the hyperplane defi...
Definition: transformer.c:1716
bool transformer_empty_p(transformer t)
If true is returned, the transformer certainly is empty.
Definition: transformer.c:2455
transformer transformer_inverse_apply(transformer tf, transformer post)
transformer transformer_inverse_apply(transformer tf, transformer post): apply transformer tf on prec...
Definition: transformer.c:1657
transformer invariant_wrt_transformer(transformer p, transformer tf)
transformer invariant_wrt_transformer(transformer p, transformer tf): Assume that tf is a fix-point o...
Definition: transformer.c:1948
transformer transformer_apply(transformer tf, transformer pre)
transformer transformer_apply(transformer tf, transformer pre): apply transformer tf on precondition ...
Definition: transformer.c:1559
transformer transformer_to_domain(transformer tf)
Return the domain of relation tf in a newly allocated transformer.
Definition: transformer.c:772
transformer transformer_range(transformer tf)
Return the range of relation tf in a newly allocated transformer.
Definition: transformer.c:714
entity entity_to_old_value(entity)
Definition: value.c:869