PIPS
unstructured.c
Go to the documentation of this file.
1 /*
2 
3  $Id: unstructured.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  * Computation of transformers and postconditions and total preconditions
30  * in unstructured (i.e. CFG).
31  *
32  * Accurate results are obtained by restructuring CFG into a set of
33  * non-deterministic CFG's using Bourdoncle's partitioning as implemented
34  * in control/bourdoncle.c. The cycle heads are chosen using Bourdoncle's
35  * heuristics. Then the graph is augmented with new nodes in order that
36  * cycle heads are the only entry and exit node of the cycles in each
37  * scc. So the input CFG is transformed into a non-deterministic
38  * DAG. Some nodes of the DAG point to SCC's. Each SCC is represented by
39  * a DAG whose leaves point back to the cycle head. The SCC DAG may
40  * contain nodes pointing to sub-SCC's.
41  *
42  * It is not clear if you want to store the node pre or
43  * postcondition. The postcondition may depend on the outgoing arc. But
44  * the precondition would have to be processed by the node transformer
45  * once for each arc. To avoid both problems the postconditions are
46  * stored without the control information. It is added later according to
47  * the outgoing arc considered. But it is not satisfactory to apply a
48  * reverse transformer to retrieve the precondition or to re-apply a
49  * convex hull on the input after having taken care of the potential
50  * cycle. All in all, it would be easier to store preconditions...
51  *
52  * Transformers between the entry point and after the current node are
53  * very similar to postcondition between the module entry point and the
54  * current node. Transformers are obtained like precondition but without
55  * a precondition at the CFG entry point.
56  *
57  * It is possible to store the star or the plus fix points. I first
58  * stored the star fix points. It is often needed. It is safe because it
59  * can be applied several times without impacting the result. However,
60  * it does not retain information about the cycle body
61  * transformer. Because the convex hull operator looses information, it
62  * is more accurate to use the plus fix point and to apply a convex hull
63  * to the direct precondition and to the cycle output. Thus, if the entry
64  * node is a test, its conditions can be added before the convex hull is
65  * performed.
66  *
67  * It might be useful to add a pseudo-node as predecessor of the CFG
68  * entry node. This pseudo-node would simplify the algorithms and the
69  * function profiles. Its post-condition would be the precondition of the
70  * CFG or no information. Without it, each node must be checked to see if
71  * it is the entry node because, then, it has an extra-predecessor.
72  *
73  * Francois Irigoin, July 2002 (First version: October 2000)
74  *
75  * Note: Bourdoncle's heuristics minimizes the number of cycles under
76  * the assumption that most information is lost when performing a
77  * widening. We do not use widening but direct computation of an
78  * upper approximation of the transition closure. And sometimes, a
79  * lot of information is lost when performing convex hulls of
80  * transformers. So, using transformers, it would be better to
81  * maximize the number of cycles to minimize the number of paths in
82  * each cycle.
83  */
84 
85 #include <stdio.h>
86 #include <string.h>
87 /* #include <stdlib.h> */
88 
89 #include "genC.h"
90 #include "database.h"
91 #include "linear.h"
92 #include "ri.h"
93 #include "effects.h"
94 #include "text.h"
95 #include "text-util.h"
96 #include "ri-util.h"
97 #include "effects-util.h"
98 #include "constants.h"
99 #include "control.h"
100 #include "effects-generic.h"
101 #include "effects-simple.h"
102 
103 #include "misc.h"
104 
105 #include "properties.h"
106 
107 #include "vecteur.h"
108 #include "contrainte.h"
109 #include "ray_dte.h"
110 #include "sommet.h"
111 #include "sg.h"
112 #include "polyedre.h"
113 
114 #include "transformer.h"
115 
116 #include "semantics.h"
117 ␌
118 /*
119  * Prettyprinting of control nodes for debugging purposes
120  */
121 
123 {
124  fprintf(stderr,
125  "ctr %p, %zd preds, %zd succs: %s",
126  c,
130  fprintf(stderr,"\tsuccessors:\n");
131  MAP(CONTROL, s, {
132  fprintf(stderr, "\t\t%p %s", s,
134  }, control_successors(c));
135  fprintf(stderr,"\tpredecessors:\n");
136  MAP(CONTROL, p, {
137  fprintf(stderr, "\t\t%p %s", p,
139  }, control_predecessors(c));
140  fprintf(stderr, "\n");
141 }
142 
144 {
145  if(ENDP(l)) {
146  fprintf(stderr, "empty control list");
147  }
148  else {
149  MAP(CONTROL, c, {
150  fprintf(stderr, "%p, %s", c,
152  }, l);
153  }
154  fprintf(stderr, "\n");
155 }
156 ␌
157 /*
158  * STORAGE AND RETRIEVAL OF INTERMEDIATE POSTCONDITIONS
159  *
160  * Node postconditions cannot be recomputed several times because
161  * preconditions are stored. Since they have to be used several times in
162  * an unknown order, it is necessary to store them.
163  *
164  * A static variable was initially used which reduced the number of
165  * parameters passed but this was not compatible with recursive calls, the
166  * embedding of unstructured within unstructured, and so on.
167  * */
168 
170  control_mapping control_postcondition_map)
171 {
172  transformer post = (transformer)
173  hash_get((hash_table) control_postcondition_map,
174  (void *) c);
175 
176  if(post == (transformer) HASH_UNDEFINED_VALUE)
177  post = transformer_undefined;
178 
179  return post;
180 }
181 
182 /* forward declaration */
184 
186  control_mapping control_postcondition_map,
187  unstructured u,
188  transformer pre_entry)
189 {
191  list preds = control_predecessors(c);
192 
193  pips_assert("c is meaningfull", !meaningless_control_p(c));
194 
195  pips_debug(2, "Begin for node %p and statement %s\n", c,
197 
198  /* Compute its precondition from the postconditions of its predecessor
199  and from the entry precondition. Use arc pred->c information to deal
200  with tests. */
201 
202  if(c==unstructured_control(u)) {
203  /* Do not forget the unstructured precondition for the entry node */
204  /* FI: I do not know why it has to be replicated. Probably because the
205  statement containing the unstructured and the statement of the
206  entry node may share the same precondition. */
207  pre = copy_transformer(pre_entry);
208  }
209  else {
210  if(ENDP(preds)) {
211  /* This is not the entry node: without predecessors, it is unreachable */
212  pre = transformer_empty();
213  }
214  else {
215  pre = load_arc_precondition(CONTROL(CAR(preds)), c, control_postcondition_map);
216  POP(preds);
217  }
218  }
219 
220  FOREACH(CONTROL, pred, preds) {
221  transformer npre = load_arc_precondition(pred, c, control_postcondition_map);
222  transformer lpre = pre;
223 
224  pips_assert("The predecessor's postcondition npre is defined",
225  !transformer_undefined_p(npre));
226 
227  pre = transformer_convex_hull(npre, lpre);
228  /* memory leak with lpre. pre_entry and postconditions cannot be
229  freed: lpre cannot be freed during the first iteration */
230  if(pred!=CONTROL(CAR(preds)))
231  free_transformer(lpre);
232  lpre = pre;
233  }
234 
235 
236  ifdebug(2) {
237  pips_debug(2, "End for node %p and statement %s with precondition %p:\n", c,
239  print_transformer(pre);
240  }
241 
242  return pre;
243 }
244 
246  control_mapping control_postcondition_map)
247 {
248  statement stat = control_statement(c);
249 
250  pips_assert("The statement is defined",
252  pips_debug(6, "Store postcondition for control %p: %s\n",
253  c, statement_identification(stat));
254  ifdebug(6) {
255  print_transformer(post);
256  }
257 
258  pips_assert("The postcondition to insert is consistent",
260 
261  pips_assert("The postcondition is not defined yet",
262  hash_get((hash_table) control_postcondition_map, (void *) c)
264  hash_put((hash_table) (control_postcondition_map),
265  (void *) c, (void *) post);
266 }
267 
269  control_mapping control_postcondition_map)
270 {
271  statement stat = control_statement(c);
272 
273  pips_assert("The statement is defined",
275  pips_assert("The postcondition is already defined",
276  hash_get((hash_table) control_postcondition_map, (void *) c)
278 
279  ifdebug(6) {
280  transformer old_post = hash_get((hash_table) control_postcondition_map,
281  (void *) c);
282  pips_debug(6, "Update postcondition for control %p and statement %s:\n",
283  c, statement_identification(stat));
284  pips_debug(6, "Old postcondition:\n");
285  print_transformer(old_post);
286  pips_debug(6, "New postcondition:\n");
287  print_transformer(post);
288  }
289 
290  hash_update((hash_table) (control_postcondition_map),
291  (void *)c, (void *) post);
292 }
293 
295 (control_mapping control_postcondition_map)
296 {
297  if(hash_table_entry_count(control_postcondition_map)>0) {
298  HASH_MAP(c, p, {
300  fprintf(stderr, "Control %p, Statement %s, Temporary postcondition:\n",
303  }, control_postcondition_map);
304  }
305  else {
306  pips_assert("The CFG contains at least one node with one statement",
307  false);
308  }
309 }
310 
312 {
313  control_mapping control_postcondition_map = NULL;
314  control_postcondition_map = MAKE_CONTROL_MAPPING();
315  return control_postcondition_map;
316 }
317 
319 {
320  /* all postconditions must be freed */
321  HASH_MAP(k,v,{
323  }, control_postcondition_map);
324 
325  FREE_CONTROL_MAPPING(control_postcondition_map);
326 
327  /* return control_mapping_undefined; */
328  return NULL;
329 }
330 ␌
331 /*
332  * STORAGE AND RETRIEVAL OF FIX POINT TRANSFORMERS
333  *
334  * */
335 
336 /* The fix point can be linked either to the entry node of the scc or to
337  the ancestor node. The ancestor node is used by default, when
338  transformer are not computed in context. So the argument is either the
339  ancestor node (transformer out of context), or the call node
340  (transformers computed in context) or the entry node (preconditions
341  computed with transformers in context). */
343  control_mapping control_fix_point_map,
344  hash_table ancestor_map,
345  hash_table scc_map)
346 {
349 
350  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
351  c_a = control_to_ancestor(c, ancestor_map);
352  }
353  else {
354  unstructured scc_u = ancestor_cycle_head_to_scc(c, scc_map);
355  if(unstructured_undefined_p(scc_u))
356  c_a = c;
357  else
358  c_a = unstructured_control(scc_u);
359  }
360 
361  ifdebug(1) pips_assert("The control node pointing to the fix point is defined",
362  !control_undefined_p(c_a));
363 
364  fptf = (transformer)
365  hash_get((hash_table) control_fix_point_map,
366  (char *) c_a);
367 
368  if(fptf == (transformer) HASH_UNDEFINED_VALUE)
369  fptf = transformer_undefined;
370 
371  pips_debug(5, "control %p, ancestor %p, transformer %p\n", c, c_a, fptf);
372 
373  /* It is assumed that cycle_head_p(c) holds, but it is not assumed that
374  its fixpoint is available.. */
375  /*
376  ifdebug(1) pips_assert("The required fix point is defined",
377  !transformer_undefined_p(fptf));
378  */
379  return fptf;
380 }
381 
383  control_mapping control_fix_point_map)
384 {
385  statement stat = control_statement(c);
386 
387  pips_assert("The statement is defined",
389  pips_debug(8, "Store fix_point for control %p: %s\n",
390  c, statement_identification(stat));
391  ifdebug(8) {
392  print_transformer(fptf);
393  }
394 
395  pips_assert("The fix_point to insert is consistent",
397 
398  pips_assert("The fix_point is not defined yet",
399  hash_get((hash_table) control_fix_point_map, (void *) c)
401  hash_put((hash_table) (control_fix_point_map),
402  (void *)c, (void *) fptf);
403 }
404 
406 {
407  control_mapping control_fix_point_map = NULL;
408  control_fix_point_map = MAKE_CONTROL_MAPPING();
409  return control_fix_point_map;
410 }
411 
413 {
414  /* all fix_points must be freed */
415  HASH_MAP(k,v,{
417  }, control_fix_point_map);
418 
419  FREE_CONTROL_MAPPING(control_fix_point_map);
420 
421  /* return control_mapping_undefined; */
422  return NULL;
423 }
424 ␌
425 /* a control is ready to be processed if all its predecessors have known
426  postconditions or can receive a trivial empty postcondition */
428  list to_be_processed,
429  list still_to_be_processed,
430  list already_processed,
431  control_mapping control_postcondition_map)
432 {
433  bool ready = true;
434  MAP(CONTROL, pred, {
435  if(gen_in_list_p(pred, already_processed)) {
436  /* useless, except for debugging */
437  ready &= true;
438  }
439  else if(!gen_in_list_p(pred, to_be_processed)) {
440  /* postcondition must be empty because pred is not reachable */
441  /* transformer pre = transformer_empty(); */
442  transformer post = load_control_postcondition(pred, control_postcondition_map);
443 
444  if(transformer_undefined_p(post)) {
445  post = transformer_empty();
446  /* transformer post = statement_to_postcondition(pre, stmt); */
447  store_control_postcondition(pred, post, control_postcondition_map);
448  }
449  else {
450  pips_assert("Postcondition for unreachable nodes must be empty",
451  transformer_empty_p(post));
452  }
453  }
454  else if(gen_in_list_p(pred, still_to_be_processed)) {
455  ready &= false;
456  }
457  else {
458  pips_internal_error("node pred does not belong to any category: %s",
460  }
461  }, control_predecessors(c));
462  return ready;
463 }
464 
465 ␌
466 /* Returns the precondition of c associated to arc pred->c in a newly
467  allocated transformer. */
469  control_mapping control_postcondition_map)
470 {
471  transformer post = load_control_postcondition(pred, control_postcondition_map);
473  int i = gen_position(c, control_successors(pred));
474  int noo = gen_occurences(c, control_successors(pred));
475 
476  if(transformer_undefined_p(post)) {
477  /* pred must be unreachable, left over by the controlizer... */
478  /* It would be nice to be able to check that it is unreachable... and
479  that we do not land here because of a bug...*/
480  /* This should never happen. */
481  pips_debug(2, "Failed for predecessor node pred=%p and node c=%p with map %p:\n",
482  pred, c, control_postcondition_map);
483  pips_assert("postconditions of predecessors are assumed initialized"
484  " (see process_ready_node().", false);
485  pre = transformer_empty();
486  }
487  else {
488  pre = transformer_dup(post);
489 
490  pips_assert("c is a successor of pred", i!=0);
491  /* let's assume that Bourdoncle's restructuring does not clutter the
492  successor list too much. */
493  pips_assert("c does not appear more than twice in the successor list",
494  noo<=2);
495 
496  if(control_test_p(pred)) {
498 
499  pips_assert("stmt is a test", statement_test_p(stmt));
500 
501  if(noo==2) {
502  /* Assume that the same node is in the true and false successor lists. */
503  /* Do not bother with the test condition... and FI loose the side effects. */
504  /* If side effects can be detected, perform a convex hull of the
505  true and false branches as nothing else is available. */
506  ;
507  }
508  else {
509  /* add the test condition */
511 
512  if(i%2==1) { /* One of the true successors */
514  transformer_undefined, true);
515 
516  }
517  else{ /* One of the false successors */
519  transformer_undefined, false);
520  }
521  }
522  }
523  }
524  ifdebug(2) {
525  string msg = control_test_p(pred)? (i%2==1? "true" : "false"): "standard";
526  pips_debug(2, "End for %s arc of position %d between predecessor node pred=%p"
527  " and node c=%p with precondition %p:\n",
528  msg, i, pred, c, pre);
529  print_transformer(pre);
530  }
531 
532  return pre;
533 }
534 ␌
535 /*
536  * Handle the fix_point_map
537  *
538  * - load_cycle_fix_point(c, fix_point_map)
539  *
540  * -
541  *
542  * */
543 
545 {
547 
548  if((fptf = (transformer) hash_get(fix_point_map, (void *) c))
550  pips_assert("c is not a cycle head", false);
551 
552  return fptf;
553 }
554 ␌
555 /* In fact, non-deterministic unstructured to effects */
557  hash_table ancestor_map,
558  hash_table scc_map)
559 {
560  list el = NIL;
561  list nodes = NIL;
562  control e = unstructured_control(scc); /* entry point */
563 
564  pips_debug(6, "Effect list for unstructured %p with entry %p:begin\n",
565  scc, e);
566 
568  if(!meaningless_control_p(c)) {
571 
573 
574  if(cycle_head_p(c, ancestor_map, scc_map)) {
575  unstructured sub_scc = cycle_head_to_scc(c, ancestor_map, scc_map);
576  if(scc!=sub_scc) {
577  list sl = unstructured_to_effects(sub_scc, ancestor_map, scc_map);
578  list nl = list_undefined;
579  ifdebug(7) {
580  pips_debug(7, "Sub-effect list for unstructured %p with entry %p:\n",
581  sub_scc, unstructured_control(sub_scc));
582  print_effects(sl);
583  pips_debug(7, "Union with previous effects:\n");
584  print_effects(el);
585  }
587  el = nl;
588  ifdebug(7) {
589  pips_debug(7, "Resulting in:\n");
590  print_effects(el);
591  }
592  }
593  }
594  }
595  }, e, nodes);
596  gen_free_list(nodes);
597 
598  pips_debug(6, "Effect list for unstructured %p with entry %p:end\n",
599  scc, e);
600 
601  return el;
602 }
604  hash_table ancestor_map,
605  hash_table scc_map)
606 {
607  list el = unstructured_to_effects(scc, ancestor_map, scc_map);
608 
609  ifdebug(6) {
610  control e = unstructured_control(scc); /* entry point */
611  pips_debug(6, "Effect list for unstructured %p with entry %p:\n",
612  scc, e);
613  print_effects(el);
614  }
615 
616  return el;
617 }
618 
619 /*
620  * Perform a convex hull of the postconditions of the predecessors and
621  * compute the node transformer even if no predecessors exist and store
622  * the postcondition if required:
623  *
624  * - process_ready_node()
625  *
626  * - process_unreachable_node()
627  *
628  * */
629 
631  transformer pre_entry,
632  transformer n_pre,
633  unstructured u,
634  control_mapping control_postcondition_map,
635  hash_table ancestor_map,
636  hash_table scc_map,
637  list partition,
638  control_mapping fix_point_map,
639  bool postcondition_p)
640 {
643  list preds = control_predecessors(c);
645 
646  ifdebug(2) {
647  pips_debug(2, "Begin for control %p with pre_entry=%p:\n", c, pre_entry);
648  print_transformer(pre_entry);
649  pips_debug(2, "Begin with n_pre=%p:\n", n_pre);
650  print_transformer(n_pre);
651  pips_debug(5, "to process node %s\n", statement_identification(control_statement(c)));
652  }
653 
654  /* Compute its precondition pre from the postconditions of its predecessor
655  and from the entry precondition. Use arc pred->c information to deal
656  with tests. */
657 
658  if(c==unstructured_control(u)) {
659  /* Do not forget the unstructured precondition for the entry node */
660  /* FI: I do not know why it has to be replicated. Probably because the
661  statement containing the unstructured and the statement of the
662  entry node may share the same precondition. */
663  pre = copy_transformer(pre_entry);
664  }
665  else {
666  pre = load_arc_precondition(CONTROL(CAR(preds)), c, control_postcondition_map);
667  POP(preds);
668  }
669 
670  MAP(CONTROL, pred, {
671  transformer npre = load_arc_precondition(pred, c, control_postcondition_map);
672  transformer lpre = pre;
673 
674  pre = transformer_convex_hull(npre, lpre);
675  /* memory leak with lpre. pre_entry and postconditions cannot be
676  freed: lpre cannot be freed during the first iteration */
677  /* if(pred!=CONTROL(CAR(preds))) free_transformer(lpre); */
678  free_transformer(lpre);
679  free_transformer(npre);
680  lpre = pre;
681  }, preds);
682 
683  ifdebug(2) {
684  pips_debug(2, "Precondition %p for control %p:\n", pre, c);
685  print_transformer(pre);
686  }
687 
689  /* Add the information from the current precondition. */
692  transformer r_prev_pre = transformer_range(prev_pre);
693 
694  pre = transformer_range_intersection(pre, r_prev_pre);
695  free_transformer(r_prev_pre);
696  ifdebug(2) {
697  pips_debug(2, "Refined precondition %p for control %p:\n", pre, c);
698  print_transformer(pre);
699  }
700  }
701 
702  /* If the control is a cycle head, find and apply its fix point
703  tranformer to the precondition before proceeding into the node itself */
704 
705  if(cycle_head_p(c, ancestor_map, scc_map)) {
706  transformer fptf = load_control_fix_point(c, fix_point_map, ancestor_map, scc_map);
708  transformer pre_no_cycle = transformer_undefined;
709 
710  if(transformer_undefined_p(fptf)) {
711  unstructured scc_u = cycle_head_to_scc(c, ancestor_map, scc_map);
712  /* unstructured_to_flow_insensitive_transformer(scc_u) cannot be
713  used because it assumes that all transformers for statements in
714  scc_u are defined, which is not true yet. */
715  /* transformer tf_u = unstructured_to_flow_insensitive_transformer(scc_u); */
716  list scc_e = non_deterministic_unstructured_to_effects(scc_u, ancestor_map, scc_map);
717  transformer tf_u = effects_to_transformer(scc_e);
718  /* n_pre_u is assumed more accurate than n_pre */
719  transformer n_pre_u = invariant_wrt_transformer(pre, tf_u);
720 
721  ifdebug(6) {
722  pips_debug(6, "Rough fixpoint transformer %p for unstructured %p:\n", tf_u, scc_u);
723  print_transformer(tf_u);
724  pips_debug(6, "Resulting in generic node precondition %p:\n", n_pre_u);
725  print_transformer(n_pre_u);
726  }
727 
728  free_transformer(tf_u);
729  gen_free_list(scc_e);
730 
732  (partition, /* Bourdoncle's processing ordering */
733  scc_u, /* A non-deterministic acyclic control flow graph */
734  ancestor_map, /* Mapping from non-deterministic nodes to deterministic nodes */
735  scc_map, /* mapping from deterministic nodes to non-deterministic cycles */
736  fix_point_map,
737  pre, /* precondition on entry */
738  n_pre_u, /* precondition true for any node of scc_u. */
739  control_postcondition_map, /* */
740  false); /* Compute transformers */
741 
742  ifdebug(2) {
743  pips_debug(2, "Fixpoint transformer %p for control %p:\n", fptf, c);
744  print_transformer(fptf);
745  }
746  }
747 
748  /* The cycle is entered */
749  pre_cycle = transformer_apply(fptf, pre);
750  /* Or the cycle is not entered and the store is not in fptf's domain. */
751  pre_no_cycle = transformer_dup(pre);
752 
753  if(control_test_p(c)) {
754  /* Have we followed a true or a false branch? We'll know later but
755  it is better to add this information before the convex hull is
756  performed. */
759 
760  /* FI: I do not know why an empty context is passed down. */
761  if(true_successors_only_p(c)) {
762  pre_no_cycle = precondition_add_condition_information(pre_no_cycle, e,
763  transformer_undefined, true);
764  }
765  else if(false_successors_only_p(c)) {
766  pre_no_cycle = precondition_add_condition_information(pre_no_cycle, e,
767  transformer_undefined, false);
768  }
769  }
770  free_transformer(pre);
771  pre = transformer_convex_hull(pre_cycle, pre_no_cycle);
772 
773  ifdebug(2) {
774  pips_debug(2, "Precondition after cycle execution %p for control %p:\n", pre, c);
775  print_transformer(pre);
776  pips_debug(2, "derived from pre_cycle %p:\n", pre_cycle);
777  print_transformer(pre_cycle);
778  pips_debug(2, "and from pre_no_cycle %p:\n", pre_no_cycle);
779  print_transformer(pre_no_cycle);
780  }
781 
782  free_transformer(pre_cycle);
783  free_transformer(pre_no_cycle);
784  }
785 
786  /* Propagate the precondition thru the node to obtain a postcondition
787  which does not include arc information (FI: hard if side-effects?) */
788 
789  if(postcondition_p) {
790  /* FI: The transformer might have to be recomputed before the call if
791  the option is selected? It does not seem to be located in
792  statement_to_postcondition() */
793  /* FI: is this correct when the statement is a test since the node
794  only exploits the condition? It might be because of the convex hull
795  nullifying the condition and hence the arc information. */
796  /* FI: statement_to_postcondition() cannot always be used because the
797  statement may appear in different non-deterministic nodes; pre is
798  only of of the many preconditions that can hold before stmt is
799  executed; statement_to_postcondition() should be called later when
800  the whole unstructured has been analyzed. */
801  /* post = statement_to_postcondition(pre, stmt); */
803 
804  pips_assert("The statement transformer is defined",
806  post = transformer_apply(tf, pre);
807 
808  ifdebug(2) {
809  pips_debug(2, "Postcondition %p for control %p:\n", post, c);
810  print_transformer(post);
811  pips_debug(2, "derived from pre %p:\n", pre);
812  print_transformer(pre);
813  pips_debug(2, "and from tf %p:\n", tf);
814  print_transformer(tf);
815  }
816  }
817  else {
818  /* The statement transformer may have been computed earlier thru a fix
819  point calculation, but the transformer may not be correct if it
820  were computed in context (property SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT true). */
823 
824  if(transformer_undefined_p(tfp)) {
825  tf = statement_to_transformer(stmt, pre);
826  }
827  else {
828  if(get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
829  /* We are in trouble: the transformer attached to a statement
830  should be the convex hull of its transformers computed in all
831  its context. Our options:
832 
833  1. fix statement_to_transformer() to perform the convex hulls when needed
834 
835  2. turn off the property
836  SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT as soon as an
837  untructured is entered and restore it on exit
838 
839  3. assume that statement stmt is not a compound statement and
840  try to fix the problem locally.
841 
842  Let's live very dangerously and try 1... */
844 
845  tf = tfn;
846  }
847  else {
848  tf = tfp;
849  }
850  }
851  post = transformer_apply(tf, pre);
852  }
853 
854  store_control_postcondition(c, post, control_postcondition_map);
855 
856  ifdebug(2) {
857  pips_debug(2, "Postcondition %p stored for control %p:\n", post, c);
858  print_transformer(post);
859  }
860 }
861 
863  control_mapping control_postcondition_map,
864  bool postcondition_p)
865 {
867 
868  pips_debug(9,"Statement %s", safe_statement_identification(s));
869 
870  if(!meaningless_control_p(c)) {
872  pips_internal_error("Improper control restructuration, statement with no ordering:%s",
874  }
875 
877  (load_control_postcondition(c, control_postcondition_map))) {
879 
880  if(postcondition_p) {
882  post = statement_to_postcondition(pre, s);
883  }
884  else {
885  /* Careful, this may have been done earlier by the CONTROL_MAP in
886  unstructured_to_transformers() */
888  /* FI: We should use the generic node precondition n_pre; it
889  should be an additional component in the context. */
891  }
892  post = transformer_empty();
893  }
894 
895  semantics_user_warning("After restructuration, unexpected unreachable node:%s",
897 
898  store_control_postcondition(c, post, control_postcondition_map);
899  }
900  else if(postcondition_p
902  /* Problem with ELSIP in ARC2D after partial redundancy elimination */
903  /* pips_internal_error(statement_identification(s)); */
906 
907  pips_assert("the new postcondition is empty", transformer_empty_p(post));
908  pips_assert("the previous postcondition is empty",
909  transformer_empty_p(load_control_postcondition(c, control_postcondition_map)));
910 
911  semantics_user_warning("After restructuration (?),"
912  " postcondtion for unexpected unreachable node:%s",
914  }
915  else if(!postcondition_p
917  /* Problem with SHALLOW in SWIM */
919 
920  semantics_user_warning("After restructuration (?),"
921  " transformer for unexpected unreachable node:%s",
923  }
924  }
925  return true;
926 }
927 ␌
928 /*
929  * DERIVE STATEMENT PRECONDITIONS
930  *
931  */
932 
933 /* State that d depends on c: cycle c must be processed before cycle d can be processed */
934 static void add_cycle_dependency(control d, control c, control_mapping cycle_dependencies_map)
935 {
936  list dependencies = (list) hash_get((hash_table) cycle_dependencies_map,
937  (void *) d);
938 
939  if(dependencies == (list) HASH_UNDEFINED_VALUE) {
940  dependencies = CONS(CONTROL, c, NIL);
941  hash_put((hash_table) (cycle_dependencies_map),
942  (void *) d, (void *) dependencies);
943  }
944  else {
945  /* Update the hash_table by side effect */
946  dependencies = gen_nconc(dependencies, CONS(CONTROL, c, NIL));
947  }
948 }
949 
950 /* c has been processed and no other cycle can depend on it */
951 static void remove_cycle_dependencies(control c, control_mapping cycle_dependencies_map)
952 {
953  HASH_MAP(d, dependencies, {
954  /* Oops... gen_remove() might change the pointer */
955  gen_remove((list*) (&dependencies), c);
956  hash_update((hash_table) (cycle_dependencies_map),
957  (void *) d, (void *) dependencies);
958  }, cycle_dependencies_map);
959 }
960 
961 /* Some cycle may appear nowhere but in the DAG and have no entries in the
962  table. In that case, they have an empty dependency list. */
963 static list get_cycle_dependencies(control d, control_mapping cycle_dependencies_map)
964 {
965  list dependencies = (list) hash_get((hash_table) cycle_dependencies_map,
966  (void *) d);
967 
968  if(dependencies == (list) HASH_UNDEFINED_VALUE) {
969  dependencies = NIL;
970  }
971 
972  return dependencies;
973 }
974 
976  transformer pre,
977  hash_table precondition_map)
978 {
979  transformer t_pre = (transformer) hash_get(precondition_map, k);
980 
981  if(t_pre == (transformer) HASH_UNDEFINED_VALUE) {
982  pips_debug(2, "No previous precondition. Current one %p:\n", pre);
983  ifdebug(2) print_transformer(pre);
984  hash_put(precondition_map, k, (void *) transformer_dup(pre));
985  }
986  else {
987  transformer n_t_pre = transformer_convex_hull(pre, t_pre);
988  hash_update(precondition_map, k, (void *) n_t_pre);
989  pips_debug(2, "Previous precondition %p:\n", t_pre);
990  ifdebug(2) print_transformer(t_pre);
991  pips_debug(2, "New precondition %p:\n", n_t_pre);
992  ifdebug(2) print_transformer(n_t_pre);
993  free_transformer(t_pre);
994  }
995 }
996 
998  transformer pre,
999  statement_mapping statement_temporary_precondition_map)
1000 {
1001  pips_debug(2, "For statement %s:\n", statement_identification(s));
1003  ((void *) s, pre, (hash_table) statement_temporary_precondition_map);
1004 }
1005 
1007 (statement_mapping statement_temporary_precondition_map)
1008 {
1009  if(hash_table_entry_count(statement_temporary_precondition_map)>0) {
1010  HASH_MAP(s, p, {
1011  fprintf(stderr, "Statement %s, Temporary precondition:\n",
1014  }, statement_temporary_precondition_map);
1015  }
1016  else {
1017  pips_assert("The DAG contains at least one control node with one statement", false);
1018  }
1019 }
1020 
1022  transformer pre,
1023  control_mapping cycle_temporary_precondition_map)
1024 {
1026 
1027  pips_debug(2, "For control %p with statement %s:\n", c, statement_identification(s));
1029  ((void *) c, pre, (hash_table) cycle_temporary_precondition_map);
1030 
1031  ifdebug(6) {
1032  pips_debug(6, "Precondition %p for cycle %p:\n", pre, c);
1033  print_transformer(pre);
1034  }
1035 }
1036 
1038  control_mapping cycle_temporary_precondition_map,
1039  hash_table ancestor_map,
1040  hash_table scc_map __attribute__ ((__unused__)))
1041 {
1043  control c_a = control_undefined;
1044 
1045  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1046  c_a = control_to_ancestor(c, ancestor_map);
1047  }
1048  else {
1049  /*
1050  unstructured scc_u = ancestor_cycle_head_to_scc(c, scc_map);
1051  c_a = unstructured_control(scc_u);
1052  */
1053  c_a = c;
1054  }
1055 
1056  t_pre = (transformer) hash_get(cycle_temporary_precondition_map, (void *) c_a);
1057 
1058  pips_assert("The cycle precondition is available",
1059  t_pre != (transformer) HASH_UNDEFINED_VALUE);
1060 
1061  ifdebug(6) {
1062  pips_debug(6, "Precondition %p for cycle %p:\n", t_pre, c_a);
1063  print_transformer(t_pre);
1064  }
1065 
1066  return t_pre;
1067 }
1068 
1070  statement_mapping statement_temporary_precondition_map)
1071 {
1072  transformer t_pre = (transformer) hash_get(statement_temporary_precondition_map, (void *) s);
1073 
1074  pips_assert("The cycle precondition is available",
1075  t_pre != (transformer) HASH_UNDEFINED_VALUE);
1076 
1077  return t_pre;
1078 }
1079 
1081 (list partition, /* Is it relevant? */
1082  unstructured c_u, /* The cycle unstructured */
1083  hash_table ancestor_map,
1084  hash_table scc_map,
1085  control_mapping fix_point_map,
1086  control_mapping cycle_temporary_precondition_map, /* To be updated when a cycle head is encountered */
1087  statement_mapping statement_temporary_precondition_map, /* To be updated each time a statement is encountered */
1088  transformer c_pre, /* precondition of cycle c_u, already processed with the fix point */
1089  transformer pre, /* aproximate precondition holding for all nodes */
1090  control_mapping control_postcondition_map) /* Very likely the transformer paths wrt the entry point and not really a postcondition. Let's update it as a real postcondition. */
1091 {
1092  /* Yet another forward DAG propagation with an exception for the cycle
1093  head: cut-and-paste and adapt */
1094  list to_be_processed = NIL; /* forward reachable nodes in u */
1095  list still_to_be_processed = NIL;
1096  list already_processed = NIL;
1097  control e = unstructured_control(c_u);
1098  statement es = control_statement(e);
1100 
1101  /* FI: Please the compiler complaining about useless parameters (and
1102  remove them later!) */
1103  pips_assert("Please the compiler", partition==partition);
1104  pips_assert("Please the compiler",
1105  cycle_temporary_precondition_map==cycle_temporary_precondition_map);
1106  pips_assert("Please the compiler", pre==pre);
1107 
1108  /* wide_forward_control_map_get_blocs(unstructured_control(u), &to_be_processed); */
1109  forward_control_map_get_blocs(unstructured_control(c_u), &to_be_processed);
1110  still_to_be_processed = gen_copy_seq(to_be_processed);
1111 
1112  /* Take care of the entry node whose precondition does not rely on its
1113  predecessors */
1114  /* post = statement_to_postcondition(c_pre, es); */ /* c_pre is USED */
1115  post = transformer_apply(load_statement_transformer(es), c_pre);
1116  update_control_postcondition(e, post, control_postcondition_map);
1117  gen_remove(&still_to_be_processed, e);
1118  already_processed = CONS(CONTROL, e, NIL);
1119 
1120  /* Propagate the postcondition downwards */
1121 
1122  while(!ENDP(still_to_be_processed)) {
1123  int count = -1;
1124  do {
1125  list l = list_undefined;
1126 
1127  /* process forward */
1128  pips_debug(5, "Try forward processing for\n");
1129  ifdebug(5) print_control_node_unss_sem(still_to_be_processed);
1130 
1131  count = 0;
1132  for(l=still_to_be_processed; !ENDP(l); ) {
1133  control c = CONTROL(CAR(l));
1134  POP(l); /* right away because c's cdr might be modified */
1135  if(meaningless_control_p(c)
1136  || ready_to_be_processed_p(c, to_be_processed,
1137  still_to_be_processed,
1138  already_processed,
1139  control_postcondition_map)) {
1140  if(!meaningless_control_p(c)) {
1141  control c_a = control_undefined;
1142  /*
1143  process_ready_node(c, n_pre, n_pre, ndu, control_postcondition_map,
1144  ancestor_map, scc_map, partition, fix_point_map, postcondition_p);
1145  */
1146  statement c_s = control_statement(c);
1147  transformer pre =
1148  get_control_precondition(c, control_postcondition_map, c_u, c_pre);
1152 
1153  /* Already done earlier
1154  if(cycle_head_p(c, ancestor_map, scc_map)) {
1155  transformer fp_tf = load_control_fix_point(a, fix_point_map, ancestor_map, scc_map);
1156  e_pre = transformer_apply(fp_tf, pre);
1157  update_cycle_temporary_precondition
1158  (a, e_pre, cycle_temporary_precondition_map);
1159  }
1160  else {
1161  e_pre = transformer_dup(pre);
1162  }
1163  */
1164  e_pre = transformer_dup(pre);
1165  if(cycle_head_p(c, ancestor_map, scc_map)) {
1167  /*
1168  transformer n_pre = transformer_undefined;
1169  transformer t_sub_scc = transformer_undefined;
1170  */
1171 
1172  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1173  /* fix point are unique for all replication of a cycle */
1174  c_a = control_to_ancestor(c, ancestor_map);
1175  sub_scc = ancestor_cycle_head_to_scc(c_a, scc_map);
1176  }
1177  else {
1178  sub_scc = ancestor_cycle_head_to_scc(c, scc_map);
1179  c_a = unstructured_control(sub_scc);
1180  }
1181 
1183  (c_a, e_pre, cycle_temporary_precondition_map);
1184  /* (a, e_pre, cycle_temporary_precondition_map); */
1185 
1186  /* Go down the subcycle... when necessary... since there is a loop somewhere else and the cycles are called in the right order? */
1187  /*
1188  cycle_to_flow_sensitive_preconditions
1189  (partition, sub_scc, ancestor_map, scc_map, fix_point_map,
1190  cycle_temporary_precondition_map, statement_temporary_precondition_map,
1191  e_pre, n_pre, control_postcondition_map);
1192  */
1193  }
1195  (c_s, e_pre, statement_temporary_precondition_map);
1196  /* post = statement_to_postcondition(transformer_dup(e_pre), c_s); */
1197  /* FI: you should use the really current precondition using
1198  load_statement_temporary_precondition() */
1199  /* post = transformer_apply(load_statement_transformer(c_s), e_pre); */
1200  /* Hard to track memory leaks... */
1201  /* It is much too late to update the control postcondition! */
1202  /* update_control_postcondition(c, post, control_postcondition_map); */
1203  /* FI: just to see what happens, without any understanding of the process */
1205  statement_temporary_precondition_map);
1206  if(cycle_head_p(c, ancestor_map, scc_map)) {
1207  transformer ctf = load_control_fix_point(c, fix_point_map,
1208  ancestor_map, scc_map);
1209  c_e_pre = transformer_apply(ctf, f_e_pre);
1210  }
1211  else {
1212  c_e_pre = transformer_dup(f_e_pre);
1213  }
1214  post = transformer_apply(load_statement_transformer(c_s), c_e_pre);
1215  /* FI: what is the point when control are replicated? */
1216  update_control_postcondition(c, post, control_postcondition_map);
1217  free_transformer(c_e_pre);
1218  }
1219  gen_remove(&still_to_be_processed, c);
1220  already_processed = gen_append(already_processed, CONS(CONTROL, c, NIL));
1221  count++;
1222  }
1223  }
1224  } while(count!=0);
1225  if(!ENDP(still_to_be_processed)) {
1226  pips_assert("still_to_be_processed is empty because of the Bourdoncle's restructuring",
1227  false);
1228  }
1229  }
1230  /* The precondition for the entry node may be improved by now using the
1231  precondition of its predecessors and the cycle entry. OK, but to what end? */
1232 }
1233 
1235 (list partition,
1236  unstructured ndu,
1237  hash_table ancestor_map,
1238  hash_table scc_map,
1239  control_mapping fix_point_map,
1240  transformer pre_u,
1241  transformer pre,
1242  control_mapping control_postcondition_map)
1243 {
1244  /* A statement may appear in several nodes, and the same is true for cycles. */
1245  statement_mapping statement_temporary_precondition_map = MAKE_STATEMENT_MAPPING();
1246  control_mapping cycle_temporary_precondition_map = MAKE_CONTROL_MAPPING();
1247  control_mapping cycle_dependencies_map = MAKE_CONTROL_MAPPING();
1248  list still_to_be_processed = NIL;
1249  list already_processed = NIL;
1250  control e = unstructured_control(ndu);
1251  list nl = NIL;
1252  list c_c = list_undefined;
1253 
1254  ifdebug(2) {
1255  pips_debug(2, "Begin with control_postcondition_map=%p:\n",
1256  control_postcondition_map);
1257  print_control_postcondition_map(control_postcondition_map);
1258  }
1259 
1260  /*
1261  * Process first the nodes in the embedding graph, in any order since
1262  * node postconditions are assumed available.
1263  *
1264  */
1265  control_map_get_blocs(e, &nl);
1266 
1267  for(c_c = nl; !ENDP(c_c); POP(c_c)) {
1268  control c = CONTROL(CAR(c_c));
1269 
1270  if(!meaningless_control_p(c)) {
1271  control c_a = control_undefined;
1272  transformer pre = get_control_precondition(c, control_postcondition_map, ndu, pre_u);
1275 
1276  if(cycle_head_p(c, ancestor_map, scc_map)) {
1277  transformer fp_tf = load_control_fix_point(c, fix_point_map, ancestor_map, scc_map);
1278 
1279  /* DUPLICATED CODE */
1280 
1281  /* The cycle is entered */
1282  transformer pre_cycle = transformer_apply(fp_tf, pre);
1283  /* Or the cycle is not entered and the store is not in fptf's domain. */
1284  transformer pre_no_cycle = transformer_dup(pre);
1285  if(control_test_p(c)) {
1286  /* Have we followed a true or a false branch? We'll know later but
1287  it is better to add this information before the convex hull is
1288  performed. */
1291 
1292  /* FI: I do not know why an empty context is passed down. */
1293  if(true_successors_only_p(c)) {
1294  pre_no_cycle = precondition_add_condition_information(pre_no_cycle, e,
1295  transformer_undefined, true);
1296  }
1297  else if(false_successors_only_p(c)) {
1298  pre_no_cycle = precondition_add_condition_information(pre_no_cycle, e,
1299  transformer_undefined, false);
1300  }
1301  }
1302  /* free_transformer(pre); */
1303  e_pre = transformer_convex_hull(pre_cycle, pre_no_cycle);
1304  free_transformer(pre_cycle);
1305  free_transformer(pre_no_cycle);
1306 
1307  /* END OF DUPLICATED CODE */
1308 
1309  /* e_pre = transformer_apply(fp_tf, pre); */
1310 
1311  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1312  /* fix point are unique for all replication of a cycle */
1313  c_a = control_to_ancestor(c, ancestor_map);
1314  }
1315  else {
1317  }
1318  update_cycle_temporary_precondition(c_a, e_pre, cycle_temporary_precondition_map);
1319  /* update_cycle_temporary_precondition(a, e_pre, cycle_temporary_precondition_map); */
1320  }
1321  else {
1322  e_pre = transformer_dup(pre);
1323  }
1324  /* FI: sharing between statement_temporary_precondition and
1325  statement_temporary_precondition; freeing the second one frees
1326  part of the first one */
1327  update_statement_temporary_precondition(s, e_pre, statement_temporary_precondition_map);
1328  }
1329  }
1330 
1331  gen_free_list(nl);
1332 
1333  ifdebug(2) {
1334  pips_debug(2, "\nPreconditions for statements after ND DAG processing:\n");
1335  print_statement_temporary_precondition(statement_temporary_precondition_map);
1336  pips_debug(2, "End of preconditions for statements after ND DAG processing:\n\n");
1337  }
1338 
1339  /*
1340  * Process the cycles from top to bottom in width first?
1341  * Let's use the partition generated by Bourdoncle?!?
1342  *
1343  * Since cycles are not duplicated when transformers are not computed in
1344  * context, the preconditions of all their instances must be unioned
1345  * before preconditions can be propagated down in the cycles. When
1346  * cycles are replicated to have one cycle per cycle call site, the same
1347  * scheme can be used, as long as dependencies are properly computed.
1348  *
1349  * Each cycle c depends on a list of cycles, each of these containing a
1350  * cycle call site to c.
1351  *
1352  * When cycles are not replicated, the dependencies are based on the
1353  * ancestor of the head, so as to have a unique representative. When
1354  * cycles are replicated according to cycle call sites, the dependencies
1355  * are based on the head of the cycle.
1356  *
1357  * It is not clear than a topological order exists. Assume that C2
1358  * occurs in an entry path to C1 and within C1. Somehow the precise
1359  * precondition of C1 depends on C2's postcondition which depends on
1360  * C2's precondition. C2's precondition depends on C1's postcondition
1361  * which depends on C1's precondition and here is the loop.
1362  *
1363  * However, in the previous case, the first instance of C2 can be dealt
1364  * with its transformer and the precondition of its first instance.
1365  *
1366  * */
1367 
1368  /* Build the cycle dependencies */
1369  pips_debug(2, "Compute dependencies for %d cycle%s\n",
1370  hash_table_entry_count(scc_map),
1371  hash_table_entry_count(scc_map)>1? "s":"");
1372  HASH_MAP(c, cndu, {
1373  /* control a = control_to_ancestor(c, ancestor_map); */
1374  /* unstructured scc_ u = cycle_head_to_scc(c, ancestor_map, scc_map); */
1375  list nl = NIL;
1376  list c_cc = list_undefined;
1377  control head = unstructured_control((unstructured) cndu);
1378  statement hs = control_statement(head);
1379 
1380  pips_debug(8, "Compute dependencies for cycle %p with statement %s\n",
1381  head, statement_identification(hs));
1382 
1383  control_map_get_blocs(head, &nl);
1384 
1385  for(c_cc=nl; !ENDP(c_cc); POP(c_cc)) {
1386  control cc = CONTROL(CAR(c_cc));
1387 
1388  if(!meaningless_control_p(cc)
1389  && cycle_head_p(cc, ancestor_map, scc_map)) {
1390  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1391  /* build dependencies among ancestors, which are representative of scc's */
1392  control aa = control_to_ancestor(cc, ancestor_map);
1393  if(aa!=c) {
1394  /* then cc depends on c */
1395  add_cycle_dependency(aa, (control) c, cycle_dependencies_map);
1396  }
1397  }
1398  else {
1399  /* build dependencies among heads, which are representative of scc's */
1400  unstructured scc_u = ancestor_cycle_head_to_scc(cc, scc_map);
1401  control head_scc = unstructured_control(scc_u);
1402  if(head_scc!=(control)c) {
1403  add_cycle_dependency(head_scc, head, cycle_dependencies_map);
1404  }
1405  }
1406  }
1407  }
1408 
1409  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1410  still_to_be_processed = CONS(CONTROL, (control) c, still_to_be_processed);
1411  }
1412  else {
1413  still_to_be_processed = CONS(CONTROL, head, still_to_be_processed);
1414  }
1415  gen_free_list(nl);
1416  }, scc_map);
1417 
1418  ifdebug(2) {
1419  if(hash_table_entry_count(cycle_dependencies_map)>0) {
1420  pips_debug(2, "cycle dependencies:\n");
1421  HASH_MAP(c, l, {
1423  pips_debug(2, "Cycle %p with statement %s depends on:\n",
1424  c, statement_identification(s));
1426  }, cycle_dependencies_map);
1427  }
1428  else {
1429  /* No cycles with dependencies */
1430  pips_debug(2, "no cycles with dependencies\n");
1431  }
1432  }
1433 
1434  /* While some cycles still have to be processed. */
1435  while(!ENDP(still_to_be_processed)) {
1436  int count = -1;
1437  do {
1438  list l = list_undefined;
1439  count = 0;
1440  for(l=still_to_be_processed; !ENDP(l); ) {
1441  control c = CONTROL(CAR(l));
1442 
1443  list dep = get_cycle_dependencies(c, cycle_dependencies_map);
1444  POP(l); /* right away because c's cdr might be modified */
1445 
1446  ifdebug(8) {
1447  if(ENDP(dep)) {
1448  pips_debug(8, "Process cycle %p with statement %s\n",
1450  }
1451  }
1452 
1453  if(ENDP(dep)) {
1454  /* The precondition of cycle c is complete */
1455  /* control a = control_to_ancestor(c, ancestor_map); */
1457  cycle_temporary_precondition_map,
1458  ancestor_map, scc_map);
1459  transformer fp_tf = load_control_fix_point(c, fix_point_map, ancestor_map, scc_map);
1461  transformer f_c_pre = transformer_apply(fp_tf, c_pre);
1462  transformer e_c_pre = transformer_convex_hull(f_c_pre, c_pre);
1463 
1464  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT"))
1465  c_u = cycle_head_to_scc(c, ancestor_map, scc_map);
1466  else
1467  c_u = proper_cycle_head_to_scc(c, scc_map);
1468 
1470  (partition, c_u, ancestor_map, scc_map, fix_point_map,
1471  cycle_temporary_precondition_map, statement_temporary_precondition_map,
1472  e_c_pre, pre, control_postcondition_map);
1473  remove_cycle_dependencies(c, cycle_dependencies_map);
1474  gen_remove(&still_to_be_processed, c);
1475  already_processed = gen_append(already_processed, CONS(CONTROL, c, NIL));
1476  count++;
1477  }
1478  }
1479  } while(count!=0);
1480 
1481  pips_assert("All cycles have been processed",
1482  ENDP(still_to_be_processed));
1483  }
1484 
1485  /*
1486  * Exploit the temporary preconditions
1487  *
1488  */
1489  HASH_MAP(s, s_pre, {
1490  transformer post =
1492  free_transformer(post);
1493  }, statement_temporary_precondition_map);
1494 
1495 }
1496 
1497 ␌
1498 /*
1499  * PROCESSING OF CYCLIC OR ACYCLIC CFG FOR PATH TRANSFORMERS, PATH
1500  * PRECONDITIONS, INNER TRANSFORMERS AND INNER PRECONDITIONS.
1501  *
1502  * - dag_or_cycle_to_flow_sensitive_postconditions_or_transformers()
1503  *
1504  * - dag_to_flow_sensitive_postconditions_or_transformers()
1505  *
1506  * - cycle_to_flow_sensitive_postconditions_or_transformers()
1507  * */
1508 
1510 (list partition, /* Bourdoncle's processing ordering */
1511  unstructured ndu, /* A non-deterministic acyclic control flow graph */
1512  hash_table ancestor_map, /* Mapping from non-deterministic nodes to deterministic nodes */
1513  hash_table scc_map, /* mapping from deterministic nodes to non-deterministic cycles */
1514  control_mapping fix_point_map, /* mapping from cycle heads to fix point transformers*/
1515  transformer e_pre, /* precondition on entry */
1516  transformer n_pre, /* precondition true for any node. */
1517  hash_table control_postcondition_map, /* */
1518  bool postcondition_p, /* Compute transformers or preconditions */
1519  bool is_dag) /* Should ndu be a dag or a cycle? */
1520 {
1522  list to_be_processed = NIL; /* forward reachable nodes in u */
1523  list still_to_be_processed = NIL;
1524  list already_processed = NIL;
1525  list cannot_be_reached = NIL;
1526 
1527  ifdebug(2) {
1528  pips_debug(2, "Begin for unstructured %p with e_pre=%p:\n", ndu, e_pre);
1529  print_transformer(e_pre);
1530  }
1531 
1532  /* The whole business could be simplified by using a larger definition of "to_be_processed". */
1533  /* wide_forward_control_map_get_blocs(unstructured_control(u), &to_be_processed); */
1534  forward_control_map_get_blocs(unstructured_control(ndu), &to_be_processed);
1535  control_map_get_blocs(unstructured_control(ndu), &cannot_be_reached);
1536  still_to_be_processed = gen_copy_seq(to_be_processed);
1537  gen_list_and_not(&cannot_be_reached, to_be_processed);
1538 
1539  /* Take care of unreachable nodes */
1540 
1541  if(!ENDP(cannot_be_reached)) {
1542  /* FI: Wouldn't it be better to clean up the unstructured? Aren't they
1543  supposed to be clean? This piece of code contradict
1544  get_control_precondition() where the problem could be fixed at a
1545  lower cost. Another place where the problem is handled is
1546  ready_to_be_processed_p(), but it is called on
1547  still_to_be_processed, which does not take into account unreachable
1548  nodes. To make things worse, the daVinci printouts only include,
1549  most of the time, only reachable nodes. */
1550  ifdebug(3) {
1551  pips_debug(3, "Process unreachable nodes in unstructured %p\n", ndu);
1552  print_control_node_unss_sem(cannot_be_reached);
1553  }
1554  MAP(CONTROL, cbrc, {
1555  if(!meaningless_control_p(cbrc)) {
1557  store_control_postcondition(cbrc, etf, control_postcondition_map);
1558  }
1559  }, cannot_be_reached);
1560  gen_free_list(cannot_be_reached);
1561  cannot_be_reached = list_undefined;
1562  }
1563 
1564  pips_assert("Node lists are defined", !list_undefined_p(to_be_processed)
1565  && !list_undefined_p(still_to_be_processed) && ENDP(already_processed) );
1566 
1567  /* Take care of the entry node */
1568 
1569  if(!is_dag && !postcondition_p) {
1570  /* The entry node must be handled in a specific way... but not in the
1571  specific way implemented in process_ready_node() which only deals
1572  with DAG's. The entry node cannot be a meaningless control node. */
1573  control e = unstructured_control(ndu);
1574  statement es = control_statement(e);
1578 
1579  /* Since control nodes have been replicated, it is difficult to
1580  predict if es has already been processed or not. */
1581  if(transformer_undefined_p(etf)) {
1582  etf = statement_to_transformer(es, n_pre);
1583  }
1584 
1585  post = transformer_apply(etf, init);
1586 
1587  store_control_postcondition(e, post, control_postcondition_map);
1588 
1589  gen_remove(&still_to_be_processed, e);
1590  already_processed = CONS(CONTROL, e, NIL);
1591  }
1592 
1593  /* make_control_postcondition_map(); */
1594 
1595  /* Take care of the forward reachable control nodes */
1596 
1597  while(!ENDP(still_to_be_processed)) {
1598  int count = -1;
1599  do {
1600  list l = list_undefined;
1601 
1602  /* process forward */
1603  pips_debug(5, "Try forward processing for\n");
1604  ifdebug(2) print_control_node_unss_sem(still_to_be_processed);
1605 
1606  count = 0;
1607  for(l=still_to_be_processed; !ENDP(l); ) {
1608  control c = CONTROL(CAR(l));
1609  POP(l); /* right away because c's cdr might be modified */
1610  if(meaningless_control_p(c)
1611  || ready_to_be_processed_p(c, to_be_processed,
1612  still_to_be_processed,
1613  already_processed,
1614  control_postcondition_map)) {
1615  if(!meaningless_control_p(c)) {
1616  process_ready_node(c, e_pre, n_pre, ndu, control_postcondition_map,
1617  ancestor_map, scc_map, partition, fix_point_map, postcondition_p);
1618  }
1619  gen_remove(&still_to_be_processed, c);
1620  already_processed = gen_append(already_processed, CONS(CONTROL, c, NIL));
1621  count++;
1622  }
1623  }
1624  } while(count!=0);
1625  if(!ENDP(still_to_be_processed)) {
1626  pips_assert("still_to_be_processed is empty because of the Bourdoncle's restructuring",
1627  false);
1628  }
1629  }
1630 
1631  /* Compute fix point transformer for cycle */
1632  if(!is_dag && !postcondition_p) {
1634  control e = unstructured_control(ndu);
1635  list preds = control_predecessors(e);
1636  control e_a = control_undefined;
1637  // FI: we also need SEMANTICS_USE_DERIVATIVE_LIST = TRUE
1638  // but this should be soon the default option
1639  if(!get_bool_property("SEMANTICS_USE_TRANSFORMER_LISTS")) {
1640  /* Compute the convex hull of the paths associated to each predecessor
1641  of the entry. Since this is a cycle, preds cannot be empty. */
1642  control pred = CONTROL(CAR(preds));
1643  transformer path_tf =
1644  load_arc_precondition(pred, e, control_postcondition_map);
1645  /* transformer fp_tf_plus = transformer_undefined; */
1646 
1647  POP(preds);
1648  FOREACH(CONTROL, pred, preds) {
1649  transformer pred_tf =
1650  load_arc_precondition(pred, e, control_postcondition_map);
1651  transformer old_path_tf = path_tf;
1652 
1653  pips_assert("Partial path transformer pred_tf is defined",
1654  !transformer_undefined_p(pred_tf));
1655  path_tf = transformer_convex_hull(old_path_tf, pred_tf);
1656  free_transformer(old_path_tf);
1657  }
1658 
1659  fp_tf = (*transformer_fix_point_operator)(path_tf);
1660  /* If an entry range is known, do not use it as there may be more than
1661  one occurence of the cycle and more than one entry range. Keep this
1662  refinement to the precondition computation phase? It might be too
1663  late. The the data structure should be change to store more than
1664  one fix point per cycle. */
1665  /* Not convincing anyway: you should apply fp_tf_plus to e_pre for the
1666  next two lines to make sense. */
1667  /* Use the + fix point to preserve more information about the output
1668  and do not forget to perform a convex hull when you need a * fix
1669  point in process_ready_node() */
1670  fp_tf = transformer_combine(fp_tf, path_tf);
1671  /*
1672  fp_tf = transformer_convex_hull(fp_tf_plus, e_pre);
1673  */
1674  free_transformer(path_tf);
1675  }
1676  else {
1677  /* Instead of computing the convex hull over all paths before
1678  computing the fix point, compute the fix point of a list of
1679  transformers. */
1680  list tl = NIL;
1681  FOREACH(CONTROL, pred, preds) {
1682  transformer pred_tf =
1683  load_arc_precondition(pred, e, control_postcondition_map);
1684  tl = CONS(TRANSFORMER, pred_tf, tl);
1685  }
1687  gen_free_list(tl);
1688  }
1689 
1690  /* e may have many synonyms */
1691 
1692  if(!get_bool_property("SEMANTICS_COMPUTE_TRANSFORMERS_IN_CONTEXT")) {
1693  /* fix point are unique for all replication of a cycle */
1694  e_a = control_to_ancestor(e, ancestor_map);
1695  }
1696  else {
1697  /* each cycle replication has its own fix-point */
1698  e_a = e;
1699  }
1700  store_control_fix_point(e_a, fp_tf, fix_point_map);
1701 
1702  /* We might want to return the corresponding fix point? */
1703  tf = fp_tf;
1704  }
1705 
1706  gen_free_list(to_be_processed);
1707  to_be_processed = list_undefined;
1708  gen_free_list(still_to_be_processed);
1709  still_to_be_processed = list_undefined;
1710  gen_free_list(already_processed);
1711  already_processed = list_undefined;
1712 
1713  ifdebug(2) {
1714  pips_debug(2, "End for %s of %s %p with entry node %s and with transformer %p\n",
1715  postcondition_p? "postcondition" : "transformer",
1716  is_dag? "dag" : "cycle", ndu,
1718  print_transformer(tf);
1719  }
1720 
1721  return tf;
1722 }
1723 
1725 (list partition, /* Bourdoncle's processing ordering */
1726  unstructured ndu, /* A non-deterministic acyclic control flow graph */
1727  hash_table ancestor_map, /* Mapping from non-deterministic nodes to deterministic nodes */
1728  hash_table scc_map, /* mapping from deterministic nodes to non-deterministic cycles */
1729  control_mapping fix_point_map, /* mapping from cycle heads to fix point transformers*/
1730  transformer e_pre, /* precondition on entry */
1731  transformer n_pre, /* precondition true for any node. */
1732  hash_table control_postcondition_map, /* */
1733  bool postcondition_p) /* Compute transformers or preconditions */
1734 {
1736 
1738  (partition, ndu, ancestor_map, scc_map, fix_point_map, e_pre, n_pre,
1739  control_postcondition_map, postcondition_p, true);
1740 
1741  return tf;
1742 }
1743 
1745 (list partition, /* Bourdoncle's processing ordering */
1746  unstructured ndu, /* A non-deterministic acyclic control flow graph */
1747  hash_table ancestor_map, /* Mapping from non-deterministic nodes to deterministic nodes */
1748  hash_table scc_map, /* mapping from deterministic nodes to non-deterministic cycles */
1749  control_mapping fix_point_map, /* mapping from cycle heads to fix point transformers*/
1750  transformer e_pre, /* precondition on entry */
1751  transformer n_pre, /* precondition true for any node. */
1752  hash_table control_postcondition_map, /* */
1753  bool postcondition_p) /* Compute transformers or preconditions */
1754 {
1756 
1758  (partition, ndu, ancestor_map, scc_map, fix_point_map, e_pre, n_pre,
1759  control_postcondition_map, postcondition_p, false);
1760 
1761  return tf;
1762 }
1763 
1764 ␌
1765 /*
1766  * PROCESSING OF AN UNSTRUCTURED
1767  *
1768  * - local_process_unreachable_node()
1769  *
1770  * - node_to_path_transformer_or_postcondition()
1771  *
1772  * - unstructured_to_accurate_postconditions_or_transformer()
1773  *
1774  */
1775 
1776 typedef struct {
1777  bool pcond;
1780 
1782 {
1783  process_unreachable_node(c, pcontext->smap, pcontext->pcond);
1784 }
1785 
1786 /* A debug function to prettyprint the result */
1788 {
1789  if(!meaningless_control_p(c)) {
1790  control_mapping control_postcondition_map = pcontext->smap;
1792  transformer tf = load_control_postcondition(c, control_postcondition_map);
1793 
1794  pips_assert("Postcondition tf is defined", !transformer_undefined_p(tf));
1795  fprintf(stderr, "Statement %s", statement_identification(s));
1796  pips_assert("Transformer or postcondition is consistent",
1798  print_transformer(tf);
1799  }
1800 }
1801 
1802 /* A debug function to prettyprint the fix points */
1804 {
1805  control_mapping control_fix_point_map = pcontext->smap;
1807  transformer tf = load_control_postcondition(c, control_fix_point_map);
1808 
1809  /* Most control nodes are not associated to a fix point */
1810  if(!transformer_undefined_p(tf)) {
1811  fprintf(stderr, "Statement %s", statement_identification(s));
1812  pips_assert("Transformer or postcondition is consistent",
1814  print_transformer(tf);
1815  }
1816 }
1817 
1818 /* compute either the postconditions in an unstructured or the transformer
1819  of this unstructured. In both cases, transformers for all nodes used to be
1820  supposed to be available. */
1822 (transformer pre_u, /* precondition at entry: e_pre */
1823  transformer pre, /* precondition true for every node: n_pre */
1824  unstructured u,
1825  bool postcondition_p)
1826 {
1828  hash_table ancestor_map = hash_table_undefined;
1829  hash_table scc_map = hash_table_undefined;
1830  control_mapping fix_point_map = make_control_fix_point_map();
1832  list partition = bourdoncle_partition(u, &ndu, &ancestor_map, &scc_map);
1833  control_mapping control_postcondition_map = make_control_postcondition_map();
1834  transformer pre_u_r = transformer_range(pre_u);
1835  transformer pre_r = transformer_range(pre);
1836 
1837  recursive_context context = { postcondition_p, control_postcondition_map };
1838 
1839  recursive_context fcontext = { postcondition_p, fix_point_map };
1840 
1841  ifdebug(2) {
1842  pips_debug(2, "Begin for %s with nodes:\n",
1843  postcondition_p? "postconditions" : "transformer");
1844  /* Do not go down into nested unstructured */
1847  pips_debug(2, "With entry nodes\n");
1849  pips_debug(2, "And exit node\n");
1851  pips_debug(2, "And embedding graph:\n");
1854  }
1855 
1856  /* Propagate the precondition in the DAG and recompute the cycle
1857  transformers or compute the path transformers and the cycle fix point
1858  transformers. */
1860  (partition, ndu, ancestor_map, scc_map, fix_point_map,
1861  postcondition_p? pre_u : pre_u_r, postcondition_p? pre : pre_r,
1862  control_postcondition_map, postcondition_p);
1863 
1864  if(postcondition_p) {
1865  /* Compute the real precondition for each statement and propagate
1866  postconditions in it. */
1867 
1869  (partition, ndu, ancestor_map, scc_map, fix_point_map, pre_u, pre,
1870  control_postcondition_map);
1871  }
1872 
1873  /* Take care of unreachable nodes */
1875  ndu, (void *) & context,
1878  NULL);
1879 
1880  ifdebug(2) {
1881  pips_debug(2, "%s for unstructured\n",
1882  postcondition_p? "Postconditions": "Path transformer");
1884  ndu, (void *) & context,
1888  NULL);
1889  pips_debug(2, "End of map\n");
1890  if(hash_table_entry_count(fix_point_map)>0) {
1891  pips_debug(2, "Fix point map:\n");
1893  u, (void *) & fcontext,
1897  NULL);
1898  pips_debug(2, "End of fix point map\n");
1899  pips_debug(2, "Dump fix point map %p:\n", fix_point_map);
1900  HASH_MAP(k, v, {
1901  control c = (control) k;
1903  transformer fp_tf = (transformer) v;
1904 
1906  fprintf(stderr, "Statement %s", statement_identification(s));
1907  print_transformer(fp_tf);
1908  }, fix_point_map);
1909  pips_debug(2, "End of fix point map dump\n");
1910  }
1911  else {
1912  fprintf(stderr, "No fix point. Empty fix point map\n");
1913  }
1914  }
1915 
1916  post = copy_transformer
1918  control_postcondition_map));
1919  control_postcondition_map = free_control_postcondition_map(control_postcondition_map);
1920  fix_point_map = free_control_fix_point_map(fix_point_map);
1921 
1922  ifdebug(2) {
1923  pips_assert("The postcondition post is defined", !transformer_undefined_p(post));
1924  pips_debug(2, "End with unstructured postcondition:\n");
1925  print_transformer(post);
1926  }
1927 
1928  /* Get rid of the auxiliary data structures */
1929  bourdoncle_free(ndu, ancestor_map, scc_map);
1930 
1931  return post;
1932 }
1933 ␌
1934 /*
1935  * COMPUTATION OF POSTCONDITIONS OF UNSTRUCTURED AND IN UNSTRUCTURED
1936  *
1937  *
1938  * - unstructured_to_postconditions()
1939  *
1940  * - unstructured_to_accurate_postconditions()
1941  *
1942  * - unreachable_node_to_transformer()
1943  *
1944  * - unstructured_to_global_transformer()
1945  *
1946  * - unstructured_to_accurate_transformer()
1947  *
1948  *
1949  */
1950 
1951 static transformer
1953  transformer pre, /* precondition holding for any node */
1954  transformer pre_first, /* precondition holding at entry */
1955  unstructured u)
1956 {
1957  list nodes = NIL ;
1958  control entry_node = unstructured_control(u) ;
1959  control exit_node = unstructured_exit(u) ;
1962  transformer exit_post = transformer_undefined;
1963 
1964  pips_debug(8, "begin\n");
1965 
1966  /* SHARING! Every statement gets a pointer to the same precondition!
1967  * I do not know if it's good or not but beware the bugs!!!
1968  */
1969  /* FI: changed to make free_transformer_mapping possible without
1970  * testing sharing.
1971  *
1972  * pre and pre_first can or not be used depending on the
1973  * unstructured structure. They are always duplicated and
1974  * the caller has to take care of their de-allocation.
1975  */
1976  CONTROL_MAP(c, {
1977  statement st = control_statement(c) ;
1978  if(c==entry_node && ENDP(control_predecessors(c)) && statement_test_p(st)) {
1979  /* special case for the first node if it has no predecessor */
1980  /* and if it is a test, as it always should, at least if */
1981  /* unspaghettify has been applied... */
1982  /* this is pretty useless and should be generalized to the
1983  DAG part of the CFG */
1984  c_pre = transformer_dup(pre_first);
1985  post = statement_to_postcondition(c_pre, st);
1986  transformer_free(post);
1987  }
1988  else {
1990 
1991  c_pre = transformer_dup(pre);
1992  c_pre_m = c_pre;
1993 
1994  /* refine the precondition if the node has only one
1995  predecessor and if this predecessor is a test and if the
1996  test can be exploited */
1997  if(gen_length(control_predecessors(c))==1 && c!=entry_node) {
1998  control prev_c = CONTROL(CAR(control_predecessors(c)));
1999  statement prev_st = control_statement(prev_c);
2000 
2001  if(statement_test_p(prev_st)) {
2002  /* the condition is true if c is the first successor of prev_c */
2003  bool true_false = (c==(CONTROL(CAR(control_successors(prev_c)))));
2006 
2007  c_pre_m = precondition_add_condition_information(c_pre, e, context, true_false);
2009  }
2010  }
2011 
2012  post = statement_to_postcondition(c_pre_m, st);
2013  if(c==exit_node) {
2014  exit_post = post;
2015  }
2016  else {
2017  transformer_free(post);
2018  }
2019  }
2020  }, entry_node, nodes);
2021 
2022  gen_free_list(nodes) ;
2023 
2024  if(transformer_undefined_p(exit_post)) {
2025  exit_post = transformer_empty();
2026  }
2027 
2028  ifdebug(8) {
2029  pips_debug(8, "exit postcondition:\n");
2030  (void) print_transformer(exit_post) ;
2031  }
2032  pips_debug(8, "end\n");
2033 
2034  return exit_post;
2035 }
2036 
2037 /* compute pre- and post-conditions in an unstructured from the entry
2038  precondition pre and return the exit postcondition. pre_u is pre
2039  filtered by the u's transformer and can be used for any node. */
2041 (transformer pre_u, transformer pre, unstructured u)
2042 {
2044  list succs = NIL;
2045  control head = unstructured_control(u);
2046  /* control tail = unstructured_exit(u); */
2047 
2048  forward_control_map_get_blocs(head, &succs);
2049 
2050  if(((int)gen_length(succs))>get_int_property("SEMANTICS_MAX_CFG_SIZE1")) {
2051  semantics_user_warning("\nControl flow graph too large for an accurate analysis (%d nodes)\n"
2052  "Have you fully restructured your code?\n", gen_length(succs));
2053  post = unstructured_to_postconditions(pre, pre_u, u);
2054  }
2055  else if(!get_bool_property("SEMANTICS_ANALYZE_UNSTRUCTURED")) {
2056  semantics_user_warning("\nControl flow graph not analyzed accurately"
2057  " because property SEMANTICS_ANALYZE_UNSTRUCTURED is not set\n");
2058  post = unstructured_to_postconditions(pre_u, pre, u);
2059  }
2060  else if(!get_bool_property("SEMANTICS_FIX_POINT")) {
2061  post = unstructured_to_postconditions(pre_u, pre, u);
2062  }
2063  else {
2065  (pre_u, pre, u, true);
2066  }
2067  gen_free_list(succs);
2068 
2069  pips_assert("Postcondition for unstructured is consistent",
2071 
2072  return post;
2073 }
2074 
2076  transformer pre,
2077  unstructured u,
2078  transformer tf)
2079 {
2080  transformer post;
2081  control c;
2082 
2083  pips_debug(8, "begin\n");
2084 
2085  pips_assert("unstructured u is defined", u!=unstructured_undefined);
2086 
2087  c = unstructured_control(u);
2088  if(control_predecessors(c) == NIL && control_successors(c) == NIL) {
2089  /* there is only one statement and no arcs in u; no need for a
2090  fix-point */
2091  pips_debug(8, "unique node\n");
2092  /* FI: pre should not be duplicated because
2093  * statement_to_postcondition() means that pre is not
2094  * going to be changed, just post produced.
2095  */
2097  control_statement(c));
2098  }
2099  else {
2100  /* Do not try anything clever! God knows what may happen in
2101  unstructured code. Postcondition post is not computed recursively
2102  from its components but directly derived from u's transformer.
2103  Preconditions associated to its components are then computed
2104  independently, hence the name unstructured_to_postconditionS
2105  instead of unstructured_to_postcondition */
2106  /* propagate as precondition an invariant for the whole
2107  unstructured u assuming that all nodes in the CFG are fully
2108  connected, unless tf is not feasible because the unstructured
2109  is never exited or exited thru a call to STOP which invalidates
2110  the previous assumption. */
2113 
2114  pips_debug(8, "complex: based on transformer\n");
2115  if(transformer_empty_p(tf)) {
2117  }
2118  else {
2119  tf_u = tf;
2120  }
2121  pre_n = invariant_wrt_transformer(pre, tf_u);
2122  ifdebug(8) {
2123  pips_debug(8, "filtered over approximated precondition holding for any node pre_n:\n");
2124  (void) print_transformer(pre_n) ;
2125  }
2126  /* FI: I do not know if I should duplicate pre or not. */
2127  /* FI: well, dumdum, you should have duplicated tf! */
2128  /* FI: euh... why? According to comments about transformer_apply()
2129  * neither arguments are modified...
2130  */
2131  /* post = unstructured_to_postconditions(pre_n, pre, u); */
2132  post = unstructured_to_flow_sensitive_postconditions(pre, pre_n, u);
2133  pips_assert("A valid postcondition is returned",
2134  !transformer_undefined_p(post));
2135  if(transformer_undefined_p(post)) {
2136  post = transformer_apply(transformer_dup(tf), pre);
2137  }
2138  transformer_free(pre_n);
2139  }
2140 
2141  pips_debug(8, "end\n");
2142 
2143  return post;
2144 }
2145 ␌
2146 /*
2147  * COMPUTATION OF TRANSFORMERS FOR UNSTRUCTUREDS AND THEIR COMPONENTS
2148  *
2149  * - unreachable_node_to_transformer()
2150  *
2151  * - unstructured_to_flow_insensitive_transformer()
2152  *
2153  * - unstructured_to_accurate_transformer()
2154  *
2155  *
2156  */
2157 
2159 {
2161 
2162  pips_debug(9,"Statement %s", statement_identification(s));
2163 
2165  semantics_user_warning("Improper control restructuration, statement with no ordering:%s"
2166  "May result from an unreachable exit node\n",
2168  }
2169 
2171  semantics_user_warning("After restructuration, unexpected unreachable node:%s",
2174  }
2175 }
2176 
2177 /* This simple fix-point over-approximates the CFG by a fully connected
2178  * graph. Each vertex can be executed at any time any number of times.
2179  *
2180  * The fix point is easy to compute because it is the fix point of the
2181  * convex hull all each node transformers.
2182  *
2183  * The result is sometimes surprising as users see the real paths and
2184  * cannot understand why a variable is declared modified when it obviously
2185  * is not. This mostly choses in node preconditions since the overall
2186  * unstructured transformer is not displayed usually and since it is
2187  * globally correct.
2188  *
2189  * But it is a perfectly valid over-approximation usable by automatic
2190  * analyses.
2191  *
2192  * Using the effects of the unstructured to derive a fix point leads to
2193  * the same surprise although it is as correct, using the same over
2194  * approximation of the control flow graph but a cruder version of the
2195  * transformers.
2196  *
2197  * This function is also used when computing preconditions if the exit
2198  * node is not reached (?). It assumes that transformers for all
2199  * statements in the unstructured have already been computed.
2200  *
2201  * Two modes are possible: the transitive closure of the convex hull
2202  * of all elementary transformers, or the transitive closure of the
2203  * transformer list.
2204  */
2205 
2207 {
2208  /* Assume any reachable node is executed at each iteration. A fix-point
2209  of the result can be used to approximate the node preconditions. Some
2210  nodes can be discarded because they do not modify the store such as
2211  IF statements (always) and CONTINUE statements (if they do not link
2212  the entry and the exit nodes). */
2213 
2214  list nodes = NIL;
2215  /* Entry node */
2216  control entry_node = unstructured_control(u);
2217  control exit_node = unstructured_exit(u);
2218  transformer tf_u = transformer_empty();
2220  bool tfl_p = get_bool_property("SEMANTICS_USE_TRANSFORMER_LISTS");
2221  list tfl = NIL;
2222 
2223  pips_debug(8,"begin\n");
2224 
2225  FORWARD_CONTROL_MAP(c, {
2226  statement st = control_statement(c);
2227  /* transformer_convex_hull has side effects on its arguments:-( */
2228  /* Should be fixed now, 29 June 2000 */
2229  /* transformer tf_st = copy_transformer(load_statement_transformer(st)); */
2231  transformer tf_old = tf_u;
2232 
2233  if(statement_test_p(st)) {
2234  /* Any side effect? */
2235  if(!ENDP(transformer_arguments(tf_st))) {
2236  if(tfl_p) {
2237  tfl = CONS(TRANSFORMER, tf_st, tfl);
2238  }
2239  else {
2240  tf_u = transformer_convex_hull(tf_old, tf_st); /* test */
2241  free_transformer(tf_old);
2242  }
2243  }
2244  }
2245  else {
2246  if(continue_statement_p(st)) {
2248  && gen_find_eq(exit_node, control_successors(c))!=chunk_undefined) {
2249  if(tfl_p) {
2250  tfl = CONS(TRANSFORMER, tf_st, tfl);
2251  }
2252  else {
2253  tf_u = transformer_convex_hull(tf_old, tf_st); /* continue */
2254  free_transformer(tf_old);
2255  }
2256  }
2257  }
2258  else {
2259  if(tfl_p) {
2260  tfl = CONS(TRANSFORMER, tf_st, tfl);
2261  }
2262  else {
2263  tf_u = transformer_convex_hull(tf_old, tf_st); /* other */
2264  free_transformer(tf_old);
2265  }
2266  }
2267  }
2268 
2269  ifdebug(1) {
2270  pips_assert("tf_st is internally consistent",
2272  if(!tfl_p)
2273  pips_assert("tf_u is internally consistent",
2275  }
2276 
2277  }, entry_node, nodes) ;
2278 
2279  gen_free_list(nodes) ;
2280 
2281  if(tfl_p) {
2282  // FI: apparently, we need T* rather than T+
2283  fp_tf_u = transformer_list_transitive_closure(tfl);
2284  gen_free_list(tfl);
2285  }
2286  else
2287  fp_tf_u = (*transformer_fix_point_operator)(tf_u);
2288 
2289  ifdebug(8) {
2290  pips_debug(8,"Result for one step tf_u:\n");
2291  print_transformer(tf_u);
2292  pips_assert("tf_u is internally consistent",
2294  pips_debug(8,"Result for fix-point fp_tf_u:\n");
2295  print_transformer(fp_tf_u);
2296  pips_assert("fp_tf_u is internally consistent",
2298  }
2299 
2300  pips_debug(8,"end\n");
2301 
2302  return fp_tf_u;
2303 }
2304 ␌
2305 /* Computation of transformers associated to each node of u and to each of
2306  * its sub-statements.
2307  * */
2308 
2310  unstructured u,
2311  transformer pre) /* pre is valid for any node of u */
2312 {
2313  list blocs = NIL ;
2314  control ct = unstructured_control(u) ;
2315 
2316  pips_debug(5,"begin\n");
2317 
2318  /* There is no need to compute transformers for unreachable code,
2319  * using CONTROL_MAP, but this may create storage and prettyprinter
2320  * problems because of the data structure inconsistency.
2321  */
2322  CONTROL_MAP(c, {
2323  statement st = control_statement(c) ;
2324  (void) statement_to_transformer(st, pre) ;
2325  }, ct, blocs) ;
2326 
2327  gen_free_list(blocs) ;
2328 
2329  pips_debug(5,"end\n");
2330 }
2331 
2333  transformer e_pre, /* precondition on entrance */
2334  list e) /* effects of u */
2335 {
2337  list succs = NIL;
2338  control head = unstructured_control(u);
2339  control tail = unstructured_exit(u);
2340  /* approximate store condition for all control nodes: simple context for
2341  improved transformer derivation; it is not a precondition and should have no
2342  arguments. */
2344  /* Same as previous one for the store on entry in the unstructured. This
2345  the entry node usually has predecessors in the CFG, this is not the
2346  context for the entry node. It is not a precondition. */
2348 
2349  if(transformer_undefined_p(e_pre)) {
2350  /* No information available on entrance */
2351  pre = transformer_identity();
2352  }
2353  else {
2354  /* Cheapest fix point transformer. The flow insensitive fix point
2355  could be used instead. */
2357 
2358  /* pre is replaced by its range condition later when needed*/
2359  pre = transformer_safe_apply(fpf, e_pre);
2360  free_transformer(fpf);
2361  }
2362 
2363  pips_debug(8,"begin\n");
2364 
2365  forward_control_map_get_blocs(head, &succs);
2366 
2367  /* Transformers should be computed precisely whether the unstructured is
2368  left by the exit node or by an explicit or implicit call to STOP. */
2369  if(true || gen_in_list_p(tail, succs)) {
2370  /* computing the transformer for u is like computing the postcondition
2371  with no information on entry: no, the input context may be used to
2372  refine the transformer. */
2373 
2374  if(transformer_undefined_p(e_pre)) {
2375  pre_u = transformer_identity();
2376  }
2377  else {
2378  /* pre_u is restricted to its range later when needed. */
2379  pre_u = transformer_dup(e_pre);
2380  }
2381 
2382  /* These tests should be performed at the scc level */
2383  if(((int)gen_length(succs))>get_int_property("SEMANTICS_MAX_CFG_SIZE2")) {
2384  semantics_user_warning("\nControl flow graph too large for any analysis (%d nodes)\n"
2385  "Have you fully restructured your code?\n", gen_length(succs));
2387 
2388  if(!gen_in_list_p(tail, succs)) {
2389  tf = transformer_empty();
2390  }
2391  else {
2392  tf = effects_to_transformer(e);
2393  }
2394  }
2395  else if(((int)gen_length(succs))>get_int_property("SEMANTICS_MAX_CFG_SIZE1")) {
2396  semantics_user_warning("\nControl flow graph too large for an accurate analysis (%d nodes)\n"
2397  "Have you fully restructured your code?\n", gen_length(succs));
2399 
2400  if(!gen_in_list_p(tail, succs)) {
2401  tf = transformer_empty();
2402  }
2403  else {
2405  }
2406  }
2407  else if(!get_bool_property("SEMANTICS_ANALYZE_UNSTRUCTURED")) {
2408  semantics_user_warning("\nControl flow graph not analyzed accurately"
2409  " because property SEMANTICS_ANALYZE_UNSTRUCTURED is not set\n");
2411 
2412  if(!gen_in_list_p(tail, succs)) {
2413  tf = transformer_empty();
2414  }
2415  else {
2417  }
2418  }
2419  else if(!get_bool_property("SEMANTICS_FIX_POINT")) {
2420  /* Not really linked to fix point issue, but a way to know we are
2421  using a FAST option. */
2423 
2424  if(!gen_in_list_p(tail, succs)) {
2425  tf = transformer_empty();
2426  }
2427  else {
2429  }
2430  }
2431  else {
2433  (pre_u, pre, u, false);
2434  }
2435  free_transformer(pre_u);
2436  }
2437 
2438  if(!gen_in_list_p(tail, succs)) {
2439  /* Do something for nodes unreachable from the entry but linked to the exit */
2440  /* The control flow graph is never exited... by the exit node */
2441  /* The unstructured is never exited, but all nodes are supposed to
2442  have transformers. This would never occur if the control
2443  restructuration were clean unless an infinite loop is stopped
2444  within a called procedure. Control effects are not reported. */
2445  /* FI: pre should be used! */
2447  u,
2450  NULL);
2451  }
2452 
2453  /* Might be useless because it's now performed just above and more
2454  generally by a gen_multi_recurse() */
2455  if(!gen_in_list_p(tail, succs)) {
2456  pips_assert("if exit is not reached, tf is empty", transformer_empty_p(tf));
2457  tf = transformer_empty();
2458  }
2459 
2460  gen_free_list(succs);
2461  free_transformer(pre);
2462 
2463  pips_debug(8,"end\n");
2464 
2465  return tf;
2466 }
2467 ␌
2468 /*
2469  * TOTAL PRECONDITIONS
2470  *
2471  */
2472 
2474 (transformer t_post_u, transformer pre, unstructured u)
2475 {
2478  /* control tail = unstructured_exit(u); */
2479 
2480  pips_assert("Not implemented yet", false);
2481  pips_assert("Shut up the compiler", t_post_u==t_post_u && pre==pre && u==u);
2482 
2483  pips_assert("Total precondition for unstructured is consistent",
2484  transformer_consistency_p(t_pre));
2485 
2486  return post;
2487 }
float a2sf[2] __attribute__((aligned(16)))
USER generates a user error (i.e., non fatal) by printing the given MSG according to the FMT.
Definition: 3dnow.h:3
int get_int_property(const string)
void free_transformer(transformer p)
Definition: ri.c:2616
transformer copy_transformer(transformer p)
TRANSFORMER.
Definition: ri.c:2613
static int count
Definition: SDG.c:519
transformer transformer_dup(transformer t_in)
transformer package - basic routines
Definition: basic.c:49
void transformer_free(transformer t)
Definition: basic.c:68
transformer transformer_identity()
Allocate an identity transformer.
Definition: basic.c:110
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 transformer_internal_consistency_p(transformer t)
Same as above but equivalenced variables should not appear in the argument list or in the predicate b...
Definition: basic.c:790
bool meaningless_control_p(control c)
Is exported to exploit non-deterministic control flow graphs.
Definition: bourdoncle.c:154
bool control_test_p(control c)
Check that a node is used as a test in a CFG.
Definition: bourdoncle.c:175
control control_to_ancestor(control vertex, hash_table ancestor_map)
If vertex is an ancestor control node from the input control graph, return vertex,...
Definition: bourdoncle.c:854
void bourdoncle_free(unstructured ndu, hash_table ancestor_map, hash_table scc_map)
Definition: bourdoncle.c:2506
list bourdoncle_partition(unstructured u, unstructured *p_ndu, hash_table *p_ancestor_map, hash_table *p_scc_map)
Definition: bourdoncle.c:1902
bool cycle_head_p(control c, hash_table ancestor_map, hash_table scc_map)
This node is a cycle call site.
Definition: bourdoncle.c:2385
unstructured ancestor_cycle_head_to_scc(control a, hash_table scc_map)
scc_map maps either the ancestor node to its scc if the transformers are computed without context,...
Definition: bourdoncle.c:2356
unstructured proper_cycle_head_to_scc(control h, hash_table scc_map)
Retrieve a scc_u from its head.
Definition: bourdoncle.c:2368
bool false_successors_only_p(control c)
Definition: bourdoncle.c:2481
bool true_successors_only_p(control c)
Definition: bourdoncle.c:2474
unstructured cycle_head_to_scc(control c, hash_table ancestor_map, hash_table scc_map)
The ancestor of this node is associated to a specific cycle.
Definition: bourdoncle.c:2433
bool refine_transformers_p
Transformer recomputation cannot be of real use unless an interprocedural analysis is performed.
list load_cumulated_rw_effects_list(statement)
bool effects_same_action_p(effect, effect)
list EffectsMayUnion(list l1, list l2, bool(*union_combinable_p)(effect, effect))
list EffectsMayUnion(list l1, list l2, union_combinable_p) input : two lists of effects output : a li...
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
#define chunk_undefined
obsolete
Definition: genC.h:79
#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 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
#define FORWARD_CONTROL_MAP(ctl, code, c, list)
Walk through all the controls forward-reachable from a given control node of an unstructured.
void gen_multi_recurse(void *o,...)
Multi recursion visitor function.
Definition: genClib.c:3428
void gen_context_multi_recurse(void *o, void *context,...)
Multi-recursion with context function visitor.
Definition: genClib.c:3373
bool gen_false(__attribute__((unused)) gen_chunk *unused)
Return false and ignore the argument.
Definition: genClib.c:2796
void gen_null(__attribute__((unused)) void *unused)
Ignore the argument.
Definition: genClib.c:2752
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
#define list_undefined_p(c)
Return if a list is undefined.
Definition: newgen_list.h:75
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
int gen_position(const void *item, const list l)
Element ranks are strictly positive as for first, second, and so on.
Definition: list.c:995
#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
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
void gen_list_and_not(list *a, const list b)
Compute A = A inter non B:
Definition: list.c:963
#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
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
void * gen_find_eq(const void *item, const list seq)
Definition: list.c:422
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
#define list_undefined
Undefined list definition :-)
Definition: newgen_list.h:69
#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
list gen_full_copy_list(list l)
Copy a list structure with element copy.
Definition: list.c:535
test statement_test(statement)
Get the test of a statement.
Definition: statement.c:1348
bool statement_test_p(statement)
Definition: statement.c:343
string statement_identification(statement)
Like external_statement_identification(), but with internal information, the hexadecimal address of t...
Definition: statement.c:1700
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
string safe_statement_identification(statement)
Definition: statement.c:1726
void * hash_get(const hash_table htp, const void *key)
this function retrieves in the hash table pointed to by htp the couple whose key is equal to key.
Definition: hash.c:449
void hash_put(hash_table htp, const void *key, const void *val)
This functions stores a couple (key,val) in the hash table pointed to by htp.
Definition: hash.c:364
void hash_update(hash_table htp, const void *key, const void *val)
update key->val in htp, that MUST be pre-existent.
Definition: hash.c:491
int hash_table_entry_count(hash_table htp)
now we define observers in order to hide the hash_table type...
Definition: hash.c:818
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_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 STATEMENT_ORDERING_UNDEFINED
mapping.h inclusion
Definition: newgen-local.h:35
#define MAKE_CONTROL_MAPPING()
Definition: newgen-local.h:82
#define MAKE_STATEMENT_MAPPING()
Definition: newgen-local.h:43
#define FREE_CONTROL_MAPPING(map)
Definition: newgen-local.h:84
#define HASH_MAP(k, v, code, ht)
Definition: newgen_hash.h:60
#define HASH_UNDEFINED_VALUE
value returned by hash_get() when the key is not found; could also be called HASH_KEY_NOT_FOUND,...
Definition: newgen_hash.h:56
#define hash_table_undefined
Value of an undefined hash_table.
Definition: newgen_hash.h:49
struct cons * list
Definition: newgen_types.h:106
#define print_transformer(t)
Definition: print.c:357
#define print_effects(e)
Definition: print.c:334
#define unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
static int init
Maximal value set for Fortran 77.
Definition: entity.c:320
#define transformer_undefined
Definition: ri.h:2847
#define transformer_undefined_p(x)
Definition: ri.h:2848
#define control_undefined
Definition: ri.h:916
#define TRANSFORMER(x)
TRANSFORMER.
Definition: ri.h:2841
#define control_predecessors(x)
Definition: ri.h:943
#define statement_ordering(x)
Definition: ri.h:2454
#define unstructured_undefined
Definition: ri.h:2980
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define control_domain
newgen_controlmap_domain_defined
Definition: ri.h:98
#define CONTROL(x)
CONTROL.
Definition: ri.h:910
#define transformer_arguments(x)
Definition: ri.h:2871
#define control_successors(x)
Definition: ri.h:945
#define control_undefined_p(x)
Definition: ri.h:917
#define unstructured_exit(x)
Definition: ri.h:3006
#define unstructured_undefined_p(x)
Definition: ri.h:2981
#define test_condition(x)
Definition: ri.h:2833
struct _newgen_struct_transformer_ * transformer
Definition: ri.h:431
#define control_statement(x)
Definition: ri.h:941
#define statement_undefined_p(x)
Definition: ri.h:2420
transformer statement_to_postcondition(transformer, statement)
end of the non recursive section
transformer effects_to_transformer(list e)
list of effects
transformer statement_to_transformer(statement s, transformer spre)
stmt precondition
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
#define semantics_user_warning
transformer precondition_add_condition_information(transformer pre, expression c, transformer context, bool veracity)
context might be derivable from pre as transformer_range(pre) but this is sometimes very computationa...
Definition: expression.c:1111
transformer dag_or_cycle_to_flow_sensitive_postconditions_or_transformers(list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer e_pre, transformer n_pre, hash_table control_postcondition_map, bool postcondition_p, bool is_dag)
Should ndu be a dag or a cycle?
static void update_control_postcondition(control c, transformer post, control_mapping control_postcondition_map)
Definition: unstructured.c:268
static list get_cycle_dependencies(control d, control_mapping cycle_dependencies_map)
Some cycle may appear nowhere but in the DAG and have no entries in the table.
Definition: unstructured.c:963
transformer cycle_to_flow_sensitive_postconditions_or_transformers(list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer e_pre, transformer n_pre, hash_table control_postcondition_map, bool postcondition_p)
Compute transformers or preconditions.
transformer load_statement_temporary_precondition(statement s, statement_mapping statement_temporary_precondition_map)
transformer unstructured_to_flow_sensitive_postconditions(transformer pre_u, transformer pre, unstructured u)
compute pre- and post-conditions in an unstructured from the entry precondition pre and return the ex...
static void store_control_postcondition(control c, transformer post, control_mapping control_postcondition_map)
Definition: unstructured.c:245
static control_mapping free_control_postcondition_map(control_mapping control_postcondition_map)
Definition: unstructured.c:318
static control_mapping make_control_postcondition_map()
Definition: unstructured.c:311
static void cycle_to_flow_sensitive_preconditions(list partition, unstructured c_u, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, control_mapping cycle_temporary_precondition_map, statement_mapping statement_temporary_precondition_map, transformer c_pre, transformer pre, control_mapping control_postcondition_map)
Very likely the transformer paths wrt the entry point and not really a postcondition.
void print_statement_temporary_precondition(statement_mapping statement_temporary_precondition_map)
static control_mapping free_control_fix_point_map(control_mapping control_fix_point_map)
Definition: unstructured.c:412
transformer load_cycle_fix_point(control c, hash_table fix_point_map)
Definition: unstructured.c:544
transformer unstructured_to_postcondition(transformer pre, unstructured u, transformer tf)
transformer load_cycle_temporary_precondition(control c, control_mapping cycle_temporary_precondition_map, hash_table ancestor_map, hash_table scc_map __attribute__((__unused__)))
static void unreachable_node_to_transformer(control c)
static control_mapping make_control_fix_point_map()
Definition: unstructured.c:405
static void local_process_unreachable_node(control c, recursive_context *pcontext)
transformer unstructured_to_transformer(unstructured u, transformer e_pre, list e)
effects of u
void update_temporary_precondition(void *k, transformer pre, hash_table precondition_map)
Definition: unstructured.c:975
static transformer load_arc_precondition(control, control, control_mapping)
forward declaration
Definition: unstructured.c:468
static list unstructured_to_effects(unstructured scc, hash_table ancestor_map, hash_table scc_map)
In fact, non-deterministic unstructured to effects.
Definition: unstructured.c:556
void update_statement_temporary_precondition(statement s, transformer pre, statement_mapping statement_temporary_precondition_map)
Definition: unstructured.c:997
transformer unstructured_to_flow_sensitive_total_preconditions(transformer t_post_u, transformer pre, unstructured u)
static void process_ready_node(control c, transformer pre_entry, transformer n_pre, unstructured u, control_mapping control_postcondition_map, hash_table ancestor_map, hash_table scc_map, list partition, control_mapping fix_point_map, bool postcondition_p)
Definition: unstructured.c:630
static transformer unstructured_to_postconditions(transformer pre, transformer pre_first, unstructured u)
static void store_control_fix_point(control c, transformer fptf, control_mapping control_fix_point_map)
Definition: unstructured.c:382
transformer unstructured_to_flow_insensitive_transformer(unstructured u)
This simple fix-point over-approximates the CFG by a fully connected graph.
static bool ready_to_be_processed_p(control c, list to_be_processed, list still_to_be_processed, list already_processed, control_mapping control_postcondition_map)
a control is ready to be processed if all its predecessors have known postconditions or can receive a...
Definition: unstructured.c:427
static void dag_to_flow_sensitive_preconditions(list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer pre_u, transformer pre, control_mapping control_postcondition_map)
void update_cycle_temporary_precondition(control c, transformer pre, control_mapping cycle_temporary_precondition_map)
static void remove_cycle_dependencies(control c, control_mapping cycle_dependencies_map)
c has been processed and no other cycle can depend on it
Definition: unstructured.c:951
static list non_deterministic_unstructured_to_effects(unstructured scc, hash_table ancestor_map, hash_table scc_map)
Definition: unstructured.c:603
static transformer get_control_precondition(control c, control_mapping control_postcondition_map, unstructured u, transformer pre_entry)
Definition: unstructured.c:185
transformer unstructured_to_flow_sensitive_postconditions_or_transformers(transformer pre_u, transformer pre, unstructured u, bool postcondition_p)
compute either the postconditions in an unstructured or the transformer of this unstructured.
static transformer load_control_fix_point(control c, control_mapping control_fix_point_map, hash_table ancestor_map, hash_table scc_map)
The fix point can be linked either to the entry node of the scc or to the ancestor node.
Definition: unstructured.c:342
transformer dag_to_flow_sensitive_postconditions_or_transformers(list partition, unstructured ndu, hash_table ancestor_map, hash_table scc_map, control_mapping fix_point_map, transformer e_pre, transformer n_pre, hash_table control_postcondition_map, bool postcondition_p)
Compute transformers or preconditions.
static transformer load_control_postcondition(control c, control_mapping control_postcondition_map)
Definition: unstructured.c:169
static void print_control_node_unss_sem(list l)
Definition: unstructured.c:143
static void print_control_node_uns(control c)
semantical analysis
Definition: unstructured.c:122
static void print_cycle_head_to_fixpoint(control c, recursive_context *pcontext)
A debug function to prettyprint the fix points.
static void add_cycle_dependency(control d, control c, control_mapping cycle_dependencies_map)
State that d depends on c: cycle c must be processed before cycle d can be processed.
Definition: unstructured.c:934
static void unstructured_to_transformers(unstructured u, transformer pre)
Computation of transformers associated to each node of u and to each of its sub-statements.
void print_control_postcondition_map(control_mapping control_postcondition_map)
unstructured.c
Definition: unstructured.c:295
static void node_to_path_transformer_or_postcondition(control c, recursive_context *pcontext)
A debug function to prettyprint the result.
static bool process_unreachable_node(control c, control_mapping control_postcondition_map, bool postcondition_p)
Definition: unstructured.c:862
transformer load_statement_precondition(statement)
transformer load_statement_transformer(statement)
#define ifdebug(n)
Definition: sg.c:47
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
Definition: delay.c:253
control_mapping smap
Definition: statement.c:54
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_safe_apply(transformer tf, transformer pre)
Definition: transformer.c:1627
bool transformer_empty_p(transformer t)
If true is returned, the transformer certainly is empty.
Definition: transformer.c:2455
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_range_intersection(transformer tf, transformer r)
Allocate a new transformer rtf that is tf with its range restricted by the range r.
Definition: transformer.c:830
transformer transformer_combine(volatile transformer t1, transformer t2)
transformer transformer_combine(transformer t1, transformer t2): compute the composition of transform...
Definition: transformer.c:238
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_range(transformer tf)
Return the range of relation tf in a newly allocated transformer.
Definition: transformer.c:714
transformer transformer_list_transitive_closure(list)
Compute (U tfl)*.
transformer transformer_list_transitive_closure_plus(list)
Compute (U tfl)+.