PIPS
forward_substitution.c
Go to the documentation of this file.
1 /*
2 
3  $Id: forward_substitution.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 #ifdef HAVE_CONFIG_H
25  #include "pips_config.h"
26 #endif
27 /*
28  * Perform forward substitution when possible.
29  *
30  * The main purpose of such a transformation is to undo manual
31  * optimizations targeted to some particular architecture...
32  *
33  * What kind of interface should be available?
34  * global? per loop?
35  *
36  * basically there should be some common stuff with partial evaluation,
37  * as suggested by CA, and I agree, but as I looked at the implementation
38  * in the other file, I cannot really guess how to merge and parametrize
39  * both stuff as one... FC.
40  *
41  * This information is only implemented to forward substitution within
42  * a sequence. Things could be performed at the control flow graph level.
43  *
44  * An important issue is to only perform the substitution only if correct.
45  * Thus conversions are inserted and if none is available, the propagation
46  * and substitution are not performed.
47  */
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 
53 #include "genC.h"
54 #include "linear.h"
55 #include "ri.h"
56 #include "effects.h"
57 
58 #include "dg.h"
59 
62 
63 
64 #include "graph.h"
65 #include "ri-util.h"
66 #include "prettyprint.h"
67 #include "effects-util.h"
68 #include "text-util.h"
69 #include "database.h"
70 #include "misc.h"
71 #include "pipsdbm.h"
72 #include "resources.h"
73 
74 #include "effects-generic.h"
75 #include "effects-simple.h"
76 #include "properties.h"
77 
78 #include "expressions-local.h"
79 #include "expressions.h"
80 
81 #include "ricedg.h"
82 
83 /* structure to hold a substitution to be performed forward.
84  */
85 typedef struct
86 {
87  statement source; /* the statement where the definition was found. */
88  reference ref; /* maybe could be a reference to allow arrays? SG:done*/
89  expression val; /* the result of the substitution. */
90 }
92 
93 /* newgen-looking make/free
94  */
95 static p_substitution
97 {
99  basic bval = basic_of_expression(val),
100  bref = basic_of_reference(ref);
101 
102  pips_assert("defined basics", !(basic_undefined_p(bval) || basic_undefined_p(bref)));
103 
105  pips_assert("malloc ok", subs);
106  subs->source = source;
107  subs->ref = ref;
108  if (basic_equal_p(bval, bref))
109  subs->val = copy_expression(val);
110  else
111  {
112  entity conv = basic_to_generic_conversion(bref);
113  if (entity_undefined_p(conv))
114  {
115  pips_user_warning("no conversion function...");
116  free(subs);
117  return NULL;
118  }
119  subs->val = MakeUnaryCall(conv,copy_expression(val));
120  }
121  free_basic(bval);
122  return subs;
123 }
124 
125 static void
127 {
128  if (subs) {
130  free(subs);
131  }
132 }
133 
134 static bool no_write_effects_on_var(entity var, list le)
135 {
136  FOREACH(EFFECT, e, le)
139  return false;
140  return true;
141 }
142 
143 static bool functionnal_on_effects(reference ref, list /* of effect */ le)
144 {
145  FOREACH(EFFECT, e, le) {
149  return false;
150  }
151  return true;
152 }
153 
154 /* returns whether there is other write proper effect than on var
155  * or if some variable conflicting with var is read... (?)
156  * proper_effects must be available.
157  */
159 {
161 
162  ifdebug(1) {
163  pips_assert("efs is consistent", effects_consistent_p(efs));
164  }
165 
167 }
168 
169 /* Whether it is a candidate of a substitution operation. that is:
170  * (1) it is a call
171  * (2) it is an assignment call
172  * (3) the assigned variable is a scalar (sg: no longer true !)
173  * (4) there are no side effects in the expression
174  *
175  * Note: a substitution candidate might be one after substitutions...
176  * but not before? So effects should be recomputed? or updated?
177  * eg: x = 1; x = x + 1;
178  */
180 {
181  pips_assert("true", only_scalar==only_scalar);
182  list /* of expression */ args;
183  call c;
184  entity fun;
185  syntax svar;
187 
188  if (!instruction_call_p(i)) return NULL; /* CALL */
189 
190  c = instruction_call(i);
191  fun = call_function(c);
192 
193  if (!ENTITY_ASSIGN_P(fun)) return NULL; /* ASSIGN */
194 
195 
196  args = call_arguments(c);
197  pips_assert("2 args to =", gen_length(args)==2);
198  svar = expression_syntax(EXPRESSION(CAR(args)));
199 
200  if(!syntax_reference_p(svar)) // What about subscripts ?
201  return NULL;
202 
204 
205  //if (only_scalar && ENDP(reference_indices(ref))) return NULL; /* SCALAR */
206 
207  if (!functionnal_on(ref, s)) return NULL; /* NO SIDE EFFECTS */
208 
209  return make_substitution(s, ref, EXPRESSION(CAR(CDR(args))));
210 }
211 
212 /* x = a(i) ;
213  * a(j) = x ;
214  *
215  * we can substitute x but it cannot be continued.
216  * just a hack for this very case at the time.
217  * maybe englobing parallel loops or dependence information could be use for
218  * a better decision? I'll think about it on request only.
219  */
221 {
223  bool ok = (x!=NULL);
225  return ok;
226 }
227 
228 /* s = r ;
229  * s = s + w ; // read THEN write...
230  */
232 {
234  call c;
235  list args;
236  syntax svar;
237  entity var;
238  list le;
239 
240  if (!instruction_call_p(i))
241  return false;
242 
243  c = instruction_call(i);
245  return false;
246 
247  /* it is an assignment */
248  args = call_arguments(c);
249  pips_assert("2 args to =", gen_length(args)==2);
250  svar = expression_syntax(EXPRESSION(CAR(args)));
251  pips_assert("assign to a reference", syntax_reference_p(svar));
253 
254  if (!entity_scalar_p(var)) return false;
255 
258  gen_full_free_list(le);
259 
260  return cool;
261 }
262 
263 /* do perform the substitution var -> val everywhere in s
264  */
266 {
267  syntax s = expression_syntax(e);
268  if (syntax_reference_p(s)) {
269 
271  if (reference_equal_p(r,subs->ref))
272  {
273  ifdebug(2) {
274  pips_debug(2,"substituing %s to %s\n",
277  }
278  /* FI->FC: the syntax may be freed but not always the reference it
279  contains because it can also be used in effects. The bug showed on
280  transformations/Validation/fs01.f, fs02.f, fs04.f. I do not know why the
281  effects are still used after the statement has been updated (?). The bug
282  can be avoided by closing and opening the workspace which generates
283  independent references in statements and in effects. Is there a link with
284  the notion of cell = reference+preference? */
287  }
288  else
289  {
290  ifdebug(2) {
291  pips_debug(2,"not substituting ");
293  fputs(" to ",stderr);
294  print_reference(r);
295  fputs("\n",stderr);
296  }
297  }
298  }
299 }
300 
301 static bool
303 {
304  entity op = call_function(c);
307  {
308  expression lhs = binary_call_lhs(c);
310  gen_recurse_stop(lhs);
311  }
312  return true;
313 }
314 
315 static void
317  p_substitution subs, /* substitution to perform */
318  void * s /* where to do this */)
319 {
323  NULL);
325 }
326 
327 static void
329 {
330  /* special case */
331  pips_assert("assign call", statement_call_p(s));
332 
333  call c = statement_call(s);
337 }
338 
339 /* whether there are some conflicts between s1 and s2
340  * according to successor table successors
341  */
342 static bool
344 {
345  pips_assert("true", sub==sub);
346  pips_debug(2, "looking for conflict with statement\n");
347  ifdebug(2) { print_statement(s2); }
348  list s1_successors = hash_get(successors,s1);
349  FOREACH(SUCCESSOR,s,s1_successors)
350  {
352  pips_debug(2, "checking:\n");
353  ifdebug(2) { print_statement(ss); }
354  if(statement_in_statement_p(ss,s2))
355  {
357  {
358  /* if there is a write-* conflict, we cannot do much */
359  if ( effect_write_p(conflict_sink(c)) &&
361  {
362  /* this case is safe */
365  continue;
366  ifdebug(2) {
367  pips_debug(2, "conflict found on reference, with") ;
370  fputs("\n",stderr) ;
371  }
372  return true;
373  }
374  }
375  }
376  }
377 
378  pips_debug(2, "no conflict\n");
379  return false;
380 }
381 
382 struct s_p_s {
385  bool stop;
386 };
387 
388 static bool
390 {
391  if(!statement_block_p(anext))
392  {
393  ifdebug(1) {
394  pips_debug(1, "with statement:\n");
395  print_statement(anext);
396  }
397  if (some_conflicts_between(param->successors,param->subs->source, anext, param->subs))
398  {
399  /* for some special case the substitution is performed.
400  * in some cases effects should be updated?
401  */
402  if (cool_enough_for_a_last_substitution(anext))// &&
403  // !some_conflicts_between(param->successors,param->subs->source, anext, param->subs))
404  perform_substitution(param->subs, anext);
405  else
406  if (other_cool_enough_for_a_last_substitution(anext, param->subs->ref))
408  param->stop=true;
409 
410  /* now STOP propagation!
411  */
412  gen_recurse_stop(NULL);
413  }
414  else
415  perform_substitution(param->subs, anext);
416  }
417  return true;
418 }
419 
420 /* top-down forward substitution of reference in SEQUENCE only.
421  */
422 static bool
424 {
425  if(statement_block_p(stat))
426  {
427  ifdebug(1) {
428  pips_debug(1, "considering block statement:\n");
429  print_statement(stat);
430  }
432  for(list ls = statement_block(stat);!ENDP(ls);POP(ls))
433  {
434  statement first = STATEMENT(CAR(ls));
435  if(assignment_statement_p(first))
436  {
437  ifdebug(1) {
438  pips_debug(1, "considering assignment statement:\n");
439  print_statement(first);
440  }
441  p_substitution subs = substitution_candidate(first, true);
442  if (subs)
443  {
444  /* scan following statements and substitute while no conflicts.
445  */
446  struct s_p_s param = { subs, successors,false};
447  bool once = false;
448  FOREACH(STATEMENT,next,CDR(ls))
449  {
450  param.stop=false;
452  if(param.stop) break;
453  else once=true;
454  }
455 
457  if(once && get_bool_property("FORWARD_SUBSTITUTE_OPTIMISTIC_CLEAN"))
459  }
460  }
461  }
463  }
464  return true;
465 }
466 
467 /* interface to pipsmake.
468  * should have proper and cumulated effects...
469  */
471 {
472  debug_on("FORWARD_SUBSTITUTE_DEBUG_LEVEL");
473 
474  /* set require resources.
475  */
481  graph dg = (graph) db_get_memory_resource(DBR_DG, module_name, true);
482 
483  /* do the job here:
484  */
486 
487  /* return result and clean.
488  */
490 
496 
497  debug_off();
498 
499  return true;
500 }
bool effects_consistent_p(effects p)
Definition: effects.c:541
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
syntax copy_syntax(syntax p)
SYNTAX.
Definition: ri.c:2442
void free_expression(expression p)
Definition: ri.c:853
void free_basic(basic p)
Definition: ri.c:107
static reference ref
Current stmt (an integer)
Definition: adg_read_paf.c:163
static graph dg
dg is the dependency graph ; FIXME : should not be static global ?
Definition: chains.c:124
static list successors(list l)
#define conflict_sink(x)
Definition: dg.h:167
#define CONFLICT(x)
CONFLICT.
Definition: dg.h:134
#define dg_arc_label_conflicts(x)
Definition: dg.h:201
#define conflict_source(x)
Definition: dg.h:165
effects load_proper_rw_effects(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)
list proper_effects_of_expression(expression)
#define effect_any_reference(e)
FI: cannot be used as a left hand side.
#define effect_write_p(eff)
#define effect_read_p(eff)
#define effect_scalar_p(eff) entity_scalar_p(effect_entity(eff))
#define effect_variable(e)
For COMPATIBILITY purpose only - DO NOT USE anymore.
action_kind effect_action_kind(effect)
Definition: effects.c:1055
#define action_kind_store_p(x)
Definition: effects.h:259
#define effects_effects(x)
Definition: effects.h:710
#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
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
static void perform_substitution_in_expression(expression e, p_substitution subs)
do perform the substitution var -> val everywhere in s
static bool no_write_effects_on_var(entity var, list le)
static void perform_substitution(p_substitution subs, void *s)
static void free_substitution(p_substitution subs)
static void perform_substitution_in_assign(p_substitution subs, statement s)
struct t_substitution * p_substitution
bool forward_substitute(const char *module_name)
interface to pipsmake.
static bool call_flt(call c, p_substitution subs)
static bool some_conflicts_between(hash_table successors, statement s1, statement s2, p_substitution sub)
whether there are some conflicts between s1 and s2 according to successor table successors
static bool functionnal_on_effects(reference ref, list le)
static bool other_cool_enough_for_a_last_substitution(statement s, reference ref)
s = r ; s = s + w ; // read THEN write...
dg_vertex_label vertex_label
static bool functionnal_on(reference ref, statement s)
returns whether there is other write proper effect than on var or if some variable conflicting with v...
static p_substitution make_substitution(statement source, reference ref, expression val)
newgen-looking make/free
dg_arc_label arc_label
static bool do_substitute(statement anext, struct s_p_s *param)
static bool cool_enough_for_a_last_substitution(statement s)
x = a(i) ; a(j) = x ;
static p_substitution substitution_candidate(statement s, bool only_scalar)
Whether it is a candidate of a substitution operation.
static bool fs_filter(statement stat, graph dg)
top-down forward substitution of reference in SEQUENCE only.
#define gen_context_recurse(start, ctxt, domain_number, flt, rwt)
Definition: genC.h:285
void gen_full_free_list(list l)
Definition: genClib.c:1023
void * malloc(YYSIZE_T)
void free(void *)
#define successor_vertex(x)
Definition: graph.h:118
#define successor_arc_label(x)
Definition: graph.h:116
struct _newgen_struct_graph_ * graph
Definition: graph.h:31
#define SUCCESSOR(x)
SUCCESSOR.
Definition: graph.h:86
bool entities_may_conflict_p(entity e1, entity e2)
Check if two entities may conflict.
Definition: conflicts.c:984
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
void gen_null2(__attribute__((unused)) void *u1, __attribute__((unused)) void *u2)
idem with 2 args, to please overpeaky compiler checks
Definition: genClib.c:2758
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
instruction make_instruction_block(list statements)
Build an instruction block from a list of statements.
Definition: instruction.c:106
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
#define POP(l)
Modify a list pointer to point on the next element of the list.
Definition: newgen_list.h:59
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
size_t gen_length(const list l)
Definition: list.c:150
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
#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
list statement_block(statement)
Get the list of block statements of a statement sequence.
Definition: statement.c:1338
call statement_call(statement)
Get the call of a statement.
Definition: statement.c:1406
bool statement_call_p(statement)
Definition: statement.c:364
statement update_statement_instruction(statement, instruction)
Replace the instruction in statement s by instruction i.
Definition: statement.c:3039
bool assignment_statement_p(statement)
Test if a statement is an assignment.
Definition: statement.c:135
bool statement_in_statement_p(statement, statement)
Definition: statement.c:4076
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_table_free(hash_table htp)
this function deletes a hash table that is no longer useful.
Definition: hash.c:327
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 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_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 debug_off()
Definition: misc-local.h:160
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
void unnormalize_expression(void *st)
void unnormalize_expression(expression exp): puts all the normalized field of expressions in "st" to ...
Definition: normalize.c:452
string reference_to_string(reference r)
Definition: expression.c:87
string expression_to_string(expression e)
Definition: expression.c:77
void print_reference(reference r)
Definition: expression.c:142
void print_statement(statement)
Print a statement on stderr.
Definition: statement.c:98
#define binary_call_rhs(c)
#define ENTITY_ASSIGN_P(e)
#define statement_block_p(stat)
#define binary_call_lhs(c)
#define ASSIGN_OPERATOR_NAME
Definition: ri-util-local.h:95
entity update_operator_to_regular_operator(entity op)
Returns the binary operator associated to a C update operator such as +=.
Definition: entity.c:2154
bool same_entity_p(entity e1, entity e2)
predicates on entities
Definition: entity.c:1321
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 entity_intrinsic(const char *name)
FI: I do not understand this function name (see next one!).
Definition: entity.c:1292
void update_expression_syntax(expression e, syntax s)
frees expression syntax of e and replace it by the new syntax s
Definition: expression.c:3564
bool reference_equal_p(reference r1, reference r2)
Definition: expression.c:1500
expression MakeUnaryCall(entity f, expression a)
Creates a call expression to a function with one argument.
Definition: expression.c:342
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
entity basic_to_generic_conversion(basic)
returns the corresponding generic conversion entity, if any.
Definition: type.c:2758
basic basic_of_expression(expression)
basic basic_of_expression(expression exp): Makes a basic of the same basic as the expression "exp".
Definition: type.c:1383
bool entity_scalar_p(entity)
The concrete type of e is a scalar type.
Definition: variable.c:1113
bool basic_equal_p(basic, basic)
Definition: type.c:927
basic basic_of_reference(reference)
Retrieves the basic of a reference in a newly allocated basic object.
Definition: type.c:1459
#define syntax_reference_p(x)
Definition: ri.h:2728
#define expression_domain
newgen_execution_domain_defined
Definition: ri.h:154
#define syntax_reference(x)
Definition: ri.h:2730
#define call_function(x)
Definition: ri.h:709
#define reference_variable(x)
Definition: ri.h:2326
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define call_domain
newgen_callees_domain_defined
Definition: ri.h:58
#define basic_undefined_p(x)
Definition: ri.h:557
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define entity_undefined_p(x)
Definition: ri.h:2762
#define reference_indices(x)
Definition: ri.h:2328
#define instruction_call_p(x)
Definition: ri.h:1527
#define statement_instruction(x)
Definition: ri.h:2458
#define syntax_undefined
Definition: ri.h:2676
#define instruction_call(x)
Definition: ri.h:1529
#define call_arguments(x)
Definition: ri.h:711
#define expression_syntax(x)
Definition: ri.h:1247
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
hash_table statements_to_successors(list, graph)
creates a hash_table containing statements from statements as keys and their respective succesors acc...
Definition: util.c:1018
s1
Definition: set.c:247
#define ifdebug(n)
Definition: sg.c:47
static bool ok
static char * x
Definition: split_file.c:159
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
Definition: replace.c:135
hash_table successors
p_substitution subs
structure to hold a substitution to be performed forward.
reference ref
the statement where the definition was found.
expression val
maybe could be a reference to allow arrays? SG:done