PIPS
dynamic_declarations.c
Go to the documentation of this file.
1 /*
2 
3  $Id: dynamic_declarations.c 23065 2016-03-02 09:05:50Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 
25 // do not compile unless used
26 #include "phases.h"
27 #ifdef BUILDER_CLEAN_UNUSED_DYNAMIC_VARIABLES
28 
29 #ifdef HAVE_CONFIG_H
30  #include "pips_config.h"
31 #endif
32 /*
33  * clean the declarations of a module.
34  * to be called from pipsmake.
35  */
36 
37 #include <stdio.h>
38 
39 #include "genC.h"
40 #include "linear.h"
41 
42 #include "pipsdbm.h"
43 #include "misc.h"
44 #include "properties.h"
45 
46 #include "ri.h"
47 #include "effects.h"
48 #include "ri-util.h"
49 #include "effects-util.h"
50 
51 #include "effects-generic.h" // used
52 #include "control.h" // for clean_up_sequences, module_reorder
53 #include "transformations.h" // clean_declarations
54 
55 /****************************************************** DYNAMIC DECLARATIONS */
56 
57 #define expr_var(e) reference_variable(expression_reference(e))
58 
59 #define call_assign_p(c) \
60  same_string_p(entity_local_name(call_function(c)), ASSIGN_OPERATOR_NAME)
61 
62 struct helper {
63  int removed_vars; // how many variables where removed
64  const char* module; // current module being cleaned up
65  const char* func_malloc; // allocation function
66  const char* func_free; // deallocation function
67  set referenced; // referenced entities
68 };
69 
70 // Pass 1: collect local referenced variables
71 static bool ignore_call_flt(call c, struct helper * ctx)
72 {
73  // ignores free(var)
74  if (same_string_p(entity_local_name(call_function(c)), ctx->func_free))
75  return false;
76 
77  // ignores "var = malloc(...)" (but not malloc arguments!)
78  if (call_assign_p(c))
79  {
80  list args = call_arguments(c);
81  pips_assert("2 args to assign", gen_length(args)==2);
82  expression val = EXPRESSION(CAR(CDR(args)));
83 
84  if (expression_call_p(val) &&
86  ctx->func_malloc))
87  {
88  pips_debug(5, "malloc called\n");
90  }
91 
92  // ??? should I also ignore "var = NULL"?
93  // and other constant assignments?
94  }
95 
96  return true;
97 }
98 
99 static bool reference_flt(reference r, struct helper * ctx)
100 {
101  // pips_debug(9, "%s used in statement %" _intFMT "\n",
102  // entity_name(reference_variable(r)),
103  // statement_number((statement) gen_get_ancestor(statement_domain, r)));
104  set_add_element(ctx->referenced, ctx->referenced, reference_variable(r));
105  return true;
106 }
107 
108 static bool loop_flt(loop l, struct helper * ctx)
109 {
110  set_add_element(ctx->referenced, ctx->referenced, loop_index(l));
111  return true;
112 }
113 
114 static bool unused_local_variable_p(entity var, set used, const char* module)
115 {
116  bool unused = same_string_p(entity_module_name(var), module)
117  // keep function auto-declaration for recursion
119  && !set_belong_p(used, var)
120  && !formal_parameter_p(var)
122  pips_debug(8, "%s is %sused (%d)\n",
123  entity_name(var), unused? "UN": "", set_belong_p(used, var));
124  return unused;
125 }
126 
127 // Pass 2:
128 static void cleanup_call(call c, struct helper * ctx)
129 {
130  pips_debug(6, "call to %s\n", entity_name(call_function(c)));
131 
132  bool replace = false;
133 
134  if (same_string_p(entity_local_name(call_function(c)), ctx->func_free))
135  {
136  // get FREE-d variable, which is the first and only argument
137  list args = call_arguments(c);
138  if (gen_length(args)==1)
139  {
140  expression arg = EXPRESSION(CAR(args));
141  if (expression_reference_p(arg) &&
142  unused_local_variable_p(expr_var(arg), ctx->referenced, ctx->module))
143  replace = true;
144  }
145  // else what?
146  }
147  else if (call_assign_p(c))
148  {
149  list args = call_arguments(c);
150  expression val = EXPRESSION(CAR(CDR(args)));
151  if (expression_call_p(val) &&
153  ctx->func_malloc))
154  {
155  expression arg = EXPRESSION(CAR(args));
156  if (expression_reference_p(arg) &&
157  unused_local_variable_p(expr_var(arg), ctx->referenced, ctx->module))
158  replace = true;
159  }
160  // var = NULL?
161  }
162 
163  if (replace)
164  {
165  pips_debug(6, "replacing...\n");
166  instruction ins =
168  if (instruction_call_p(ins) && instruction_call(ins)==c)
169  // continue is appropriate only if call is an instruction!
171  else
172  // ??? otherwise, let us try 0
175  call_arguments(c) = NIL;
176  }
177 }
178 
179 static void cleanup_stat_decls(statement s, struct helper * ctx)
180 {
181  list decls = statement_declarations(s), kept = NIL;
182  FOREACH(ENTITY, var, decls)
183  if (!unused_local_variable_p(var, ctx->referenced, ctx->module))
184  kept = CONS(ENTITY, var, kept);
185  else
186  ctx->removed_vars++;
188  gen_free_list(decls);
189 }
190 
191 static void dynamic_cleanup(string module, statement stat)
192 {
194 
195  struct helper help;
196  help.module = module;
197  // use dynamic definition for malloc/free.
198  help.func_malloc = get_string_property("DYNAMIC_ALLOCATION");
199  help.func_free = get_string_property("DYNAMIC_DEALLOCATION");
200  help.referenced = set_make(set_pointer);
201 
202  // transitive closure as dynamic allocation may depend one from another.
203  // eg in FREIA, images are created with the size of another...
204  do {
205  help.removed_vars = 0;
206  set_clear(help.referenced);
207 
208  // pass 1: collect references in code
210  (stat, &help,
211  reference_domain, reference_flt, gen_null,
213  call_domain, ignore_call_flt, gen_null,
214  NULL);
215 
216  // and in initializations
219  (entity_initial(var), &help,
220  reference_domain, reference_flt, gen_null,
221  call_domain, ignore_call_flt, gen_null,
222  NULL);
223 
224  // pass 2: cleanup calls to "= malloc" and "free" in code
226  (stat, &help,
227  call_domain, gen_true, cleanup_call,
228  statement_domain, gen_true, cleanup_stat_decls,
229  NULL);
230 
231  // and in declarations
232  list decls = entity_declarations(mod), kept = NIL;
233  FOREACH(ENTITY, var, decls)
234  {
235  // pips_debug(8, "considering %s\n", entity_name(var));
236  if (unused_local_variable_p(var, help.referenced, module))
237  {
238  value init = entity_initial(var);
240  {
241  free_value(init);
243  }
244  help.removed_vars++;
245  }
246  else
247  kept = CONS(ENTITY, var, kept);
248  }
249 
250  // is it useful? declarations are attached to statements in C.
251  entity_declarations(mod) = gen_nreverse(kept);
252  gen_free_list(decls), decls = NIL;
253 
254  } while (help.removed_vars>0);
255 
256  set_free(help.referenced);
257 }
258 
259 /* A phase to remove useless dynamic heap variables that are not used but
260  with malloc()/free()
261 
262  The names of the functions used to allocate/deallocate the variable can
263  be specified by the DYNAMIC_ALLOCATION and DYNAMIC_DEALLOCATION
264  properties.
265 
266  @param[in] module is the module name we want to clean
267 
268  @return true since everything should behave well...
269  */
271 {
272  debug_on("PIPS_CUDV_DEBUG_LEVEL");
273 
274  // get stuff from pipsdbm
277  ((statement) db_get_memory_resource(DBR_CODE, module, true) );
278 
279  dynamic_cleanup(module, get_current_module_statement());
281 
282  // results
285 
286  // cleanup
289  debug_off();
290 
291  return true;
292 }
293 
294 #endif // BUILDER_CLEAN_UNUSED_DYNAMIC_VARIABLES
value make_value_unknown(void)
Definition: ri.c:2847
void free_value(value p)
Definition: ri.c:2787
bool clean_up_sequences(statement s)
Recursively clean up the statement sequences by fusing them if possible and by removing useless one.
#define call_assign_p(c)
Definition: compiler-util.c:87
entity int_to_entity(_int c)
Definition: constant.c:453
char * get_string_property(const char *)
void gen_full_free_list(list l)
Definition: genClib.c:1023
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
statement get_current_module_statement(void)
Get the current module statement.
Definition: static.c:208
entity set_current_module_entity(entity)
static.c
Definition: static.c:66
void gen_recurse_stop(void *obj)
Tells the recursion not to go in this object.
Definition: genClib.c:3251
void gen_context_multi_recurse(void *o, void *context,...)
Multi-recursion with context function visitor.
Definition: genClib.c:3373
gen_chunk * gen_get_ancestor(int, const void *)
return the first ancestor object found of the given type.
Definition: genClib.c:3560
void gen_null(__attribute__((unused)) void *unused)
Ignore the argument.
Definition: genClib.c:2752
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
#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
#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
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
static GtkWidget * help
Definition: gtk_schoose2.c:52
#define debug_on(env)
Definition: misc-local.h:157
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define debug_off()
Definition: misc-local.h:160
#define same_string_p(s1, s2)
void set_free(set)
Definition: set.c:332
set set_clear(set)
Assign the empty set to s s := {}.
Definition: set.c:326
bool set_belong_p(const set, const void *)
Definition: set.c:194
@ 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
static bool loop_flt(loop l, extract_expr_p context)
Definition: optimize.c:173
static char * module
Definition: pips.c:74
static list referenced
returns the list of referenced variables
Definition: utils.c:60
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define entity_declarations(e)
MISC: newgen shorthands.
#define CONTINUE_FUNCTION_NAME
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
entity local_name_to_top_level_entity(const char *n)
This function try to find a top-level entity from a local name.
Definition: entity.c:1450
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
static int init
Maximal value set for Fortran 77.
Definition: entity.c:320
const char * entity_module_name(entity e)
See comments about module_name().
Definition: entity.c:1092
entity entity_intrinsic(const char *name)
FI: I do not understand this function name (see next one!).
Definition: entity.c:1292
bool expression_call_p(expression e)
Definition: expression.c:415
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
type ultimate_type(type)
Definition: type.c:3466
bool formal_parameter_p(entity)
Definition: variable.c:1489
#define call_function(x)
Definition: ri.h:709
#define reference_variable(x)
Definition: ri.h:2326
#define loop_domain
newgen_language_domain_defined
Definition: ri.h:218
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define instruction_domain
newgen_functional_domain_defined
Definition: ri.h:202
#define call_domain
newgen_callees_domain_defined
Definition: ri.h:58
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define reference_domain
newgen_range_domain_defined
Definition: ri.h:338
#define entity_name(x)
Definition: ri.h:2790
struct _newgen_struct_instruction_ * instruction
Definition: ri.h:207
#define instruction_call_p(x)
Definition: ri.h:1527
#define statement_declarations(x)
Definition: ri.h:2460
#define instruction_call(x)
Definition: ri.h:1529
#define call_arguments(x)
Definition: ri.h:711
#define entity_type(x)
Definition: ri.h:2792
#define value_expression_p(x)
Definition: ri.h:3080
#define type_variable_p(x)
Definition: ri.h:2947
#define loop_index(x)
Definition: ri.h:1640
#define entity_initial(x)
Definition: ri.h:2796
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
bool clean_unused_dynamic_variables(string)
dynamic_declarations.c