PIPS
statement.c
Go to the documentation of this file.
1 /*
2 
3  $Id: statement.c 23412 2017-08-09 15:07:09Z irigoin $
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 
25 /*
26 This file contains functions used to compute points-to sets at statement level.
27 */
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 
32 #include "genC.h"
33 #include "linear.h"
34 
35 #include "ri.h"
36 #include "ri-util.h"
37 
38 #include "effects.h"
39 #include "effects-util.h"
40 
41 #include "misc.h"
42 #include "properties.h"
43 
44 #include "points-to.h"
45 
46 /* FI: short term attempt at providing a deep copy to avoid sharing
47  * between sets. If elements are shared, it quickly becomes impossible
48  * to deep free any set.
49  */
51 {
53  /*
54  HASH_MAP(k, v, {
55  points_to pt = (points_to) k;
56  points_to npt = copy_points_to(pt);
57  hash_put( out->table, (void *) npt, (void *) npt );
58  }, m->table);
59  */
60  SET_FOREACH(points_to, pt, m) {
61  points_to npt = copy_points_to(pt);
62  set_add_element(out, out, (void *) npt);
63  }
64  return out;
65 }
66 
68 {
69  // Dynamic type check
71  pips_assert("\"in\" is a points_to_graph", n==points_to_graph_domain);
72  pt_map out = new_pt_map();
73  set in_s = points_to_graph_set(in);
74  set out_s = points_to_graph_set(out);
75  SET_FOREACH(points_to, pt, in_s) {
76  points_to npt = copy_points_to(pt);
77  set_add_element(out_s, out_s, (void *) npt);
78  }
80  return out;
81 }
82 ␌
83 /* The input points-to information of a statement is updated by the
84  * analysis of the statement because of the on-demand approach. The
85  * formal context with its stubs is built onloy when necessary.
86  */
89 
91 {
92  pips_assert("statement_points_to_context is undefined",
96 }
97 
99 {
102 }
103 
105 {
107  add_arc_to_pt_map(pt, in);
108  //update_points_to_graph_with_arc(pt, in);
109  pips_assert("in is consistent", consistent_pt_map_p(in));
110 }
111 
113 {
115  //add_arc_to_pt_map(pt, in);
117  pips_assert("in is consistent", consistent_pt_map_p(in));
118 }
119 
121 {
122  //statement s = stack_head(current_statement_points_to_context);
124  return statement_number(s);
125 }
126 
128 {
130  return in;
131 }
132 
134 {
137 }
138 
140 {
143 }
144 
146 {
148 }
149 ␌
150 /* See points_to_statement()
151  *
152  *
153  */
155 {
156  pips_assert("pt_in is consistent", consistent_pt_map_p(pt_in));
159  pt_map pt_out = new_pt_map();
160  pt_out = full_copy_pt_map(pt_in);
162 
163  if(points_to_graph_bottom(pt_in)) {
164  // The information about dead code must be propagated downwards
165  pt_out = instruction_to_points_to(i, pt_out);
166  pips_assert("The resulting points-to graph is bottom",
167  points_to_graph_bottom(pt_out));
168  }
169  else {
170 
171  init_heap_model(s);
172  // FI: it would be nice to stack the current statement in order to
173  // provide more helpful error messages
175 
176  if(declaration_statement_p(s)) {
177  /* Process the declarations */
178  pt_out = declaration_statement_to_points_to(s, pt_out);
179  pips_assert("pt_out is consistent", consistent_pt_map_p(pt_out));
180  /* Go down recursively, although it is currently useless since a
181  declaration statement is a call to CONTINUE */
182  pt_out = instruction_to_points_to(i, pt_out);
183  }
184  else {
185  pt_out = instruction_to_points_to(i, pt_out);
186  }
187 
188  pips_assert("pt_out is consistent", consistent_pt_map_p(pt_out));
189 
190  /* Get the current version of pt_in, updated by the analysis of s. */
192 
193  pips_assert("pt_in is consistent", consistent_pt_map_p(pt_in));
194 
196  }
197 
198  /* Either pt_in or pt_out should be stored in the hash_table
199  *
200  * But it might be smarter (or not) to require or not the storage.
201  */
202  // FI: currently, this is going to be redundant most of the time
203  pt_map pt_merged;
204  if(bound_pt_to_list_p(s)) {
205  points_to_list ptl_prev = load_pt_to_list(s);
206  list ptl_prev_l = gen_full_copy_list(points_to_list_list(ptl_prev));
207  pt_map pt_prev = new_pt_map();
208  pt_prev = graph_assign_list(pt_prev, ptl_prev_l);
209  gen_free_list(ptl_prev_l);
210  pt_merged = merge_points_to_graphs(pt_in, pt_prev);
211  }
212  else
213  pt_merged = pt_in;
214  fi_points_to_storage(pt_merged, s, true);
215 
216  /* Eliminate local information if you exit a block */
217  if(statement_sequence_p(s)) {
220  bool main_p = ms==s && entity_main_module_p(m);
221  bool body_p = ms==s;
223  /* The statement context is know unknown: it has been popped
224  above. No precise error message in
225  points_to_set_block_projection() */
227  points_to_graph_set(pt_out) =
228  points_to_set_block_projection(points_to_graph_set(pt_out), dl, main_p, body_p);
230  }
231 
232  /* Because arc removals do not update the approximations of the
233  remaining arcs, let's upgrade approximations before the
234  information is passed. Useful for arithmetic02. */
236 
237  /* Really dangerous here: if pt_map "in" is empty, then pt_map "out"
238  * must be empty to...
239  *
240  * FI: we have a problem to denote unreachable statement. To
241  * associate an empty set to them woud be a way to avoid problems
242  * when merging points-to along different control paths. But you
243  * might also wish to start with an empty set... And anyway, you can
244  * find declarations in dead code...
245  */
246  // FI: a temporary fix to the problem, to run experiments...
247  //if(empty_pt_map_p(pt_in) && !declaration_statement_p(s)
248  // && s!=get_current_module_statement())
249  // clear_pt_map(pt_out); // FI: memory leak?
250 
251  pips_assert("pt_out is consistent on exit", consistent_pt_map_p(pt_out));
252 
254 
255  return pt_out;
256 }
257 
258 /* See points_to_init()
259  *
260  * pt_in is modified by side-effects and returned
261  */
263 {
264  pt_map pt_out = pt_in;
265  //set pt_out = set_generic_make(set_private, points_to_equal_p, points_to_rank);
266  list l = NIL;
267  //bool type_sensitive_p = !get_bool_property("ALIASING_ACROSS_TYPES");
268 
269  list l_decls = statement_declarations(s);
270 
271  pips_debug(1, "declaration statement \n");
272 
273  FOREACH(ENTITY, e, l_decls) {
275  if(pointer_type_p(et)
277  || struct_type_p(et)
278  || array_of_struct_type_p(et)) {
279  if( !storage_rom_p(entity_storage(e)) ) {
280  // FI: could be simplified with variable_initial_expression()
281  value v_init = entity_initial(e);
282  /* generate points-to due to the initialisation */
283  if(value_expression_p(v_init)){
284  expression exp_init = value_expression(v_init);
287  // See C standard for type compatibility + PIPS idiosyncrasies
288  // This should be extended to cope with the C type hierarchy
289  // accept side effects
290  pt_out = expression_to_points_to(exp_init, pt_out, true);
291  //if(array_pointer_type_equal_p(et, it)
292  //if(concrete_type_equal_p(et, it)
293  if(type_structurally_equal_p(et, it)
294  || array_pointer_type_equal_p(et, it)
295  || type_void_star_p(et) || type_void_star_p(it)
296  || integer_type_p(it)
297  || (char_star_type_p(et) && string_type_p(it))
298  || overloaded_type_p(it)) // PIPS own compatibility...
299  pt_out = assignment_to_points_to(lhs,
300  exp_init,
301  pt_out);
302  else {
303  pips_user_warning("Type mismatch for initialization of \"%s\" at line %d.\n",
304  entity_user_name(e),
306  clear_pt_map(pt_out);
307  points_to_graph_bottom(pt_out) = true;
308  }
309  /* AM/FI: abnormal sharing (lhs); the reference may be
310  reused in the cel... */
311  /* free_expression(lhs); */
312  }
313  else {
315  // C Standard: if e is a static pointer, it is implicly
316  // initialized to NULL
317  if(pointer_type_p(et) && variable_static_p(e)) {
318  cell source = CELL(CAR(l));
319  cell sink = make_null_cell();
320  points_to pt = make_points_to(source, sink,
323  add_arc_to_pt_map(pt, pt_out);
324  // The declared variable is local
325  // add_arc_to_points_to_context(copy_points_to(pt));
326  }
327  else {
328  FOREACH(CELL, source, l) {
329  cell sink = cell_to_nowhere_sink(source);
330  points_to pt = make_points_to(source, sink,
333  add_arc_to_pt_map(pt, pt_out);
334  // The declared variable is local
335  // add_arc_to_points_to_context(copy_points_to(pt));
336  }
337  }
338  }
339  }
340  }
341  else {
342  /* The initialization expression may use pointers, directly or
343  indirectly via struct and arrays. */
345  if(!expression_undefined_p(ie)) {
346  pt_out = expression_to_points_to(ie, pt_out, true);
347  free_expression(ie);
348  }
349  }
350  /* Take care of expressions in array sizing (see array12.c) */
351  if(array_type_p(et)) {
352  variable ev = type_variable(et);
353  list dl = variable_dimensions(ev);
354  FOREACH(DIMENSION, d, dl) {
357  pt_out = expression_to_points_to(l, pt_out, true);
358  pt_out = expression_to_points_to(u, pt_out, true);
359  }
360  }
361  }
362 
363  return pt_out;
364 }
365 
366 /* See points_to_statement()
367  *
368  * pt_in is modified by side-effects and returned
369  */
371 {
372  pt_map pt_out = pt_in;
373  tag it = instruction_tag(i);
374  switch(it) {
377  pt_out = sequence_to_points_to(seq, pt_in);
378  break;
379  }
380  case is_instruction_test: {
381  test t = instruction_test(i);
382  pt_out = test_to_points_to(t, pt_in);
383  break;
384  }
385  case is_instruction_loop: {
386  loop l = instruction_loop(i);
387  pt_out = loop_to_points_to(l, pt_in);
388  break;
389  }
392  pt_out = whileloop_to_points_to(wl, pt_in);
393  break;
394  }
395  case is_instruction_goto: {
396  pips_internal_error("Go to instructions should have been removed "
397  "before the analysis is started\n");
398  break;
399  }
400  case is_instruction_call: {
401  call c = instruction_call(i);
402  if(points_to_graph_bottom(pt_in))
403  pt_out = pt_in;
404  else
405  pt_out = call_to_points_to(c, pt_out, NIL, true);
406  break;
407  }
410  pt_out = unstructured_to_points_to(u, pt_in);
411  break;
412  }
414  pips_internal_error("Not implemented\n");
415  break;
416  }
417  case is_instruction_forloop: {
419  pt_out = forloop_to_points_to(fl, pt_in);
420  break;
421  }
424  if(points_to_graph_bottom(pt_in))
425  pt_out = pt_in;
426  else
427  pt_out = expression_to_points_to(e, pt_in, true);
428  break;
429  }
430  default:
431  pips_internal_error("Unexpected instruction tag %d\n", it);
432  }
433  return pt_out;
434 }
435 
437 {
438  pt_map pt_out = pt_in;
439  //bool store = true; // FI: management and use of store_p? Could be useful? How is it used?
440  // pt_out = points_to_sequence(seq, pt_in, store);
442  pt_out = statement_to_points_to(st, pt_out);
443  }
444 
445  return pt_out;
446 }
447 ␌
448 
449 /* expand the domain of pt_f according to the domain of pt_t */
451 {
452  set s_t = points_to_graph_set(pt_t);
453  set s_f = points_to_graph_set(pt_f);
454  SET_FOREACH(points_to, a_t, s_t) {
455  cell c_t = points_to_source(a_t);
456  bool found_p = false;
457  SET_FOREACH(points_to, a_f, s_f) {
458  cell c_f = points_to_source(a_f);
459  if(points_to_cell_equal_p(c_t, c_f)) {
460  found_p = true;
461  break;
462  }
463  }
464  if(!found_p) {
465  reference r_t = cell_any_reference(c_t);
466  entity v_t = reference_variable(r_t);
467  if(formal_parameter_p(v_t) || entity_stub_sink_p(v_t)) {
469  pt_f = pointer_assignment_to_points_to(e_t, e_t, pt_f);
470  if(points_to_graph_bottom(pt_f))
471  pips_internal_error("Unexpected information loss.");
472  }
473  }
474  }
475 }
476 
477 /* Make sure that pt_t and pt_f have the same definition domain except
478  if one of them is bottom */
480 {
481  if(!points_to_graph_bottom(pt_t)) {
482  if(!points_to_graph_bottom(pt_f)) {
483  expand_points_to_domain(pt_t, pt_f);
484  expand_points_to_domain(pt_f, pt_t);
485  }
486  }
487 }
488 
489 /* Computing the points-to information after a test.
490  *
491  * All the relationships are of type MAY, even if the same arc is
492  * defined, e.g. "if(c) p = &i; else p=&i;".
493  *
494  * Might be refined later by using preconditions.
495  */
497 {
498  pt_map pt_out = pt_map_undefined;
499 
500  //bool store = true;
501  // pt_out = points_to_test(t, pt_in, store);
502  // Translation of points_to_test
503  statement ts = test_true(t);
504  statement fs = test_false(t);
505  expression c = test_condition(t);
506  pt_map pt_t = pt_map_undefined;
507  pt_map pt_f = pt_map_undefined;
508 
509  /* Make sure the condition is exploited, either because of side
510  * effects or simply because of dereferencements.
511  *
512  * This cannot be done here because of side-effects.
513  *
514  * FI: because the conditions must be evaluated for true and false?
515  */
516  //pt_in = expression_to_points_to(c, pt_in);
517  //list el = expression_to_proper_constant_path_effects(c);
518  //if(!effects_write_p(el))
519  // pt_in = expression_to_points_to(c, pt_in, true);
520  //gen_free_list(el);
521 
522  // The side effects won't be taken into account when the condition
523  // is evaluated
524  pt_in = expression_to_points_to(c, pt_in, true);
525 
526  pt_map pt_in_t = full_copy_pt_map(pt_in);
527  pt_map pt_in_f = full_copy_pt_map(pt_in);
528 
529  /* condition's side effect and information are taked into account, e.g.:
530  *
531  * "if(p=q)" or "if(*p++)" or "if(p)" which implies p->NULL in the
532  * else branch. FI: to be checked with test cases */
533  if(!points_to_graph_bottom(pt_in_t)) // FI: we are in dead code
534  pt_in_t = condition_to_points_to(c, pt_in_t, true);
535  pt_t = statement_to_points_to(ts, pt_in_t);
536 
537  if(!points_to_graph_bottom(pt_in_f)) // FI: we are in dead code
538  pt_in_f = condition_to_points_to(c, pt_in_f, false);
539  pt_f = statement_to_points_to(fs, pt_in_f);
540 
541  pips_assert("pt_t is consistent", points_to_graph_consistent_p(pt_t));
542  pips_assert("pt_f is consistent", points_to_graph_consistent_p(pt_f));
543 
544  /* We must use a common definition domain for both relations in
545  order to obatin a really consistent points-to relation after the
546  merge. This is similar to what is done in semantics for scalar
547  preconditions. */
548  equalize_points_to_domains(pt_t, pt_f);
549 
550  pt_out = merge_points_to_graphs(pt_t, pt_f);
551 
552  pips_assert("pt_out is consistent", points_to_graph_consistent_p(pt_out));
553 
554  // FI: we should take care of pt_t and pt_f to avoid memory leaks
555  // In that specific case, clear_pt_map() and free_pt_map() should be ok
556 
557  pips_assert("pt_out is consistent", points_to_graph_consistent_p(pt_out));
558 
561  free_pt_map(pt_t), free_pt_map(pt_f);
562 
563  pips_assert("pt_out is consistent", points_to_graph_consistent_p(pt_out));
564 
565  return pt_out;
566 }
567 
568 /* FI: I assume that pointers and pointer arithmetic cannot appear in
569  * a do loop, "do p=q, r, 1" is possible with "p", "q" and "r"
570  * pointing towards the same array... Let's hope the do loop
571  * conversion does not catch such cases.
572  */
574 {
575  pt_map pt_out = pt_in;
576  statement b = loop_body(l);
577  //bool store = false;
578  //pt_out = points_to_loop(l, pt_in, store);
579 
580  /* loop range expressions may require some points-to information
581  * See for instance Pointers/Mensi.sub/array_init02.c
582  *
583  * Side effects might have to be taken into account... But side
584  * effects should also prevent PIPS from transforming a for loop
585  * into a do loop.
586  */
587  range r = loop_range(l);
589  expression bound = range_upper(r);
590  expression inc = range_increment(r);
591  pt_in = expression_to_points_to(init, pt_in, false);
592  pt_in = expression_to_points_to(bound, pt_in, false);
593  pt_in = expression_to_points_to(inc, pt_in, false);
594 
595  pt_out = any_loop_to_points_to(b,
599  pt_in);
600 
601  return pt_out;
602 }
603 
605 {
606  pt_map pt_out = pt_in;
607  statement b = whileloop_body(wl);
609 
610  //bool store = false;
612  //pt_out = points_to_whileloop(wl, pt_in, store);
613  //pt_out = expression_to_points_to(c, pt_out, false);
614  pt_out = expression_to_points_to(c, pt_out, true);
615  pt_out = any_loop_to_points_to(b,
617  c,
619  pt_in);
620  }
621  else {
622  // pt_out = points_to_do_whileloop(wl, pt_in, store);
623  /* Execute the first iteration */
624  pt_out = statement_to_points_to(b, pt_out);
625  pt_out = any_loop_to_points_to(b,
627  c,
629  pt_out);
630  }
631 
632  //statement ws = whileloop_body(wl);
633  //list dl = statement_declarations(ws);
634  // FI: to be improved
635  //if(declaration_statement_p(ws) && !ENDP(dl))
636  // pt_out = points_to_set_block_projection(pt_out, dl);
637 
639 
640  return pt_out;
641 }
642 
643 /* Perform the same k-limiting scheme for all kinds of loops
644  *
645  * The do while loop must use an external special treatment for the
646  * first iteration.
647  *
648  * Derived from points_to_forloop() and from Amira's work.
649  *
650  * pt_in is modified by side effects.
651  */
652 //pt_map old_any_loop_to_points_to(statement b,
654  expression init, // can be undefined
655  expression c, // can be undefined
656  expression inc, // ca be undefined
657  pt_map pt_in)
658 {
659  pt_map pt_out = pt_in;
660 
661  if(points_to_graph_bottom(pt_in)) {
662  (void) statement_to_points_to(b, pt_in);
663  }
664  else {
665  int i = 0;
666  // FI: k is linked to the cycles in points-to graph, and should not
667  // be linked to the number of convergence iterations. I assume here
668  // that the minimal number of iterations is greater than the
669  // k-limiting factor
670  int k = get_int_property("POINTS_TO_PATH_LIMIT")
671  + get_int_property("POINTS_TO_SUBSCRIPT_LIMIT")
672  + get_int_property("POINTS_TO_OUT_DEGREE_LIMIT")
673  +10; // Safety margin: might be set to max of both properties + 1 or 2...
674 
675  /* First, enter or skip the loop: initialization + condition check */
677  pt_out = expression_to_points_to(init, pt_out, true);
678  pt_map pt_out_skip = full_copy_pt_map(pt_out);
679  if(!expression_undefined_p(c)) {
680  pt_out = expression_to_points_to(c, pt_out, true);
681  pt_out = condition_to_points_to(c, pt_out, true);
682  pt_out_skip = condition_to_points_to(c, pt_out_skip, false);
683  }
684 
685  /* Comput pt_out as loop invariant: pt_out holds at the beginning of
686  * the loop body.
687  *
688  * pt_out(i) = f(pt_out(i-1)) U pt_out(i-1)
689  *
690  * prev = pt_out(i-1)
691  *
692  * Note: the pt_out variable is also used to carry the loop exit
693  * points-to set.
694  */
695  pt_map prev = new_pt_map();
696  // FI: it should be a while loop to reach convergence
697  // FI: I keep it a for loop for safety
698  bool fix_point_p = false;
699  for(i = 0; i<k+2 ; i++) {
700  /* prev receives the current points-to information, pt_out */
701  clear_pt_map(prev);
702  prev = assign_pt_map(prev, pt_out);
703  clear_pt_map(pt_out);
704 
705  /* Depending on the kind of loops, execute the body and then
706  possibly the incrementation and the condition */
707  // FI: here, storage_p would be useful to avoid unnecessary
708  // storage and update for each substatement at each iteration k
709  pt_out = statement_to_points_to(b, prev);
710  if(!expression_undefined_p(inc))
711  pt_out = expression_to_points_to(inc, pt_out, true);
712  // FI: should be condition_to_points_to() for conditions such as
713  // while(p!=q);
714  // The condition is not always defined (do loops)
715  if(!expression_undefined_p(c)) {
716  pt_out = condition_to_points_to(c, pt_out, true);
718  }
719 
720  /* Merge the previous resut and the current result. */
721  // FI: move to pt_map
722  pt_out = merge_points_to_graphs(prev, pt_out);
723 
724  pt_out = normalize_points_to_graph(pt_out);
726 
727  // pips_assert("", consistent_points_to_graph_p(pt_out));
728 
729  /* Check convergence */
731  fix_point_p = true;
732  /* Add the last iteration to obtain the pt_out holding when
733  exiting the loop */
734  pt_out = statement_to_points_to(b, prev);
735 
737  if(!expression_undefined_p(inc))
738  pt_out = expression_to_points_to(inc, pt_out, true);
739 
741  if(!expression_undefined_p(c))
742  pt_out = condition_to_points_to(c, pt_out, false);
743 
745  break;
746  }
747  else {
748  ifdebug(1) {
749  pips_debug(1, "\n\nAt iteration i=%d:\n\n", i);
750  print_points_to_set("Loop points-to set prev:\n",
751  points_to_graph_set(prev));
752  print_points_to_set("Loop points-to set pt_out:\n",
753  points_to_graph_set(pt_out));
754  }
755  }
756  }
757 
758  if(!fix_point_p) {
759  print_points_to_set("Loop points-to set prev:\n", points_to_graph_set(prev));
760  print_points_to_set("Loop points-to set pt_out:\n", points_to_graph_set(pt_out));
761  pips_internal_error("Loop convergence not reached in %d iterations.\n", i);
762  }
763 
764  /* FI: I suppose that p[i] is replaced by p[*] and that MAY/MUST
765  information is changed accordingly. */
767 
768  // pips_assert("", consistent_points_to_graph_p(pt_out));
769 
770  pt_out = merge_points_to_graphs(pt_out, pt_out_skip);
771  }
772 
773  // pips_assert("", consistent_points_to_graph_p(pt_out));
774 
775  return pt_out;
776 }
777 
778 /* Perform the same k-limiting scheme for all kinds of loops
779  *
780  * The do while loop must use an external special treatment for the
781  * first iteration.
782  *
783  * Derived from the initial any_loop_to_points_to(): the iteration
784  * scheme is slighlty different but we end up with the same final
785  * iteration with all unioned states. Seems problematic at least in
786  * the presence of calls to free() because iter() is never normalized
787  * and always introduces new vertices and arcs in "pt_out". See
788  * list05.c.
789  *
790  * pt_in is modified by side effects.
791  */
793  expression init, // can be undefined
794  expression c, // can be undefined
795  expression inc, // ca be undefined
796  pt_map pt_in)
797 {
798  // return old_any_loop_to_points_to(b, init, c, inc, pt_in);
799  pt_map pt_out = pt_in;
800 
801  if(points_to_graph_bottom(pt_in)) {
802  (void) statement_to_points_to(b, pt_in);
803  }
804  else {
805  int i = 0;
806  // FI: k is linked to the cycles in points-to graph, and should not
807  // be linked to the number of convergence iterations. I assume here
808  // that the minimal number of iterations is greater than the
809  // k-limiting factor
810  int k = get_int_property("POINTS_TO_PATH_LIMIT")
811  + get_int_property("POINTS_TO_SUBSCRIPT_LIMIT")
812  + get_int_property("POINTS_TO_OUT_DEGREE_LIMIT")
813  +10; // Safety margin: might be set to max of both properties + 1 or 2...
814 
815  /* First, enter or skip the loop: initialization + condition check */
817  pt_out = expression_to_points_to(init, pt_out, true);
818  pt_map pt_out_skip = full_copy_pt_map(pt_out);
819  if(!expression_undefined_p(c)) {
820  pt_out = condition_to_points_to(c, pt_out, true);
821  pt_out_skip = condition_to_points_to(c, pt_out_skip, false);
822  }
823 
824  /* Compute pt_out as loop invariant: pt_out holds at the beginning of
825  * the loop body.
826  *
827  * pt_out(i) = pt_out(i-1) U pt_iter(i)
828  *
829  * pt_iter(i) = f(pt_iter(i-1))
830  *
831  * pt_prev == pt_iter(i-1), pt_out_prev == pt_out(i-1)
832  *
833  * Note: the pt_out variable is also used to carry the loop exit
834  * points-to set.
835  */
836  pt_map pt_out_prev = new_pt_map();
837  pt_map prev = new_pt_map();
838  pt_map pt_iter = new_pt_map();
839  pt_iter = assign_pt_map(pt_iter, pt_out);
840 
841  // FI: it should be a while loop to reach convergence
842  // FI: I keep it a for loop for safety
843  bool fix_point_p = false;
844  for(i = 0; i<k+2 ; i++) {
845  /* prev receives the current points-to information, pt_iter */
846  clear_pt_map(prev);
847  prev = assign_pt_map(prev, pt_iter);
848  clear_pt_map(pt_iter);
849 
850  /* Depending on the kind of loop, execute the body and then
851  possibly the incrementation and the condition */
852  // FI: here, storage_p would be useful to avoid unnecessary
853  // storage and update for each substatement at each iteration k
854  pt_iter = statement_to_points_to(b, prev);
855  if(!expression_undefined_p(inc))
856  pt_iter = expression_to_points_to(inc, pt_iter, true);
857  // FI: should be condition_to_points_to() for conditions such as
858  // while(p!=q);
859  // The condition is not always defined (do loops)
860  if(!expression_undefined_p(c))
861  pt_iter = condition_to_points_to(c, pt_iter, true);
862 
863  /* Merge the previous resut and the current result. */
864  // FI: move to pt_map
865  pt_out_prev = assign_pt_map(pt_out_prev, pt_out);
866  pt_out = merge_points_to_graphs(pt_out, pt_iter);
867 
868  pt_out = normalize_points_to_graph(pt_out);
869 
870  /* Check convergence */
871  if(set_equal_p(points_to_graph_set(pt_out_prev),
872  points_to_graph_set(pt_out))) {
873  fix_point_p = true;
874  /* Add the last iteration to obtain the pt_out holding when
875  exiting the loop */
876  pt_out = statement_to_points_to(b, pt_out_prev);
877  if(!expression_undefined_p(inc))
878  pt_out = expression_to_points_to(inc, pt_out, true);
879  if(!expression_undefined_p(c))
880  pt_out = condition_to_points_to(c, pt_out, false);
881  break;
882  }
883  else {
884  //ifdebug(1) {
885  if(true) {
886  pips_debug(1, "\n\nAt iteration i=%d:\n\n", i);
887  print_points_to_set("Loop points-to set pt_out_prev:\n",
888  points_to_graph_set(pt_out_prev));
889  print_points_to_set("Loop points-to set pt_out:\n",
890  points_to_graph_set(pt_out));
891  }
892  }
893  }
894 
895  if(!fix_point_p) {
896  print_points_to_set("Loop points-to set pt_out:\n", points_to_graph_set(pt_out));
897  print_points_to_set("Loop points-to set pt_out_prev:\n", points_to_graph_set(pt_out_prev));
898  pips_internal_error("Loop convergence not reached after %d iterations.\n", k+2);
899  }
900 
901  /* FI: I suppose that p[i] is replaced by p[*] and that MAY/MUST
902  information is changed accordingly. */
903  points_to_graph_set(pt_out) =
905 
906  pt_out = merge_points_to_graphs(pt_out, pt_out_skip);
907  }
908 
909  return pt_out;
910 }
911 
913 {
914  //bool type_sensitive_p = !get_bool_property("ALIASING_ACROSS_TYPES");
915  //entity anywhere = entity_undefined;
916  set pt_out_s = points_to_graph_set(pt_out);
917 
918  SET_FOREACH(points_to, pt, pt_out_s){
919  cell sc = points_to_source(pt);
920  reference sr = cell_any_reference(sc);
921  list sl = reference_indices(sr);
922 
923  cell kc = points_to_sink(pt);
924  reference kr = cell_any_reference(kc);
925  list kl = reference_indices(kr);
926 
927  if((int)gen_length(sl)>k){
928  bool to_be_freed = false;
929  type sc_type = cell_to_type(sc, &to_be_freed);
930  sc = make_anywhere_cell(sc_type);
931  if(to_be_freed) free_type(sc_type);
932  }
933 
934  if((int)gen_length(kl)>k){
935  bool to_be_freed = false;
936  type kc_type = cell_to_type(kc, &to_be_freed);
937  kc = make_anywhere_cell(kc_type);
938  if(to_be_freed) free_type(kc_type);
939  }
940 
941  points_to npt = make_points_to(sc, kc,
944  if(!points_to_equal_p(npt,pt)){
945  // FC: why assigning pt_out to itself?
946  pt_out = remove_arc_from_pt_map_(pt, pt_out);
947  pt_out = remove_arc_from_pt_map_(npt, pt_out);
948  }
949  else {
950  // FI: memory leak
951  // free_points_to(npt);
952  }
953  }
954  return pt_out;
955 }
956 
957 ␌
959 {
960  pt_map pt_out = pt_in;
961 
962  pt_out = new_points_to_unstructured(u, pt_in, true);
963 
964  return pt_out;
965 }
966 
968 {
969  pt_map pt_out = pt_in;
970  pips_internal_error("Not implemented yet for multitest %p\n", mt);
971  return pt_out;
972 }
973 
975 {
976  pt_map pt_out = pt_in;
977  statement b = forloop_body(fl);
980  expression inc = forloop_increment(fl);
981 
982  pt_out = any_loop_to_points_to(b, init, c, inc, pt_in);
983  return pt_out;
984 }
int get_int_property(const string)
approximation make_approximation_exact(void)
Definition: effects.c:185
approximation copy_approximation(approximation p)
APPROXIMATION.
Definition: effects.c:132
descriptor make_descriptor_none(void)
Definition: effects.c:442
points_to make_points_to(cell a1, cell a2, approximation a3, descriptor a4)
bool points_to_graph_consistent_p(points_to_graph p)
points_to copy_points_to(points_to p)
POINTS_TO.
void free_expression(expression p)
Definition: ri.c:853
void free_type(type p)
Definition: ri.c:2658
#define add_arc_to_pt_map(a, s)
#define pt_map_undefined
points_to_graph pt_map
#define consistent_pt_map_p(s)
#define clear_pt_map(pt)
#define assign_pt_map(x, y)
#define free_pt_map(pt)
#define new_simple_pt_map()
#define new_pt_map()
static FILE * out
Definition: alias_check.c:128
bool entity_stub_sink_p(entity e)
test if an entity is a stub sink for a formal parameter e.g.
cell make_anywhere_cell(type t)
set points_to_independent_store(set s)
cell cell_to_nowhere_sink(cell source)
assuming source is a reference to a pointer, build the corresponding sink when the pointer is not ini...
type cell_to_type(cell, bool *)
Definition: type.c:513
reference cell_any_reference(cell)
API for reference.
Definition: effects.c:77
bool points_to_cell_equal_p(cell, cell)
Definition: points_to.c:916
points_to_list load_pt_to_list(statement)
bool bound_pt_to_list_p(statement)
#define CELL(x)
CELL.
Definition: effects.h:424
statement get_current_module_statement(void)
Get the current module statement.
Definition: static.c:208
entity get_current_module_entity(void)
Get the entity of the current module.
Definition: static.c:85
#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
#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
list gen_full_copy_list(list l)
Copy a list structure with element copy.
Definition: list.c:535
bool statement_sequence_p(statement s)
Statement classes induced from instruction type.
Definition: statement.c:335
bool declaration_statement_p(statement s)
Had to be optimized according to Beatrice Creusillet.
Definition: statement.c:224
#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
bool set_equal_p(const set, const set)
returns whether s1 == s2
Definition: set.c:316
#define SET_FOREACH(type_name, the_item, the_set)
enumerate set elements in their internal order.
Definition: newgen_set.h:78
set set_clear(set)
Assign the empty set to s s := {}.
Definition: set.c:326
set set_add_element(set, const set, const void *)
Definition: set.c:152
#define stack_undefined
Definition: newgen_stack.h:55
void * stack_head(const stack)
returns the item on top of stack s
Definition: stack.c:420
void stack_push(void *, stack)
stack use
Definition: stack.c:373
void stack_free(stack *)
type, bucket_size, policy
Definition: stack.c:292
stack stack_make(int, int, int)
allocation
Definition: stack.c:246
void * stack_pop(stack)
POPs one item from stack s.
Definition: stack.c:399
#define stack_undefined_p(s)
Definition: newgen_stack.h:56
int tag
TAG.
Definition: newgen_types.h:92
pt_map update_points_to_graph_with_arc(points_to a, pt_map pt)
Instead of simply adding the new arc, make sure the consistency is not broken.
Definition: passes.c:183
void fi_points_to_storage(pt_map ptm, statement s, bool store)
Definition: passes.c:97
#define remove_arc_from_pt_map_(a, s)
pt_map call_to_points_to(call c, pt_map pt_in, list el, bool side_effect_p)
Three different kinds of calls are distinguished:
Definition: expression.c:306
pt_map condition_to_points_to(expression c, pt_map in, bool true_p)
Update points-to set "in" according to the content of the expression using side effects.
Definition: expression.c:2512
pt_map pointer_assignment_to_points_to(expression lhs, expression rhs, pt_map pt_in)
Definition: expression.c:1437
pt_map expression_to_points_to(expression e, pt_map pt_in, bool side_effect_p)
Update pt_in and pt_out according to expression e.
Definition: expression.c:115
pt_map assignment_to_points_to(expression lhs, expression rhs, pt_map pt_in)
Definition: expression.c:1163
static void expand_points_to_domain(points_to_graph pt_t, points_to_graph pt_f)
expand the domain of pt_f according to the domain of pt_t
Definition: statement.c:450
void reset_statement_points_to_context()
Definition: statement.c:139
int points_to_context_statement_line_number()
Definition: statement.c:120
void update_statement_points_to_context_with_arc(points_to pt)
Definition: statement.c:112
set full_copy_simple_pt_map(set m)
FI: short term attempt at providing a deep copy to avoid sharing between sets.
Definition: statement.c:50
static stack statement_points_to_context
The input points-to information of a statement is updated by the analysis of the statement because of...
Definition: statement.c:87
pt_map declaration_statement_to_points_to(statement s, pt_map pt_in)
See points_to_init()
Definition: statement.c:262
pt_map loop_to_points_to(loop l, pt_map pt_in)
FI: I assume that pointers and pointer arithmetic cannot appear in a do loop, "do p=q,...
Definition: statement.c:573
bool statement_points_to_context_defined_p()
Definition: statement.c:145
pt_map whileloop_to_points_to(whileloop wl, pt_map pt_in)
Definition: statement.c:604
void add_arc_to_statement_points_to_context(points_to pt)
Definition: statement.c:104
void init_statement_points_to_context()
Definition: statement.c:90
pt_map new_any_loop_to_points_to(statement b, expression init, expression c, expression inc, pt_map pt_in)
Perform the same k-limiting scheme for all kinds of loops.
Definition: statement.c:792
pt_map points_to_context_statement_in()
Definition: statement.c:127
void push_statement_points_to_context(statement s, pt_map in)
Definition: statement.c:98
pt_map pop_statement_points_to_context(void)
Definition: statement.c:133
pt_map k_limit_points_to(pt_map pt_out, int k)
Definition: statement.c:912
pt_map sequence_to_points_to(sequence seq, pt_map pt_in)
Definition: statement.c:436
pt_map forloop_to_points_to(forloop fl, pt_map pt_in)
Definition: statement.c:974
void equalize_points_to_domains(points_to_graph pt_t, points_to_graph pt_f)
Make sure that pt_t and pt_f have the same definition domain except if one of them is bottom.
Definition: statement.c:479
pt_map full_copy_pt_map(pt_map in)
Definition: statement.c:67
static stack current_statement_points_to_context
Definition: statement.c:88
pt_map any_loop_to_points_to(statement b, expression init, expression c, expression inc, pt_map pt_in)
Perform the same k-limiting scheme for all kinds of loops.
Definition: statement.c:653
pt_map statement_to_points_to(statement s, pt_map pt_in)
See points_to_statement()
Definition: statement.c:154
pt_map unstructured_to_points_to(unstructured u, pt_map pt_in)
Definition: statement.c:958
pt_map test_to_points_to(test t, pt_map pt_in)
Computing the points-to information after a test.
Definition: statement.c:496
pt_map multitest_to_points_to(multitest mt, pt_map pt_in)
Definition: statement.c:967
pt_map instruction_to_points_to(instruction i, pt_map pt_in)
See points_to_statement()
Definition: statement.c:370
void reset_heap_model(void)
Definition: sinks.c:1185
void upgrade_approximations_in_points_to_set(pt_map)
When arcs have been removed from a points-to relation, the approximations of remaining arcs may not c...
pt_map graph_assign_list(pt_map, list)
FI: I add functions dealing with points_to_graph variable, i.e.
cell make_null_cell(void)
Definition: sinks.c:95
pt_map normalize_points_to_graph(pt_map)
For the time being, control the out-degree of the vertices in points-to graph "ptg" and fuse the vert...
set points_to_set_block_projection(set, list, bool, bool)
Remove from "pts" arcs based on at least one local entity in list "l" and preserve those based on sta...
void print_points_to_set(string, set)
list variable_to_pointer_locations(entity)
variable.c
Definition: variable.c:66
pt_map remove_unreachable_stub_vertices_in_points_to_graph(pt_map)
int points_to_equal_p(const void *, const void *)
returns true if two points-to arcs "vpt1" and "vpt2" are equal.
Definition: points_to_set.c:98
pt_map new_points_to_unstructured(unstructured, pt_map, bool)
void init_heap_model(statement)
Definition: sinks.c:1179
bool consistent_points_to_graph_p(points_to_graph)
pt_map merge_points_to_graphs(pt_map, pt_map)
#define points_to_approximation(x)
#define points_to_sink(x)
#define points_to_list_list(x)
#define points_to_graph_domain_number(x)
#define points_to_graph_bottom(x)
#define points_to_graph_set(x)
#define points_to_source(x)
#define points_to_graph_domain
Definition: print.c:373
const char * entity_user_name(entity e)
Since entity_local_name may contain PIPS special characters such as prefixes (label,...
Definition: entity.c:487
bool entity_main_module_p(entity e)
Definition: entity.c:700
static int init
Maximal value set for Fortran 77.
Definition: entity.c:320
expression reference_to_expression(reference r)
Definition: expression.c:196
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
bool array_type_p(type)
Definition: type.c:2942
bool type_void_star_p(type)
Definition: type.c:5765
type expression_to_type(expression)
For an array declared as int a[10][20], the type returned for a[i] is int [20].
Definition: type.c:2486
bool array_of_pointers_type_p(type)
Definition: type.c:3025
statement pop_statement_global_stack(void)
Definition: static.c:352
statement get_current_statement_from_statement_global_stack(void)
Definition: static.c:344
bool integer_type_p(type)
Definition: type.c:3298
type entity_basic_concrete_type(entity)
retrieves or computes and then returns the basic concrete type of an entity
Definition: type.c:3677
bool pointer_type_p(type)
Check for scalar pointers.
Definition: type.c:2993
bool type_structurally_equal_p(type, type)
Type t1 and t2 are equal if their basic concrete components are equal.
Definition: type.c:586
bool array_pointer_type_equal_p(type, type)
assume that a pointer to type x is equal to a 1-D array of x
Definition: type.c:609
bool formal_parameter_p(entity)
Definition: variable.c:1489
expression variable_initial_expression(entity)
Returns a copy of the initial (i.e.
Definition: variable.c:1899
bool struct_type_p(type)
Returns true if t is of type derived and if the derived type is a struct.
Definition: type.c:3121
void push_statement_on_statement_global_stack(statement)
Definition: static.c:333
type compute_basic_concrete_type(type)
computes a new type which is the basic concrete type of the input type (this new type is not stored i...
Definition: type.c:3556
bool overloaded_type_p(type)
Returns true if t is a variable type with a basic overloaded.
Definition: type.c:2666
bool char_star_type_p(type)
Beware of typedefs.
Definition: type.c:5774
bool string_type_p(type)
Definition: type.c:2854
bool array_of_struct_type_p(type)
Definition: type.c:3133
bool variable_static_p(entity)
true if v appears in a SAVE statement, or in a DATA statement, or is declared static i C.
Definition: variable.c:1579
#define loop_body(x)
Definition: ri.h:1644
#define forloop_initialization(x)
Definition: ri.h:1366
#define reference_variable(x)
Definition: ri.h:2326
#define range_upper(x)
Definition: ri.h:2290
#define forloop_increment(x)
Definition: ri.h:1370
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define instruction_loop(x)
Definition: ri.h:1520
#define test_false(x)
Definition: ri.h:2837
#define dimension_lower(x)
Definition: ri.h:980
#define whileloop_evaluation(x)
Definition: ri.h:3166
#define type_variable(x)
Definition: ri.h:2949
#define entity_storage(x)
Definition: ri.h:2794
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define range_increment(x)
Definition: ri.h:2292
#define expression_undefined
Definition: ri.h:1223
@ is_instruction_goto
Definition: ri.h:1473
@ is_instruction_unstructured
Definition: ri.h:1475
@ is_instruction_whileloop
Definition: ri.h:1472
@ is_instruction_expression
Definition: ri.h:1478
@ is_instruction_test
Definition: ri.h:1470
@ is_instruction_multitest
Definition: ri.h:1476
@ is_instruction_call
Definition: ri.h:1474
@ is_instruction_sequence
Definition: ri.h:1469
@ is_instruction_forloop
Definition: ri.h:1477
@ is_instruction_loop
Definition: ri.h:1471
#define instruction_tag(x)
Definition: ri.h:1511
#define test_true(x)
Definition: ri.h:2835
#define sequence_statements(x)
Definition: ri.h:2360
#define dimension_upper(x)
Definition: ri.h:982
#define reference_indices(x)
Definition: ri.h:2328
#define instruction_sequence(x)
Definition: ri.h:1514
#define instruction_forloop(x)
Definition: ri.h:1538
#define instruction_expression(x)
Definition: ri.h:1541
#define expression_undefined_p(x)
Definition: ri.h:1224
#define test_condition(x)
Definition: ri.h:2833
#define instruction_whileloop(x)
Definition: ri.h:1523
#define range_lower(x)
Definition: ri.h:2288
#define variable_dimensions(x)
Definition: ri.h:3122
#define whileloop_body(x)
Definition: ri.h:3162
#define statement_declarations(x)
Definition: ri.h:2460
#define statement_instruction(x)
Definition: ri.h:2458
#define instruction_call(x)
Definition: ri.h:1529
#define loop_range(x)
Definition: ri.h:1642
#define storage_rom_p(x)
Definition: ri.h:2525
#define forloop_condition(x)
Definition: ri.h:1368
#define instruction_test(x)
Definition: ri.h:1517
#define whileloop_condition(x)
Definition: ri.h:3160
#define statement_number(x)
Definition: ri.h:2452
#define value_expression_p(x)
Definition: ri.h:3080
#define evaluation_before_p(x)
Definition: ri.h:1159
#define forloop_body(x)
Definition: ri.h:1372
#define value_expression(x)
Definition: ri.h:3082
#define instruction_unstructured(x)
Definition: ri.h:1532
#define entity_initial(x)
Definition: ri.h:2796
#define ifdebug(n)
Definition: sg.c:47
the stack head
Definition: stack.c:62
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