PIPS
scalarization.c
Go to the documentation of this file.
1 /*
2 
3  $Id: scalarization.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_SCALARIZATION) || \
28  defined(BUILDER_CONSTANT_ARRAY_SCALARIZATION) || \
29  defined(BUILDER_QUICK_SCALARIZATION)
30 
31 #ifdef HAVE_CONFIG_H
32  #include "pips_config.h"
33 #endif
34 /* package scalarization
35  *
36  * Substitute array references by scalar references when legal and
37  * profitable in loop bodies. The key function is loop_scalarization().
38  *
39  * The legality condition is based on a linear algebra function to
40  * decide if a region function defined a function from any one
41  * iteration towards an array element.
42  *
43  * Because the C3 linear library cannot create new entities, i.e. new
44  * dimensions, the c_functional_graph_p() cannot have a clean
45  * interface.
46  *
47  * Nevertheless, some functions should be moved in linear.
48  */
49 
50 #include <stdlib.h>
51 #include <stdio.h>
52 
53 #include "genC.h"
54 #include "linear.h"
55 
56 #include "misc.h"
57 #include "pipsdbm.h"
58 #include "properties.h"
59 
60 #include "ri.h"
61 #include "ri-util.h"
62 #include "prettyprint.h" // for debugging
63 
64 #include "effects-util.h" // used
65 #include "effects-simple.h" // used
66 #include "control.h" // module_reorder
67 
68 #include "text-util.h" // used
69 
70 #include "transformer.h" // used
71 #include "semantics.h" // used
72 #include "effects-generic.h" // used
73 #include "effects-convex.h" // used
74 
75 #include "dg.h"
76 /* instantiation of the dependence graph */
77 typedef dg_arc_label arc_label;
79 #include "graph.h"
80 
81 //////////////////// Properties
82 
83 static int scalarization_across_control_test_level = 0;
84 
85 static bool scalarization_across_control_test_is_exactness_p()
86 {
87  return (scalarization_across_control_test_level == 0);
88 }
89 
90 static bool scalarization_across_control_test_is_strict_test_p()
91 {
92  return (scalarization_across_control_test_level == 1);
93 }
94 
95 static void scalarization_across_control_test_level_init()
96 {
97  const char * test_s =
98  get_string_property("SCALARIZATION_ACROSS_CONTROL_TEST");
99 
100  if (strstr(test_s, "strict"))
101  scalarization_across_control_test_level = 1;
102  else if (strstr(test_s, "cheap"))
103  scalarization_across_control_test_level = 2;
104  else
105  scalarization_across_control_test_level = 0;
106 }
107 
108 static void scalarization_across_control_test_level_reset()
109 {
110  scalarization_across_control_test_level = 0;
111 }
112 
113 ////////////////////
114 
115 /*
116  * WARNING ! This function introduces side-effects on g
117  *
118  * MA: It probably shouldn't be located here (seems very "linear" oriented)
119  */
120 static Psysteme sc_add_offset_variables(Psysteme g, Pbase b, Pbase db) {
121  Pbase gb = sc_base(g);
122 
123  /* check validity conditions:
124  - b must appear in g's basis but db must not, and
125  - b and db must have the same dimension.
126  */
127  if (base_included_p(b,gb)
128  && !base_included_p(db,gb)
129  && base_dimension(b)==base_dimension(db)
130  ) {
131 
132  Pcontrainte eqs = sc_egalites(g);
133  Pcontrainte ineqs = sc_inegalites(g);
135 
136  /* update g's basis */
137  Pbase tb = sc_base(g);
138  sc_base(g) = base_union(tb, db);
139  sc_dimension(g) += base_dimension(db);
140  base_rm(tb);
141 
142  for(c = eqs ; !CONTRAINTE_UNDEFINED_P(c) ; c = contrainte_succ(c)) {
143  Pbase cb = BASE_NULLE;
144  Pbase cdb = BASE_NULLE;
145  for (cb=b,cdb=db ;
146  !BASE_NULLE_P(cb) ;
147  cb = vecteur_succ(cb), cdb = vecteur_succ(cdb)) {
148  Variable v = vecteur_var(cb);
149  Variable dv = vecteur_var(cdb);
150  Value coeff = vect_coeff(v, contrainte_vecteur(c));
151  vect_add_elem(&(contrainte_vecteur(c)), dv, coeff);
152  }
153  }
154 
155  for(c = ineqs ; !CONTRAINTE_UNDEFINED_P(c) ; c= contrainte_succ(c)) {
156  Pbase cb = BASE_NULLE;
157  Pbase cdb = BASE_NULLE;
158  for (cb=b,cdb=db ;
159  !BASE_NULLE_P(cb) ;
160  cb = vecteur_succ(cb), cdb = vecteur_succ(cdb)) {
161  Variable v = vecteur_var(cb);
162  Variable dv = vecteur_var(cdb);
163  Value coeff = vect_coeff(v, contrainte_vecteur(c));
164  vect_add_elem(&(contrainte_vecteur(c)), dv, coeff);
165  }
166  }
167  }
168  return g;
169 }
170 
171 
172 /*
173  This function checks that graph g is a function graph from domain d
174  to range r.
175 
176  Return value :
177  - true if the graph is certainly functional,
178  - false if it *might* be not functional.
179 
180  NOTE: parameter dr could be derived from r within this function,
181  but we do not know how to create generic variables in Linear. The
182  initial implementation used a PIPS function to generate the new
183  variables.
184  *
185  * MA: It probably shouldn't be located here (seems very "linear" oriented)
186  */
187 static bool sc_functional_graph_p(Psysteme g, Pbase d, Pbase r, Pbase dr)
188 {
189  bool functional_p = true;
190 
191  Psysteme g1, g2;
192 
193  // check validity conditions: d and r should be included in g's basis.
194  Pbase gb = sc_base(g);
195  if (!(base_included_p(d, gb) && base_included_p(r, gb))) {
196  // illegal arguments
197  functional_p = false; //TODO
198  }
199  else {
200 
201  Pbase cr = BASE_UNDEFINED;
202 
203  // Create two copies of g
204  g1 = sc_copy(g);
205  g2 = sc_copy(g);
206 
207  // Substitute r by r + dr in g2 (indexed by dimension)
208  g2 = sc_add_offset_variables(g2, r, dr);
209 
210  // Merge g1 and g2 into a unique system g1, eliminating redundencies.
211  g1 = sc_append(g1, g2);
212  g1 = sc_elim_redond(g1);
213 
214  // Project g1 on dr space. If projection fails, return FALSE.
215  Pbase dr4 = BASE_NULLE;
216  // dr4 := list of variables of g1's basis which are not in dr
217  for ( cr = sc_base(g1) ; !BASE_UNDEFINED_P(cr) ; cr = vecteur_succ(cr) ) {
218  Variable vr = vecteur_var(cr);
219  if (!base_find_variable(dr, vr))
220  dr4 = base_add_variable(dr4, vr);
221  }
222  sc_projection_along_variables_ofl_ctrl(&g1, dr4, OFL_CTRL);
223  base_rm(dr4);
224  /*
225  ifdebug(1) {
226  pips_debug(1, "g1 =\n");
227  sc_print(g1, (get_variable_name_t)entity_local_name);
228  }
229  */
230  if (SC_EMPTY_P(g1) || sc_empty_p(g1)) {
231  functional_p = false;
232  }
233  else {
234  // Check that all r_b_i variables are null, using sc_minmax_of_variables()
235  for ( cr = dr ; !BASE_UNDEFINED_P(cr) ; cr = vecteur_succ(cr) ) {
236  Psysteme g1b = sc_copy(g1);
237  Variable dv = vecteur_var(cr);
238  Value pmin, pmax;
239  bool feasible_p = sc_minmax_of_variable(g1b,dv, &pmin, &pmax);
240  if (!(feasible_p
241  && value_eq(VALUE_ZERO, pmin)
242  && value_eq(VALUE_ZERO, pmax))) {
243  functional_p = false;
244  break;
245  }
246  }
247  }
248  // Cleanup
249  sc_rm(g1);
250  sc_rm(g2);
251  }
252  return functional_p;
253 }
254 
255 
256 /*
257  This function checks that graph g is a total function graph, i.e. a
258  mapping graph,from domain d to range r.
259  *
260  * MA: It probably shouldn't be located here (seems very "linear" oriented)
261 */
262 static bool sc_totally_functional_graph_p( Psysteme g, // function graph
263  Pbase d, // domain's basis
264  Psysteme D, // membership predicate for functional domain
265  Pbase r, // range's predicate
266  Pbase dr // difference variable
267  )
268 {
269  bool totally_functional_p = false;
270 
271  if (sc_functional_graph_p(g, d, r, dr)) {
272 
273  // Check args coherence : d should be included in D's basis.
274  if (base_included_p(d, sc_base(D))) {
275 
276  // Project g on d along r.
277  Psysteme g1 = sc_copy(g);
278  sc_projection_along_variables_ofl_ctrl(&g1, r, OFL_CTRL);
279 
280  // By definition of a total function, D must be included in g1.
281  totally_functional_p = sc_inclusion_p_ofl_ctrl(D, g1, OFL_CTRL);
282  }
283  }
284  return totally_functional_p;
285 }
286 
287 
288 // We need a Pbase to accumulate loop indices during loop traversal
289 static Pbase loop_indices_b = BASE_NULLE;
290 
291 // These are needed for callback function reference_substitute
292 struct subst_ref_ctx {
293  reference scalarized_reference;
294  entity scalarized_replacement_variable;
295 };
296 
297 // gen_recurse callback function for
298 // statement_substitute_scalarized_array_references
299 static bool reference_substitute(reference r, struct subst_ref_ctx *ctx) {
300  bool result = true;
301  entity v = reference_variable(r);
302  entity scalarized_v = reference_variable(ctx->scalarized_reference);
303  // This test proved to strong by conditional04 because the region
304  // computation does too good a job...
305  // if(reference_equal_p(r,ctx->scalarized_reference)) {
306  if(v==scalarized_v) {
307  // Scalarize only if r refers to an array element and not to a slice
308  list inds = reference_indices(r);
309  size_t d = type_depth(ultimate_type(entity_type(v)));
310  if (gen_length(inds) == d) {
311  reference_variable(r) = ctx->scalarized_replacement_variable;
312  reference_indices(r) = NIL; // TODO: add missing gen_full_free_list(reference_indices(r))
313  result = false; /* do not recurse in reference indices which are discarded */
314  }
315  }
316  return result;
317 }
318 
319 static bool declarations_reference_substitute(statement st,
320  struct subst_ref_ctx *ctx) {
321  if (declaration_statement_p(st)) {
323  value init_val = entity_initial(decl);
324  if (! value_undefined_p(init_val)) {
325  gen_context_recurse(init_val, ctx,
326  reference_domain, reference_substitute, gen_null2);
327  }
328  }
329  }
330  return true;
331 }
332 
333 static void statement_substitute_scalarized_array_references(statement st,
334  reference pvr,
335  entity s) {
336  //TODO: create context ansd use gen_multi_recurse_with_context
337  struct subst_ref_ctx ctx;
338  ctx.scalarized_reference = pvr;
339  ctx.scalarized_replacement_variable = s;
341  statement_domain, declarations_reference_substitute, gen_null,
342  reference_domain, reference_substitute, gen_null,
343  NULL);
344 }
345 
346 
347 static void * car_effect_to_variable(gen_chunk car) {
348  return effect_variable(EFFECT(car)); // type 'entity'
349 }
350 
351 
352 static Pbase make_phi_base(int phi_min, int phi_max) {
353  Pbase phi_b = BASE_NULLE;
354  int i;
355  for(i=phi_min; i<=phi_max; i++) {
356  phi_b = base_add_variable(phi_b, (Variable) make_phi_entity(i));
357  }
358  return(phi_b);
359 }
360 
361 
362 static effect effect_write_or_read_on_variable(list el,
363  entity v,
364  bool write_p) {
365  effect result = effect_undefined;
366  if(v) {
367  FOREACH(EFFECT, e, el) {
368  if (store_effect_p(e)) {
369  action a = effect_action(e);
370  entity ev = effect_entity(e);
371  if(same_entity_p(ev, v)
372  && (write_p ? action_write_p(a) : action_read_p(a))) {
373  return(e);
374  }
375  }
376  }
377  }
378  return result;
379 }
380 
381 
382 /* Check that the region function r in pr is constant when the store
383  * sigma is modified by transformer t. You want for all sigma,
384  *
385  * r(sigma) = r(t(sigma))
386  *
387  * which can be rewritten
388  *
389  * {dphi | \exists sigma \exists sigma' \exists phi t.q.
390  * t(sigma,sigma')
391  * ^ r(sigma,phi)
392  * ^ r(sigma',phi+dphi)} = {0}
393  *
394  * This criterion is for constant singleton region in context...
395  */
396 static bool __attribute__ ((__unused__)) constant_region_in_context_p(effect pr,
397  transformer t __attribute__ ((__unused__)))
398 {
399  entity v = effect_variable(pr);
400  int nd = type_depth(entity_type(v));
401  bool constant_p = (nd==0);
402 
403 
404  if(!constant_p) {
406  if (descriptor_convex_p(d)) {
407  ifdebug(2) {
408  pips_debug(2,"Considering regions : ");
409  print_region(pr);
410  }
411 
412  /* Try a simple test first: none of the arguments in t appears
413  * in a constraint of pr */
414  Psysteme sc = descriptor_convex(d);
415  list args = transformer_arguments(t);
416  Pbase eb = sc_to_minimal_basis(sc);// effective base of sc
417 
418  constant_p = true;
419  FOREACH(ENTITY, a, args) {
420  Variable vp = base_find_variable(eb, (Variable) a);
421  if(vp == (Variable) a) {
422  constant_p = false;
423  break;
424  }
425  }
426 
427  if(!constant_p) {
428  /* Here, we should have a more sophisticated test... */
429  ;
430  // Clean-up
431  //base_rm(phi_b);
432  //base_rm(d_phi_b);
433  }
434  pips_debug(2, "returning: %s\n", bool_to_string(constant_p));
435  }
436  }
437 
438  return constant_p;
439 }
440 
441 
442 /* Check that region r has a unique element with respect to the subset
443  of the space defined by basis loop_indices_p and by the predicate
444  of precondition p. In other words, the relationship between the
445  iterations i and the array element phi is a function, by definition
446  of a function.
447 
448  This cannot be checked without auxiliary variables. It is not
449  possible to create PIPS compatible variables in Linear. Hence, they
450  are created here.
451 
452  The proof is based on r(i)=phi and r(i)=phi+dphi and r is a
453  function implies dphi=0. If dphi!=0, then r cannot be a function.
454 
455  But we also want that each iteration uses at least one element. The
456  function must be a total function. FI: I do not remember why we
457  need a total function.
458 */
459 static bool region_totally_functional_graph_p(effect pr,
460  Pbase loop_indices_b,
461  transformer p) {
462  bool rtfg_p = false;
463 
465  pips_assert("d is a convex descriptot", descriptor_convex_p(d));
467  entity pv = effect_variable(pr);
468  int nd = type_depth(entity_type(pv));
470 
471  Pbase phi_b = make_phi_base(1, nd);
472  Pbase d_phi_b = BASE_NULLE;
473  Pbase cr = BASE_NULLE;
474 
475  /* Build base d_phi_b using
476  * make_local_temporary_integer_value_entity(void) */
477  for ( cr = phi_b ; !BASE_UNDEFINED_P(cr) ; cr = vecteur_succ(cr) ) {
479  d_phi_b = base_add_variable(d_phi_b, (Variable) e_d_phi_b);
480  }
481 
482  rtfg_p = sc_totally_functional_graph_p(sc_union, loop_indices_b,
483  D, phi_b, d_phi_b);
484  base_rm(phi_b);
485  base_rm(d_phi_b);
486 
487  return rtfg_p;
488 }
489 
490 
491 static bool singleton_region_in_context_p(effect pr,
492  transformer prec, // a range
493  Pbase loop_indices_b, // domain
494  bool strict_p) {
495  bool singleton_p = false;
496  // Check if the referenced variable is scalar or array
497  // D is not needed if we are interested in a partial function even
498  // over D
499  // Psysteme D = predicate_system(transformer_relation(prec));
500  entity pv = effect_variable(pr);
501  int nd = type_depth(entity_type(pv));
502 
504  Psysteme sc_union = SC_UNDEFINED;
505  if (descriptor_convex_p(d)) {
507  } else {
508  pips_internal_error("convex region expected\n");
509  }
510 
511  if(!sc_empty_p(sc_union)) {
512  Pbase phi_b = make_phi_base(1, nd);
513  Pbase d_phi_b = BASE_NULLE;
514  Pbase cr = BASE_NULLE;
515 
516  /* Build base d_phi_b using
517  * make_local_temporary_integer_value_entity(void) */
518  for ( cr = phi_b ; !BASE_UNDEFINED_P(cr) ; cr = vecteur_succ(cr) ) {
520  d_phi_b = base_add_variable(d_phi_b, (Variable) e_d_phi_b);
521  }
522 
523  if(strict_p) {
525  singleton_p = sc_totally_functional_graph_p(sc_union, loop_indices_b,
526  D, phi_b, d_phi_b);
527  } else {
528  // A loop may be entered or not, so the region is not a total
529  //function, Maybe the name of this function should be changed
530  singleton_p = sc_functional_graph_p(sc_union, loop_indices_b,
531  phi_b, d_phi_b);
532  }
533 
534  // Clean-up
535  base_rm(phi_b);
536  base_rm(d_phi_b);
537  }
538  return singleton_p;
539 }
540 
541 
542 /* Generate a scalar variable sv to replace all references to pv in
543  s. If iv or ov are defined, generate a copy-in and a copy-out
544  statements. */
545 static void scalarize_variable_in_statement(entity pv,
546  statement s,
547  entity iv,
548  entity ov) {
549  // Create new temp var of same type as the array element pv
550  type pvt = ultimate_type(entity_type(pv));
551  variable pvtv = type_variable(pvt);
552  basic pvb = variable_basic(pvtv);
553  basic svb = copy_basic(pvb);
554 
555  // Copy the a reference to pv, just in case we need it later
557 
558  if (reference_undefined_p(pvr)) { /* may happen with quick_scalarization */
559  return;
560  }
561 
562 
563  ifdebug(3){
564  pips_debug(3, "begin for entity %s and statement:\n",
565  entity_name(pv));
566  print_statement(s);
567  }
568 
569  // Create a new variable and add
570  // its declaration to the current module
571  // If no default prefix is defined, use the variable name
572  // as prefix
573  const char* dpref = get_string_property("SCALARIZATION_PREFIX");
574  const char* epref = strlen(dpref)==0?
575  concatenate(entity_user_name(pv), "_", NULL)
576  : dpref;
579  svb);
580  /* FI: the language could be checked, but Fortran prettyprinter
581  ignores the qualifier and the qualifier benefits the complexity
582  analyzer. */
583  if (get_bool_property("SCALARIZATION_USE_REGISTERS"))
586 
587  if(get_bool_property("SCALARIZATION_PRESERVE_PERFECT_LOOP_NEST")) {
588  // declaration at module level
590  } else {
591  // Declare the scalar variable as local as possible
592  // but at the beginning of the current statement if it is a block,
593  // since scalarized references may happen in declarations initializations
594  if (statement_sequence_p(s)) {
595  if (c_module_p(m)) {
597  }
599  } else {
601  }
602  }
603 
604  pips_debug(1,"Creating variable %s for variable %s\n",
605  entity_name(sv), entity_name(pv));
606 
607  // Substitute all references to pv with references to new variable
608  statement_substitute_scalarized_array_references(s, pvr, sv);
609 
610  ifdebug(3){
611  pips_debug(3, "statement after substitution by sv (%s):\n",
612  entity_name(sv));
613  print_statement(s);
614  }
615 
616 
617  // Take care of copy-in and copy-out code if necessary
618  if (get_bool_property("SCALARIZATION_FORCE_OUT")
619  || !entity_undefined_p(ov)) {
620  // Generate copy-out code
623  insert_statement(s, co_s, false);
624  } else {
625  //free_reference(pvr);
626  }
627 
628  if (!entity_undefined_p(iv)) {
630  || get_bool_property("SCALARIZATION_PRESERVE_PERFECT_LOOP_NEST")) {
631  // Generate copy-in code with an assignment statement:
632  statement ci_s =
635  insert_statement(s, ci_s, true);
636  } else if(c_language_module_p(m)) {
637  // in a less intrusive way?
640  // The initialization is not necessarily generated at the right
641  //spot when dealing with loops, or, looking at the problem
642  //differently, the declaration of the scalarized variable is not
643  //located properly...
644  } else {
645  pips_user_error("Module \"%s\" is not written in Fortran or C.\n"
646  "Other languages are not supported by "
647  "the scalarization pass.\n", entity_user_name(m));
648  }
649  } else {
650  //free_reference(pvr);
651  }
652 }
653 
654 
655 /* Union of all effects on pv in list crwl
656  *
657  * Note: the usual assumption is made, no more than two effects on pv
658  * in crwl...
659  * No, the assumption is that there is no more than two effects
660  * on a memory access path. BC.
661  *
662  * The return effect is given a read action on memory. A read-or-write
663  * action would be more meaningful.
664  */
665 static effect unified_rw_effect_of_variable(entity pv, list crwl) {
666  effect pru = effect_undefined;
667 
668  //int nd = type_depth(entity_type(pv));
669  Psysteme sc_union = SC_UNDEFINED;
670  Psysteme sc1 = SC_UNDEFINED;
671  effect pr1 = effect_undefined;
672  Psysteme sc2 = SC_UNDEFINED;
673  effect pr2 = effect_undefined;
674  tag app1, app2;
675 
676  // action_write_p(effect_action(pr))))
677  if ((pr1 = effect_write_or_read_on_variable(crwl, pv, true))
678  != effect_undefined) {
679  descriptor d1 = effect_descriptor(pr1);
680  app1 = effect_approximation_tag(pr1);
681  if (descriptor_convex_p(d1)) {
682  sc1 = descriptor_convex(d1);
683  }
684  } else {
685  app1 = is_approximation_may;
686  }
687 
688  //!(action_write_p(effect_action(pr)))))
689  /* Search Effect with the opposite action */
690  if ((pr2 = effect_write_or_read_on_variable(crwl, pv, false))
691  != effect_undefined) {
692  descriptor d2= effect_descriptor(pr2);
693  app2 = effect_approximation_tag(pr2);
694  if (descriptor_convex_p(d2)) {
695  sc2 = descriptor_convex(d2);
696  }
697  } else {
698  app2 = is_approximation_may;
699  }
700 
701  tag app_t = approximation_or(app1, app2);
702 
703  // we enforce that oneof the effect is exact to be sure that no accesses
704  // are unduely moved out of control
705  if (!scalarization_across_control_test_is_exactness_p()
706  || app_t == is_approximation_exact) {
707  /* Merge Read and Write Effects constraints on pv */
708  if (!SC_UNDEFINED_P(sc1) && sc_dimension(sc1) !=0) {
709  if (!SC_UNDEFINED_P(sc2) && sc_dimension(sc2) !=0) {
710  sc_union=sc_cute_convex_hull(sc2,sc1);
711  } else {
712  sc_union=sc_dup(sc1);
713  }
714  } else {
715  if (!SC_UNDEFINED_P(sc2) && sc_dimension(sc2) !=0) {
716  sc_union=sc_dup(sc2);
717  } else {
718  sc_union = SC_UNDEFINED;
719  }
720  }
721  if(!SC_UNDEFINED_P(sc_union)) {
723  action a = make_action_read(make_action_kind_store()); // arbitrary choice
724  approximation ap = make_approximation_may(); // safe default
726  pru = make_effect(c, a, ap, d);
727  }
728  }
729  return pru;
730 }
731 
732 
733 struct scalarization_ctx {
734  // To keep track of already scalarized variables
735  list scalarized_variables;
736 
737  // To associate a list of privatized variables to each statement
738  hash_table statement_scalarized_variables;
739 
740  // Flag that indicate if we should keep perfect parallel loop nest
741  bool keep_perfect_parallel;
742 
743  // Loops that should not be scalarized (according to previous property)
744  set blacklisted_loops;
745 
746  // Do not scalarize "&vars..."
747  bool skip_address_of_variables;
748 };
749 
750 
751 static void blacklist_perfectly_nested_parallel_loop(statement s,
752  set blacklisted_loops) {
753  if(statement_loop(s)) {
755  for(int d=2;d<=depth;d++) {
757  pips_assert("Perfectly nested loops coherency !",
759  set_add_element(blacklisted_loops,blacklisted_loops,s);
760  }
761  }
762 }
763 
764 
765 
766 
767 /* This function has been replaced by statement_scalarization() */
768 static bool loop_scalarization(loop l, struct scalarization_ctx *ctx)
769 {
770  entity i = loop_index(l);
771  statement s = loop_body(l);
772  ifdebug(1) {
773  pips_debug(1, "Statement:\n");
774  print_statement(s);
775  }
776 
778  transformer prec_r = transformer_range(prec);
779  //Psysteme D = predicate_system(transformer_relation(transformer_range(prec)));
780 
781  effects ie = load_in_effects(s);
782  effects oe = load_out_effects(s);
784 
785  bool memory_effects_only_p = get_bool_property("MEMORY_EFFECTS_ONLY");
786  bool memory_in_out_regions_only_p =
787  get_bool_property("MEMORY_IN_OUT_EFFECTS_ONLY");
788 
789  list irl = effects_effects(ie);
790  list orl = effects_effects(oe);
791  list crwl = effects_effects(crwe);
792 
793  if (!memory_effects_only_p) {
794  crwl = effects_store_effects(crwl);
795  }
796 
797  if (!memory_in_out_regions_only_p) {
798  irl = effects_store_effects(irl);
799  orl = effects_store_effects(orl);
800  }
801 
802  ifdebug(1) {
803  pips_debug(1, "Entering function...\n");
804  pips_debug(1,
805  "Entering level-%d loop, index=%s\n",
806  base_dimension(loop_indices_b), entity_name(i));
807  pips_debug(1, "OUT regions:\n");
808  print_regions(orl);
809  pips_debug(1, "CUMULATED RW regions:\n");
810  print_regions(crwl);
811  }
812 
813  Pvecteur var_already_seen = VECTEUR_NUL;
814  // Each variable in effects is a candidate for scalarization
815  FOREACH (EFFECT, pr, crwl) {
816  // Now we determine which read/write effects are not copied out.
817  entity pv = effect_variable(pr);
818  // Does the current variable appear in the in effect?
819  entity iv = (entity) gen_find(pv,
820  irl,
821  (bool(*)()) gen_eq,
822  car_effect_to_variable);
823  // Does the current variable appear in the out effect?
824  entity ov = (entity) gen_find(pv,
825  orl,
826  (bool(*)()) gen_eq,
827  car_effect_to_variable);
828 
830  if (descriptor_convex_p(d) &&
831  !entity_is_argument_p(pv, ctx->scalarized_variables)
832  && !vect_coeff(pv,var_already_seen)) {
833  ifdebug(2) {
834  pips_debug(2,"Considering regions : ");
835  print_region(pr);
836  }
837  vect_add_elem(&var_already_seen,pv,1);
838 
839  effect pru = unified_rw_effect_of_variable(pv, crwl);
840  int nd = type_depth(entity_type(pv));
841 
842  if (!effect_undefined_p(pru)) {
843 
844  ifdebug(2) {
845  pips_debug(2,"pru not undefined: ");
846  print_region(pru);
847  }
848 
849  // Estimate the dynamic number of *element* and *variable*
850  // occurrences in the loop body
851  int neo = count_references_to_variable_element(s, pv);
852  int nvo = count_references_to_variable(s, pv);
853 
854  /* Legality criterion:
855 
856  if nvo is greater than neo, there must be hidden references
857  to the array, due for instance to a function call, and the
858  substitution might break dependence arcs.
859 
860  So, we go on only if the two are equal.
861 
862  We assume that array variables cannot be declared volatile
863  */
864 
865  if (nvo != neo) {
866  ifdebug(2) {
867  pips_debug(2,
868  "Legality criterion not met: %d!=%d (nvo!=neo)\n",
869  nvo, neo);
870  }
871  } else {
872 
873  bool read_pv = effects_read_variable_p(crwl, pv);
874  bool written_pv = effects_write_variable_p(crwl, pv);
875  bool read_and_written_pv = read_pv && written_pv;
876 
877  /* Profitability criterion:
878 
879  - nd > 0: it's an array (do not scalarize scalar variables)
880 
881  - neo > 2: if the number of references if greater than 2, the
882  copy-in and copy-out code overhead is assumed to be small
883  enough to make scalarization profitable.
884 
885  - neo > 1: if the number of references is 2, the copy-in *xor*
886  the copy-out overhead meets the above criterion.
887 
888  - else: if there is neither copy-in nor copy-out,
889  privatization is always useful.
890 
891  FI: we should also check if the reference is loop invariant
892  and then decide that it is always profitable to scalarize
893  it... See scalarization34 in Transformations. We should
894  check if the region is a constant function.
895  */
896 
897  if (nd <= 0 // Scalar
898  || (neo <= 2 && // Two or less references
899  (neo < 2 || read_and_written_pv) && // ...
900  (!entity_undefined_p(iv) || !entity_undefined_p(ov)) // At least copy in or copy out !
901  )
902  ) {
903  ifdebug(2) {
904  pips_debug(2,"Profitability criterion not met: (nd) %d>0 (scalar) "
905  "or not one of the following: (%d&&%d&&%d) "
906  "(neo) %d <= 2 and "
907  "((neo) %d <= 1 || %d read_and_written_pv) and "
908  "(%d (!entity_undefined_p(iv)) || %d (!entity_undefined_p(ov)))\n",
909  nd,
910  neo <= 2,
911  (neo <= 1 || read_and_written_pv),
912  (!entity_undefined_p(iv) || !entity_undefined_p(ov)),
913  neo,
914  neo,
915  !read_and_written_pv,
916  entity_undefined_p(iv),
917  entity_undefined_p(ov));
918  }
919  } else {
920  if(region_totally_functional_graph_p(pru,
921  loop_indices_b,
922  prec_r)) {
923  /* The array references can be replaced by references to a
924  scalar */
925  scalarize_variable_in_statement(pv, s, iv, ov);
926  ctx->scalarized_variables = arguments_add_entity(ctx->scalarized_variables,
927  pv);
928  }
929  // Clean-up
931  }
932  }
933  }
934  //sc_rm(sc_union);
935  free_effect(pru);
936  }
937  }
938  vect_rm(var_already_seen);
939 
940  // Do not leak
941  if (!memory_in_out_regions_only_p) {
942  gen_free_list(orl);
943  gen_free_list(irl);
944  }
945  if (!memory_effects_only_p) {
946  gen_free_list(crwl);
947  }
948  return true;
949 }
950 
951 typedef struct {
952  bool constant_p;
953  entity e;
954  list trans_args;
955 } reference_testing_ctxt;
956 
957 static bool reference_constant_wrt_ctxt_p(reference ref,
958  reference_testing_ctxt *ctxt) {
959  bool continue_p = true;
960  if (reference_variable(ref) == ctxt->e) {
963  FOREACH(EFFECT, eff_exp, l_eff_exp) {
964  entity e_exp = effect_entity(eff_exp);
965  /* if the indice contains a reference to an array element, we assume it
966  * is not constant
967  * we could use the cumulated effects of the current statement for more
968  * precision but as we could not scalarize the array because the region
969  * would not contain a single element, it's of no use here.
970  */
971  if (!entity_scalar_p(e_exp)) {
972  ctxt->constant_p = false;
973  } else if (entity_in_list_p(e_exp, ctxt->trans_args)) {
974  ctxt->constant_p = false;
975  }
976  }
977  gen_full_free_list(l_eff_exp);
978  if (!ctxt->constant_p) {
979  break;
980  }
981  }
982  continue_p = ctxt->constant_p;
983  }
984  return continue_p;
985 }
986 
987 
988 static bool declarations_reference_constant_wrt_ctxt_p(statement st,
989  reference_testing_ctxt *p_ctxt) {
990  if (declaration_statement_p(st)) {
992  value init_val = entity_initial(decl);
993  if (! value_undefined_p(init_val)) {
994  gen_context_recurse(init_val, p_ctxt,
995  reference_domain, reference_constant_wrt_ctxt_p, gen_null2);
996  }
997  }
998  }
999  return true;
1000 }
1001 
1002 
1003 static bool statement_entity_references_constant_in_context_p(statement s,
1004  entity e,
1005  list l_modified_variables) {
1006  int nd = type_depth(entity_type(e));
1007  bool constant_p = (nd==0);
1008 
1009  if(!constant_p) {
1010  pips_debug(2,"Considering entity : %s\n", entity_name(e));
1011 
1012  /* none of the modified variables appears in an index of a reference from entity e */
1013  reference_testing_ctxt ctxt;
1014  ctxt.constant_p = true;
1015  ctxt.e = e;
1016  ctxt.trans_args = l_modified_variables;
1017 
1018  gen_context_multi_recurse(s, &ctxt,
1019  statement_domain, declarations_reference_constant_wrt_ctxt_p, gen_null,
1020  reference_domain, reference_constant_wrt_ctxt_p, gen_null,
1021  NULL);
1022  constant_p = ctxt.constant_p;
1023  pips_debug(2, "returning: %s\n", bool_to_string(constant_p));
1024  }
1025 
1026  return constant_p;
1027 }
1028 
1029 typedef struct {
1030  entity e;
1031  bool used_through_external_calls;
1032 } calls_test_ctxt;
1033 
1034 
1035 
1036 
1037 static bool entity_accessed_in_call_in(call c, calls_test_ctxt *ctxt)
1038 {
1039  entity func = call_function(c);
1040  type uet = ultimate_type(entity_type(func));
1041  if(type_functional_p(uet) && value_code_p(entity_initial(func)))
1042  {
1043  // get the summary effects of the function
1044  const char *func_name = module_local_name(func);
1045  list func_eff = effects_to_list((effects) db_get_memory_resource(DBR_SUMMARY_REGIONS,
1046  func_name,
1047  true));
1048  /* tests if the function may refer to the global variable */
1049  list l_conflicts = effects_entities_which_may_conflict_with_scalar_entity(func_eff, ctxt->e);
1050  if (!ENDP(l_conflicts))
1051  {
1052  ctxt->used_through_external_calls = true;
1053  gen_free_list(l_conflicts);
1054  }
1055  }
1056  return (!ctxt->used_through_external_calls);
1057 }
1058 
1059 static bool entity_accessed_in_statement_declarations_calls_in(statement s, calls_test_ctxt * ctxt)
1060 {
1061  if (declaration_statement_p(s))
1062  {
1063  list l_decls = statement_declarations(s);
1064  FOREACH(ENTITY, e, l_decls)
1065  {
1067  call_domain, entity_accessed_in_call_in, gen_null2);
1068  }
1069  }
1070  return (!ctxt->used_through_external_calls);
1071 }
1072 
1073 static bool entity_accessed_through_calls_in_statement_p(entity e, statement s)
1074 {
1075  calls_test_ctxt ctxt;
1076  ctxt.e = e;
1077  ctxt.used_through_external_calls = false;
1078  gen_context_multi_recurse(s, &ctxt,
1079  statement_domain, entity_accessed_in_statement_declarations_calls_in, gen_null,
1080  call_domain, entity_accessed_in_call_in, gen_null, NULL);
1081  return (ctxt.used_through_external_calls);
1082 }
1083 
1084 
1085 /* Scalarize array references in any kind of statement
1086  *
1087  * The first cut is a cut-and-paste of loop_scalarization()
1088  */
1089 static bool statement_scalarization(statement s,
1090  struct scalarization_ctx *ctx) {
1091  ifdebug(1) {
1092  pips_debug(1, "Statement:\n");
1093  print_statement(s);
1094  }
1095 
1098  // Psysteme D = predicate_system(transformer_relation(transformer_range(prec)));
1099 
1100  bool memory_effects_only_p = get_bool_property("MEMORY_EFFECTS_ONLY");
1101  bool memory_in_out_regions_only_p =
1102  get_bool_property("MEMORY_IN_OUT_EFFECTS_ONLY");
1103 
1104  effects ie = load_in_effects(s);
1105  effects oe = load_out_effects(s);
1107 
1108  list irl = effects_effects(ie);
1109  list orl = effects_effects(oe);
1110  list crwl = effects_effects(crwe);
1111 
1112  if (!memory_effects_only_p) {
1113  crwl = effects_store_effects(crwl);
1114  }
1115 
1116  if (!memory_in_out_regions_only_p) {
1117  irl = effects_store_effects(irl);
1118  orl = effects_store_effects(orl);
1119  }
1120 
1121  /* List of entities forbidden in an array subscript,
1122  * because modified in the statement
1123  * or because declared deeper in the statement.
1124  */
1125  set declared_entities = get_declared_entities(s);
1126  FOREACH(entity, e, transformer_arguments(tran)) {
1127  set_add_element(declared_entities,declared_entities,e);
1128  }
1129  list forbiden_variables_in_subscript = set_to_list(declared_entities);
1130  set_free(declared_entities);
1131 
1132  /* List of variables than shoud be privatized in s */
1133  list local_scalarized_variables = NIL;
1134 
1135  ifdebug(1) {
1136  pips_debug(1, "Entering function...\n");
1137  pips_debug(1, "With statement...\n");
1138  print_statement(s);
1139  pips_debug(1, "OUT regions:\n");
1140  print_regions(orl);
1141  pips_debug(1, "CUMULATED RW regions:\n");
1142  print_regions(crwl);
1143  }
1144 
1145  Pvecteur var_already_seen = VECTEUR_NUL;
1146  // Each variable in effects is a candidate for scalarization
1147  FOREACH (EFFECT, pr, crwl) {
1148  // Now we determine which read/write effects are not copied out.
1149 
1150  // I'm not sure this works for arrays of structures for instance
1151  // because there may be several paths with different lengths
1152  // from a same entity.
1153  // All the computation is done in reference to the entity pv
1154  // whereas it should be done in reference to a memory access path.
1155  // BC (02/20/2012).
1156  entity pv = effect_variable(pr); // Private variable
1157  int nd = type_depth(entity_type(pv));
1158 
1159  if(!entity_is_argument_p(pv, ctx->scalarized_variables) // sclarized at
1160  // a higher level?
1161  && !vect_coeff(pv,var_already_seen) // Each variable may appear
1162  // several times in the
1163  // effect list
1164  && nd > 0 // Only array references can be scalarized
1165  && !entity_volatile_variable_p(pv) // Volatile arrays cannot be scalarized
1166  && (!top_level_entity_p(pv) || !entity_accessed_through_calls_in_statement_p(pv, s)) // global arrays accessed through calls cannot yet be scalarized
1167  ) {
1168  // Does the current variable appear in the in effect?
1169  entity iv = (entity) gen_find(pv,
1170  irl,
1171  (bool(*)()) gen_eq,
1172  car_effect_to_variable);
1173  // Does the current variable appear in the out effect?
1174  entity ov = (entity) gen_find(pv,
1175  orl,
1176  (bool(*)()) gen_eq,
1177  car_effect_to_variable);
1178 
1179  descriptor d = effect_descriptor(pr);
1180  if (descriptor_convex_p(d)) {
1181  ifdebug(2) {
1182  pips_debug(2,"Considering regions : ");
1183  print_region(pr);
1184  }
1185  vect_add_elem(&var_already_seen,pv,1);
1186 
1187  // scalarization_across_control_test_level is checked inside
1188  // if it is equal to 0 and there is not at least one exact effect
1189  // then an undefined effect is returned.
1190  effect pru = unified_rw_effect_of_variable(pv, crwl);
1191 
1192  if (!effect_undefined_p(pru)) { // FI: this should be an assert?
1193  // Estimate the dynamic number of *element* and *variable*
1194  // occurrences in the loop body
1195  int neo = count_references_to_variable_element(s, pv);
1196  int nvo = count_references_to_variable(s, pv);
1197 
1198  /* Legality criterion:
1199 
1200  if nvo is greater than neo, there must be hidden references
1201  to the array, due for instance to a function call, and the
1202  substitution might break dependence arcs.
1203 
1204  So, we go on only if the two are equal.
1205  */
1206 
1207  if (nvo != neo) {
1208  ifdebug(2) {
1209  pips_debug(2,
1210  "Legality criterion not met : %d!=%d (nvo!=neo)\n",
1211  nvo, neo);
1212  }
1213  } else {
1214 
1215  bool read_pv = effects_read_variable_p(crwl, pv);
1216  bool written_pv = effects_write_variable_p(crwl, pv);
1217  bool read_and_written_pv = read_pv && written_pv;
1218  int threshold = get_int_property("SCALARIZATION_THRESHOLD");
1219 
1220  if(threshold<2) {
1221  pips_user_error("The scalarization threshold should be at "
1222  "least 2\nCheck property SCALARIZATION_THRESHOLD\n");
1223  }
1224 
1225  /* Profitability criterion:
1226 
1227  - nd > 0: it's an array (do not scalarize scalar variables)
1228 
1229  - neo > 2: if the number of references if greater than 2, the
1230  copy-in and copy-out code overhead is assumed to be small
1231  enough to make scalarization profitable.
1232 
1233  - neo > 1: if the number of references is 2, the copy-in *xor*
1234  the copy-out overhead meets the above criterion.
1235 
1236  - else: if there is neither copy-in nor copy-out,
1237  privatization is always useful.
1238 
1239  FI: we should also check if the reference is loop invariant
1240  and then decide that it is always profitable to scalarize
1241  it... See scalarization34 in Transformations. We should
1242  check if the region is a constant function.
1243  */
1244 
1245  if (nd <= 0 // Scalar -> FI: this is already tested above...
1246  || (neo <= threshold && // Two or fewer references
1247  (neo < threshold || read_and_written_pv) && // ...
1248  (!entity_undefined_p(iv) || !entity_undefined_p(ov)) // At least copy in or copy out !
1249  )
1250  ) {
1251  ifdebug(2) {
1252  pips_debug(2,"Profitability criterion not met: (nd) %d>0 (scalar) "
1253  "or not one of the following : (%d&&%d&&%d) "
1254  "(neo) %d <= 2 and "
1255  "((neo) %d <= 1 || %d read_and_written_pv) and "
1256  "(%d (!entity_undefined_p(iv)) || %d (!entity_undefined_p(ov)))\n",
1257  nd,
1258  neo <= 2,
1259  (neo <= 1 || read_and_written_pv),
1260  (!entity_undefined_p(iv) || !entity_undefined_p(ov)),
1261  neo,
1262  neo,
1263  !read_and_written_pv,
1264  entity_undefined_p(iv),
1265  entity_undefined_p(ov));
1266  }
1267  } else {
1268  pips_debug(1,"Profitability criterion met \n");
1269  bool strict_p = scalarization_across_control_test_is_strict_test_p();
1270  /* Check that a unique element of pv is used. Its region
1271  must be constant within the statement, i.e. wrt to the
1272  statement transformer tran.
1273 
1274  This last criterion is not strong enough, because variables
1275  modified in the statement have already been eliminated from
1276  regions. We enforce a stronger criterion implemented by
1277  statement_entity_references_constant_in_context_p which checks
1278  that each reference from pru entity has constant indices wrt
1279  to the statement transformer tran and has no complex indices
1280  (array elements, structs). BC.
1281  */
1282  /* prec might have to be replaced by prec_r, its range. */
1283  /* It is not clear if a unique element of pv should
1284  always be used, wasting some opportunities but
1285  making sure that no non-existing reference is added,
1286  or if at most a unique element is used, which may to
1287  spurious out of bounds accesses. See scalarization30
1288  for an example and explanations. */
1289  if (//constant_region_in_context_p(pru, tran)
1290  statement_entity_references_constant_in_context_p(s,
1291  effect_entity(pru),
1292  forbiden_variables_in_subscript )
1293  && singleton_region_in_context_p(pru, prec,
1294  loop_indices_b, strict_p)) {
1295  /* The array references can be replaced a references to a
1296  scalar */
1297  // FI: this must be postponed to the bottom up phase
1298  //scalarize_variable_in_statement(pv, s, iv, ov);
1299  local_scalarized_variables =
1300  arguments_add_entity(local_scalarized_variables, pv);
1301  ctx->scalarized_variables =
1302  arguments_add_entity(ctx->scalarized_variables, pv);
1303  }
1305  }
1306  }
1307  }
1308  //sc_rm(sc_union);
1309  free_effect(pru);
1310  }
1311  }
1312  }
1313  vect_rm(var_already_seen);
1314 
1315  /* Associate the current list of privatized variables to statement s */
1316  hash_put(ctx->statement_scalarized_variables,
1317  (void *) s,
1318  (void *) local_scalarized_variables);
1319 
1320  // Do not leak
1321  if (!memory_in_out_regions_only_p) {
1322  gen_free_list(orl);
1323  gen_free_list(irl);
1324  }
1325  if (!memory_effects_only_p) {
1326  gen_free_list(crwl);
1327  }
1328  gen_free_list(forbiden_variables_in_subscript);
1329  return true;
1330 }
1331 
1332 
1333 /* gen_recurse callback on entering a statement. If it's a loop,
1334  * process it. Stack the loop index to build the iteration
1335  * space. Perform loop scalarization.
1336  */
1337 static bool scalarization_loop_statement_in(statement ls,
1338  struct scalarization_ctx *ctx) {
1339  bool result_p = true;
1340 
1341  if (statement_loop_p(ls)) {
1342  loop l = statement_loop(ls);
1343 
1344  /* Insert a marker to keep track of the privatized variables
1345  inside loop l, lest they are privatized a second time in an inner
1346  loop.
1347  */
1348  entity i = loop_index(l);
1349  ctx->scalarized_variables = arguments_add_entity(ctx->scalarized_variables,
1350  i);
1351 
1352  // Accumulate new index in "domain" basis
1353  loop_indices_b = base_add_variable(loop_indices_b, (Variable) i);
1354 
1355  result_p = loop_scalarization(l,ctx);
1356  }
1357 
1358  return result_p;
1359 }
1360 
1361 
1362 /* gen_recurse callback on exiting a statement. If it's a loop, process it.
1363  * unstack all variables related to loops internal wrt the current
1364  * loop to restore the current iteration space.
1365  */
1366 static void scalarization_loop_statement_out(statement s,
1367  struct scalarization_ctx *ctx) {
1368  if (statement_loop_p(s)) {
1369  loop l = statement_loop(s);
1370  entity i = loop_index(l);
1371  list nl = NIL;
1372 
1373  pips_debug(1, "Exiting loop with index %s, size=%d\n",
1374  entity_name(i), base_dimension(loop_indices_b));
1375 
1376  /* Remove variables privatized in the current loop, so that
1377  successive loops do not interfere with each other.
1378  */
1379  for (list el=ctx->scalarized_variables; !ENDP(el); POP(el)) {
1380  entity e = ENTITY(CAR(el));
1381  if (e == i) {
1382  break;
1383  } else {
1384  nl = CONS(ENTITY, e, nl);
1385  }
1386  }
1387  gen_free_list(ctx->scalarized_variables);
1388  ctx->scalarized_variables = gen_nreverse(nl);
1389 
1390  loop_indices_b = base_remove_variable(loop_indices_b, (Variable) i);
1391  }
1392 }
1393 
1394 
1395 /* gen_recurse callback on entering a statement. If it is not a
1396  * declaration statement process it: keep track of scalarized
1397  * variables.
1398  */
1399 static bool scalarization_statement_in(statement s,
1400  struct scalarization_ctx *ctx) {
1401  bool result_p = true;
1402 
1403  // In fact, only sequences and loops are good candidates... although
1404  // the comma and the assignment operator could also lead to
1405  // some scalarization...
1406  //
1407  // Call statements are not as appropriate for the profitability
1408  // criterion... but this has been fixed with a profitability threshold
1409  //
1410  // This test must be exactly replicated in scalaration_statement_out
1411  if(!declaration_statement_p(s) /*&& !statement_call_p(s)*/
1412  && !set_belong_p(ctx->blacklisted_loops, s)) {
1413 
1414  result_p = statement_scalarization(s,ctx);
1415 
1416  if (statement_loop_p(s)) {
1417  loop l = statement_loop(s);
1418  entity i = loop_index(l);
1419 
1420  pips_debug(1, "Exiting loop with index %s, size=%d\n",
1421  entity_name(i), base_dimension(loop_indices_b));
1422 
1423  loop_indices_b = base_add_variable(loop_indices_b, (Variable) i);
1424 
1425  if(ctx->keep_perfect_parallel) {
1426  blacklist_perfectly_nested_parallel_loop(s, ctx->blacklisted_loops);
1427  }
1428  }
1429  }
1430 
1431  return result_p;
1432 }
1433 
1434 typedef struct {
1435  entity var;
1436  bool found;
1437  set seen;
1438 } aov_ctx;
1439 
1440 static void aov_call(call c, aov_ctx * ctx)
1441 {
1442  entity called = call_function(c);
1443  if (ENTITY_ADDRESS_OF_P(called))
1444  {
1445  list args = call_arguments(c);
1446  pips_assert("1 arg to &", gen_length(args) == 1);
1447  if (set_belong_p(ctx->seen, EXPRESSION(CAR(args))))
1448  {
1449  ctx->found = true;
1450  gen_recurse_stop(NULL);
1451  }
1452  }
1453 }
1454 
1455 static void aov_cast(cast c, aov_ctx * ctx)
1456 {
1457  expression e = cast_expression(c);
1458  if (set_belong_p(ctx->seen, e))
1459  {
1462  if (enclosing)
1463  set_add_element(ctx->seen, ctx->seen, enclosing);
1464  }
1465 }
1466 
1467 static void aov_ref(reference r, aov_ctx * ctx)
1468 {
1469  if (reference_variable(r) == ctx->var)
1470  {
1473  if (enclosing)
1474  set_add_element(ctx->seen, ctx->seen, enclosing);
1475  }
1476 }
1477 
1478 // return whether "&v" exists in statement s
1479 // this is not really efficient, maybe some data structure could be used
1480 // to keep track of that... but we want in statement s *only*...
1481 static bool address_of_variable_in_statement(statement s, entity v)
1482 {
1483  aov_ctx ctx;
1484  ctx.var = v;
1485  ctx.found = false;
1486  ctx.seen = set_make(set_pointer);
1487 
1488  gen_context_multi_recurse(s, &ctx,
1489  call_domain, gen_true, aov_call,
1490  cast_domain, gen_true, aov_cast,
1491  reference_domain, gen_true, aov_ref,
1492  NULL);
1493 
1494  set_free(ctx.seen);
1495  return ctx.found;
1496 }
1497 
1498 
1499 /* gen_recurse callback on exiting a statement. Privatize the
1500  variables collected during the top-down phase */
1501 static void scalarization_statement_out(statement s,
1502  struct scalarization_ctx *ctx) {
1503  // This test must be exactly replicated in scalaration_statement_in
1504  if(!declaration_statement_p(s) /*&& !statement_call_p(s)*/
1505  && !set_belong_p(ctx->blacklisted_loops,s)) {
1506 
1507  /* If statement s is a loop, remove its loop index from basis
1508  loop_indices_b which keep track of loop nesting. Do it before
1509  s is updated by privatization: the added declarations may
1510  require s to be changed into a sequence and the loop moved
1511  down in the AST */
1512  if (statement_loop_p(s)) {
1513  loop l = statement_loop(s);
1514  entity i = loop_index(l);
1515 
1516  pips_debug(1, "Exiting loop with index %s, size=%d\n",
1517  entity_name(i), base_dimension(loop_indices_b));
1518 
1519  loop_indices_b = base_remove_variable(loop_indices_b, (Variable) i);
1520  }
1521 
1522  /* Retrieve the variables to privatize for statement s */
1523  list local_scalarized_variables =
1524  (list) hash_get(ctx->statement_scalarized_variables, (void *) s);
1525 
1526  if(!ENDP(local_scalarized_variables)) {
1527  /* The ENDP test is not necessary but it saves time, especially
1528  when using gdb... */
1529 
1530  /* Privatize each of them, with copy_in or copy_out when necessary */
1531  bool memory_in_out_regions_only_p =
1532  get_bool_property("MEMORY_IN_OUT_EFFECTS_ONLY");
1533 
1534  effects ie = load_in_effects(s);
1535  effects oe = load_out_effects(s);
1536  list irl = effects_effects(ie);
1537  list orl = effects_effects(oe);
1538 
1539  if (!memory_in_out_regions_only_p) {
1540  irl = effects_store_effects(irl);
1541  orl = effects_store_effects(orl);
1542  }
1543  ifdebug(3) {
1544  pips_debug(3, "statement before replacements:\n");
1545  print_statement(s);
1546  }
1547  FOREACH(ENTITY, pv, local_scalarized_variables)
1548  {
1549  if (ctx->skip_address_of_variables &&
1550  address_of_variable_in_statement(s, pv))
1551  {
1552  pips_debug(4, "skipping variable %s\n", entity_name(pv));
1553  continue;
1554  }
1555 
1556  entity iv = (entity)
1557  gen_find(pv, irl, (bool (*)())gen_eq, car_effect_to_variable);
1558  // Does the current variable appear in the out effect?
1559  entity ov = (entity)
1560  gen_find(pv, orl, (bool (*)())gen_eq, car_effect_to_variable);
1561  scalarize_variable_in_statement(pv, s, iv, ov);
1562  }
1563 
1564 
1565  ifdebug(3) {
1566  pips_debug(3, "statement on exit:\n");
1567  print_statement(s);
1568  }
1569 
1570  /* Remove variables scalarized in s from the list of scalarized
1571  variables so that
1572  successive statements do not interfere with each other. */
1573  ctx->scalarized_variables =
1574  arguments_difference(ctx->scalarized_variables,
1575  local_scalarized_variables);
1576 
1577  /* This list is no longer useful. It is still accessible via the
1578  hashtable statement_scalarized_variables but s should not be
1579  visited again. If the lists are not freed one by one, they
1580  should be freed later when the hash_tabe itself is freed */
1581  gen_free_list(local_scalarized_variables);
1582 
1583  // Do not leak
1584  if (!memory_in_out_regions_only_p) {
1585  gen_free_list(orl);
1586  gen_free_list(irl);
1587  }
1588  }
1589  }
1590  return;
1591 }
1592 
1593 
1594 bool scalarization(const string module_name)
1595 {
1596  entity module;
1597  statement module_stat;
1598 
1601 
1603  module_name,
1604  true));
1605  module_stat = get_current_module_statement();
1606 
1607 
1609  module_name,
1610  true));
1612  module_name,
1613  true));
1614 
1616 
1617  // Used for statement scalarization
1619  module_name,
1620  true));
1621  // Used for loop scalarization
1623  module_name,
1624  true));
1626  db_get_memory_resource(DBR_IN_REGIONS, module_name, true));
1628  db_get_memory_resource(DBR_OUT_REGIONS, module_name, true));
1629 
1630 
1631  debug_on("SCALARIZATION_DEBUG_LEVEL");
1632  pips_debug(1, "begin\n");
1633 
1634  // Context for gen_context_recurse
1635  struct scalarization_ctx ctx;
1636  ctx.keep_perfect_parallel =
1637  get_bool_property("SCALARIZATION_KEEP_PERFECT_PARALLEL_LOOP_NESTS");
1638  ctx.blacklisted_loops = set_make(set_pointer);
1639  ctx.skip_address_of_variables =
1640  get_bool_property("SCALARIZATION_SKIP_ADDRESS_OF_VARIABLES");
1641 
1642  scalarization_across_control_test_level_init();
1643 
1644  if (false) {
1645  // DEAD CODE
1646  /* We now traverse our module's statements looking for loop statements. */
1647  loop_indices_b = BASE_NULLE;
1648  ctx.scalarized_variables = NIL;
1649  gen_context_recurse(module_stat,
1650  &ctx,
1652  scalarization_loop_statement_in,
1653  scalarization_loop_statement_out);
1654  } else {
1655  /* We now traverse our module's statements looking for all
1656  statements. We look for constant array references to scalarize
1657  on the way down. The effective scalarization is performed during
1658  the bottom-up phase. */
1659  loop_indices_b = BASE_NULLE;
1660  ctx.scalarized_variables = NIL;
1661  ctx.statement_scalarized_variables = hash_table_make(hash_pointer, 0);
1662  gen_context_recurse(module_stat,
1663  &ctx,
1665  scalarization_statement_in,
1666  scalarization_statement_out);
1667  /* Not enough the lists should be freed too... but they are freed
1668  on the way by scalarization_statement_out() */
1669  hash_table_free(ctx.statement_scalarized_variables);
1670  ifdebug(1) {
1671  pips_assert("scalarized_variables is empty",
1672  ENDP(ctx.scalarized_variables));
1673  pips_assert("loop_indices_b is empty", BASE_NULLE_P(loop_indices_b));
1674  }
1675  }
1676 
1677  set_free(ctx.blacklisted_loops); // No leak
1678 
1679  scalarization_across_control_test_level_reset();
1680  pips_debug(1, "end\n");
1681  debug_off();
1682 
1683  /* Save modified code to database */
1684  module_reorder(module_stat);
1685  DB_PUT_MEMORY_RESOURCE(DBR_CODE, strdup(module_name), module_stat);
1686 
1687  /* TODO: Cleanup after scalarization */
1688  pips_assert("Loop index Pbase is empty", BASE_NULLE_P(loop_indices_b));
1689 
1692 
1697  reset_in_effects();
1699 
1701 
1702  /* Return value */
1703  bool good_result_p = true;
1704 
1705  return (good_result_p);
1706 
1707 }
1708 
1709 /*
1710  * Scalarization of constant array references: constant_array_scalarization
1711  *
1712  * For instance, a[0] is replaced by a_0.
1713  */
1714 typedef struct {
1715  entity array;
1716  bool constant_p;
1717 } references_constant_param;
1718 
1719 static void all_array_references_constant_walker(reference ref,
1720  references_constant_param* p) {
1721  if(same_entity_p(p->array,reference_variable(ref))) {
1723  p->constant_p &= extended_expression_constant_p(offset)
1724  && (!ENDP(reference_indices(ref)));
1726  }
1727 }
1728 
1729 static bool all_array_references_constant_p(statement in, entity array) {
1730  references_constant_param p = { array,true};
1731  gen_context_recurse(in, &p,
1733  gen_true2,
1734  all_array_references_constant_walker);
1735  return p.constant_p;
1736 }
1737 
1738 typedef struct {
1739  entity array;
1740  hash_table mapping;
1741 } replace_references_constant_param;
1742 
1743 static void replace_constant_array_references_walker(reference ref,
1744  replace_references_constant_param *p) {
1745  if(same_entity_p(p->array,reference_variable(ref))) {
1746  /* we know for sure all indices are constant */
1748  intptr_t value;
1750  pips_internal_error("reference index should be constants");
1751  /* add one to the value, because 0 seems reserved */
1752  entity var = (entity)hash_get(p->mapping,(void*)(1+value));
1753  if(var == HASH_UNDEFINED_VALUE) {
1757  /* FI: let's try to maintain the storage section */
1758  storage as = entity_storage(p->array);
1759  if(storage_ram_p(as)) {
1760  ram ar = storage_ram(as);
1761  storage vs = entity_storage(var);
1762  ram vr = storage_ram(vs);
1763  ram_section(vr) = ram_section(ar);
1764  }
1765  else {
1766  pips_internal_error("Arrays should be allocated in RAM.\n");
1767  }
1768 
1769  hash_put(p->mapping,(void*)(1+value),var);
1771  }
1775  reference_variable(ref)=var;
1776  }
1777 }
1778 
1779 static void replace_constant_array_references(statement in, entity array) {
1780  replace_references_constant_param p = { array,
1782  gen_context_recurse(in, &p,
1784  gen_true2,
1785  replace_constant_array_references_walker);
1786  // FI: hos is the hash-table freed?
1787 }
1788 
1789 /* Pass constant_array_scalarization
1790  */
1791 
1792 static int inverse_compare_entities(const entity *pe1, const entity *pe2)
1793 {
1794  return -compare_entities(pe1, pe2);
1795 }
1796 
1797 bool constant_array_scalarization(const string module_name)
1798 {
1801  module_name,
1802  true));
1804  set sreferenced_entities = get_referenced_entities(cms);
1805  // Use a sorted list of entities to generate code deterministically
1806  list rel = set_to_sorted_list(sreferenced_entities,
1807  (gen_cmp_func_t) inverse_compare_entities);
1808  list del = NIL; // dynamic entity list
1809  list sel = NIL; // static entity list
1810 
1811  FOREACH(entity, e, rel) {
1812  if((entity_array_p(e)||entity_pointer_p(e)) &&
1813  all_array_references_constant_p(cms,e)) {
1814  // Check legality...
1816  && !formal_parameter_p(e)) {
1817  /* Do we have to cope with some array initialization? */
1820  sel = CONS(ENTITY, e, sel);
1821  else
1822  del = CONS(ENTITY, e, del);
1823  }
1824  else {
1825  /* FI: another option would be to split the initialization
1826  * as part of the constant array scalarization pass. It is
1827  * not possible to call brace_expression_to_statements()
1828  * here because we do not iterate over the statements but
1829  * over the variables. Another option would be to add a
1830  * property to split_initialization to restrict the list of
1831  * variables to process.
1832  */
1833  pips_user_warning("Array \"%s\" is not scalarized, "
1834  "because its initialization should be split. "
1835  "\nApply pass split_initialization first.\n",
1836  entity_user_name(e));
1837  }
1838  // FI: should the initial declaration be removed?
1839  // This could be left to another pass cleaning unused declarations:
1840  // CLEAN_DECLARATIONS?
1841  }
1842  else {
1843  pips_user_warning("Array \"%s\" is not scalarized "
1844  "because the resulting code is likely to be wrong\n",
1845  entity_user_name(e));
1846  }
1847  }
1848  }
1849 
1850  /* Perform the replacement for non-static arrays */
1851  FOREACH(entity, e, del) {
1852  replace_constant_array_references(cms,e);
1853  }
1854 
1855  /* Perform the replacement for static arrays */
1856  FOREACH(entity, e, sel) {
1857  replace_constant_array_references(cms,e);
1858  }
1859 
1860  /* Perform the replacement for static arrays... once you know how to
1861  generate the declarations of the elements properly... */
1862  /* FOREACH(entity, e, del) { */
1863  /* replace_constant_array_references(cms,e); */
1864  /* } */
1865 
1866  set_free(sreferenced_entities);
1867  gen_free_list(rel); gen_free_list(del); gen_free_list(sel);
1868 
1873 
1874  return true;
1875 }
1876 
1877 
1878 /***********************************************************************/
1879 /* QUICK SCALARIZATION */
1880 /***********************************************************************/
1881 
1882 /*
1883  scalarizes arrays in already parallel loops. uses only the dg and
1884  simple effects (both proper and cumulated).
1885  */
1886 
1887 /** checks whether an effect memory path describes a set of array elements
1888  */
1889 static bool array_effect_p(effect eff) {
1890  bool result = false;
1891  entity e = effect_entity(eff);
1892  if (!entity_scalar_p(e) && ! effects_package_entity_p(e)) {
1894 
1895  if (type_variable_p(t)) {
1898  result = (gen_length(inds) == gen_length(dims));
1899  }
1900  }
1901  return result;
1902 }
1903 
1904 
1905 /** returns true if entity e belongs to C module "main"
1906 
1907  could be moved to ri-util/entity.c, but this version is specific
1908  because we assume that entity_module_main_p cannot return true if
1909  the current module is not the "main" module. This is not valid in
1910  the general case, for instance when performing interprocedural
1911  translations. However, this choice has been made for performance
1912  reasons.
1913  */
1914 static bool entity_module_main_p(entity e) {
1916  static bool current_module_main_p = false;
1917  bool result = false;
1918 
1921  if (c_module_p(current_module)) {
1923  if (strcmp(current_module_name, "main") == 0) {
1924  current_module_main_p = true;
1925  }
1926  pips_debug(8, "module name: %s, local_name: %s, returning %s\n",
1928  bool_to_string(current_module_main_p));
1929  }
1930  }
1931 
1932  /* in the context of scalarization, an entity which is scalarizable
1933  is an entity declared in the current module - so the current module
1934  must be the "main" function.
1935  */
1936  if (current_module_main_p) {
1938  pips_debug(8, "does entity %s belong to module main? %s\n ",
1939  entity_name(e), bool_to_string(result));
1940  } else {
1941  result = false;
1942  }
1943 
1944  return result;
1945 }
1946 
1947 
1948 /** checks if an entity meets the scalarizability criteria.
1949  */
1950 static bool scalarizable_entity_p(entity e) {
1951  storage s = entity_storage( e ) ;
1952  bool result = true;
1953 
1954  pips_debug(3,
1955  "checking entity %s, with storage %s \n",
1957 
1958  ifdebug(3) {
1959  if (storage_ram_p(s))
1960  fprintf(stderr,
1961  " and section %s\n",
1963  }
1964  /* global arrays are not considered as scalarizable because we
1965  solely rely on internal dependencies. OUT regions would be
1966  necessary to handle them (OUT simple effects should not be
1967  precise enough), but we want to keep this algorithm very cheap on
1968  purpose.
1969 
1970  we allow scalarization of arrays with "static" qualifier when
1971  they are declared in the "main" module of a C application.
1972  */
1973  result = entity_array_p( e ) && !entity_volatile_variable_p(e) &&
1974  ((storage_formal_p( s )
1976  ||
1977  (storage_ram_p( s )
1981  && entity_module_main_p(e)))
1982  )
1983  );
1984 
1985  pips_debug(3, "returning %s\n", bool_to_string(result));
1986  return(result);
1987 }
1988 
1989 
1990 /**
1991  if the statement st is a loop, gather the scalarizable candidates
1992  in loops_scalarizable_candidates.
1993 
1994  The candidates are the scalarizable array entities for which there
1995  are cumulated effects attached to the loop body, or which are
1996  declared inside the loop body.
1997  */
1998 static bool statement_compute_scalarizable_candidates(statement st,
1999  hash_table loops_scalarizable_candidates) {
2000  if (statement_loop_p(st)) {
2001  loop l = statement_loop(st);
2002  statement b = loop_body(l);
2003  set scalarizable_candidates = set_make(set_pointer);
2004 
2005  pips_debug(1, "Entering loop statement %td (ordering %03zd)\n",
2006  statement_number( st ), statement_ordering(st)) ;
2007 
2008  ifdebug(1) {
2010  }
2011  /* first scan the cumulated effects in search of candidates */
2013  entity e = effect_entity( eff ) ;
2015  && scalarizable_entity_p(e)
2016  && action_write_p(effect_action(eff))
2017  && array_effect_p(eff)
2018  && !set_belong_p(scalarizable_candidates, e)) {
2019  pips_debug(2, "adding array: %s from effects.\n", entity_name(e));
2020  set_add_element(scalarizable_candidates, scalarizable_candidates, e) ;
2021  }
2022  }
2023 
2024  /* then scan the loop_body declarations because they do not belong to
2025  * cumulated effects */
2028  && scalarizable_entity_p(e)
2029  && !set_belong_p(scalarizable_candidates, e)) {
2030  pips_debug(2, "adding array: %s from declarations.\n", entity_name(e));
2031  set_add_element(scalarizable_candidates, scalarizable_candidates, e) ;
2032  }
2033  }
2034 
2035  ifdebug(1) {
2036  pips_debug(1, "candidates:");
2037  SET_FOREACH(entity, e, scalarizable_candidates) {
2038  fprintf(stderr, " %s", entity_local_name(e));
2039  }
2040  fprintf(stderr, "\n");
2041  }
2042 
2043  /* finally put the set of candidates in the input hash table */
2044  hash_put(loops_scalarizable_candidates, l, scalarizable_candidates);
2045  pips_debug(1, "leaving loop\n");
2046  }
2047  return true;
2048 }
2049 
2050 
2051 /** remove scalarizable candidate e from the
2052  loops_scalarizable_candidates corresponding to the loops which are
2053  in ls but not in prefix.
2054  */
2055 static void remove_scalarizable_candidate_from_loops(list prefix,
2056  list ls,
2057  entity e,
2058  hash_table loops_scalarizable_candidates) {
2059  pips_debug(1, "Begin\n");
2060 
2061  if(ENDP(prefix)) {
2062  if(!ENDP(ls)) {
2063  ifdebug(1) {
2064  pips_debug(1, "Removing %s from locals of ", entity_name(e)) ;
2065  FOREACH(STATEMENT, st, ls) {
2066  pips_debug(1, "%td ", statement_number(st)) ;
2067  }
2068  pips_debug(1, "\n" ) ;
2069  }
2070  FOREACH(STATEMENT, st, ls) {
2071  pips_assert( "instruction i is a loop", statement_loop_p(st)) ;
2072  set scalarizable_candidates =
2073  (set) hash_get(loops_scalarizable_candidates,
2074  (char *) statement_loop(st));
2075  set_del_element(scalarizable_candidates, scalarizable_candidates, e);
2076  pips_debug(1, "Variable %s is removed from scalarizable candidates of "
2077  "statement %td\n",
2078  entity_name(e), statement_number(st));
2079  }
2080  } else {
2081  pips_debug(1, "ls is empty, end of recursion\n");
2082  }
2083  } else {
2084  pips_assert( "The first statements in prefix and in ls are the same statement",
2085  STATEMENT( CAR( prefix )) == STATEMENT( CAR( ls ))) ;
2086 
2087  pips_debug(1, "Recurse on common prefix\n");
2088 
2089  remove_scalarizable_candidate_from_loops(CDR(prefix), CDR(ls), e,
2090  loops_scalarizable_candidates);
2091  }
2092 
2093  pips_debug(1, "End\n");
2094 }
2095 
2096 
2097 /**
2098  Main part of the scalarization process: if edges from vertex @param
2099  v corresponding to statement @param st may prevent scalarization of
2100  effect @param eff entity, then remove the latter from non common
2101  enclosing loops in @param loops_scalarizable_candidates.
2102 
2103 
2104  This is mostly inspired from scalar variable privatization algorithm
2105  */
2106 static void update_scalarizable_candidates(vertex v, statement st,
2107  effect eff,
2108  hash_table loops_scalarizable_candidates) {
2110  entity e = effect_entity(eff);
2111 
2112  ifdebug(1) {
2113  if(statement_loop_p(st)) {
2114  pips_debug(1, "Trying to scalarize %s in loop statement %td "
2115  "(ordering %03zd)",
2117  } else {
2118  pips_debug(1, "Trying to scalarize %s in statement %td\n",
2119  entity_local_name( e ), statement_number( st )) ;
2120  }
2121  }
2122 
2123  FOREACH(SUCCESSOR, succ, vertex_successors(v)) {
2124  vertex succ_v = successor_vertex( succ ) ;
2126  dg_arc_label arc_l = (dg_arc_label)successor_arc_label( succ ) ;
2128  instruction succ_i = statement_instruction( succ_st ) ;
2129  list succ_ls = load_statement_enclosing_loops( succ_st ) ;
2130  list prefix = gen_common_prefix( ls, succ_ls ) ;
2131 
2133  effect sc_eff = conflict_source( c ) ;
2134  effect sk_eff = conflict_sink( c ) ;
2135  bool keep = true;
2136  if(store_effect_p(sc_eff) && store_effect_p(sk_eff)
2137  && e == effect_entity(sc_eff)
2138  && e == effect_entity(sk_eff)) {
2139  ifdebug(3) {
2140  pips_debug(3, "source effect:");
2141  print_effect(sc_eff);
2142  pips_debug(3, "sink effect:");
2143  print_effect(sk_eff);
2144  }
2145 
2146  /* Take into account def-def and use-def edges only
2147  if they are on a single and same element
2148  which is true if the indices are constants
2149  or only depend on common enclosing loops indices.
2150  */
2151  if(action_write_p(effect_action(sk_eff))) {
2152  set common_loop_indices = set_make(set_pointer);
2153  pips_debug(3, "common loop indices :");
2154  FOREACH(statement, s, prefix) {
2155  loop l = statement_loop(s);
2156  ifdebug(3) {
2157  fprintf(stderr, "%s ", entity_name(loop_index(l)));
2158  }
2159  set_add_element(common_loop_indices, common_loop_indices, loop_index(l));
2160  }
2161  ifdebug(3) {
2162  fprintf(stderr, "\n");
2163  }
2164  list sc_inds = reference_indices(effect_any_reference(sc_eff));
2165  list sk_inds = reference_indices(effect_any_reference(sk_eff));
2166 
2167  for(;
2168  keep && !ENDP(sc_inds) && !ENDP(sk_inds);
2169  POP(sc_inds), POP(sk_inds)) {
2170  expression sc_exp = EXPRESSION(CAR(sc_inds));
2171  expression sk_exp = EXPRESSION(CAR(sk_inds));
2172  if (unbounded_expression_p(sc_exp) ||
2173  unbounded_expression_p(sk_exp)) {
2174  keep = false;
2175  } else {
2176  list l_eff_sc_exp = proper_effects_of_expression(sc_exp);
2177  FOREACH(EFFECT, eff_sc_exp, l_eff_sc_exp) {
2178  entity e_sc_exp = effect_entity(eff_sc_exp);
2179  if (!set_belong_p(common_loop_indices, e_sc_exp)) {
2180  keep = false;
2181  break;
2182  }
2183  }
2184  gen_full_free_list(l_eff_sc_exp);
2185  keep = keep && expression_equal_p(sc_exp, sk_exp);
2186  }
2187 
2188  }
2189  set_free(common_loop_indices);
2190  } /* if(action_write_p(effect_action(sk_eff))) */
2191 
2192  /* PC dependance and the sink is a loop index - shouldn't be necessary here */
2193  else if(action_read_p( effect_action( sk_eff )) &&
2194  (instruction_loop_p( succ_i) ||
2195  is_implied_do_index( e, succ_i))) {
2196  keep = true;
2197  } else {
2198  pips_debug(5,"Conflict for %s between statements %td and %td\n",
2199  entity_local_name(e),
2200  statement_number(st),
2201  statement_number(succ_st));
2202 
2203  if (v==succ_v) {
2204  /* No decision can be made from this couple of effects alone */
2205  keep = true;
2206  } else {
2207  pips_debug(5,"remove %s from candidates in non common enclosing loops\n",
2208  entity_local_name(e));
2209  keep = false;
2210  }
2211  }
2212  if (!keep) {
2213  pips_debug(1, "cannot keep candidate\n");
2214  /* e cannot be a local variable at a lower level than
2215  the common prefix because of this dependence
2216  arc. */
2217  remove_scalarizable_candidate_from_loops(prefix,
2218  ls,
2219  e,
2220  loops_scalarizable_candidates);
2221  remove_scalarizable_candidate_from_loops(prefix,
2222  succ_ls,
2223  e,
2224  loops_scalarizable_candidates);
2225  }
2226  }
2227  } /* FOREACH(CONFLICT, c, dg_arc_label_conflicts(arc_l)) */
2228  gen_free_list( prefix ) ;
2229  } /* FOREACH(SUCCESSOR, succ, vertex_successors(v)) */
2230 
2231  pips_debug(1, "End\n");
2232 }
2233 
2234 /** local context type for scalarizability post-tests
2235  */
2236 typedef struct {
2237  entity e;
2238  bool result;
2239  reference first_ref;
2240  list l_inds_first_ref;
2241 } scalarizability_test_ctxt;
2242 
2243 /** checks that all scalarizable proper effects of statement @param s
2244  on current @param s ctxt entity are on the same reference
2245  currently stored in @param ctxt.
2246  */
2247 static bool entity_can_be_scalarized_in_statement_in(statement s,
2248  scalarizability_test_ctxt *ctxt) {
2249  pips_debug(1, "entering statement %td\n", statement_number(s));
2250  ifdebug(1){print_statement(s);}
2252  bool continue_p = true;
2253 
2255  && !entity_in_list_p(ctxt->e, statement_declarations(s))) {
2256  /* the statement has no cumulated effect from entity e, and e is
2257  not declared inside: it cannot prevent scalarization, nor it's
2258  inner statements.
2259  */
2260  continue_p = false;
2261  } else {
2262  /* the statement has cumulated effects from entity e; check its
2263  proper effects before going to inner statements
2264  */
2265  l_eff = load_proper_rw_effects_list(s);
2266  FOREACH(EFFECT, eff, l_eff) {
2267  reference eff_ref = effect_any_reference(eff);
2268  entity eff_e = reference_variable(eff_ref);
2269  if (store_effect_p(eff) && eff_e == ctxt->e) {
2270  if (reference_undefined_p(ctxt->first_ref)) {
2271  ctxt->first_ref = eff_ref;
2272  ctxt->l_inds_first_ref = reference_indices(ctxt->first_ref);
2273  } else {
2274  /* check that current ref is similar to first ref */
2275  list l_inds_eff_ref = reference_indices(eff_ref);
2276 
2277  pips_assert("all scalarizable references have the same number "
2278  "of indices",
2279  gen_length(l_inds_eff_ref) == gen_length(ctxt->l_inds_first_ref));
2280 
2281  list l_first = ctxt->l_inds_first_ref;
2282  FOREACH(EXPRESSION, eff_exp, l_inds_eff_ref) {
2283  expression first_exp = EXPRESSION(CAR(l_first));
2284  if (!expression_equal_p(first_exp, eff_exp)) {
2285  ctxt->result = false;
2286  continue_p = false; /* no need to go on recursing on statements */
2287  break;
2288  }
2289  POP(l_first);
2290  }
2291  if (!ctxt->result)
2292  break;
2293  }
2294  } /* if (eff_e == e) */
2295  } /* FOREACH(EFFECT, eff, l_eff) */
2296  }
2297  return continue_p;
2298 }
2299 
2300 
2301 /** after gathering scalarizable candidates, checks that entity @param
2302  e can be scalarized in statement @param s according to 2 criteria:
2303 
2304  1- there are no hidden references to the array due for
2305  instance to a function call
2306  2- all the accessed references are strictly the same;
2307  3- the privatizable reference indices do not depend on variables modified
2308  inside the loop body.
2309  */
2310 static bool entity_can_be_scalarized_in_statement_p(entity e, statement s,
2311  list l_modified_variables)
2312 {
2313  bool result = true;
2314 
2315  pips_debug(2, "checking for entity %s in statement %td\n",
2316  entity_name(e), statement_number(s));
2317  /* First check that there are no hidden references to the array due for
2318  instance to a function call.
2319  */
2320 
2321  // Estimate the dynamic number of *element* and *variable*
2322  // occurrences in the loop body
2323  int neo = count_references_to_variable_element(s, e);
2324  int nvo = count_references_to_variable(s, e);
2325  if (nvo != neo) {
2326  pips_debug(2,
2327  "First legality criterion not met: %d!=%d (nvo!=neo)\n",
2328  nvo, neo);
2329  result = false;
2330  } else {
2331  scalarizability_test_ctxt ctxt;
2332  ctxt.result = true;
2333  ctxt.e = e;
2334  ctxt.first_ref = reference_undefined;
2335  ctxt.l_inds_first_ref = NIL;
2336  gen_context_recurse(s, &ctxt,
2337  statement_domain, entity_can_be_scalarized_in_statement_in, gen_null2);
2338  result = ctxt.result;
2339  if (!result) {
2340  pips_debug(2,"Second legality criterion not met\n");
2341  } else if (reference_undefined_p(ctxt.first_ref)) {
2342  pips_debug(2,"No remaining reference found\n");
2343  result = false;
2344  } else {
2345  // check that the reference indices do not depend on variables
2346  // modified in the statement
2347  ifdebug(3) {
2348  pips_debug(3, "checking reference %s wrt entities:\n",
2349  words_to_string(effect_words_reference(ctxt.first_ref)));
2350  print_entities(l_modified_variables);
2351  }
2352  reference_testing_ctxt ref_test_ctxt;
2353  ref_test_ctxt.constant_p = true;
2354  ref_test_ctxt.e = e;
2355  ref_test_ctxt.trans_args = l_modified_variables;
2356  (void) reference_constant_wrt_ctxt_p(ctxt.first_ref, &ref_test_ctxt);
2357  ref_test_ctxt.trans_args = NIL;
2358  result = ref_test_ctxt.constant_p;
2359  pips_debug(2,"Third legality criterion %s met\n", result? "" : "not");
2360  }
2361  }
2362  return result;
2363 }
2364 
2365 /** check if loop scalarizable candidates are legal candidates
2366 
2367  legacy criteria:
2368 
2369  1- we only scalarize e if all references are on the same
2370  memory location. we could scalarize different references if we had
2371  a scalarize_reference_in_statement function.
2372  2- references cannot be scalarized if accesses are performed through calls
2373 
2374 */
2375 static void check_loop_scalarizable_candidates(loop l,
2376  hash_table loops_scalarizable_candidates) {
2377  set loop_scalarizable_candidates = hash_get(loops_scalarizable_candidates, l);
2378  statement body = loop_body(l);
2379  list l_loop =
2381  list l_modified_variables =
2384  if (entity_scalar_p(e)) {
2385  l_modified_variables = CONS(ENTITY, e, l_modified_variables);
2386  }
2387  }
2388 
2389  SET_FOREACH(entity, e, loop_scalarizable_candidates) {
2390  if (!entity_can_be_scalarized_in_statement_p(e,
2391  body,
2392  l_modified_variables)) {
2393  remove_scalarizable_candidate_from_loops(NIL,
2394  l_loop,
2395  e,
2396  loops_scalarizable_candidates);
2397  }
2398  }
2399  gen_free_list(l_loop);
2400  gen_free_list(l_modified_variables);
2401 }
2402 
2403 
2404 /** check if scalarizable candidates are legal candidates
2405 
2406  legacy criteria:
2407 
2408  1- we only scalarize e if all references are on the same
2409  memory location. we could scalarize different references if we had
2410  a scalarize_reference_in_statement function.
2411  2- references cannot be scalarized if accesses are performed through calls
2412 
2413 */
2414 static void check_scalarizable_candidates(statement s,
2415  hash_table loops_scalarizable_candidates) {
2416  gen_context_recurse(s, loops_scalarizable_candidates,
2417  loop_domain, gen_true2, check_loop_scalarizable_candidates);
2418 }
2419 
2420 /** Once scalarizable candidates have been discovered, and checked,
2421  actually perform the scalarization on the loop @param l.
2422 
2423  */
2424 static void loop_scalarize_candidates(loop l,
2425  hash_table loops_scalarizable_candidates) {
2426  set loop_scalarizable_candidates = hash_get(loops_scalarizable_candidates, l);
2427 
2428  /* be deterministic! */
2429  list l_loop_scalarizable_candidates =
2430  set_to_sorted_list(loop_scalarizable_candidates,
2432 
2433  FOREACH(entity, e, l_loop_scalarizable_candidates) {
2434  pips_debug(3, "entity %s is going to be scalarized in loop with index %s\n",
2436  scalarize_variable_in_statement(e,
2437  loop_body(l),
2440  }
2441  gen_free_list(l_loop_scalarizable_candidates);
2442 }
2443 
2444 
2445 /** Once scalarizable candidates have been discovered, and checked,
2446  actually perform the scalarization on the loops reachable from
2447  statement @param s.
2448 
2449  */
2450 static void scalarize_candidates(statement s,
2451  hash_table loops_scalarizable_candidates) {
2452  gen_context_recurse(s, loops_scalarizable_candidates,
2453  loop_domain, gen_true2, loop_scalarize_candidates);
2454 }
2455 
2456 bool quick_scalarization(const string module_name)
2457 {
2458  entity module;
2459  statement module_stat;
2460 
2463 
2465  module_name,
2466  true) );
2467  module_stat = get_current_module_statement();
2468 
2470  db_get_memory_resource(DBR_PROPER_EFFECTS, module_name, true));
2471 
2473  db_get_memory_resource(DBR_CUMULATED_EFFECTS, module_name, true) );
2474 
2476 
2477  /* Get the data dependence graph (chains) : */
2479  module_name,
2480  true);
2481 
2483  set_ordering_to_statement(module_stat);
2484 
2485  debug_on("SCALARIZATION_DEBUG_LEVEL");
2486  pips_debug(1, "begin\n");
2487 
2488  /* Build maximal lists of scalarizable candidates */
2489  hash_table loops_scalarizable_candidates = hash_table_make(hash_pointer, 0);
2490  gen_context_recurse(module_stat, loops_scalarizable_candidates,
2491  statement_domain, statement_compute_scalarizable_candidates, gen_null2);
2492 
2493  /* remove non private variables from locals */
2497 
2498  pips_debug(1, "Entering statement %03zd :\n", statement_ordering(st));
2499  ifdebug(4) {
2500  print_statement(st);
2501  }
2502 
2504  ifdebug(4) {
2505  pips_debug(1, "effect :");
2506  print_effect(eff);
2507  }
2508  if( action_write_p(effect_action(eff)) && array_effect_p(eff)) {
2509  update_scalarizable_candidates( v, st, eff,
2510  loops_scalarizable_candidates) ;
2511  }
2512  }
2513  }
2514 
2515  /* modify code with scalarized variables
2516  */
2517  /* first check if candidates are really scalarizable
2518  * with scalarize_variable_in_statement*/
2519  check_scalarizable_candidates(module_stat, loops_scalarizable_candidates);
2520  scalarize_candidates(module_stat, loops_scalarizable_candidates);
2521 
2522  /* free hash_table of scalarizable candidates */
2523  HASH_FOREACH(loop, l, set, s_candidates, loops_scalarizable_candidates) {
2524  set_free(s_candidates);
2525  }
2526  hash_table_free(loops_scalarizable_candidates);
2527 
2528  pips_debug(1, "end\n");
2529  debug_off();
2530 
2531  /* Save modified code to database */
2532  module_reorder(module_stat);
2533  DB_PUT_MEMORY_RESOURCE(DBR_CODE, strdup(module_name), module_stat);
2534 
2542 
2543  return (true);
2544 }
2545 
2546 #endif // BUILDER_ * _ SCALARIZATION
float a2sf[2] __attribute__((aligned(16)))
USER generates a user error (i.e., non fatal) by printing the given MSG according to the FMT.
Definition: 3dnow.h:3
static hash_table seen
static function to store whether a module has been seen during the recursive generation of the daVinc...
Definition: graph.c:85
int get_int_property(const string)
static string current_module
Definition: message.c:63
action make_action_read(action_kind _field_)
Definition: effects.c:123
cell make_cell_reference(reference _field_)
Definition: effects.c:293
action_kind make_action_kind_store(void)
Definition: effects.c:65
void free_effect(effect p)
Definition: effects.c:451
descriptor make_descriptor_convex(Psysteme _field_)
Definition: effects.c:439
approximation make_approximation_may(void)
Definition: effects.c:179
effect make_effect(cell a1, action a2, approximation a3, descriptor a4)
Definition: effects.c:484
value make_value_expression(expression _field_)
Definition: ri.c:2850
basic copy_basic(basic p)
BASIC.
Definition: ri.c:104
reference make_reference(entity a1, list a2)
Definition: ri.c:2083
void free_expression(expression p)
Definition: ri.c:853
reference copy_reference(reference p)
REFERENCE.
Definition: ri.c:2047
struct _newgen_struct_entity_ * entity
Definition: abc_private.h:14
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
static reference ref
Current stmt (an integer)
Definition: adg_read_paf.c:163
struct _newgen_struct_expression_ * expression
Definition: alias_private.h:21
bool entity_abstract_location_p(entity al)
bool entity_is_argument_p(entity e, cons *args)
Definition: arguments.c:150
cons * arguments_add_entity(cons *a, entity e)
Definition: arguments.c:85
cons * arguments_difference(cons *a1, cons *a2)
set difference: a1 - a2 ; similar to set intersection
Definition: arguments.c:233
#define VALUE_ZERO
int Value
#define value_eq(v1, v2)
bool operators on values
Pbase base_add_variable(Pbase b, Variable var)
Pbase base_add_variable(Pbase b, Variable v): add variable v as a new dimension to basis b at the end...
Definition: base.c:88
Pbase base_remove_variable(Pbase b, Variable v)
Pbase base_remove_variable(b, v): remove basis vector relative to v from b; abort if v is not in b;.
Definition: base.c:122
Variable base_find_variable(Pbase b, Variable v)
Variable base_find_variable(Pbase b, Variable v): returns variable v if variable v is one of b's elem...
Definition: base.c:155
bool base_included_p(Pbase b1, Pbase b2)
Pbase base_included_p(Pbase b1, Pbase b2): include_p = b1 is included in b2 – with the set meaning re...
Definition: base.c:640
Pbase base_union(Pbase b1, Pbase b2)
Pbase base_union(Pbase b1, Pbase b2): compute a new basis containing all elements of b1 and all eleme...
Definition: base.c:428
static Psysteme sc_union(Psysteme sc1, Psysteme sc2)
Definition: chernikova.h:1476
#define CONTRAINTE_UNDEFINED_P(c)
#define contrainte_succ(c)
#define contrainte_vecteur(c)
passage au champ vecteur d'une contrainte "a la Newgen"
#define CONTRAINTE_UNDEFINED
#define dg_vertex_label_statement(x)
Definition: dg.h:235
struct _newgen_struct_dg_arc_label_ * dg_arc_label
Definition: dg.h:60
#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
struct _newgen_struct_dg_vertex_label_ * dg_vertex_label
Definition: dg.h:68
static Value offset
Definition: translation.c:283
entity make_phi_entity(int)
void print_regions(list)
effects load_out_effects(statement)
list effects_store_effects(list)
effects load_in_effects(statement)
list load_proper_rw_effects_list(statement)
void reset_out_effects(void)
void reset_proper_rw_effects(void)
void set_proper_rw_effects(statement_effects)
void set_cumulated_rw_effects(statement_effects)
void set_out_effects(statement_effects)
void set_in_effects(statement_effects)
void reset_in_effects(void)
list load_cumulated_rw_effects_list(statement)
effects load_cumulated_rw_effects(statement)
list effects_to_written_scalar_entities(list)
void reset_cumulated_rw_effects(void)
list proper_effects_of_expression(expression)
bool is_implied_do_index(entity, instruction)
#define effect_any_reference(e)
FI: cannot be used as a left hand side.
#define effect_approximation_tag(eff)
#define effect_variable(e)
For COMPATIBILITY purpose only - DO NOT USE anymore.
bool effects_read_variable_p(list, entity)
Definition: effects.c:1123
list effect_words_reference(reference)
prettyprint.c
Definition: prettyprint.c:68
bool effects_write_variable_p(list, entity)
Definition: effects.c:1091
entity effect_entity(effect)
cproto-generated files
Definition: effects.c:52
bool store_effect_p(effect)
Definition: effects.c:1062
tag approximation_or(tag, tag)
tag approximation_or(tag t1, tag t2) input : two approximation tags.
Definition: effects.c:1213
list effects_to_list(effects)
Definition: effects.c:209
#define effect_undefined_p(x)
Definition: effects.h:615
#define effect_action(x)
Definition: effects.h:642
#define effect_undefined
Definition: effects.h:614
#define action_write_p(x)
Definition: effects.h:314
#define action_read_p(x)
Definition: effects.h:311
#define descriptor_convex_p(x)
Definition: effects.h:599
#define effect_descriptor(x)
Definition: effects.h:646
#define effects_effects(x)
Definition: effects.h:710
#define descriptor_convex(x)
Definition: effects.h:601
@ is_approximation_may
Definition: effects.h:341
@ is_approximation_exact
Definition: effects.h:343
#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
char * get_string_property(const char *)
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
#define gen_context_recurse(start, ctxt, domain_number, flt, rwt)
Definition: genC.h:285
void gen_full_free_list(list l)
Definition: genClib.c:1023
#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 vertex_vertex_label(x)
Definition: graph.h:152
#define vertex_successors(x)
Definition: graph.h:154
#define SUCCESSOR(x)
SUCCESSOR.
Definition: graph.h:86
#define graph_vertices(x)
Definition: graph.h:82
#define VERTEX(x)
VERTEX.
Definition: graph.h:122
bool effects_may_read_or_write_memory_paths_from_entity_p(list l_eff, entity e)
tests whether the input effects list may contain effects with a memory path from the input entity e; ...
Definition: conflicts.c:1130
list effects_entities_which_may_conflict_with_scalar_entity(list fx, entity e)
Definition: conflicts.c:1273
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
entity get_current_module_entity(void)
Get the entity of the current module.
Definition: static.c:85
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_current_ancestor(int)
Return current object of that type...
Definition: genClib.c:3587
gen_chunk * gen_get_ancestor(int, const void *)
return the first ancestor object found of the given type.
Definition: genClib.c:3560
void gen_null2(__attribute__((unused)) void *u1, __attribute__((unused)) void *u2)
idem with 2 args, to please overpeaky compiler checks
Definition: genClib.c:2758
bool gen_true2(__attribute__((unused)) gen_chunk *u1, __attribute__((unused)) void *u2)
Definition: genClib.c:2785
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
void clean_enclosing_loops(void)
Definition: loop.c:58
statement get_first_inner_perfectly_nested_loop(statement stat)
Return the inner loop in a perfect loop-nest.
Definition: loop.c:508
statement_mapping loops_mapping_of_statement(statement stat)
Definition: loop.c:155
int depth_of_parallel_perfect_loop_nest(statement s)
Compute the depth of a parallel perfect loop-nest.
Definition: loop.c:436
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
#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
list gen_common_prefix(const list l1, const list l2)
return the common list prefix of lists l1 and l2.
Definition: list.c:1033
#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
void * gen_find(const void *item, const list seq, gen_filter2_func_t test, gen_extract_func_t extract)
Definition: list.c:398
bool gen_eq(const void *obj1, const void *obj2)
Definition: list.c: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
loop statement_loop(statement)
Get the loop of a statement.
Definition: statement.c:1374
bool statement_loop_p(statement)
Definition: statement.c:349
bool statement_sequence_p(statement)
Statement classes induced from instruction type.
Definition: statement.c:335
statement make_assign_statement(expression, expression)
Definition: statement.c:583
int count_references_to_variable(statement, entity)
Definition: statement.c:3655
statement add_declaration_statement_at_beginning(statement, entity)
Definition: statement.c:2795
int count_references_to_variable_element(statement, entity)
Definition: statement.c:3666
reference find_reference_to_variable(statement, entity)
Definition: statement.c:3543
void insert_statement(statement, statement, bool)
This is the normal entry point.
Definition: statement.c:2570
bool declaration_statement_p(statement)
Had to be optimized according to Beatrice Creusillet.
Definition: statement.c:224
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
void hash_table_free(hash_table htp)
this function deletes a hash table that is no longer useful.
Definition: hash.c:327
#define D(A)
Definition: iabrev.h:56
#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 pips_internal_error
Definition: misc-local.h:149
#define debug_off()
Definition: misc-local.h:160
#define pips_user_error
Definition: misc-local.h:147
string bool_to_string(bool)
Definition: string.c:243
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
@ hash_int
Definition: newgen_hash.h:32
@ 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
#define HASH_FOREACH(key_type, k, value_type, v, ht)
Definition: newgen_hash.h:71
#define HASH_DEFAULT_SIZE
Definition: newgen_hash.h:26
#define same_string_p(s1, s2)
set set_del_element(set, const set, const void *)
Definition: set.c:265
struct _set_chunk * set
Definition: newgen_set.h:38
list set_to_list(const set)
create a list from a set the set is not freed
Definition: set.c:436
list set_to_sorted_list(const set, gen_cmp_func_t)
Definition: set.c:447
#define SET_FOREACH(type_name, the_item, the_set)
enumerate set elements in their internal order.
Definition: newgen_set.h:78
void set_free(set)
Definition: set.c:332
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
int tag
TAG.
Definition: newgen_types.h:92
struct cons * list
Definition: newgen_types.h:106
int(* gen_cmp_func_t)(const void *, const void *)
Definition: newgen_types.h:114
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
statement ordering_to_statement(int o)
Get the statement associated to a given ordering.
Definition: ordering.c:111
void reset_ordering_to_statement(void)
Reset the mapping from ordering to statement.
Definition: ordering.c:185
static char * module
Definition: pips.c:74
Psysteme sc_cute_convex_hull(Psysteme, Psysteme)
returns s1 v s2.
Definition: sc_enveloppe.c:369
#define print_effect(e)
Definition: print.c:336
#define print_region(x)
Definition: print.c:343
#define print_effects(e)
Definition: print.c:334
void print_statement(statement)
Print a statement on stderr.
Definition: statement.c:98
static bool constant_p(entity e)
This function return a bool indicating if related entity e represents a constant.
static const char * prefix
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define ENTITY_ADDRESS_OF_P(e)
bool dynamic_area_p(entity aire)
Definition: area.c:68
bool stack_area_p(entity aire)
Definition: area.c:104
bool static_area_p(entity aire)
Definition: area.c:77
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
bool entity_in_list_p(entity ent, list ent_l)
look for ent in ent_l
Definition: entity.c:2221
int compare_entities(const entity *pe1, const entity *pe2)
Comparison function for qsort.
Definition: entity.c:1328
bool entity_array_p(entity e)
Is e a variable with an array type?
Definition: entity.c:754
bool same_entity_p(entity e1, entity e2)
predicates on entities
Definition: entity.c:1321
bool local_entity_of_module_p(entity e, entity module)
This test shows that "e" has been declared in "module".
Definition: entity.c:1069
bool c_module_p(entity m)
Test if a module "m" is written in C.
Definition: entity.c:2777
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
string storage_to_string(storage s)
Definition: entity.c:2030
bool effects_package_entity_p(entity e)
checks if an entity is an IO_EFFECTS_PACKAGE_NAME, a MALLOC_EFFECTS_NAME or a RAND_EFFECTS_PACKAGE_NA...
Definition: entity.c:1181
const char * module_local_name(entity e)
Returns the module local user name.
Definition: entity.c:582
void print_entities(list l)
Definition: entity.c:167
set get_declared_entities(void *elem)
retrieves the set of entities declared in elem
Definition: entity.c:3086
bool top_level_entity_p(entity e)
Check if the scope of entity e is global.
Definition: entity.c:1130
bool parameter_passing_by_value_p(entity f)
Definition: entity.c:2116
const char * entity_module_name(entity e)
See comments about module_name().
Definition: entity.c:1092
bool entity_pointer_p(entity e)
Definition: entity.c:745
void set_register_qualifier(entity v)
Assuming that v is of type variable, add a qualifier register.
Definition: entity.c:778
set get_referenced_entities(void *elem)
retrieves the set of entities used in elem beware that this entities may be formal parameters,...
Definition: entity.c:3063
bool expression_integer_value(expression e, intptr_t *pval)
Definition: eval.c:792
expression reference_to_expression(reference r)
Definition: expression.c:196
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
bool expression_equal_p(expression e1, expression e2)
Syntactic equality e1==e2.
Definition: expression.c:1347
bool unbounded_expression_p(expression e)
Definition: expression.c:4329
expression reference_offset(reference ref)
computes the offset of a C reference with its origin
Definition: expression.c:3807
bool extended_expression_constant_p(expression exp)
Returns true if the value of the expression does not depend syntactically on the current store.
Definition: expression.c:2461
bool c_language_module_p(entity m)
Definition: module.c:447
bool fortran_language_module_p(entity m)
Definition: module.c:452
type ultimate_type(type)
Definition: type.c:3466
list load_statement_enclosing_loops(statement)
bool entity_static_variable_p(entity)
return true if the entity is declared with the keyword static
Definition: variable.c:1146
void AddLocalEntityToDeclarationsOnly(entity, entity, statement)
Add the variable entity e to the list of variables of the function module.
Definition: variable.c:253
void AddLocalEntityToDeclarations(entity, entity, statement)
Add the variable entity e to the list of variables of the function module.
Definition: variable.c:233
bool entity_volatile_variable_p(entity)
Definition: variable.c:1637
bool entity_scalar_p(entity)
The concrete type of e is a scalar type.
Definition: variable.c:1113
void AddEntityToCurrentModule(entity)
Add a variable entity to the current module declarations.
Definition: variable.c:260
type entity_basic_concrete_type(entity)
retrieves or computes and then returns the basic concrete type of an entity
Definition: type.c:3677
size_t type_depth(type)
Number of steps to access the lowest leave of type t without dereferencing.
Definition: type.c:4880
bool formal_parameter_p(entity)
Definition: variable.c:1489
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
void set_enclosing_loops_map(statement_mapping)
basic basic_of_reference(reference)
Retrieves the basic of a reference in a newly allocated basic object.
Definition: type.c:1459
#define type_functional_p(x)
Definition: ri.h:2950
#define value_undefined_p(x)
Definition: ri.h:3017
#define loop_body(x)
Definition: ri.h:1644
#define value_code_p(x)
Definition: ri.h:3065
#define expression_domain
newgen_execution_domain_defined
Definition: ri.h:154
struct _newgen_struct_value_ * value
Definition: ri.h:455
#define storage_formal_p(x)
Definition: ri.h:2522
#define reference_undefined
Definition: ri.h:2302
#define cast_domain
newgen_call_domain_defined
Definition: ri.h:66
#define instruction_loop_p(x)
Definition: ri.h:1518
#define call_function(x)
Definition: ri.h:709
#define reference_variable(x)
Definition: ri.h:2326
#define loop_domain
newgen_language_domain_defined
Definition: ri.h:218
#define reference_undefined_p(x)
Definition: ri.h:2303
#define ENTITY(x)
ENTITY.
Definition: ri.h:2755
#define statement_ordering(x)
Definition: ri.h:2454
#define value_unknown_p(x)
Definition: ri.h:3077
#define type_variable(x)
Definition: ri.h:2949
#define entity_storage(x)
Definition: ri.h:2794
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define storage_ram_p(x)
Definition: ri.h:2519
#define call_domain
newgen_callees_domain_defined
Definition: ri.h:58
#define ram_section(x)
Definition: ri.h:2249
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define cast_expression(x)
Definition: ri.h:747
#define entity_undefined_p(x)
Definition: ri.h:2762
#define reference_domain
newgen_range_domain_defined
Definition: ri.h:338
#define entity_undefined
Definition: ri.h:2761
#define entity_name(x)
Definition: ri.h:2790
#define transformer_relation(x)
Definition: ri.h:2873
#define transformer_arguments(x)
Definition: ri.h:2871
#define reference_indices(x)
Definition: ri.h:2328
#define variable_dimensions(x)
Definition: ri.h:3122
#define statement_declarations(x)
Definition: ri.h:2460
#define statement_instruction(x)
Definition: ri.h:2458
#define storage_ram(x)
Definition: ri.h:2521
#define call_arguments(x)
Definition: ri.h:711
#define statement_undefined_p(x)
Definition: ri.h:2420
#define entity_type(x)
Definition: ri.h:2792
#define statement_number(x)
Definition: ri.h:2452
#define type_variable_p(x)
Definition: ri.h:2947
#define predicate_system(x)
Definition: ri.h:2069
#define loop_index(x)
Definition: ri.h:1640
#define variable_basic(x)
Definition: ri.h:3120
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
#define entity_initial(x)
Definition: ri.h:2796
int enclosing
This is an horrendous hack.
Definition: rice.c:67
void sc_rm(Psysteme ps)
void sc_rm(Psysteme ps): liberation de l'espace memoire occupe par le systeme de contraintes ps;
Definition: sc_alloc.c:277
Pbase sc_to_minimal_basis(Psysteme ps)
creation d'une base contenant toutes les variables apparaissant avec des coefficients non-nuls dans l...
Definition: sc_alloc.c:76
bool sc_empty_p(Psysteme sc)
bool sc_empty_p(Psysteme sc): check if the set associated to sc is the constant sc_empty or not.
Definition: sc_alloc.c:350
Psysteme sc_dup(Psysteme ps)
Psysteme sc_dup(Psysteme ps): should becomes a link.
Definition: sc_alloc.c:176
Psysteme sc_copy(Psysteme ps)
Psysteme sc_copy(Psysteme ps): duplication d'un systeme (allocation et copie complete des champs sans...
Definition: sc_alloc.c:230
bool sc_minmax_of_variable(Psysteme ps, Variable var, Value *pmin, Value *pmax)
void sc_minmax_of_variable(Psysteme ps, Variable var, Value *pmin, *pmax): examine un systeme pour tr...
Definition: sc_eval.c:143
Psysteme sc_append(Psysteme s1, Psysteme s2)
Psysteme sc_append(Psysteme s1, Psysteme s2): calcul de l'intersection des polyedres definis par s1 e...
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
char * strdup()
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
transformer load_statement_precondition(statement)
void set_transformer_map(statement_mapping)
transformer load_statement_transformer(statement)
void reset_precondition_map(void)
void set_precondition_map(statement_mapping)
void reset_transformer_map(void)
#define ifdebug(n)
Definition: sg.c:47
static entity array
#define intptr_t
Definition: stdint.in.h:294
char * current_module_name
le type des coefficients dans les vecteurs: Value est defini dans le package arithmetique
Definition: vecteur-local.h:89
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
string words_to_string(cons *lw)
Definition: print.c:211
static int depth
la sequence de nids
bool quick_scalarization(const string)
bool scalarization(const string)
scalarization.c
bool constant_array_scalarization(const string)
transformer transformer_range(transformer tf)
Return the range of relation tf in a newly allocated transformer.
Definition: transformer.c:714
void reset_temporary_value_counter(void)
Definition: value.c:250
entity make_local_temporary_integer_value_entity(void)
Definition: value.c:629
void free_value_mappings(void)
Normal call to free the mappings.
Definition: value.c:1212
#define sc_inclusion_p_ofl_ctrl(ps1, ps2, ofl)
Definition: union-local.h:82
@ keep
bj > b1 -> h1/hj = h1
Definition: union-local.h:61
A gen_chunk is used to store every object.
Definition: genC.h:58
#define exp
Avoid some warnings from "gcc -Wshadow".
Definition: vasnprintf.c:207
#define vecteur_var(v)
#define VECTEUR_NUL
DEFINITION DU VECTEUR NUL.
#define BASE_UNDEFINED_P(b)
#define vecteur_succ(v)
#define base_rm(b)
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 BASE_UNDEFINED
#define base_dimension(b)
#define BASE_NULLE
MACROS SUR LES BASES.
#define OFL_CTRL
I do thing that overflows are managed in a very poor manner.
#define BASE_NULLE_P(b)
void vect_rm(Pvecteur v)
void vect_rm(Pvecteur v): desallocation des couples de v;
Definition: alloc.c:78
void vect_add_elem(Pvecteur *pvect, Variable var, Value val)
void vect_add_elem(Pvecteur * pvect, Variable var, Value val): addition d'un vecteur colineaire au ve...
Definition: unaires.c:72
Value vect_coeff(Variable var, Pvecteur vect)
Variable vect_coeff(Variable var, Pvecteur vect): coefficient de coordonnee var du vecteur vect —> So...
Definition: unaires.c:228