PIPS
dead_code_elimination.c
Go to the documentation of this file.
1 /*
2 
3  $Id: dead_code_elimination.c 23495 2018-10-24 09:19:47Z 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 
25 // do not compile unless required
26 #include "phases.h"
27 #if defined(BUILDER_DEAD_CODE_ELIMINATION) || \
28  defined(BUILDER_DEAD_CODE_ELIMINATION_WITH_OUT_REGIONS)
29 
30 #ifdef HAVE_CONFIG_H
31 #include "pips_config.h"
32 #endif
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "genC.h"
39 #include "linear.h"
40 
41 #include "misc.h"
42 #include "pipsdbm.h"
43 #include "properties.h"
44 
45 #include "ri.h"
46 #include "effects.h"
47 #include "ri-util.h"
48 #include "prettyprint.h"
49 #include "effects-util.h"
50 
51 #include "text-util.h"
52 
53 #include "control.h" // module_reorder
54 
55 #include "semantics.h" // used: set and reset_precondition_map()
56 #include "effects-generic.h" // used
57 #include "effects-simple.h" // used
58 #include "callgraph.h" // used
59 
60 #include "dg.h"
61 // Instantiation of the dependence graph:
62 typedef dg_arc_label arc_label;
64 #include "graph.h"
65 
66 #include "ricedg.h" // used
67 
68 // for module_clean_declarations
69 // and loop_bound_minimization_with_out_regions_on_statement
70 #include "transformations.h"
71 
72 static graph dependence_graph;
73 
74 static hash_table ordering_to_dg_mapping;
75 
76 static set the_useful_statements;
77 
78 /* Define the mapping to store the statements generating something
79  useful for a given statement and the functions used to deal
80  with. It is a mapping from a statement to a *set* of statements,
81  those that generate interesting use-def values.*/
82 static hash_table statements_use_def_dependence;
83 
84 
85 /* Define a static stack and related functions to remember the current
86  statement for build_statement_to_statement_father_mapping(): */
88 
89 
90 /*
91  * A string list of user functions that we want to preserve from elimination
92  */
93 static list keeped_functions = 0;
94 
95 /*
96  * A string list of user functions prefix that we want to preserve from elimination
97  */
98 static list keeped_functions_prefix = 0;
99 
100 
101 static void dead_code_elimination_error_handler(void)
102 {
103  error_reset_current_statement_stack();
104 }
105 
106 /* Define the mapping to store the statement owning the statements and the
107  functions used to deal with: */
109 
110 
111 static void
112 add_statement_to_the_statement_to_statement_father_mapping(statement s)
113 {
114  /* Pop the current_statement_stack: */
115  current_statement_rewrite(s);
116 
117  pips_debug(4, "add_statement_to_the_statement_to_statement_father_mapping statement %p (%#zx), father %p\n",
118  s, statement_ordering(s), current_statement_head());
119 
120  /* First add the current father for this statement: */
121  /* Since statement_undefined == hash_undefined_value, we cannot put
122  a statement_undefined in the hash_table... */
123  if (current_statement_head() != statement_undefined)
124  store_statement_father(s, current_statement_head());
125 }
126 
127 
128 /* Define the mapping to store the control fathers of the statements
129  and the functions used to deal with: */
131 
132 
133 /* Build a mapping from a statement to its eventual control father. */
134 static void
135 set_control_statement_father(control c)
136 {
137  store_control_father(control_statement(c), c);
138 }
139 
140 
141 static void
142 build_statement_to_statement_father_mapping(statement s)
143 {
144  pips_debug(4, "statement %p (%#zx)\n", s, statement_ordering(s));
145 
146  make_current_statement_stack();
147  // The first statement has no father:
148  current_statement_push(statement_undefined);
149 
151  // Just push the current statement on the current_statement_stack:
152  current_statement_filter,
153  add_statement_to_the_statement_to_statement_father_mapping,
154  // Build a mapping from a statement to its eventual control father.
155  control_domain, gen_true, set_control_statement_father,
156  NULL);
157 
158  free_current_statement_stack();
159 }
160 
161 
162 /* Build the mapping from each statement to the statements generating
163  something useful for it: */
164 static void
165 build_statement_to_statement_dependence_mapping(graph dependence_graph)
166 {
167  statements_use_def_dependence = hash_table_make(hash_pointer, 0);
168 
170  {
171  statement s1 = vertex_to_statement(a_vertex);
172 
173  pips_debug(7, "build_statement_to_statement_dependence_mapping"
174  "\tSuccessor list: %p for statement ordering %p\n",
175  vertex_successors(a_vertex),
177 
178  FOREACH(successor, a_successor, vertex_successors(a_vertex))
179  {
180  vertex v2 = successor_vertex(a_successor);
182  dg_arc_label an_arc_label = successor_arc_label(a_successor);
183  pips_debug(7, "\t%p (%#zx) --> %p (%#zx) with conflicts\n",
185  s2, statement_ordering(s2));
186  // Try to find at least one of the use-def chains
187  // between s and a successor:
188  FOREACH(conflict, a_conflict, dg_arc_label_conflicts(an_arc_label))
189  {
190  statement use, def;
191 
192  ifdebug(7)
193  {
194  fprintf(stderr, "\t\tfrom ");
195  print_words(stderr, words_effect(conflict_source(a_conflict)));
196  fprintf(stderr, " to ");
197  print_words(stderr, words_effect(conflict_sink(a_conflict)));
198  fprintf(stderr, "\n");
199  }
200 
201  // Something is useful for the current statement
202  // if it writes something that is used in the current statement:
204  && action_read_p(effect_action(conflict_sink(a_conflict)))) {
205  def = s1;
206  use = s2;
207  // Mark that we will visit the node that defined a
208  // source for this statement, if not already visited:
209  set statements_set =
210  (set) hash_get(statements_use_def_dependence, (void *) use);
211 
212  if (statements_set == (set) HASH_UNDEFINED_VALUE) {
213  // It is the first dependence we found for s1. Create the set:
214  statements_set = set_make(set_pointer);
215  hash_put(statements_use_def_dependence,
216  (void *) use, (void *) statements_set);
217  }
218 
219  // Mark the fact that s2 create something useful for s1:
220  set_add_element(statements_set, statements_set, (void *) def);
221 
222  ifdebug(6)
223  fprintf(stderr, "\tUse: statement %p (%#zx). "
224  "Def: statement %p (%#zx).\n",
225  use, statement_ordering(use),
226  def, statement_ordering(def));
227  // One use-def is enough for this variable couple:
228  break;
229  }
230  }
231  }
232  }
233 }
234 
235 
236 static void
237 free_statement_to_statement_dependence_mapping()
238 {
239  HASH_MAP(key, value,
240  {
241  set_free((set) value);
242  },
243  statements_use_def_dependence);
244 }
245 
246 /* unused */
247 #if 0
248 static void
249 mark_this_node_and_its_predecessors_in_the_dg_as_useful(set s,
250  vertex v)
251 {
252  if (set_belong_p(s, (char *) v))
253  /* We have already seen this node: */
254  return;
255 
256  /* Mark the current vertex as useful: */
257  set_add_element(s, s, (char *) v);
258 
259  pips_debug(6, "mark_this_node_and_its_predecessors_in_the_dg_as_useful: vertex %p marked, statement ordering (%#x).\n",
260  v,
261  dg_vertex_label_statement(vertex_vertex_label(v)));
262 
263  MAP(SUCCESSOR, a_successor,
264  {
265  dg_arc_label label = successor_arc_label(a_successor);
266  /* Try to find at least one use-def chain: */
267  MAP(CONFLICT, a_conflict,
268  {
269  /* Something is useful for the current statement if
270  it writes something that is used in the current
271  statement: */
272  if (effect_read_p(conflict_source(a_conflict))
273  && effect_write_p(conflict_sink(a_conflict))) {
274  /* Mark the node that generate something useful
275  for the current statement as useful: */
276  mark_this_node_and_its_predecessors_in_the_dg_as_useful(s,
277  successor_vertex(a_successor));
278  /* Only needed to mark once: */
279  break;
280  }
281  },
282  dg_arc_label_conflicts(label));
283  },
284  vertex_successors(v));
285 }
286 #endif
287 
288 
289 static void
290 iterate_through_the_predecessor_graph(statement s,
291  set elements_to_visit)
292 {
293  pips_debug(6, "iterate_through_the_predecessor_graph, statement %p (%#zx).\n",
294  s, statement_ordering(s));
295 
296  /* Mark the current statement as useful: */
297  set_add_element(the_useful_statements, the_useful_statements, (char *) s);
298 
299  /* First mark the dependence graph predecessors: */
300  {
301  set statements_set = (set) hash_get(statements_use_def_dependence,
302  (char *) s);
303  if (statements_set != (set) HASH_UNDEFINED_VALUE) {
304  /* There is at least one statement that generates something
305  useful for s: */
306  SET_MAP(element,
307  {
308  statement s2 = (statement) element;
309 
310  /* Mark that we will visit the node that defined a
311  source for this statement, if not already
312  visited: */
313  set_add_element(elements_to_visit,
314  elements_to_visit,
315  (char *) s2);
316  pips_debug(6, "\tstatement %p (%#zx) useful by use-def.\n",
317  s2, statement_ordering(s2));
318  },
319  statements_set);
320  }
321  }
322 
323  /* Mark the father too for control dependences: */
324  if (bound_statement_father_p(s)) {
325  statement father = load_statement_father(s);
326  set_add_element(elements_to_visit, elements_to_visit, (char *) father);
327  pips_debug(6, "\tstatement %p (%#zx) useful as the statement owner.\n",
328  father, statement_ordering(father));
329  }
330 
331  {
332  /* And if the statement is in an unstructured, mark all the
333  controlling unstructured nodes predecessors as useful, that
334  is all the unstructured IF back-reachable. */
335  if (bound_control_father_p(s)) {
336  list blocks = NIL;
337  control control_father = load_control_father(s);
338  BACKWARD_CONTROL_MAP(pred, {
339  if (gen_length(control_successors(pred)) == 2) {
340  /* pred is an unstructured IF that control control_father: */
341  set_add_element(elements_to_visit,
342  elements_to_visit,
343  (char *) control_statement(pred));
344  pips_debug(6, "\tstatement unstructed IF %p (%#zx) useful by control dependence.\n",
345  control_statement(pred), statement_ordering(control_statement(pred)));
346  }
347  }, control_father, blocks);
348  gen_free_list(blocks);
349  }
350  }
351 }
352 
353 
354 static void
355 propagate_the_usefulness_through_the_predecessor_graph()
356 {
357  pips_debug(5, "Entering propagate_the_usefulness_through_the_predecessor_graph\n");
358 
359  gen_set_closure((void (*)(void *, set)) iterate_through_the_predecessor_graph,
360  the_useful_statements);
361 
362  pips_debug(5, "Exiting propagate_the_usefulness_through_the_predecessor_graph\n");
363 }
364 
365 
366 
367 
368 static bool match_call_to_user_function(call c, bool *user_function_found) {
369  const char* match_name = entity_local_name(call_function(c));
370 
371  FOREACH(STRING, func, keeped_functions) {
372  if(strcmp(match_name,func)==0) {
373  *user_function_found = true;
374  }
375  }
376 
377  FOREACH(STRING, func_prefix, keeped_functions_prefix) {
378  if(strncmp(match_name,func_prefix,strlen(func_prefix))==0) {
379  *user_function_found = true;
380  }
381  }
382 
383 
384  return !user_function_found;
385 }
386 
387 static bool statement_call_a_keep_function_p( statement s ) {
388  bool user_function_found = false;
389  if(statement_call_p(s) || statement_expression_p(s)) {
390  gen_context_recurse(s,&user_function_found, call_domain, match_call_to_user_function, gen_null2);
391  }
392 
393  /* FIXME : LOOP header && so one... */
394 
395  return user_function_found;
396 }
397 
398 /* FI: not only if it is useful, but if it is legal... */
399 static void use_def_deal_if_useful(statement s) {
400  bool this_statement_has_an_io_effect;
401  /* When a call by reference is used... */
402  bool this_statement_writes_a_procedure_argument;
403  bool this_statement_is_a_format;
404  bool this_statement_is_an_unstructured_test = false;
405  /* FI: any statement that does not have a must/exact continuation
406  * should be preserved. For the time being, only exact
407  * non-continuing calls are checked: return, exit and abort. Since
408  * exceptions are not taken into account, the semantics of the code
409  * may be changed.
410  *
411  * Exact non-continuation can be checked with the statement
412  * transformer. beatrice Creusillet has also developped a
413  * continuation analysis.
414  */
415  bool this_statement_is_a_c_return;
416  bool outside_effect_p = false;
417  bool this_statement_call_a_user_function;
418 
419  ifdebug(5) {
420  int debugLevel = get_debug_level();
421  set_debug_level(0);
422  fprintf(stderr, "statement %p (%#zx)\n",
423  s, statement_ordering(s));
424  print_text(stderr, Text_Statement(get_current_module_entity(), 0, s));
425  set_debug_level(debugLevel);
426  }
427 
428  if (statement_ordering(s) == STATEMENT_ORDERING_UNDEFINED) {
429  pips_user_warning("exited since it found a statement without ordering: statement %p (%#x)\n", s, statement_ordering(s));
430  return;
431  }
432 
433  /* The possible reasons to have useful code: */
434  /* - the statement does an I/O: */
435  this_statement_has_an_io_effect = statement_io_effect_p(s);
436 
437  /* - the statement writes a procedure argument or the return
438  variable of the function, so the value may be used by another
439  procedure: */
440  /* Regions out should be more precise: */
441  this_statement_writes_a_procedure_argument =
442  statement_has_a_formal_argument_write_effect_p(s);
443 
444  /* Avoid to remove formats in a first approach: */
445  this_statement_is_a_format = instruction_format_p(statement_instruction(s));
446 
447  /* Unstructured tests are very hard to deal with since they can
448  have major control effects, such as leading to an infinite loop,
449  etc. and it is very hard to cope with... Thus, keep all
450  unstructured tests in this approach since I cannot prove the
451  termination of the program and so on. */
452  if (bound_control_father_p(s)) {
453  control control_father = load_control_father(s);
454  if (gen_length(control_successors(control_father)) == 2)
455  /* It is an unstructured test: keep it: */
456  this_statement_is_an_unstructured_test = true;
457  }
458 
459  /* All statements with control effects such as exit() or abort()
460  should be preserved. Continuations should be checked for
461  user-defined functions. Exceptions are also a problem. */
462  this_statement_is_a_c_return = return_statement_p(s)
463  || exit_statement_p(s) || abort_statement_p(s);
464 
465  /* Check if this statement write some other things than a local variable */
466  list effects_list = load_proper_rw_effects_list(s);
467  entity current_func = get_current_module_entity();
468  FOREACH(EFFECT, eff,effects_list) {
469  reference a_reference = effect_any_reference(eff);
470  entity touched = reference_variable(a_reference);
471  if(effect_write_p(eff)
472  && (!entity_local_variable_p(touched,current_func)
473  /* FI: we should also check that the static effect is
474  leaked by the function but this is hard to check and is
475  usually not intended by the programmer. See
476  Transformations/Dead_code_elimination.sub/use_def_elim07/08. */
477  || entity_static_variable_p(touched))) {
478  outside_effect_p = true;
479  pips_debug(7, "Statement %p, outside effect on %s (module %s)\n",
480  s,
481  entity_name(touched),
482  entity_local_name(current_func));
483  break;
484  }
485  }
486 
487  this_statement_call_a_user_function = statement_call_a_keep_function_p(s);
488 
489  ifdebug(6) {
490  pips_debug(6, "Statement %p:\n%s\n Statement number: %" _intFMT "\n", s,
491  text_to_string(statement_to_text(s)), statement_number(s));
492  if (outside_effect_p)
493  pips_debug(6, "Statement %p has an outside effect.\n", s);
494  if (this_statement_has_an_io_effect)
495  pips_debug(6, "Statement %p has an io effect.\n", s);
496  if (this_statement_writes_a_procedure_argument)
497  pips_debug(6,"Statement %p writes an argument of its procedure.\n", s);
498  if (this_statement_is_a_format)
499  pips_debug(6, "Statement %p is a FORMAT.\n", s);
500  if (this_statement_is_an_unstructured_test)
501  pips_debug(6, "Statement %p is an unstructured test.\n", s);
502  if (this_statement_is_a_c_return)
503  pips_debug(6, "Statement %p is a C return.\n", s);
504  }
505 
506 
507 
508  if (this_statement_has_an_io_effect
509  || outside_effect_p
510  || this_statement_writes_a_procedure_argument
511  || this_statement_is_a_format
512  || this_statement_is_an_unstructured_test
513  || this_statement_is_a_c_return
514  || this_statement_call_a_user_function
515  )
516  /* Mark this statement as useful: */
517  set_add_element(the_useful_statements, the_useful_statements, (char *) s);
518 
519  pips_debug(5, "end\n");
520 }
521 
522 
523 static void remove_this_statement_if_useless(statement s, set entities_to_remove) {
524  if (! set_belong_p(the_useful_statements, (char *) s)) {
525  pips_debug(6, "remove_this_statement_if_useless removes statement %p (%#zx).\n", s, statement_ordering(s));
526  ifdebug(7) {
527  print_statement(s);
528  }
529  // If this is a "declaration statement" keep track of removed declarations
530  if(empty_statement_or_continue_p(s)) {
531  FOREACH(ENTITY,e, statement_declarations(s)) {
532  set_add_element(entities_to_remove,entities_to_remove,e);
533  }
534  }
535 
536  // Get rid of declarations
537  gen_free_list(statement_declarations(s));
538  statement_declarations(s) = NIL;
539 
540  // Free old instruction
541  free_instruction(statement_instruction(s));
542 
543  // Replace statement with a continue, so that we keep label && comments
544  statement_instruction(s) = make_continue_instruction();
545  } else {
546  // Get rid of removed entity in declarations
547  if(statement_declarations(s) != NIL) {
548  SET_FOREACH(entity,e,entities_to_remove) {
549  pips_debug(5,"Declaration removed for %s\n",entity_name(e));
550  gen_remove(&statement_declarations(s),e);
551  }
552  }
553  /*
554  * Let dive into sequence and really remove the statement, it's a lot
555  * cleaner than keeping empty statement when there's not label or comment
556  */
557  if(statement_block_p(s)) {
558  pips_debug(6,"Checking sequence\n");
559  list statement_to_remove = NIL;
560  FOREACH(statement,st,statement_block(s)) {
561  if (! set_belong_p(the_useful_statements, (char *) st)
562  && empty_statement_or_continue_without_comment_p(st) ) {
563  pips_debug(4,"Register %p to be removed\n",st);
564  statement_to_remove = CONS(STATEMENT,st,statement_to_remove);
565  }
566  }
567  FOREACH(statement,st,statement_to_remove) {
568  gen_remove_once(&sequence_statements(statement_sequence(s)),st);
569  }
570  gen_free_list(statement_to_remove);
571 
572  // If the sequence is empty now, mark as removable :-)
573  if(empty_statement_or_continue_without_comment_p(s)) {
574  set_add_element(the_useful_statements,the_useful_statements,s);
575  }
576  }
577  }
578  pips_debug(6, "end\n");
579  ifdebug(7) {
580  print_statement(s);
581  }
582 }
583 
584 
585 static void
586 remove_all_the_non_marked_statements(statement s)
587 {
588  pips_debug(5, "Entering remove_all_the_non_marked_statements\n");
589 
590  // Keep track of removed entities
591  set entities_to_remove = set_make(set_pointer);
592 
593  gen_context_recurse(s, entities_to_remove,
594  /* Since statements can be nested, only remove in a
595  bottom-up way: */
596  statement_domain, gen_true2, remove_this_statement_if_useless);
597 
598  ifdebug(6) {
599  SET_FOREACH(entity,e,entities_to_remove) {
600  pips_debug(6,"Entity '%s' has been totaly removed\n",entity_name(e));
601  }
602  }
603 
604  set_free(entities_to_remove);
605 
606  pips_debug(5, "Exiting remove_all_the_non_marked_statements\n");
607 }
608 
609 
610 /**
611  * Caution : callees may be changed and should be updated for the module
612  * owning this statement !
613  */
614 static void
615 dead_code_elimination_on_a_statement(statement s)
616 {
617  the_useful_statements = set_make(set_pointer);
618  init_control_father();
619  init_statement_father();
620 
621  ordering_to_dg_mapping = compute_ordering_to_dg_mapping(dependence_graph);
622 
623  build_statement_to_statement_father_mapping(s);
624  build_statement_to_statement_dependence_mapping(dependence_graph);
625 
626  /* Mark as useful the seed statements: */
627  gen_recurse(s, statement_domain,
628  gen_true,
629  use_def_deal_if_useful);
630 
631  /* Propagate the usefulness through all the predecessor graph: */
632  propagate_the_usefulness_through_the_predecessor_graph();
633 
634  remove_all_the_non_marked_statements(s);
635 
636  hash_table_free(ordering_to_dg_mapping);
637  free_statement_to_statement_dependence_mapping();
638  close_statement_father();
639  close_control_father();
640  set_free(the_useful_statements);
641 }
642 
643 static bool non_empty_out_regions_p(statement s)
644 {
645  list l_out = load_statement_out_regions(s);
646  list l_out_global = load_statement_out_regions(get_current_module_statement());
647  bool main_p = entity_main_module_p(get_current_module_entity());
648  bool go_down = true;
649  if(s==get_current_module_statement()) {
650  if(entity_main_module_p(get_current_module_entity())) {
651  // FI: IO's have no impact on the out regions of a main...
652  // The OUT regions of a main function are always empty
653  set_add_element(the_useful_statements, the_useful_statements, (char *) s);
654  }
655  else {
656  /* We can remove all statements but must preserve at least one
657  * return statement, although it is useless, so as not to
658  * generate inconsistent C or Fortran code. So, this cannot be
659  * done directly...
660  */
661  set_add_element(the_useful_statements, the_useful_statements, (char *) s);
662  }
663  }
664  else if(declaration_statement_p(s)) {
665  // FI: the OUT regions do not take into account all effects
666  // all declaration statements are preserved to be conservative
667  // Other passes might be able to deal witht them, maybe after a
668  // split_initializations pass
669  set_add_element(the_useful_statements, the_useful_statements, (char *) s);
670  }
671  else if(ENDP(l_out)) {
672  go_down = false;
673  }
674  else if((ENDP(l_out_global) && !main_p)) {
675  /* FI: this does not work because OUT regions do not let
676  distinguish between functions whose returned value is used and
677  functions whose returned value is not used; somehow, the return
678  value should be taken into account by the region analysis. */
679  //go_down = false;
680  set_add_element(the_useful_statements, the_useful_statements, (char *) s);
681  }
682  else {
683  /* Mark statement as useful */
684  set_add_element(the_useful_statements, the_useful_statements, (char *) s);
685  }
686  return go_down;
687 }
688 
689 /**
690  * Caution : callees may be changed and should be updated for the module
691  * owning this statement !
692  */
693 static void
694 dead_code_elimination_on_a_statement_with_out_regions(statement s)
695 {
696  the_useful_statements = set_make(set_pointer);
697  init_control_father();
698  init_statement_father();
699 
700  //ordering_to_dg_mapping = compute_ordering_to_dg_mapping(dependence_graph);
701 
702  build_statement_to_statement_father_mapping(s);
703  //build_statement_to_statement_dependence_mapping(dependence_graph);
704 
705  /* Mark as useful the seed statements: */
706  gen_recurse(s, statement_domain,
707  gen_true,
708  use_def_deal_if_useful);
709 
710  /* Propagate the usefulness through all the predecessor graph: */
711  // propagate_the_usefulness_through_the_predecessor_graph();
712  // all statements with a non empty out region are useful
713  gen_recurse(s, statement_domain, non_empty_out_regions_p, gen_null);
714 
715  remove_all_the_non_marked_statements(s);
716 
717  //hash_table_free(ordering_to_dg_mapping);
718  //free_statement_to_statement_dependence_mapping();
719  close_statement_father();
720  close_control_father();
721  set_free(the_useful_statements);
722 }
723 
724 
725 bool dead_code_elimination_on_module(char * module_name, bool use_out_regions)
726 {
727  statement module_statement;
728  entity module = module_name_to_entity(module_name);
729 
730  /*
731  * For C code, this pass requires that effects are calculated with property
732  * MEMORY_EFFECTS_ONLY set to false because we need that the chains include
733  * arcs for declarations as these latter are separate statements now.
734  */
735  bool memory_effects_only_p = get_bool_property("MEMORY_EFFECTS_ONLY");
736  if(c_module_p(module) && memory_effects_only_p && !use_out_regions) {
737  pips_user_error("For C code, Dead code elimination should be run with property "
738  "MEMORY_EFFECTS_ONLY set to FALSE.\n"
739  "For C code, this pass requires that effects are calculated with property"
740  " MEMORY_EFFECTS_ONLY set to false because we need that the chains include"
741  " arcs for declarations as these latter are separate statements now.\n");
742  return false; // return to pass manager with a failure code
743  }
744 
745  /* Get the true ressource, not a copy. */
746  module_statement =
747  (statement) db_get_memory_resource(DBR_CODE, module_name, true);
748 
749  /* Get the data dependence graph: */
750  /* The dg is more precise than the chains, so I (RK) guess I should
751  remove more code with the dg, specially with array sections and
752  so on. */
753  /* FI: it's much too expensive; and how can you gain something
754  * with scalar variables?
755  */
756  /*
757  dependence_graph =
758  (graph) db_get_memory_resource(DBR_DG, module_name, true);
759  */
760 
761  if(!use_out_regions) {
762  dependence_graph =
763  (graph) db_get_memory_resource(DBR_CHAINS, module_name, true);
764  }
765 
766  /* The proper effect to detect the I/O operations: */
767  set_proper_rw_effects((statement_effects)
768  db_get_memory_resource(DBR_PROPER_EFFECTS,
769  module_name,
770  true));
771  if(use_out_regions) {
772  set_out_effects( (statement_effects)
773  db_get_memory_resource(DBR_OUT_REGIONS, module_name, true) );
774  set_precondition_map( (statement_mapping)
775  db_get_memory_resource(DBR_PRECONDITIONS, module_name, true) );
776  }
777 
778  set_current_module_statement(module_statement);
779  set_current_module_entity(module);
780 
781  set_ordering_to_statement(module_statement);
782 
783  debug_on("DEAD_CODE_ELIMINATION_DEBUG_LEVEL");
784  pips_debug(1, "begin dead_code_elimination\n");
785  reset_hooks_register(dead_code_elimination_error_handler);
786 
787  /* DEAD_CODE_ELIMINATION_KEEP_FUNCTIONS is a property that can be defined
788  * by the user for telling that a space separated list of functions has to
789  * be considered as important and we have to keep them
790  * Note: it doesn't work with out_regions
791  */
792  keeped_functions = strsplit(get_string_property("DEAD_CODE_ELIMINATION_KEEP_FUNCTIONS")," ");
793  keeped_functions_prefix = strsplit(get_string_property("DEAD_CODE_ELIMINATION_KEEP_FUNCTIONS_PREFIX")," ");
794 
795  if(use_out_regions) {
796  dead_code_elimination_on_a_statement_with_out_regions(module_statement);
797  }
798  else
799  dead_code_elimination_on_a_statement(module_statement);
800 
801  gen_map(free,keeped_functions);gen_free_list(keeped_functions);
802  keeped_functions = 0;
803  gen_map(free,keeped_functions_prefix);gen_free_list(keeped_functions_prefix);
804  keeped_functions_prefix = 0;
805 
806 
807  /* Reorder the module, because some statements have been deleted.
808  Well, the order on the remaining statements should be the same,
809  but by reordering the statements, the number are consecutive. Just
810  for pretty print... :-) */
811  module_reorder(module_statement);
812 
813  pips_debug(2, "done for %s\n", module_name);
814  debug_off();
815 
816  /* Apply clean declarations ! */
817  /*
818  * NL: This code are usefull to eliminate:
819  * - when an useless variable is declare with some usefull variable (int usefull, useless;)
820  * - in C, when an useless variable is initialize in the declaration (int useless=0;)
821  * - useless declaration when we use out region for dead_code_elimination
822  * (Transformations/Dead_code_declaratios.sub/use_def_elim10)
823  * - other case?
824  */
825  debug_on("CLEAN_DECLARATIONS_DEBUG_LEVEL");
826  pips_debug(1, "begin clean_declarations\n");
827 
828  set_cumulated_rw_effects(
829  (statement_effects)db_get_memory_resource(DBR_CUMULATED_EFFECTS,
830  module_name,
831  true));
832 
833  module_clean_declarations(get_current_module_entity(),
834  get_current_module_statement());
835 
836  pips_debug(1, "end clean_declarations\n");
837  debug_off();
838 
839  /*
840  * If out_regions available
841  * also reduce loop bound iteration
842  */
843  if(use_out_regions) {
844  debug_on("LOOP_BOUND_MINIMIZATION_DEBUG_LEVEL");
845  pips_debug(1, "begin loop_bound_minimization\n");
846 
847  loop_bound_minimization_with_out_regions_on_statement(get_current_module_statement());
848 
849  pips_debug(1, "end loop_bound_minimization\n");
850  debug_off();
851  }
852 
853 
854  DB_PUT_MEMORY_RESOURCE(DBR_CODE, module_name, module_statement);
855 
856  // We may have removed some function call, thus recompute the callees
857  DB_PUT_MEMORY_RESOURCE(DBR_CALLEES, module_name,
858  compute_callees(get_current_module_statement()));
859 
860 
861  reset_cumulated_rw_effects();
862  reset_proper_rw_effects();
863  if(use_out_regions) {
864  reset_out_effects();
865  reset_precondition_map();
866  }
867  reset_current_module_statement();
868  reset_current_module_entity();
869  reset_ordering_to_statement();
870 
871  reset_hooks_unregister(dead_code_elimination_error_handler);
872 
873  /* Should have worked: */
874  return true;
875 }
876 
877 bool dead_code_elimination(char * module_name)
878 {
879  debug_on("DEAD_CODE_ELIMINATION_DEBUG_LEVEL");
880  bool success = dead_code_elimination_on_module(module_name, false);
881  debug_off();
882  return success;
883 }
884 
885 bool dead_code_elimination_with_out_regions(char * module_name)
886 {
887  debug_on("DEAD_CODE_ELIMINATION_DEBUG_LEVEL");
888  bool success = dead_code_elimination_on_module(module_name, true);
889  debug_off();
890  return success;
891 }
892 
893 /* Obsolete name: it should be called dead_code_elimination()
894  *
895  * Maintained for backward compatibility.
896  */
897 bool use_def_elimination(char * module_name)
898 {
899  debug_on("USE_DEF_ELIMINATION_DEBUG_LEVEL");
900  pips_user_warning("This phase has been renamed, please use "
901  "'dead_code_elimination' from now.\n" );
902  bool success = dead_code_elimination_on_module(module_name, false);
903  debug_off();
904  return success;
905 }
906 
907 /** @} */
908 
909 /** @} */
910 
911 #endif // BUILDER_DEAD_CODE_ELIMINATION*
dg_vertex_label vertex_label
Definition: delay.c:64
dg_arc_label arc_label
Definition: delay.c:63
static graph dependence_graph
Definition: delay.c:93
#define dg_vertex_label_statement(x)
Definition: dg.h:235
#define conflict_sink(x)
Definition: dg.h:167
#define dg_arc_label_conflicts(x)
Definition: dg.h:201
#define conflict_source(x)
Definition: dg.h:165
list words_effect(effect)
#define effect_action(x)
Definition: effects.h:642
#define action_write_p(x)
Definition: effects.h:314
#define action_read_p(x)
Definition: effects.h:311
#define successor_vertex(x)
Definition: graph.h:118
#define successor_arc_label(x)
Definition: graph.h:116
#define vertex_vertex_label(x)
Definition: graph.h:152
#define vertex_successors(x)
Definition: graph.h:154
#define graph_vertices(x)
Definition: graph.h:82
void gen_multi_recurse(void *o,...)
Multi recursion visitor function.
Definition: genClib.c:3428
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
#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
hash_table hash_table_make(hash_key_type key_type, size_t size)
Definition: hash.c:294
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
statement vertex_to_statement(vertex v)
Vertex_to_statement looks for the statement that is pointed to by vertex v.
Definition: util.c:45
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define DEFINE_LOCAL_STACK(name, type)
@ hash_pointer
Definition: newgen_hash.h:32
#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
struct _set_chunk * set
Definition: newgen_set.h:38
@ set_pointer
Definition: newgen_set.h:44
set set_make(set_type)
Create an empty set of any type but hash_private.
Definition: set.c:102
set set_add_element(set, const set, const void *)
Definition: set.c:152
#define statement_ordering(x)
Definition: ri.h:2454
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define control_domain
newgen_controlmap_domain_defined
Definition: ri.h:98
#define control_statement(x)
Definition: ri.h:941
#define statement_undefined
Definition: ri.h:2419
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
static statement current_statement
s1
Definition: set.c:247
#define ifdebug(n)
Definition: sg.c:47
GENERIC_LOCAL_FUNCTION(directives, step_directives)
Copyright 2007, 2008, 2009 Alain Muller, Frederique Silber-Chaussumier.
FI: I do not understand why the type is duplicated at the set level.
Definition: set.c:59
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
void print_words(FILE *fd, cons *lw)
Definition: print.c:263