PIPS
simplify_control.c
Go to the documentation of this file.
1 /*
2  $Id: simplify_control.c 23495 2018-10-24 09:19:47Z coelho $
3 
4  Copyright 1989-2016 MINES ParisTech
5 
6  This file is part of PIPS.
7 
8  PIPS is free software: you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  any later version.
12 
13  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
14  WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  FITNESS FOR A PARTICULAR PURPOSE.
16 
17  See the GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 // do not compile unless required
25 #include "phases.h"
26 #if defined(BUILDER_SIMPLIFY_CONTROL) || \
27  defined(BUILDER_SIMPLIFY_CONTROL_DIRECTLY) || \
28  defined(BUILDER_SUPPRESS_DEAD_CODE) || \
29  defined(BUILDER_REMOVE_USELESS_LABEL)
30 
31 #ifdef HAVE_CONFIG_H
32 #include "pips_config.h"
33 #endif
34 /*
35  Dead loop elimination.
36  Ronan Keryell, 12/1993 -> 1995.
37  one trip loops fixed, FC 08/01/1998
38 */
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 
44 #include "genC.h"
45 #include "linear.h"
46 
47 #include "misc.h"
48 #include "pipsdbm.h"
49 #include "properties.h"
50 
51 #include "ri.h"
52 #include "ri-util.h"
53 #include "prettyprint.h" // for debugging
54 
55 #include "effects-generic.h" // used
56 #include "effects-simple.h" // expression_with_side_effect_p
57 
58 #include "transformer.h" // used
59 #include "semantics.h" // used
60 
61 #include "control.h" // used...
62 #include "callgraph.h" // used
63 
64 #include "transformations.h"
65 
66 /* To avoid calling unspaghettify() if unnecessary: */
67 static bool some_unstructured_ifs_have_been_changed;
68 
69 /**************************************************************** STATISTICS */
70 
71 static int dead_code_if_removed;
72 static int dead_code_if_replaced_by_its_effect;
73 static int dead_code_if_false_branch_removed;
74 static int dead_code_if_true_branch_removed;
75 static int dead_code_loop_removed;
76 static int dead_code_loop_executed_once;
77 static int dead_code_statement_removed;
78 static int dead_code_unstructured_if_removed;
79 static int dead_code_unstructured_if_replaced_by_its_effect;
80 static int dead_code_unstructured_if_false_branch_removed;
81 static int dead_code_unstructured_if_true_branch_removed;
82 static void suppress_dead_code_statement(statement);
83 
84 static transformer (*get_statement_precondition)(statement);
85 
86 static void
87 initialize_dead_code_statistics()
88 {
89  dead_code_if_removed = 0;
90  dead_code_if_replaced_by_its_effect = 0;
91  dead_code_if_false_branch_removed = 0;
92  dead_code_if_true_branch_removed = 0;
93  dead_code_loop_removed = 0;
94  dead_code_loop_executed_once = 0;
95  dead_code_statement_removed = 0;
96  dead_code_unstructured_if_removed = 0;
97  dead_code_unstructured_if_replaced_by_its_effect = 0;
98  dead_code_unstructured_if_false_branch_removed = 0;
99  dead_code_unstructured_if_true_branch_removed = 0;
101 }
102 
103 static void
104 display_dead_code_statistics()
105 {
106  if (get_bool_property("DEAD_CODE_DISPLAY_STATISTICS")) {
107  int elimination_count = dead_code_statement_removed
108  + dead_code_loop_removed
109  + dead_code_loop_executed_once
110  + dead_code_if_removed
111  + dead_code_if_replaced_by_its_effect;
112  elimination_count += dead_code_unstructured_if_removed
113  + dead_code_unstructured_if_replaced_by_its_effect;
114 
115  if (elimination_count > 0)
116  {
117  user_log("* %d dead code part%s %s been discarded. *\n",
118  elimination_count,
119  elimination_count > 1 ? "s" : "",
120  elimination_count > 1 ? "have" : "has");
121 
122  user_log("Statements removed (directly dead): %d\n",
123  dead_code_statement_removed);
124 
125  user_log("Loops: loops removed: %d, loops executed only once: %d\n",
126  dead_code_loop_removed, dead_code_loop_executed_once);
127 
128  user_log("Structured tests: \"if\" removed: %d, "
129  "\"if\" replaced by side effects: %d\n"
130  "\t(\"then\" removed: %d, "
131  "\"else\" removed: %d)\n",
132  dead_code_if_removed, dead_code_if_replaced_by_its_effect,
133  dead_code_if_true_branch_removed,
134  dead_code_if_false_branch_removed);
135 
136  user_log("Unstructured tests: \"if\" removed: %d, "
137  "\"if\" replaced by side effects: %d\n"
138  "\t(unstructured \"then\" removed: %d, "
139  "unstructured \"else\" removed: %d)\n",
140  dead_code_unstructured_if_removed,
141  dead_code_unstructured_if_replaced_by_its_effect,
142  dead_code_unstructured_if_true_branch_removed,
143  dead_code_unstructured_if_false_branch_removed);
144  /* Display also the statistics about clean_up_sequences
145  that is called in suppress_dead_code: */
147  }
148  }
149 }
150 
151 /********************************************************************* DEBUG */
152 
153 static void stdebug(int dl, string msg, statement s)
154 {
155  ifdebug(dl) {
156  pips_debug(dl, "statement %p: %s\n", s, msg);
157  if (s) {
158  print_statement(s);
159  }
160  }
161  pips_assert("The statement is consistent",
163 }
164 
165 /* Give an information on the liveness of the 2 if's branches: */
166 static dead_test
167 dead_test_filter(statement st_true, statement st_false)
168 {
169  pips_debug(5, "Begin\n");
170 
171  stdebug(9, "dead_test_filter: then branch", st_true);
172  stdebug(9, "dead_test_filter: else branch", st_false);
173 
174  ifdebug(8)
175  {
176  transformer pretrue = get_statement_precondition(st_true);
177  transformer prefalse = get_statement_precondition(st_false);
178  fprintf(stderr,"NN true and false branches");
179  sc_fprint(stderr,
181  (char* (*)(Variable)) entity_local_name);
182  sc_fprint(stderr,
184  (char* (*)(Variable)) entity_local_name);
185  }
186 
187  if (get_statement_precondition==load_statement_precondition
188  && !statement_strongly_feasible_p(st_true)) {
189  pips_debug(5, "End: then_is_dead\n");
190  return then_is_dead;
191  }
192 
193  if (get_statement_precondition==load_statement_precondition
194  && !statement_strongly_feasible_p(st_false)) {
195  pips_debug(5, "End: else_is_dead\n");
196  return else_is_dead;
197  }
198 
199  pips_debug(5, "End: nothing_about_test\n");
200  return nothing_about_test;
201 }
202 
203 /* Replace an instruction by an empty one. If there is a label on the
204  statement, put it on a continue to be coherent with the PIPS RI. */
205 static bool discard_statement_and_save_label_and_comment(statement s)
206 {
207  if (statement_loop_p(s)) {
208  /* NN -> Bug found : if we have two loops with the same label such
209  as :
210 
211  DO 100 I=1,N
212  DO 100 J=1,M
213  ......
214 
215  100 CONTINUE
216 
217  and the inner loop is a dead statement, there is an error when
218  compiling the generated file Fortran. Because the label of the
219  last statement in the inner loop might be used by an outer loop
220  and, in doubt, should be preserved.
221 
222  SOLUTION : like in full_loop_unroll()*/
225 
226  if(!entity_empty_label_p(flbl)) {
227 
231  CONS(STATEMENT, stmt, NIL ));
233  /* And put a new empty one: */
235  /* Since the RI need to have no label on instruction block: */
236 
238 
239  }
240  else {
241  /* Discard the old instruction: */
243  /* And put a new empty one: */
245 
246  /* Since the RI need to have no label on instruction block: */
248  }
249  }
250  /* FI: Why do we want to avoid eliminating declarations? If they are
251  * dead code, they should not be used anywhere? This is only useful
252  * if the elimination decision is taken according to effects...
253  */
254  else if(declaration_statement_p(s)) {
255  ; /* do not modify the declaration statement... in case it has no
256  memory effect */
257  }
258  /* "this avoids removing declarations" (previous comment)
259  *
260  * FI: If a whole block has no effect, its internal declarations are
261  * useless too. But if it is the body of a function returning a
262  * value, the return statement should be preserved for syntactic
263  * correctness. This is not done here. The main test should be
264  * if(statement_block_p(s)).
265  *
266  * Maybe also, we might want to preserve some comments. See
267  * Transformations/no_effect_statement_00
268  */
269  else if(false && !ENDP(statement_declarations(s))) {
270  if(statement_block_p(s)) {
273  discard_statement_and_save_label_and_comment(st);
274  }
275  }
276  else {
277  /* Discard the old instruction: */
279  /* And put a new empty one: */
281 
282  /* Since the RI need to have no label on instruction block: */
284  }
285  return false;
286 }
287 
288 
289 /* Use the precondition to know wether a loop is never executed
290  *
291  * The accuracy (and, hence, duration) of the test depends on
292  * the precondition normalization. There is a trade-off between
293  * the time spent in dead code elimination and the time spent
294  * in precondition computation.
295  */
296 static bool
297 dead_loop_p(loop l)
298 {
299  statement s;
300  bool feasible_p = true;
301  intptr_t c = 0;
302 
303  if(range_count(loop_range(l), &c)) {
304  feasible_p = (c>0);
305  }
306  else {
307  s = loop_body(l);
308  /* feasible_p = statement_feasible_p(s); */
309  if(get_statement_precondition==load_statement_precondition)
310  feasible_p = statement_strongly_feasible_p(s);
311  }
312  return !feasible_p;
313 }
314 
315 
316 /* Replace a loop statement with the statement inside the loop. */
317 static void
318 remove_loop_statement(statement s, instruction i, loop l)
319 {
320  range lr = loop_range(l);
321  expression rl = range_lower(lr);
322  expression rincr = range_increment(lr);
323  expression init_val = copy_expression(rl);
325  copy_expression(init_val),
326  copy_expression(rincr));
327  expression index;
329 
330  /* Assume here that index is a scalar variable... :-) */
331  pips_assert("dead_statement_filter", entity_scalar_p(loop_index(l)));
332 
333  index = make_factor_expression(1, loop_index(l));
334 
335  /* If we can, we will replace the use of the loop index in the body with
336  * the lower bound, we handle only pure simple scalar expression cases
337  */
339  || (expression_reference_p(rl)
341 
342  entity up_bound;
344  up_bound = int_to_entity(expression_to_int(rl));
345  } else {
347  }
348  replace_entity(loop_body(l),loop_index(l),up_bound);
349 
350  // A property can prevent the assignment of upper bound to loop index
351  if(get_bool_property("SIMPLIFY_CONTROL_DIRECTLY_PRIVATE_LOOP_INDICES")) {
354  } else {
359  last_val))
360  );
361  }
362  } else {
363  /* Standard case, the loop header is removed, but we have to assign value to
364  * the loop index:
365  * for(i=low;i<upper;i+=inc)
366  * =>
367  * i=low;
368  * // body...
369  * i=low+inc;
370  */
371  as1 = make_assign_statement(index, init_val);
372  as2 = make_assign_statement(copy_expression(index),last_val);
375  loop_body(l),
376  as2)
377  );
379  }
382 
383  /* fix some extra attributes */
386 
387  stdebug(4, "remove_loop_statement", s);
388 
390  free_instruction(i);
391 }
392 
393 /* true if do i = x, x or equivalent.
394  */
395 static bool loop_executed_once_p(statement s, loop l)
396 {
397  range rg;
398  expression m1, m2, m3;
399  volatile normalized n_m1, n_m2, n_m3;
400  transformer pre;
401  Psysteme precondition_ps;
402  Pvecteur pv3;
403  Pcontrainte pc3;
404  bool m3_negatif = false, m3_positif = false;
405  volatile bool retour;
406  /* Automatic variables read in a CATCH block need to be declared volatile as
407  * specified by the documentation*/
408  Psysteme volatile ps;
409 
410  retour = false;
411  rg = loop_range(l);
412  m1 = range_lower(rg);
413  m2 = range_upper(rg);
414 
415  /* m1 == m2
416  */
417  /* Not necessarily true with side effects: DO i = inc(n), inc(n) */
418  if (expression_equal_p(m1, m2))
419  return true;
420 
421  pre = get_statement_precondition(s);
422  precondition_ps = predicate_system(transformer_relation(pre));
423 
424  m3 = range_increment(rg);
425  n_m1 = NORMALIZE_EXPRESSION(m1);
426  n_m2 = NORMALIZE_EXPRESSION(m2);
427  n_m3 = NORMALIZE_EXPRESSION(m3);
428 
429  if (normalized_linear_p(n_m1) && normalized_linear_p(n_m2))
430  {
431  /* m1 - m2 == 0 redundant ?
432  */
434  normalized_linear(n_m2)));
435 
436  if (eq_redund_with_sc_p(precondition_ps, eq))
437  retour = true;
438 
440 
441  if (retour) return true;
442  }
443  if (normalized_linear_p(n_m3)) {
444  /* Teste le signe de l'incrï¿œment en fonction des prï¿œconditions : */
445  pv3 = vect_dup(normalized_linear(n_m3));
446  pc3 = contrainte_make(pv3);
447  ps = sc_dup(precondition_ps);
448  sc_add_ineg(ps, pc3);
450  sc_rm(ps);
451  return false;
452  }
453  TRY {
454  m3_negatif = sc_rational_feasibility_ofl_ctrl(ps,FWD_OFL_CTRL,true);
455  (void) vect_chg_sgn(pv3);
456  m3_positif = sc_rational_feasibility_ofl_ctrl(ps,FWD_OFL_CTRL,true);
458  }
459  pips_debug(2, "loop_increment_value positif = %d, negatif = %d\n",
460  m3_positif, m3_negatif);
461 
462  /* Vire aussi pv3 & pc3 : */
463  sc_rm(ps);
464  }
465  if ((m3_positif ^ m3_negatif) && normalized_linear_p(n_m3) &&
467  {
468  /* Si l'incrï¿œment a un signe ï¿œ connu ï¿œ et diffï¿œrent de 0 et que
469  les bornes sont connues : */
470  Pvecteur pv1, pv2, pv3, pvx, pv;
471  Pcontrainte ca, cb;
472 
473  pv1 = normalized_linear(n_m1);
474  pv2 = normalized_linear(n_m2);
475  pv3 = normalized_linear(n_m3);
476 
477  /* pv = m1 - m2, i.e. m1 - m2 <= 0 */
478  pv = vect_substract(pv1, pv2);
479 
480  /* pvx = m1 - m2 + m3, i.e. m1 + m3 -m2 <=0 */
481  pvx = vect_add(pv, pv3);
482 
483  if (m3_positif) {
484  /* L'incrï¿œment est positif. */
485  (void) vect_chg_sgn(pvx);
486  /* m1 - m2 <= 0 && m2 - m1 - m3 <= -1 */
487  }
488 
489  if (m3_negatif) {
490  (void) vect_chg_sgn(pv);
491  /* m2 - m1 >= 0 && -m2 + m1 + m3 <= -1 */
492  }
493 
494  vect_add_elem(&pvx, TCST, VALUE_ONE);
495 
496  ca = contrainte_make(pvx);
497  cb = contrainte_make(pv);
498 
499  /* ??? on overflows, should assume false...
500  */
501  retour = ineq_redund_with_sc_p(precondition_ps, ca) &&
502  ineq_redund_with_sc_p(precondition_ps, cb);
503 
504  /* Vire du mï¿œme coup pv et pvx : */
506  }
507 
508  return retour;
509 }
510 
511 /* Remplace une boucle vide par la seule initialisation de l'indice : */
512 static bool remove_dead_loop(statement s, instruction i, loop l)
513 {
514  expression index, rl;
515  range lr;
516  statement as;
517  expression init_val;
519  entity flbl;
520 
521  /* On va remplacer la boucle par l'initialisation de l'indice a`
522  sa valeur initiale seulement. */
523 
524  init_val = copy_expression(rl = range_lower(lr = loop_range(l)));
525  /*pips_assert("remove_dead_loop", gen_defined_p(init_val));*/
526  /*expression init_val = copy_expression(range_lower(loop_range(l)));*/
527 
528  /* Assume here that index is a scalar variable... :-) */
529  pips_assert("remove_dead_loop", entity_scalar_p(loop_index(l)));
530 
531  index = make_factor_expression(1, loop_index(l));
532 
533  /* NN -> Bug found : if we have two loops with the same label
534  such as :
535 
536  DO 100 I=1,N
537  DO 100 J=1,M
538  ......
539 
540  100 CONTINUE
541 
542  and the inner loop is a dead statement, there is an error when
543  compiling the generated file Fortran. Because the label of the
544  last statement in the inner loop might be used by an outer loop
545  and, in doubt, should be preserved.
546 
547  SOLUTION : like in full_loop_unroll()*/
548 
549  /* *****OLD CODE***************
550  statement_instruction(s) =
551  make_instruction_block(CONS(STATEMENT,
552  as = make_assign_statement(index , init_val),
553  NIL));
554  statement_label(as) = statement_label(s);
555  statement_label(s) = entity_empty_label();
556 
557  fix_sequence_statement_attributes(s);*/
558 
559  /* *****NEW CODE***************/
560 
561 
564  CONS(STATEMENT,
565  as = make_assign_statement(index , init_val),
566  NIL ));
567 
569 
570  if(!entity_empty_label_p(flbl)) {
573  CONS(STATEMENT, stmt, NIL ));
574  }
575 
577  /* Since the RI need to have no label on instruction block: */
581 
582  stdebug(9, "remove_dead_loop: New value of statement", s);
583 
584  free_instruction(i);
585  return false;
586 }
587 /* Return true if a statement has at least one write effect in the
588  effects list. */
589 static bool statement_write_effect_p(statement s)
590 {
591  bool write_effect_found = false;
592  list effects_list = load_proper_rw_effects_list(s);
593 
594  FOREACH(effect, an_effect, effects_list)
595  {
596  if (action_write_p(effect_action(an_effect))) {
597  write_effect_found = true;
598  break;
599  }
600  };
601 
602  return write_effect_found;
603 }
604 
605 
606 /* Remove an IF(x) statement (replace s with an empty statement) if x
607  has no write proper effect. If x has a write effect, replace s with a
608  statement as bool_var = x: (he', a french joke !)
609  this_test_is_unstructured_p is a hint for the statistics.
610  true means that you assert that the test is unstructured.
611 */
612 static void remove_if_statement_according_to_write_effects
613 (statement s, bool this_test_is_unstructured_p)
614 {
616 
617  pips_assert("statement is consistent at entry", s);
618 
619  if (statement_write_effect_p(s)) {
620  /* There is a write effect, so we cannot discard the IF
621  expression. Keep it in a temporarily variable: */
622  entity temp_var =
625  /* Create the bool_var = x: */
630 
631  if (this_test_is_unstructured_p)
632  dead_code_unstructured_if_replaced_by_its_effect++;
633  else
634  dead_code_if_replaced_by_its_effect++;
635 
636  pips_assert("statement is consistent after partial dead code removeal", s);
637  }
638  else {
639  /* There is no write effect, the statement can be discarded: */
642 
643  if (this_test_is_unstructured_p)
644  dead_code_unstructured_if_removed++;
645  else
646  dead_code_if_removed++;
647 
648  pips_debug(8, "let's use some heap\n");
649  pips_assert("statement is consistent after dead code removal", s);
650  }
651 
652  pips_debug(8, "let's use some heap\n");
653 
654  pips_assert("statement is consistent at exit", s);
655 
656  /* Discard the IF: */
657  /* FI: I do not understand why, but this free breaks the
658  unstructured containing s (case "no write effect". */
659  /* For unknown reasons, the preconditions for the true and false
660  branches are recomputed... because they are not reachable from
661  the controls... however, statements are reachable from controls
662  and statements are linked to preconditions... */
663  // free_instruction(i);
664 
665  pips_debug(8, "let's use some heap\n");
666  pips_assert("statement is consistent at exit", s);
667 }
668 
669 
670 static bool dead_deal_with_test(statement s,
671  test t)
672 {
673  statement st_true = test_true(t);
674  statement st_false = test_false(t);
675  expression c = test_condition(t);
676  enum dead_test what_is_dead = nothing_about_test;
677 
678  if(true_expression_p(c))
679  what_is_dead = else_is_dead;
680  else if(false_expression_p(c))
681  what_is_dead = then_is_dead;
682  else
683  what_is_dead = dead_test_filter(st_true, st_false);
684 
685  switch (what_is_dead) {
686 
687  case then_is_dead :
688  /* Delete the test and the useless true : */
691  remove_if_statement_according_to_write_effects(s,
692  false /* structured if */);
693  /* Concatenate an eventual IF expression (if write effects) with
694  the false branch: */
698  );
699 
700  /* Go on the recursion on the remaining branch : */
701  suppress_dead_code_statement(st_false);
702  dead_code_if_true_branch_removed++;
703  return false;
704  break;
705 
706  case else_is_dead :
707  /* Delete the test and the useless false : */
710  remove_if_statement_according_to_write_effects(s,
711  false /* structured if */);
712  /* Concatenate an eventual IF expression (if write effects) with
713  the false branch: */
718  /* Go on the recursion on the remaining branch : */
719  suppress_dead_code_statement(st_true);
720  dead_code_if_false_branch_removed++;
721  return false;
722  break;
723 
724  case nothing_about_test :
725  break;
726 
727  default :
728  pips_assert("dead_deal_with_test does not understand dead_test_filter()",
729  true);
730  }
731  return true;
732 }
733 
734 
735 /* Give an information on the liveness of the 2 unstructured if's
736  branches. Accept the statement that contains the if: */
737 static dead_test dead_unstructured_test_filter(statement st)
738 {
739  /* In an unstructured test, we need to remove the dead control
740  link according to preconditions. Unfortunately, preconditions
741  are attached to statements and not to control vertice. Hence we
742  need to recompute a precondition on these vertice: */
743  dead_test test_status;
744  transformer pre_true, pre_false;
746  transformer pre = get_statement_precondition(st);
747  expression cond = test_condition(t);
748 
749  pips_assert("Preconditions are defined for all statements",
751 
752  pips_assert("The statement is consistent",
754 
755  ifdebug(6)
756  sc_fprint(stderr,
758  (char* (*)(Variable)) entity_local_name);
759 
760  /* FI: this is the piece of code which may explain why the
761  instruction cannot be freed in
762  remove_if_statement_according_to_write_effects(). */
763  /* Compute the precondition for each branch: */
764  pre_true =
766  cond,
768  true);
769  ifdebug(6)
770  sc_fprint(stderr,
772  (char* (*)(Variable)) entity_local_name);
773 
774  pre_false =
776  cond,
778  false);
779  ifdebug(6)
780  sc_fprint(stderr,
782  (char* (*)(Variable)) entity_local_name);
783 
784  if (transformer_empty_p(pre_true)) {
785  pips_debug(5, "then_is_dead\n");
786  test_status = then_is_dead;
787  }
788  else if (transformer_empty_p(pre_false)) {
789  pips_debug(5, "else_is_dead\n");
790  test_status = else_is_dead;
791  }
792  else {
793  pips_debug(5, "nothing_about_test\n");
794  test_status = nothing_about_test;
795  }
796 
797  free_transformer(pre_true);
798  free_transformer(pre_false);
799 
800  pips_assert("The statement is consistent",
802 
803  return test_status;
804 }
805 
806 static void dead_recurse_unstructured(unstructured u)
807 {
809  //list blocs = NIL;
810  list nodes = NIL;
811 
813 
814  pips_assert("unstructured is consistent at the beginning",
816 
817  nodes = gen_nreverse(nodes);
818 
819  /* CONTROL_MAP removed for debugging */
820  FOREACH(CONTROL, c, nodes) {
821  int number_of_successors = gen_length(control_successors(c));
822 
823  pips_debug(3, "(gen_length(control_successors(c)) = %d)\n",
824  number_of_successors);
825  st = control_statement(c);
826 
827  if (number_of_successors == 0 || number_of_successors == 1) {
828  /* Ok, the statement is not an unstructured if, that
829  means that we can apply a standard elimination if
830  necessary. The statement is consistent on return. */
831  suppress_dead_code_statement(st);
832  }
833  else if (number_of_successors == 2
835  /* In an unstructured test, we need to remove the
836  dead control link according to
837  preconditions. Unfortunately, preconditions
838  are attached to statements and not to control
839  vertice. Hence we need to recompute a
840  precondition on these vertice: */
841  control true_control = CONTROL(CAR(control_successors(c)));
842  control false_control = CONTROL(CAR(CDR(control_successors(c))));
843 
844  switch (dead_unstructured_test_filter(st)) {
845  case then_is_dead :
846 
847  pips_assert("unstructured is consistent before then is dead",
849  pips_debug(3, "\"Then\" is dead...\n");
850  /* Remove the link to the THEN control
851  node. Rely on unspaghettify() to remove
852  down this path later: */
853  gen_remove_once(&control_successors(c), true_control);
854  gen_remove_once(&control_predecessors(true_control), c);
855 
856  pips_assert("unstructured is consistent after then_is_dead",
858  /* Replace the IF with nothing or its expression: */
859  remove_if_statement_according_to_write_effects
860  (control_statement(c), true /* unstructured if */);
861 
862  pips_assert("unstructured is consistent after then_is_dead",
864 
865  some_unstructured_ifs_have_been_changed = true;
866  dead_code_unstructured_if_true_branch_removed++;
867 
868  pips_assert("unstructured is consistent after then_is_dead",
870  break;
871 
872  case else_is_dead :
873 
874  pips_assert("unstructured is consistent before else_is_dead",
876  pips_debug(3, "\"Else\" is dead...\n");
877  /* Remove the link to the ELSE control
878  node. Rely on unspaghettify() to remove
879  down this path later: */
880  gen_remove_once(&control_successors(c), false_control);
881  gen_remove_once(&control_predecessors(false_control), c);
882  /* Replace the IF with nothing or its expression: */
883  remove_if_statement_according_to_write_effects
884  (control_statement(c), true /* unstructured if */);
885 
886  some_unstructured_ifs_have_been_changed = true;
887  dead_code_unstructured_if_false_branch_removed++;
888 
889  pips_assert("unstructured is consistent after else_is_dead",
891  break;
892 
893  case nothing_about_test :
894  pips_debug(3, "Nothing about this test...");
895 
896  /* same successor in both branches... remove one!
897  * maybe unspaghettify should also be okay? it seems not.
898  */
899  if (true_control==false_control)
900  {
901  gen_remove_once(&control_successors(c), false_control);
902  gen_remove_once(&control_predecessors(false_control), c);
903  /* Replace the IF with nothing or its expression: */
904  remove_if_statement_according_to_write_effects
905  (control_statement(c), true /* unstructured if */);
906 
907  some_unstructured_ifs_have_been_changed = true;
908  dead_code_unstructured_if_false_branch_removed++;
909  }
910  break;
911 
912  default :
913  pips_internal_error("does not understand dead_test_filter()");
914  }
915  }
916  else
917  pips_internal_error("Unknown unstructured type");
918 
919  /* Let's hope the unstructured is still consistent */
920  pips_assert("unstructured is consistent after some iterations",
922  }
923  gen_free_list(nodes);
924 
925  pips_assert("unstructured is consistent at the end",
927 }
928 
929 static bool zero_or_one_iteration_while_loop_p(statement s, bool one_p)
930 {
934  bool one_iteration_p = false;
935  bool zero_iteration_p = false;
936  statement wb = whileloop_body(wl);
938 
939  if (get_statement_precondition==load_statement_precondition) {
942 
943  if(evaluation_after_p(e)) {
944  // See if the repeat until is only executed once
945  // Issue: the precondition holding before the condition is
946  // re-evaluated because it has not been stored
947  transformer tp = transformer_apply(tf, prec); // test precondition
948  transformer ct = condition_to_transformer(c, tp, true);
949  one_iteration_p = transformer_empty_p(ct);
951  }
952  else {
953  if(one_p) {
954  // See if the loop condition is false when tested after the body
955  // execution. Should be useless since integrated in wb's precondition
956  // transformer fct = condition_to_transformer(c, prec, true);
958  transformer tp = transformer_apply(tf, bprec); // test precondition
959  transformer sct = condition_to_transformer(c, tp, true);
960  one_iteration_p = transformer_empty_p(sct);
962  }
963  else {
964  transformer sct = condition_to_transformer(c, prec, true);
965  zero_iteration_p = transformer_empty_p(sct);
966  free_transformer(sct);
967  }
968  }
969  }
970  else { // Preconditions and transformers cannot be used
971  if(evaluation_after_p(e)) {
972  /* Unfortunately condition_to_transformer() cannot be used
973  because the condition c may contain a call site. */
974  /* Check pathological cases: while(0) and while(false) */
975  if(expression_call_p(c)) {
976  call cc = expression_call(c);
977  entity f = call_function(cc);
978  one_iteration_p = ENTITY_ZERO_P(f) || ENTITY_FALSE_P(f);
979  }
980  }
981  else {
982  /* Unfortunately condition_to_transformer() cannot be used
983  because the condition c may contain a call site. */
984  /* Check pathological cases: while(0) and while(false) */
985  if(expression_call_p(c)) {
986  call cc = expression_call(c);
987  entity f = call_function(cc);
988  zero_iteration_p = ENTITY_ZERO_P(f) || ENTITY_FALSE_P(f);
989  }
990  }
991  }
992  bool zero_or_one_iteration_p = one_p? one_iteration_p : zero_iteration_p;
993  return zero_or_one_iteration_p;
994 }
995 
996 static bool one_iteration_while_loop_p(statement s)
997 {
998  bool one_p = zero_or_one_iteration_while_loop_p(s, true);
999  return one_p;
1000 }
1001 
1002 static bool zero_iteration_while_loop_p(statement s)
1003 {
1004  bool zero_p = zero_or_one_iteration_while_loop_p(s, false);
1005  return zero_p;
1006 }
1007 
1008 /* If it can be proven that the while loop is executed only once,
1009  * replace the while loop by its body in s.
1010  *
1011  * It is assumed that s contains a while loop.
1012  */
1013 static void simplify_while_loop(statement s)
1014 {
1018  bool one_iteration_p = one_iteration_while_loop_p(s);
1019  bool zero_iteration_p = zero_iteration_while_loop_p(s);
1020  /* Check side effects in condition */
1022  bool side_effect_p = expression_with_side_effect_p(c);
1023 
1024  if(one_iteration_p
1025  && !side_effect_p
1026  && (!evaluation_after_p(e) ||
1027  // A quick fix for FREIA demonstrations
1028  get_bool_property("SIMPLIFY_CONTROL_DO_WHILE"))
1029  // Same fix for while loops and the FREIA demonstration
1030  && get_bool_property("SIMPLIFY_CONTROL_DO_WHILE")) {
1031 
1032  // FI: this is buggy if the condition has a side effect
1033  // An expression statement should be added before the body and
1034  // another one after the body in case it is a do{}while() loop
1035 
1036  // Easiest solution: do not simplify while loops when there
1037  // conditions have side effects
1038 
1039  statement wb = whileloop_body(wl);
1041  // We should try to preserve labels, comments and statement numbers...
1043  // An issue if we have a label for s and a label for wb...
1044  ; // FI: to be seen later, wb is unlikely to have a label...
1045  // Concatenate comments...
1046  // FI: to be seen later... The parser seems to junk the loop comments
1047  string sc = statement_comments(s);
1048  string wbc = statement_comments(wb); // will be freed with wb
1049  string nc;
1050  if(empty_comments_p(sc)) {
1051  if(empty_comments_p(wbc))
1052  nc = empty_comments;
1053  else
1054  nc = strdup(wbc);
1055  }
1056  else {
1057  if(empty_comments_p(wbc))
1058  nc = strdup(sc);
1059  else
1060  nc = strdup(concatenate(sc, wbc, NULL)); // new comment
1061  free(sc);
1062  }
1065  // Get rid of obsolete pieces of data structures
1067  free_instruction(i);
1069  free_statement(wb);
1070  }
1071  else if(zero_iteration_p && !side_effect_p) {
1072  // The loop and its body can be replaced by NOP
1074  free_instruction(i);
1075  }
1076 
1077 }
1078 
1079 /* Essaye de faire le menage des blocs vides recursivement.
1080  En particulier, si les 2 branches d'un test sont vides on peut supprimer
1081  le test, si le corps d'une boucle est vide on peut supprimer la boucle.
1082 */
1083 static void
1084 dead_statement_rewrite(statement s)
1085 {
1087  tag t = instruction_tag(i);
1088 
1089  pips_debug(2, "Begin for statement %td (%td, %td)\n",
1090  statement_number(s),
1093 
1094  stdebug(2, "dead_statement_rewrite: "
1095  "The current statement st at the beginning",
1096  s);
1098 
1099  switch(t) {
1100  case is_instruction_sequence: {
1101  // It is now mostly dealt with clean_up_sequences_internal() at the
1102  // end of the function:
1103  // Make sure the declaration list at the block level fits the
1104  // declarations in the sequence in case some where eliminated
1105  list dl = statement_declarations(s);
1107  gen_free_list(dl);
1108  statement_declarations(s) = idl;
1109  break;
1110  }
1111  case is_instruction_loop:
1113  break;
1115  simplify_while_loop(s);
1116  break;
1117  case is_instruction_test:
1118  {
1119  statement st_true, st_false;
1120  test te;
1121 
1122  pips_debug(2, "is_instruction_test\n\n");
1123  stdebug(9, "dead_statement_rewrite: test", s);
1124 
1125  te = instruction_test(i);
1126  st_true = test_true(te);
1127  st_false = test_false(te);
1128  if (empty_statement_or_continue_p(st_true)
1129  && empty_statement_or_continue_p(st_false)) {
1130  /* Even if there is a label, it is useless since it is not
1131  an unstructured. */
1132  pips_debug(2, "test deletion\n");
1133  stdebug(9, "dead_statement_rewrite: ", s);
1134 
1135  remove_if_statement_according_to_write_effects
1136  (s, false /* structured if */);
1137  }
1138  break;
1139  }
1140 
1142  /* Rely on the unspaghettify() at end: */
1143  break;
1144 
1145  case is_instruction_call:
1146  break;
1147 
1149  break;
1150 
1151  default:
1152  pips_internal_error("Unexpected instruction tag %d", t);
1153  break;
1154  }
1155 
1156  // If we have now a sequence, clean it up, but be careful with
1157  // declarations and user name conflicts...
1158  // Bug here. See Transformations/until02.c
1160 
1161  pips_debug(2, "End for statement %td (%td, %td)\n",
1162  statement_number(s),
1165  stdebug(2, "dead_statement_rewrite: The current statement st at the end", s);
1166  (void) pop_statement_global_stack();
1167 }
1168 
1169 
1170 static bool dead_statement_filter(statement s)
1171 {
1172  instruction i;
1173  bool retour;
1175  list crwl = effects_effects(crwe);
1176  transformer pre = get_statement_precondition(s);
1177 
1178  pips_assert("statement s is consistent", statement_consistent_p(s));
1179 
1181 
1182  i = statement_instruction(s);
1183  pips_debug(2, "Begin for statement %td (%td, %td)\n",
1184  statement_number(s),
1187  ifdebug(8)
1188  {
1189  sc_fprint(stderr,
1191  (char* (*)(Variable)) entity_local_name);
1192  }
1193 
1194  stdebug(9, "dead_statement_filter: The current statement", s);
1195 
1196  pips_assert("statement s is consistent", statement_consistent_p(s));
1197 
1198  /* Pour permettre un affichage du code de retour simple : */
1199  for(;;) {
1201  /* Well, it is likely some unreachable code that should be
1202  removed later by an unspaghettify: */
1203  pips_debug(2, "This statement is likely unreachable. Skip...\n");
1204  retour = false;
1205  break;
1206  }
1207 
1208  /* If a statement has no write effects on the store and if it
1209  cannot hides a control effect in a user-defined function*/
1210  if (ENDP(crwl) // No effects, store, declaration, type
1211  // Beware of Property MEMORY_EFFECTS_ONLY
1213  && !format_statement_p(s) // Fortran format
1214  && ! declaration_statement_p(s) // a declaration
1215  /*&& ENDP(statement_declarations(s))*/) { // sequence with
1216  // decl. only
1217  // possible impact:
1218  // stack space ovfl.
1219  pips_debug(2, "Ignored statement %td (%td, %td)\n",
1220  statement_number(s),
1223  retour = discard_statement_and_save_label_and_comment(s);
1224  dead_code_statement_removed++;
1225  break;
1226  }
1227 
1228  /* First remove (almost) all statements with an empty precondition */
1229  /* FI: This (very CPU expensive) test must be useless
1230  * because the control sequence
1231  * can only be broken by a test or by a loop or by a test in
1232  * an unstructured. These cases already are tested elsewhere.
1233  *
1234  * Furthermore, feasible statements take longer to test than
1235  * dead statement. And they are the majority in a normal piece
1236  * of code.
1237  *
1238  * But STOP, exit(), abort() statements, guarded or not by tests,
1239  * hidden or not by function calls, can also introduce
1240  * discontinuities... Well, to please Ronan let's put a fast
1241  * accurate enough test for that last case.
1242  *
1243  * This can also happen when a function is never called, but
1244  * analyzed interprocedurally.
1245  */
1246  if (get_statement_precondition==load_statement_precondition
1247  && !statement_weakly_feasible_p(s)) {
1248  pips_debug(2, "Dead statement %td (%td, %td)\n",
1249  statement_number(s),
1252  retour = discard_statement_and_save_label_and_comment(s);
1253  dead_code_statement_removed++;
1254  break;
1255  }
1256 
1257  if (instruction_sequence_p(i)
1258  && get_statement_precondition==load_statement_precondition
1259  && !statement_feasible_p(s)) {
1260  pips_debug(2, "Dead sequence statement %td (%td, %td)\n",
1261  statement_number(s),
1264  retour = discard_statement_and_save_label_and_comment(s);
1265  dead_code_statement_removed++;
1266  break;
1267  }
1268 
1269  if (instruction_loop_p(i)) {
1270  loop l = instruction_loop(i);
1271  if (dead_loop_p(l)) {
1272  pips_debug(2, "Dead loop %s at statement %td (%td, %td)\n",
1274  statement_number(s),
1277 
1278  retour = remove_dead_loop(s, i, l);
1279  dead_code_loop_removed++;
1280  break;
1281  }
1282  else if (loop_executed_once_p(s, l)) {
1283  /* This piece of code is not ready yet */
1284  statement body = loop_body(l);
1285  ifdebug(2) {
1286  pips_debug(2,
1287  "loop %s at %td (%td, %td) executed once and only once\n",
1289  statement_number(s),
1292 
1293  stdebug(9, "dead_statement_filter", s);
1294  }
1295 
1296  remove_loop_statement(s, i, l);
1297  dead_code_loop_executed_once++;
1298  stdebug(9, "dead_statement_filter: out remove_loop_statement", s);
1299 
1300  suppress_dead_code_statement(body);
1301  retour = false;
1302  break;
1303  }
1304  else {
1305  /* Standard loop, proceed downwards */
1306  retour = true;
1307  break;
1308  }
1309  }
1310 
1311  /* FI: nothing for while loops, repeat loops and for loops;
1312  should always entered while loops be converted into repeat
1313  loops? Should while loop body postcondition be used to transform
1314  a while loop into a test? */
1315 
1316  if (instruction_test_p(i)) {
1317  test t = instruction_test(i);
1318  expression c = test_condition(t);
1320  retour = dead_deal_with_test(s, t);
1321  break;
1322  }
1323 
1324  if (instruction_unstructured_p(i)) {
1325  /* Special case for unstructured: */
1326  pips_assert("the instruction is consistent", instruction_consistent_p(i));
1327  dead_recurse_unstructured(instruction_unstructured(i));
1328  pips_assert("the instruction is consistent", instruction_consistent_p(i));
1329 
1330  /* Stop going down since it has just been done in
1331  * dead_recurse_unstructured():
1332  */
1333  retour = false;
1334  break;
1335  }
1336 
1337  /* To deal with C conditional operator, at least, at the top
1338  level in the statement, i.e. no recursive descent in the call
1339  or the expression */
1340  if(instruction_call_p(i)) {
1341  call c = instruction_call(i);
1342  entity op = call_function(c);
1343  if(ENTITY_CONDITIONAL_P(op)) {
1344  list args = call_arguments(c);
1345  expression bool_exp = EXPRESSION(CAR(args));
1346  (void) simplify_boolean_expression_with_precondition(bool_exp, pre);
1347  if(true_expression_p(bool_exp)) {
1348  expression e1 = EXPRESSION(CAR(CDR(args)));
1351  free_call(c);
1352  // Not really removed, just simplified...
1353  dead_code_statement_removed++;
1354  }
1355  else if(false_expression_p(bool_exp)) {
1356  expression e2 = EXPRESSION(CAR(CDR(CDR(args))));
1359  free_call(c);
1360  dead_code_statement_removed++;
1361  }
1362  }
1363  /* FI: no need to set retour nor to break*/
1364  }
1365 
1366  /* Well, else we are going on the inspection... */
1367  retour = true;
1368  break;
1369  }
1370 
1371  pips_assert("statement s is consistent before rewrite",
1373 
1374  if (retour == false) {
1375  /* Try to rewrite the code underneath. Useful for tests with
1376  * two empty branches
1377  */
1378  dead_statement_rewrite(s);
1379  }
1380 
1381  pips_debug(2, "End for statement %td (%td, %td): %s going down\n",
1382  statement_number(s),
1385  retour? "" : "not");
1386 
1387  pips_assert("statement s is consistent at the end",
1389  (void) pop_statement_global_stack();
1390 
1391  return retour;
1392 }
1393 
1394 /* Suppress the dead code of the given module: */
1395 static void suppress_dead_code_statement(statement mod_stmt)
1396 {
1397  pips_assert("statement d is consistent", statement_consistent_p(mod_stmt));
1398 
1399  // ??? FC: called twice?
1400  dead_statement_filter(mod_stmt);
1401 
1402  gen_recurse(mod_stmt,
1403  statement_domain, dead_statement_filter, dead_statement_rewrite);
1404 
1405  // idem?
1406  dead_statement_rewrite(mod_stmt);
1407 
1408  pips_assert("statement d is consistent", statement_consistent_p(mod_stmt));
1409 }
1410 
1411 static bool remove_useless_label_internal(statement);
1412 
1413 /*
1414  * Simply Control
1415  */
1416 static bool generic_simplify_control(
1417  const string mod_name, bool use_precondition_p)
1418 {
1419  statement mod_stmt;
1420 
1421  if(compilation_unit_p(mod_name)) {
1422  // bad idea to run simplify control on compilation unit
1423  pips_user_warning("Simplify control isn't intended to run on compilation"
1424  " unit ! Abort...");
1425  return false;
1426  }
1427 
1428  /* Get the true ressource, not a copy. */
1429  mod_stmt = (statement) db_get_memory_resource(DBR_CODE, mod_name, true);
1430 
1431  set_current_module_statement(mod_stmt);
1432  // To improve the information in warning messages
1434 
1436 
1437  /* FI: RK used a false for db_get, i.e. an impur db_get...
1438  * I do not know why
1439  */
1441  db_get_memory_resource(DBR_PROPER_EFFECTS, mod_name, true));
1442 
1443  if (use_precondition_p) {
1444  // Transformers are useful to derive preconditions for control points
1445  // where they are not stored, e.g. end of body in until loops
1447  db_get_memory_resource(DBR_TRANSFORMERS, mod_name, true));
1449  db_get_memory_resource(DBR_PRECONDITIONS, mod_name, true));
1450  }
1451 
1453  db_get_memory_resource(DBR_CUMULATED_EFFECTS, mod_name, true));
1454 
1455  debug_on("SIMPLIFY_CONTROL_DEBUG_LEVEL");
1456 
1457  ifdebug(1) {
1458  pips_debug(1, "Begin for %s\n", mod_name);
1459  pips_assert("Statements inconsistants...",
1460  statement_consistent_p(mod_stmt));
1461  }
1462 
1463  // Necessary because of simplify_boolean_expression_with_precondition()
1465  initialize_dead_code_statistics();
1466  some_unstructured_ifs_have_been_changed = false;
1467 
1468  // do the job
1469  suppress_dead_code_statement(mod_stmt);
1470 
1473 
1474  display_dead_code_statistics();
1477 
1478  debug_off();
1479 
1480  // Reorder the module, because new statements have been generated
1481  module_reorder(mod_stmt);
1482 
1483  DB_PUT_MEMORY_RESOURCE(DBR_CODE, mod_name, mod_stmt);
1484  DB_PUT_MEMORY_RESOURCE(DBR_CALLEES, mod_name,
1485  (char *) compute_callees(mod_stmt));
1486 
1490  if(use_precondition_p) {
1493  }
1495 
1496  pips_debug(1, "End for %s\n", mod_name);
1497 
1498  if (some_unstructured_ifs_have_been_changed)
1499  // Now call the unspaghettify() function to remove some unreachable
1500  // code after unstructured "if" elimination:
1501  unspaghettify(mod_name);
1502 
1503  remove_useless_label(mod_name);
1504 
1505  ifdebug(1)
1506  pips_assert("statement is still consistent...",
1507  statement_consistent_p(mod_stmt));
1508 
1509  return true;
1510 }
1511 
1512 /* Use preconditions to simplify control */
1513 bool simplify_control(const string mod_name)
1514 {
1515  get_statement_precondition = load_statement_precondition;
1516  return generic_simplify_control(mod_name, true);
1517 }
1518 
1519 static transformer
1520 load_identity_precondition(_UNUSED_ statement s)
1521 {
1522  static transformer id = transformer_undefined;
1523  if (transformer_undefined_p(id))
1524  id = transformer_identity();
1525  return id;
1526 }
1527 
1528 /* Do not use preconditions, only constant expressions */
1529 bool simplify_control_directly(const string mod_name)
1530 {
1531  get_statement_precondition = load_identity_precondition;
1532  return generic_simplify_control(mod_name, false);
1533 }
1534 
1535 /*
1536  * Simply Control old alias
1537  */
1538 bool suppress_dead_code(const string mod_name)
1539 {
1541  "This phase has been renamed, please use 'simplify_control'"
1542  " from now. The old alias 'suppress_dead_code' might be removed soon.\n" );
1543  return simplify_control(mod_name);
1544 }
1545 
1546 static bool remove_useless_label_internal(statement s)
1547 {
1548  bool changed = false;
1549 
1550  gen_context_recurse(s, &changed,
1552 
1553  // could skip if unchanged?
1554  changed |= clean_up_sequences(s);
1555 
1556  // idem?
1557  changed |= module_reorder(s);
1558 
1559  return changed;
1560 }
1561 
1562 /**
1563  * recursively remove all labels from a module
1564  * only labels in unstructured are kept
1565  * @param module_name module considered
1566  *
1567  * @return true (never fails)
1568  */
1569 bool remove_useless_label(const string module_name)
1570 {
1571  /* Get the module ressource */
1574  (statement) db_get_memory_resource(DBR_CODE, module_name, true);
1575 
1578 
1579  bool changed = remove_useless_label_internal(module_statement);
1580 
1581  if (changed)
1583 
1586 
1587  return true;
1588 }
1589 
1590 #endif // BUILDER_ * 4
void user_log(const char *format,...)
Definition: message.c:234
void free_transformer(transformer p)
Definition: ri.c:2616
bool instruction_consistent_p(instruction p)
Definition: ri.c:1124
bool unstructured_consistent_p(unstructured p)
Definition: ri.c:2751
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
bool statement_consistent_p(statement p)
Definition: ri.c:2195
void free_instruction(instruction p)
Definition: ri.c:1118
void free_call(call p)
Definition: ri.c:236
void free_statement(statement p)
Definition: ri.c:2189
static statement module_statement
Definition: alias_check.c:125
#define CATCH(what)
@ overflow_error
#define UNCATCH(what)
#define TRY
#define VALUE_ONE
transformer transformer_dup(transformer t_in)
transformer package - basic routines
Definition: basic.c:49
transformer transformer_identity()
Allocate an identity transformer.
Definition: basic.c:110
callees compute_callees(const statement stat)
Recompute the callees of a module statement.
Definition: callgraph.c:355
bool clean_up_sequences_internal(statement s)
An entry point for internal usage, such as from take_out_the_exit_node_if_not_a_continue():
void initialize_clean_up_sequences_statistics(void)
bool clean_up_sequences(statement s)
Recursively clean up the statement sequences by fusing them if possible and by removing useless one.
void display_clean_up_sequences_statistics(void)
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
entity int_to_entity(_int c)
Definition: constant.c:453
Pcontrainte contrainte_make(Pvecteur pv)
Pcontrainte contrainte_make(Pvecteur pv): allocation et initialisation d'une contrainte avec un vecte...
Definition: alloc.c:73
Pcontrainte contrainte_free(Pcontrainte c)
Pcontrainte contrainte_free(Pcontrainte c): liberation de l'espace memoire alloue a la contrainte c a...
Definition: alloc.c:184
bool unspaghettify(const string)
Try to simplify the control graph of a module by removing useless CONTINUEs, unreachable code.
list load_proper_rw_effects_list(statement)
void reset_proper_rw_effects(void)
void set_proper_rw_effects(statement_effects)
void set_cumulated_rw_effects(statement_effects)
void store_cumulated_rw_effects_list(statement, list)
list load_cumulated_rw_effects_list(statement)
effects load_cumulated_rw_effects(statement)
void reset_cumulated_rw_effects(void)
bool expression_with_side_effect_p(expression)
#define effect_action(x)
Definition: effects.h:642
#define action_write_p(x)
Definition: effects.h:314
#define effects_effects(x)
Definition: effects.h:710
bool compilation_unit_p(const char *module_name)
The names of PIPS entities carry information about their nature.
Definition: entity_names.c:56
const char * module_name(const char *s)
Return the module part of an entity name.
Definition: entity_names.c:296
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
#define gen_context_recurse(start, ctxt, domain_number, flt, rwt)
Definition: genC.h:285
#define gen_recurse(start, domain_number, flt, rwt)
Definition: genC.h:283
if(!(yy_init))
Definition: genread_lex.c:1029
void free(void *)
statement instruction_to_statement(instruction)
Build a statement from a give instruction.
Definition: statement.c:597
void control_map_get_blocs(control c, list *l)
Build recursively the list of all controls reachable from a control of an unstructured.
Definition: control.c:75
void reset_current_module_entity(void)
Reset the current module entity.
Definition: static.c:97
void reset_current_module_statement(void)
Reset the current module statement.
Definition: static.c:221
statement set_current_module_statement(statement)
Set the current module statement.
Definition: static.c:165
entity set_current_module_entity(entity)
static.c
Definition: static.c:66
entity get_current_module_entity(void)
Get the entity of the current module.
Definition: static.c:85
void replace_entity(void *s, entity old, entity new)
per variable version of replace_entities.
Definition: replace.c:113
bool gen_true2(__attribute__((unused)) gen_chunk *u1, __attribute__((unused)) void *u2)
Definition: genClib.c:2785
instruction make_instruction_block(list statements)
Build an instruction block from a list of statements.
Definition: instruction.c:106
instruction make_continue_instruction()
Creates a CONTINUE instruction, that is the FORTRAN nop, the ";" in C or the "pass" in Python for exa...
Definition: instruction.c:79
instruction make_assign_instruction(expression l, expression r)
Definition: instruction.c:87
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
void gen_remove_once(list *pl, const void *o)
Remove the first occurence of o in list pl:
Definition: list.c:691
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
size_t gen_length(const list l)
Definition: list.c:150
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
list gen_nconc(list cp1, list cp2)
physically concatenates CP1 and CP2 but do not duplicates the elements
Definition: list.c:344
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
void gen_free_list(list l)
free the spine of the list
Definition: list.c:327
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
#define CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
list gen_full_copy_list(list l)
Copy a list structure with element copy.
Definition: list.c:535
string db_get_memory_resource(const char *rname, const char *oname, bool pure)
Return the pointer to the resource, whatever it is.
Definition: database.c:755
#define DB_PUT_MEMORY_RESOURCE(res_name, own_name, res_val)
conform to old interface.
Definition: pipsdbm-local.h:66
list statement_block(statement)
Get the list of block statements of a statement sequence.
Definition: statement.c:1338
bool empty_statement_or_continue_p(statement)
Return true if the statement is an empty instruction block or a continue or a recursive combination o...
Definition: statement.c:474
bool statement_loop_p(statement)
Definition: statement.c:349
bool format_statement_p(statement)
Test if a statement is a Fortran FORMAT.
Definition: statement.c:273
statement make_assign_statement(expression, expression)
Definition: statement.c:583
void insert_comments_to_statement(statement, const char *)
Insert a comment string (if non empty) at the beginning of the comments of a statement.
Definition: statement.c:1916
bool statement_may_have_control_effects_p(statement)
Definition: statement.c:3978
list statement_to_direct_declarations(statement)
Returns the declarations contained directly in a statement s.
Definition: statement.c:3366
statement make_continue_statement(entity)
Definition: statement.c:953
bool empty_comments_p(const char *)
Definition: statement.c:107
void fix_sequence_statement_attributes(statement)
Since blocks are not represented in Fortran, they cannot carry a label.
Definition: statement.c:2016
bool declaration_statement_p(statement)
Had to be optimized according to Beatrice Creusillet.
Definition: statement.c:224
entity find_final_statement_label(statement)
Find the label associated with the last statement executed within s.
Definition: statement.c:4360
void statement_remove_useless_label(statement, bool *)
remove the label of a statement if the statement is not unstructured.
Definition: statement.c:4275
#define debug_on(env)
Definition: misc-local.h:157
#define _UNUSED_
Definition: misc-local.h:232
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_user_warning
Definition: misc-local.h:146
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define pips_internal_error
Definition: misc-local.h:149
#define debug_off()
Definition: misc-local.h:160
#define STATEMENT_ORDERING_UNDEFINED
mapping.h inclusion
Definition: newgen-local.h:35
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
int tag
TAG.
Definition: newgen_types.h:92
#define true
Definition: newgen_types.h:81
#define false
Definition: newgen_types.h:80
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
static char * module
Definition: pips.c:74
void print_statement(statement)
Print a statement on stderr.
Definition: statement.c:98
void insure_return_as_last_statement(entity, statement *)
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define PLUS_OPERATOR_NAME
#define ORDERING_NUMBER(o)
#define ORDERING_STATEMENT(o)
#define NORMALIZE_EXPRESSION(e)
#define statement_block_p(stat)
#define ENTITY_CONDITIONAL_P(e)
#define unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
#define instruction_block(i)
#define make_statement_list(stats...)
easy list constructor
#define empty_comments
Empty comments (i.e.
#define ENTITY_FALSE_P(e)
#define ENTITY_ZERO_P(e)
#define make_empty_statement
An alias for make_empty_block_statement.
const char * entity_local_name(entity e)
entity_local_name modified so that it does not core when used in vect_fprint, since someone thought t...
Definition: entity.c:453
bool c_module_p(entity m)
Test if a module "m" is written in C.
Definition: entity.c:2777
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
entity entity_empty_label(void)
Definition: entity.c:1105
bool entity_empty_label_p(entity e)
Definition: entity.c:666
entity entity_intrinsic(const char *name)
FI: I do not understand this function name (see next one!).
Definition: entity.c:1292
const char * label_local_name(entity e)
END_EOLE.
Definition: entity.c:604
bool range_count(range r, intptr_t *pcount)
The range count only can be evaluated if the three range expressions are constant and if the incremen...
Definition: eval.c:979
bool false_expression_p(expression e)
Definition: expression.c:1118
bool expression_integer_constant_p(expression e)
Definition: expression.c:2417
bool expression_call_p(expression e)
Definition: expression.c:415
int expression_to_int(expression exp)
================================================================
Definition: expression.c:2205
bool true_expression_p(expression e)
Definition: expression.c:1113
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
expression make_factor_expression(int coeff, entity vari)
Some functions to generate expressions from vectors and constraint systems.
Definition: expression.c:1631
expression MakeBinaryCall(entity f, expression eg, expression ed)
Creates a call expression to a function with 2 arguments.
Definition: expression.c:354
bool expression_equal_p(expression e1, expression e2)
Syntactic equality e1==e2.
Definition: expression.c:1347
call expression_call(expression e)
Definition: expression.c:445
bool expression_reference_p(expression e)
Test if an expression is a reference.
Definition: expression.c:528
reference expression_reference(expression e)
Short cut, meaningful only if expression_reference_p(e) holds.
Definition: expression.c:1832
basic MakeBasic(int)
END_EOLE.
Definition: type.c:128
bool entity_scalar_p(entity)
The concrete type of e is a scalar type.
Definition: variable.c:1113
entity make_new_scalar_variable(entity, basic)
Definition: variable.c:741
statement pop_statement_global_stack(void)
Definition: static.c:352
void push_statement_on_statement_global_stack(statement)
Definition: static.c:333
void free_statement_global_stack(void)
Definition: static.c:358
void make_statement_global_stack(void)
Definition: static.c:318
#define loop_body(x)
Definition: ri.h:1644
@ is_basic_logical
Definition: ri.h:573
#define transformer_undefined
Definition: ri.h:2847
#define transformer_undefined_p(x)
Definition: ri.h:2848
#define instruction_sequence_p(x)
Definition: ri.h:1512
#define normalized_linear_p(x)
Definition: ri.h:1779
#define instruction_loop_p(x)
Definition: ri.h:1518
#define call_function(x)
Definition: ri.h:709
#define reference_variable(x)
Definition: ri.h:2326
#define control_predecessors(x)
Definition: ri.h:943
#define range_upper(x)
Definition: ri.h:2290
#define instruction_loop(x)
Definition: ri.h:1520
#define statement_ordering(x)
Definition: ri.h:2454
#define test_false(x)
Definition: ri.h:2837
#define whileloop_evaluation(x)
Definition: ri.h:3166
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define CONTROL(x)
CONTROL.
Definition: ri.h:910
#define range_increment(x)
Definition: ri.h:2292
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define instruction_undefined
Definition: ri.h:1454
#define statement_label(x)
Definition: ri.h:2450
#define expression_undefined
Definition: ri.h:1223
@ is_instruction_unstructured
Definition: ri.h:1475
@ is_instruction_whileloop
Definition: ri.h:1472
@ is_instruction_expression
Definition: ri.h:1478
@ is_instruction_test
Definition: ri.h:1470
@ is_instruction_call
Definition: ri.h:1474
@ is_instruction_sequence
Definition: ri.h:1469
@ is_instruction_forloop
Definition: ri.h:1477
@ is_instruction_loop
Definition: ri.h:1471
#define instruction_tag(x)
Definition: ri.h:1511
#define transformer_relation(x)
Definition: ri.h:2873
#define test_true(x)
Definition: ri.h:2835
#define control_successors(x)
Definition: ri.h:945
#define loop_label(x)
Definition: ri.h:1646
#define instruction_unstructured_p(x)
Definition: ri.h:1530
#define instruction_call_p(x)
Definition: ri.h:1527
#define instruction_expression(x)
Definition: ri.h:1541
#define test_condition(x)
Definition: ri.h:2833
#define instruction_whileloop(x)
Definition: ri.h:1523
#define range_lower(x)
Definition: ri.h:2288
#define whileloop_body(x)
Definition: ri.h:3162
#define statement_declarations(x)
Definition: ri.h:2460
#define statement_instruction(x)
Definition: ri.h:2458
#define statement_comments(x)
Definition: ri.h:2456
#define instruction_call(x)
Definition: ri.h:1529
#define loop_range(x)
Definition: ri.h:1642
struct _newgen_struct_transformer_ * transformer
Definition: ri.h:431
#define instruction_test_p(x)
Definition: ri.h:1515
#define call_arguments(x)
Definition: ri.h:711
#define control_statement(x)
Definition: ri.h:941
#define instruction_test(x)
Definition: ri.h:1517
#define whileloop_condition(x)
Definition: ri.h:3160
#define evaluation_after_p(x)
Definition: ri.h:1162
#define statement_number(x)
Definition: ri.h:2452
#define normalized_linear(x)
Definition: ri.h:1781
#define predicate_system(x)
Definition: ri.h:2069
#define instruction_unstructured(x)
Definition: ri.h:1532
#define loop_index(x)
Definition: ri.h:1640
#define statement_undefined
Definition: ri.h:2419
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
void sc_rm(Psysteme ps)
void sc_rm(Psysteme ps): liberation de l'espace memoire occupe par le systeme de contraintes ps;
Definition: sc_alloc.c:277
Psysteme sc_dup(Psysteme ps)
Psysteme sc_dup(Psysteme ps): should becomes a link.
Definition: sc_alloc.c:176
bool ineq_redund_with_sc_p(Psysteme sc, Pcontrainte ineq)
This function returns true if the inequation ineq is redundant for the system ps and false otherwise.
bool eq_redund_with_sc_p(Psysteme sc, Pcontrainte eq)
bool eq_redund_with_sc_p(sc, eq) Psysteme sc; Pcontrainte eq;
bool sc_rational_feasibility_ofl_ctrl(Psysteme sc, int ofl_ctrl, bool ofl_res)
Pcontrainte eq
element du vecteur colonne du systeme donne par l'analyse
Definition: sc_gram.c:108
void sc_fprint(FILE *fp, Psysteme ps, get_variable_name_t nom_var)
void sc_fprint(FILE * f, Psysteme ps, char * (*nom_var)()): cette fonction imprime dans le fichier po...
Definition: sc_io.c:220
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
char * strdup()
void vect_chg_sgn(Pvecteur v)
void vect_chg_sgn(Pvecteur v): multiplie v par -1
Definition: scalaires.c:151
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
int simplify_boolean_expression_with_precondition(expression e, transformer p)
Simplification of bool expressions with precondition.
Definition: expression.c:6080
transformer condition_to_transformer(expression cond, transformer pre, bool veracity)
To capture side effects and to add C twist for numerical conditions.
Definition: expression.c:5348
void module_to_value_mappings(entity m)
void module_to_value_mappings(entity m): build hash tables between variables and values (old,...
Definition: mappings.c:624
bool statement_weakly_feasible_p(statement)
utils.c
Definition: utils.c:72
bool statement_strongly_feasible_p(statement)
Return true if statement s is reachable according to its precondition.
Definition: utils.c:99
transformer load_statement_precondition(statement)
void set_transformer_map(statement_mapping)
transformer load_statement_transformer(statement)
void reset_precondition_map(void)
void set_precondition_map(statement_mapping)
void reset_transformer_map(void)
bool statement_feasible_p(statement)
Return true if statement s is reachable according to its precondition.
Definition: utils.c:92
return(s1)
#define ifdebug(n)
Definition: sg.c:47
#define intptr_t
Definition: stdint.in.h:294
le type des coefficients dans les vecteurs: Value est defini dans le package arithmetique
Definition: vecteur-local.h:89
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
Definition: statement.c:54
struct block block
dead_test
What is returned by dead_test_filter :
@ else_is_dead
@ then_is_dead
@ nothing_about_test
bool remove_useless_label(const string)
bool simplify_control(const string)
simplify_control.c
bool simplify_control_directly(const string)
bool suppress_dead_code(const string)
bool transformer_empty_p(transformer t)
If true is returned, the transformer certainly is empty.
Definition: transformer.c:2455
transformer transformer_apply(transformer tf, transformer pre)
transformer transformer_apply(transformer tf, transformer pre): apply transformer tf on precondition ...
Definition: transformer.c:1559
void free_value_mappings(void)
Normal call to free the mappings.
Definition: value.c:1212
#define TCST
VARIABLE REPRESENTANT LE TERME CONSTANT.
void * Variable
arithmetique is a requirement for vecteur, but I do not want to inforce it in all pips files....
Definition: vecteur-local.h:60
#define FWD_OFL_CTRL
Pvecteur vect_dup(Pvecteur v_in)
Pvecteur vect_dup(Pvecteur v_in): duplication du vecteur v_in; allocation de et copie dans v_out;.
Definition: alloc.c:51
Pvecteur vect_add(Pvecteur v1, Pvecteur v2)
package vecteur - operations binaires
Definition: binaires.c:53
Pvecteur vect_substract(Pvecteur v1, Pvecteur v2)
Pvecteur vect_substract(Pvecteur v1, Pvecteur v2): allocation d'un vecteur v dont la valeur est la di...
Definition: binaires.c:75
void vect_add_elem(Pvecteur *pvect, Variable var, Value val)
void vect_add_elem(Pvecteur * pvect, Variable var, Value val): addition d'un vecteur colineaire au ve...
Definition: unaires.c:72