PIPS
for_loop_recovering.c
Go to the documentation of this file.
1 /*
2 
3  $Id: for_loop_recovering.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 required
26 #include "phases.h"
27 #ifdef BUILDER_RECOVER_FOR_LOOP
28 
29 #ifdef HAVE_CONFIG_H
30  #include "pips_config.h"
31 #endif
32 
33 /* 2 phases :
34  - recover for loops hidden in while loops:
35  see comments before try_to_recover_for_loop_in_a_while()
36  - for-loop to do-loop transformation:
37  not found (FI)
38 */
39 
40 #include "genC.h"
41 #include "linear.h"
42 
43 #include "misc.h"
44 #include "pipsdbm.h"
45 
46 #include "text.h"
47 #include "text-util.h"
48 
49 #include "ri.h"
50 #include "ri-util.h"
51 #include "prettyprint.h" // for debugging
52 
53 #include "effects.h"
54 #include "effects-util.h"
55 
56 #include "control.h" // module_reorder
57 #include "effects-generic.h" // used
58 #include "effects-simple.h" // ??? print_effect
59 
60 #include "semantics.h" // used
61 #include "transformer.h" // used
62 
63 /* Find if a variable rv can be considered as an index-like variable for
64  the given statement s.
65 
66  @return :
67  - false if rv is not considered as such;
68  - true if yes, change index_relation to the Pvector of the transformer
69  that represents the index evolution and initial_rv points to the initial
70  variable of rv in the transformer.
71 */
72 static bool
73 find_simple_for_like_variable(statement s,
74  entity rv,
75  entity * initial_rv,
76  Pvecteur * index_relation) {
77  pips_debug(5, "Look for variable %s (%p)\n", entity_global_name(rv), rv);
79  ifdebug(5) {
81  print_statement(s);
82  }
83  /* Look for the referenced variable in the transformer argument: */
85  pips_debug(5, "Name of a variable whose change value is in the transformer: %s (%p)\n", entity_global_name(e), e);
86  if (rv == e) {
87  pips_debug(5, "! Found matching variable in the statement !\n");
88  // Find or build a matching initial valued variable (...#init):
90  ifdebug(7) {
91  pips_debug(7, "sys %p\n", ps);
92  sc_syst_debug(ps);
93  text txt = make_text(NIL);
94  char crt_line[MAX_LINE_LENGTH];
95 
96  system_text_format(crt_line, ">", txt, ps,
97  (char * (*)(Variable)) pips_user_value_name, false);
98  fputs(text_to_string(txt), stderr);
99  }
100 
101  /* Search the equalities: */
102  for (Pcontrainte equality = sc_egalites(ps);
103  equality != NULL;
104  equality = equality->succ) {
105  /* For the pattern matching: */
106  bool found_value_for_current_variable = false;
107  bool found_old_value_for_current_variable = false;
108  bool found_value_for_another_variable_in_transformer = false;
109 
110  pips_debug(5, "Equality : %p\n", equality);
111  for (Pvecteur v = contrainte_vecteur(equality);
112  !VECTEUR_NUL_P(v);
113  v = v->succ) {
114  Variable var = var_of(v);
115  Value coeff = val_of(v);
116  pips_debug(5, "Value " VALUE_FMT " ", coeff);
117  if (var==TCST)
118  pips_debug(5, "for vector constant\n");
119  else {
120  pips_debug(5, "for vector variable : %s %s %s\n",
122  entity_global_name(var),
123  entity_local_name(var));
124  if (var == e) {
125  pips_debug(5, "We have found a reference to the variable"
126  " in the transformer\n");
127  found_value_for_current_variable = true;
128  }
129  else if (local_old_value_entity_p(var)
130  && value_to_variable(var) == e
131  && value_one_p(value_abs(coeff))) {
132  pips_debug(5, "We have found a reference to the initial value"
133  " of the variable in the transformer"
134  " with a factor +/- 1\n");
135  found_old_value_for_current_variable = true;
136  *initial_rv = var;
137  }
138  else if (gen_in_list_p(var, transformer_arguments(t))) {
139  pips_debug(5, "We have found a reference to another variable"
140  " marked as modified by the transformer\n");
141  /* That means that the variable e evolved according to
142  another variable var, so it is not a simple for
143  loop. Just skipping... */
144  found_value_for_another_variable_in_transformer = true;
145  break;
146  }
147  /* Else it should be a reference to a variable that is loop
148  invariant because not in the variables marked a
149  transformed by the transformer: good news. */
150  }
151  }
152  if (found_value_for_current_variable
153  && found_old_value_for_current_variable
154  && !found_value_for_another_variable_in_transformer) {
155  pips_debug(4, "We have found a relation of the form:\n"
156  "+/- i + k*i#init + invariant_loop_variables == constant\n"
157  );
158  /* Return the found relation that modelizes the index behaviour: */
159  *index_relation = contrainte_vecteur(equality);
160  return true;
161  }
162  }
163  }
164  }
165  return false;
166 }
167 
168 
169 /* Try to recover "for" loops from "while" loops in a statement.
170 
171  The algorithm used is for a statement of this form:
172 
173  while(cond)
174  body;
175 
176  For each variable i used (with read effects) in the expression cond, if
177  the loop body has a transformer of the form i == i#init+inc_1+inc_2+...
178  and inc_x are loop-invariant (that is that they do not appear in the
179  variables changed by the transformet), i is a loop index suitable for a
180  simple for-loop.
181 
182  Then replace this while-loop with:
183  for(i0 = i; cond; i0 += inc_1+inc_2+...) {
184  i = i0;
185  body;
186  }
187 
188  We can substitute any reference to i by i0 in cond. If it is not
189  possible (cond has some interprocedural side effect on i) the code is
190  still correct but less for-loop friendly.
191 
192  We use the transformer to deal with some interprocedural loop increment
193  (for example if there are some iterator-like constructions).
194 
195  Do not deal with loop with only one statement in it right now.
196 
197  TODO: could deal with any write effect on i in the loop instead of one
198  with a transformer with a form i == i#init+x
199 
200  TODO: deal with multiple index
201 
202  TODO: verify MAY or MUST?
203 
204  TODO: deal with index shifting by cloning the index where it is used,
205  such as in:
206  i = 0;
207  while (i < 100) {
208  i++;
209  a[i] = i;
210  }
211  could be transformed to:
212  for(i = 0; i < 100; i++) {
213  future_i = i + 1;
214  a[future_i] = future_i;
215  }
216  TODO: while(i-->0) {} might not be recognized, as well as
217  while(i++<n) {}
218  */
219 static void
220 try_to_recover_for_loop_in_a_while(whileloop wl) {
221  /* Get the englobing statement of the "while" assuming we are called
222  from a gen_recurse()-like function: */
225 
226  pips_debug(9, "While-loop %p, parent (instruction): %p, "
227  "whileloop of the instruction: %p\n", wl, i,
229  if ((statement_instruction(wls) != i) || (instruction_whileloop(i) != wl))
230  pips_internal_error("Cannot get the enclosing statement of the while-loop.");
231 
232  /* If it is a "do { } while()" do nothing: */
234  return;
235 
236  // Use to get the effects of the condition part of the "while":
237  list while_proper_effects = load_proper_rw_effects_list(wls);
238  // Use to get the effects of the whole loop, with condition and body:
239  //list while_cumulated_effects = load_cumulated_rw_effects_list(wls);
240 
241  FOREACH(EFFECT, an_effect, while_proper_effects) {
242  reference r = effect_any_reference(an_effect);
243  ifdebug(5) {
244  print_effect(an_effect);
245  dump_effect(an_effect);
246  }
247  pips_debug(5, "%p: %s\n", an_effect, words_to_string(effect_words_reference(r)));
248  if (effect_read_p(an_effect)) {
249  /* Look for the reference variable in the statement body transformers: */
250  entity rv = reference_variable(r);
251  entity initial_rv = entity_undefined;
252  Pvecteur index_evolution;
253  pips_debug(5, "Look for variable %s (%p)\n", entity_global_name(rv), rv);
254  bool found = find_simple_for_like_variable(whileloop_body(wl), rv,
255  &initial_rv,
256  &index_evolution);
257  if (found) {
258  ifdebug(3) {
259  pips_debug(3, "Variable %s (%p) is a nice loop-like index"
260  " with relation\n", entity_global_name(rv), rv);
261  vect_dump(index_evolution);
262  vect_print(index_evolution,
264  }
265  entity new_index =
268  // Should use ultimate type?
269  entity_basic(rv));
270  AddEntityToCurrentModule(new_index);
271  //\domain{Forloop = initialization:expression x condition:expression x increment:expression x body:statement}
272 
273 
274  /* Build the initialization part of the for-loop by initializing
275  the new index variable from the old one: */
278 
279  /* Build the conditional part of the for-loop, with the new loop
280  index instead of the old one: */
281  expression cond = whileloop_condition(wl);
282  cond = substitute_entity_in_expression(rv, new_index, cond);
283 
284  /* Build the increment part of the for-loop: */
285  expression inc = make_constraint_expression(index_evolution, rv);
286  /* Replace old variable#init by the plain one: */
288  substitute_entity_in_expression(initial_rv, new_index, inc));
289 
290  /* Add a statement "old_index = new_index" at the beginning of the
291  loop body to propagate the new index value to the old body: */
292  statement copy_new_index_to_old =
294  entity_to_expression(new_index));
295  statement for_loop_body = whileloop_body(wl);
296  insert_statement(for_loop_body, copy_new_index_to_old, true);
297 
298  forloop f = make_forloop(init, cond, inc, for_loop_body);
299  /* Modify the enclosing instruction to be a for-loop instead. It
300  works even if we are in a gen_recurse because we are in the
301  bottom-up phase of the recursion. */
303  instruction_forloop(i) = f;
304  /* Detach informations of the while-loop before freeing it: */
307  free_whileloop(wl);
309  break;
310  }
311  }
312  }
313  return;
314 }
315 
316 
317 /* Apply recursively for-loop recovering to a given statement. */
318 static void
319 recover_for_loop_in_statement(statement s) {
320  /* We need to access to the statement containing the current
321  while-loops, so ask NewGen gen_recurse to keep this informations for
322  us: */
323  /* Iterate on all the while-loops: */
324  //gen_debug = -1;
325  gen_recurse(s,
326  /* Since loop statements can be nested, only restructure in
327  a bottom-up way, : */
328  whileloop_domain, gen_true, try_to_recover_for_loop_in_a_while);
329  //gen_debug = 0;
330 }
331 
332 
333 /* The phase to apply for-loop recovering to a given code module */
334 bool recover_for_loop(const string module_name) {
336 
337  /* Get the true ressource, not a copy, since we modify it in place. */
339  (statement) db_get_memory_resource(DBR_CODE, module_name, true);
340 
344 
345  /* Construct the mapping to get the statements associated to the
346  dependence graph: */
348 
349  /* The proper effect to detect statement memory effects: */
351  db_get_memory_resource(DBR_PROPER_EFFECTS,
352  module_name,
353  true));
354 
355  /* To set up the hash table to translate value into value names */
357  db_get_memory_resource(DBR_CUMULATED_EFFECTS,
358  module_name, true));
359 
360  /* Get the transformers of the module: */
362  db_get_memory_resource(DBR_TRANSFORMERS,
363  module_name,
364  true));
365 
366  transformer summary = (transformer)
367  db_get_memory_resource(DBR_SUMMARY_TRANSFORMER, module_name, true);
368 
369  /* Build all the mapping needed by the transformer usage: */
371 
372  /* The summary precondition may be in another module's frame */
373  translate_global_values(mod, summary);
374 
375  /* Get the data dependence graph: */
376  /* The dg is more precise than the chains, so I (RK) guess I should
377  remove more code with the dg, specially with array sections and
378  so on. */
379  /* FI: it's much too expensive; and how can you gain something
380  * with scalar variables?
381  */
382  /*
383  dependence_graph =
384  (graph) db_get_memory_resource(DBR_DG, module_name, true);
385  */
386 
387  /* Get the use-def chains */
388  /*
389  Not used yet
390  dependence_graph =
391  (graph) db_get_memory_resource(DBR_CHAINS, module_name, true);
392  */
393 
394  debug_on("RECOVER_FOR_LOOP_DEBUG_LEVEL");
395 
396  recover_for_loop_in_statement(module_statement);
397 
398  pips_debug(2, "done");
399 
400  debug_off();
401 
402  /* Reorder the module, because some statements have been deleted.
403  Well, the order on the remaining statements should be the same,
404  but by reordering the statements, the number are consecutive. Just
405  for pretty print... :-) */
407 
409 
417 
418  /* Should have worked: */
419  return true;
420 }
421 
422 #endif // BUILDER_RECOVER_FOR_LOOP
void free_whileloop(whileloop p)
Definition: ri.c:2904
forloop make_forloop(expression a1, expression a2, expression a3, statement a4)
Definition: ri.c:1025
text make_text(list a)
Definition: text.c:107
static statement module_statement
Definition: alias_check.c:125
#define value_one_p(val)
#define VALUE_FMT
int Value
#define value_abs(val)
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
void system_text_format(string line, string prefix, text txt, Psysteme ps, string(*variable_name)(Variable), bool a_la_fortran)
appends ps to line/txt with prefix continuations.
void sc_syst_debug(Psysteme s)
constraint_to_text.c
#define contrainte_vecteur(c)
passage au champ vecteur d'une contrainte "a la Newgen"
void dump_effect(effect)
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 reset_cumulated_rw_effects(void)
#define effect_any_reference(e)
FI: cannot be used as a left hand side.
#define effect_read_p(eff)
#define effect_scalar_p(eff) entity_scalar_p(effect_entity(eff))
list effect_words_reference(reference)
prettyprint.c
Definition: prettyprint.c:68
#define EFFECT(x)
EFFECT.
Definition: effects.h:608
const char * module_name(const char *s)
Return the module part of an entity name.
Definition: entity_names.c:296
#define gen_recurse(start, domain_number, flt, rwt)
Definition: genC.h:283
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
gen_chunk * gen_get_recurse_ancestor(const void *)
Get the first ancestor object encountered during the recursion for the given object.
Definition: genClib.c:3546
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
#define FOREACH(_fe_CASTER, _fe_item, _fe_list)
Apply/map an instruction block on all the elements of a list.
Definition: newgen_list.h:179
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
statement make_assign_statement(expression, expression)
Definition: statement.c:583
void insert_statement(statement, statement, bool)
This is the normal entry point.
Definition: statement.c:2570
void vect_dump(Pvecteur v)
void vect_dump(Pvecteur v): print sparse vector v on stderr.
Definition: io.c:304
void vect_print(Pvecteur v, get_variable_name_t variable_name)
void vect_print(Pvecteur v, char * (*variable_name)()): impression d'un vecteur creux v sur stdout; l...
Definition: io.c:312
#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_internal_error
Definition: misc-local.h:149
#define debug_off()
Definition: misc-local.h:160
int f(int off1, int off2, int n, float r[n], float a[n], float b[n])
Definition: offsets.c:15
hash_table set_ordering_to_statement(statement s)
To be used instead of initialize_ordering_to_statement() to make sure that the hash table ots is in s...
Definition: ordering.c:172
void reset_ordering_to_statement(void)
Reset the mapping from ordering to statement.
Definition: ordering.c:185
#define print_effect(e)
Definition: print.c:336
void print_statement(statement)
Print a statement on stderr.
Definition: statement.c:98
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
const char * entity_user_name(entity e)
Since entity_local_name may contain PIPS special characters such as prefixes (label,...
Definition: entity.c:487
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
string entity_global_name(entity e)
Used instead of the macro to pass as formal argument.
Definition: entity.c:464
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
basic entity_basic(entity e)
return the basic associated to entity e if it's a function/variable/constant basic_undefined otherwis...
Definition: entity.c:1380
static int init
Maximal value set for Fortran 77.
Definition: entity.c:320
expression make_constraint_expression(Pvecteur v, Variable index)
Make an expression from a constraint v for a given index.
Definition: expression.c:1748
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
expression substitute_entity_in_expression(entity old, entity new, expression e)
This function replaces all the occurences of an old entity in the expression exp by the new entity.
Definition: expression.c:2792
expression make_assign_expression(expression lhs, expression rhs)
Make an assign expression, since in C the assignment is a side effect operator.
Definition: expression.c:390
void AddEntityToCurrentModule(entity)
Add a variable entity to the current module declarations.
Definition: variable.c:260
entity make_new_scalar_variable_with_prefix(const char *, entity, basic)
Create a new scalar variable of type b in the given module.
Definition: variable.c:592
#define reference_variable(x)
Definition: ri.h:2326
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define whileloop_evaluation(x)
Definition: ri.h:3166
#define entity_undefined
Definition: ri.h:2761
#define expression_undefined
Definition: ri.h:1223
@ is_instruction_forloop
Definition: ri.h:1477
#define instruction_tag(x)
Definition: ri.h:1511
#define transformer_relation(x)
Definition: ri.h:2873
#define transformer_arguments(x)
Definition: ri.h:2871
struct _newgen_struct_instruction_ * instruction
Definition: ri.h:207
#define instruction_forloop(x)
Definition: ri.h:1538
#define instruction_whileloop(x)
Definition: ri.h:1523
#define whileloop_body(x)
Definition: ri.h:3162
#define whileloop_domain
newgen_variable_domain_defined
Definition: ri.h:466
#define statement_instruction(x)
Definition: ri.h:2458
struct _newgen_struct_transformer_ * transformer
Definition: ri.h:431
#define whileloop_condition(x)
Definition: ri.h:3160
#define evaluation_after_p(x)
Definition: ri.h:1162
#define predicate_system(x)
Definition: ri.h:2069
#define whileloop_undefined
Definition: ri.h:3134
#define statement_undefined
Definition: ri.h:2419
void translate_global_values(entity m, transformer tf)
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
text text_for_a_transformer(transformer tran, bool is_a_transformer)
call this one from outside.
Definition: prettyprint.c:540
transformer load_statement_semantic(statement)
void set_semantic_map(statement_mapping)
void reset_semantic_map(void)
#define ifdebug(n)
Definition: sg.c:47
struct Scontrainte * succ
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
#define MAX_LINE_LENGTH
maximum length of a line when prettyprinting...
string text_to_string(text t)
SG: moved here from ricedg.
Definition: print.c:239
string words_to_string(cons *lw)
Definition: print.c:211
void dump_text(text t)
FI: print_text() should be fprint_text() and dump_text(), print_text()
Definition: print.c:205
bool recover_for_loop(const string)
for_loop_recovering.c
const char * pips_user_value_name(entity)
This function is called many times when the constraints and the system of constraints are sorted usin...
Definition: value.c:815
void free_value_mappings(void)
Normal call to free the mappings.
Definition: value.c:1212
bool local_old_value_entity_p(entity)
Return true if an entity is a local old value (such as "o#0" for a global value "i#init"....
Definition: value.c:642
entity value_to_variable(entity)
Get the primitive variable associated to any value involved in a transformer.
Definition: value.c:1624
#define TCST
VARIABLE REPRESENTANT LE TERME CONSTANT.
#define val_of(varval)
char *(* get_variable_name_t)(Variable)
Definition: vecteur-local.h:62
#define VECTEUR_NUL_P(v)
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 var_of(varval)