PIPS
loop_normalize.c
Go to the documentation of this file.
1 /*
2 
3  $Id: loop_normalize.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 #ifdef BUILDER_LOOP_NORMALIZE
28 
29 #ifdef HAVE_CONFIG_H
30  #include "pips_config.h"
31 #endif
32 /* Name : loop_normalize.c
33  * Package : loop_normalize
34  * Author : Arnauld LESERVOT & Alexis PLATONOFF
35  * Date : 27 04 93
36  * Modified : moved to Lib/transformations, AP, sep 95
37  * strongly modernized by SG
38  * Documents: "Implementation du Data Flow Graph dans Pips"
39  * Comments :
40  *
41  * Functions of normalization of DO loops. Normalization consists in changing
42  * the loop index so as to have something like:
43  * DO I = 0, UPPER, 1
44  *
45  * If the old DO loops was:
46  * DO I = lower, upper, incre
47  * then : UPPER = (upper - lower + incre)/incre - 1
48  *
49  * The normalization is done only if "incre" is a constant number.
50  * The normalization produces two statements. One assignment of the old
51  * loop index (in the exemple I) to its value function of the new index;
52  * the formula is: I = incre*NLC + lower
53  * and one assignment of the old index at the end of the loop for its final
54  * value: I = incre * MAX(UPPER+1, 0) + lower
55  *
56  * So, for exemple:
57  * DO I = 2, 10, 4
58  * INST
59  * ENDDO
60  * is normalized in:
61  * DO I = 0, 2, 1
62  * I = 4*I + 2
63  * INST
64  * ENDDO
65  * I = 14
66  *
67  * Or:
68  * DO I = 2, 1, 4
69  * INST
70  * ENDDO
71  * is normalized in:
72  * DO I = 0, -1, 1
73  * I = 4*I + 2
74  * INST
75  * ENDDO
76  * I = 2
77  *
78  * SG: normalized loop used to have a new loop counter.
79  * It made code less reeadable, so I supressed this
80  *
81  * If a loop has a label, it is removed. For example:
82  * DO 10 I = 1, 10, 1
83  * INST
84  * 10 CONTINUE
85  *
86  * is modified in:
87  * DO i = 1, 10, 1
88  * INST
89  * ENDDO
90  */
91 
92 #include <stdio.h>
93 #include <string.h>
94 
95 #include "genC.h"
96 #include "linear.h"
97 
98 #include "misc.h"
99 #include "properties.h"
100 #include "pipsdbm.h"
101 
102 #include "ri.h"
103 #include "ri-util.h"
104 #include "workspace-util.h" // for make_max_exp
105 
106 #include "control.h" // module_reorder
107 #include "transformations.h" // find_loop_from_label in "index_set_splitting"
108 
109 /**
110  * statement normalization
111  * normalize a statement if it's a loop
112  *
113  * @param s statement to normalize
114  *
115  */
117  if( statement_loop_p(s) ) {
118  // OK, it's a loop, go on
119  loop l = statement_loop(s);
120  pips_debug(4, "begin loop\n");
121  if (! constant_step_loop_p(l))
122  // Cannot normalize loops with non-constant increment
123  return;
124 
125  /* Do not normalize normal loops (loops with a 1-increment), except if
126  we ask for: */
127  if (normal_loop_p(l) && !get_bool_property("LOOP_NORMALIZE_ONE_INCREMENT"))
128  return;
129 
130  /* Do not normalize sequential loops if we ask for: */
131  if (loop_sequential_p(l) && get_bool_property("LOOP_NORMALIZE_PARALLEL_LOOPS_ONLY")) {
132  pips_debug(2,"Do not normalize this loop because it's sequential and "
133  "we asked to normalize only parallel loops\n");
134  return;
135  }
136 
137  // Get the new lower bound of the loop:
138  int new_lb = get_int_property("LOOP_NORMALIZE_LOWER_BOUND");
139 
140  entity index = loop_index(l);
141  range lr = loop_range(l);
142  // Initial loop range: rl:ru:ri
143  expression rl = range_lower(lr);
144  expression ru = range_upper(lr);
145  expression ri = range_increment(lr);
146 
147  // Number of iteration: nub = ((ru-rl)+ri)/ri
148  /* Note that in the following, make_op_exp do make some partial eval
149  for integer values! */
154  copy_expression(ri)),
155  copy_expression(ri));
156  expression nub2 = copy_expression(nub);
157 
158  expression nlc_exp = entity_to_expression(index);
159  // New range new_lb:(nub2+(new_lb-1)):1
160  range_lower(lr) = int_to_expression(new_lb);
161  range_upper(lr) =
163  nub2,
165  int_to_expression(new_lb),
166  int_to_expression(1)));
168 
169  // Base change: (index - new_lb)*ri + rl
170  expression new_index_exp =
172  copy_expression(rl),
175  nlc_exp,
176  int_to_expression(new_lb)),
177  copy_expression(ri)));
178 
179 
180  /* Commit the changes */
181 
182  /* Replace all references to index in loop_body(l) by new_index_exp */
183  replace_entity_by_expression(loop_body(l),index,new_index_exp);
184 
185  if (!entity_in_list_p(index,loop_locals(l)) && //SG: no side effect if index is private ...
186  !get_bool_property("LOOP_NORMALIZE_SKIP_INDEX_SIDE_EFFECT")) {
187  /* We want to compute the real side effect of the loop on its index:
188  its final value after the loop. */
189  expression nub3 = copy_expression(nub);
190 
191  /* Compute the final value of the loop index to have the correct side
192  effect of the loop on the original index: */
194  if ( expression_constant_p(nub3)) {
195  int upper = expression_to_int(nub3);
196  if (upper > 0)
197  exp_max = int_to_expression(upper);
198  }
199  else {
201  exp_max = make_max_exp(max_ent, copy_expression(nub),
202  int_to_expression(0));
203  }
204  if (expression_undefined_p(exp_max))
205  exp_plus = copy_expression(rl);
206  else
207  exp_plus = make_op_exp(PLUS_OPERATOR_NAME,
209  copy_expression(ri),
210  exp_max),
211  copy_expression(rl));
212 
213  expression index_exp = entity_to_expression(index);
214  /* Add after the loop the initialization of the loop index to the
215  final value: */
216  statement end_stmt = make_assign_statement(copy_expression(index_exp),
217  exp_plus);
218  insert_statement(s, end_stmt,false);
219  }
220  pips_debug( 4, "end LOOP\n");
221  }
222 }
223 
224 
225 /** Apply the loop normalization upon a module
226 
227  Try to normalize each loop into a loop with a 1-step increment
228 
229  @param mod_name name of the normalized module
230 
231  @return true
232 */
233 bool loop_normalize(const string mod_name) {
234  /* prelude */
235  debug_on("LOOP_NORMALIZE_DEBUG_LEVEL");
236  pips_debug(1, "\n\n *** LOOP_NORMALIZE for %s\n", mod_name);
237 
240  (statement) db_get_memory_resource(DBR_CODE, mod_name, true));
241 
242  string loop_label = (string)get_string_property("LOOP_LABEL");
243  //print_statement(get_current_module_statement());
244  if (!empty_string_p(loop_label)) {
245  /*
246  * User gave a label, we will work on this label only
247  */
248  entity elabel = entity_undefined;
251  if (!entity_undefined_p(elabel)) {
253  }
254  if (!statement_undefined_p(sloop)) {
256  } else {
257  pips_user_error("No loop for label %s\n", loop_label);
258  }
259  } else {
260  /* Compute the loops normalization of the module. */
263  }
264  /* commit changes */
265  module_reorder(get_current_module_statement()); ///< we may have had statements
267 
268  /* postlude */
269  pips_debug(1, "\n\n *** LOOP_NORMALIZE done\n");
270  debug_off();
273 
274  return true;
275 }
276 
277 static void do_linearize_loop_range(statement st, bool * did_something) {
278  if(statement_loop_p(st)) {
279  loop l = statement_loop(st);
280  range r = loop_range(l);
281  expression *bounds[] = {
282  &range_upper(r),
283  &range_lower(r)
284  };
285  for(size_t i = 0; i< sizeof(bounds) / sizeof(bounds[0]) ; i++) {
286  expression *bound = bounds[i];
287  normalized nbound = NORMALIZE_EXPRESSION(*bound);
288  if(normalized_complex_p(nbound)) {
291  basic_of_expression(*bound)
292  );
293  free_value(entity_initial(newe));
294  entity_initial(newe) = make_value_expression(*bound);
295  *bound=entity_to_expression(newe);
297  *did_something=true;
298  }
299 
300  }
301  }
302 }
303 
304 /** look for non affine loop_range and move them outside of the loop to make it easier for PIPS to analyze them */
305 bool linearize_loop_range(const char *module_name) {
308 
309  bool did_something = false;
310 
311 
312  string loop_label = (string)get_string_property("LOOP_LABEL");
313  //print_statement(get_current_module_statement());
314  if (!empty_string_p(loop_label)) {
315  /*
316  * User gave a label, we will work on this label only
317  */
318  entity elabel = entity_undefined;
321  if (!entity_undefined_p(elabel)) {
323  }
324  if (!statement_undefined_p(sloop)) {
325  do_linearize_loop_range(sloop,&did_something);
326  } else {
327  pips_user_error("No loop for label %s\n", loop_label);
328  }
329  } else {
331  statement_domain, gen_true2, do_linearize_loop_range);
332  }
333  if(did_something) {
334  module_reorder(get_current_module_statement()); ///< we may have had statements
336  }
339 
340  return true;
341 }
342 
343 #endif // BUILDER_LOOP_NORMALIZE
344 
int get_int_property(const string)
value make_value_expression(expression _field_)
Definition: ri.c:2850
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
void free_value(value p)
Definition: ri.c:2787
bool empty_string_p(const char *s)
Definition: entity_names.c:239
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
#define gen_recurse(start, domain_number, flt, rwt)
Definition: genC.h:283
void reset_current_module_entity(void)
Reset the current module entity.
Definition: static.c:97
void reset_current_module_statement(void)
Reset the current module statement.
Definition: static.c:221
const char * get_current_module_name(void)
Get the name of the current module.
Definition: static.c:121
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 replace_entity_by_expression(void *s, entity ent, expression exp)
replace all reference to entity ent by expression exp in s.
Definition: replace.c:220
bool gen_true2(__attribute__((unused)) gen_chunk *u1, __attribute__((unused)) void *u2)
Definition: genClib.c:2785
bool gen_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
bool loop_sequential_p(loop l)
Test if a loop is sequential.
Definition: loop.c:404
bool constant_step_loop_p(loop l)
Test if a loop has a constant step loop.
Definition: loop.c:733
bool normal_loop_p(loop l)
Test if a loop does have a 1-increment step.
Definition: loop.c:741
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
statement make_assign_statement(expression, expression)
Definition: statement.c:583
void insert_statement(statement, statement, bool)
This is the normal entry point.
Definition: statement.c:2570
bool expression_constant_p(expression)
HPFC module by Fabien COELHO.
Definition: expression.c:2453
#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 debug_off()
Definition: misc-local.h:160
#define pips_user_error
Definition: misc-local.h:147
expression make_max_exp(entity ent, expression exp1, expression exp2)
================================================================
#define TOP_LEVEL_MODULE_NAME
Module containing the global variables in Fortran and C.
Definition: naming-local.h:101
char * string
STRING.
Definition: newgen_types.h:39
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define MAX_OPERATOR_NAME
#define MINUS_OPERATOR_NAME
#define PLUS_OPERATOR_NAME
#define NORMALIZE_EXPRESSION(e)
#define DIVIDE_OPERATOR_NAME
#define MULTIPLY_OPERATOR_NAME
entity FindEntity(const char *package, const char *name)
Retrieve an entity from its package/module name and its local name.
Definition: entity.c:1503
bool entity_in_list_p(entity ent, list ent_l)
look for ent in ent_l
Definition: entity.c:2221
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
int expression_to_int(expression exp)
================================================================
Definition: expression.c:2205
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
expression int_to_expression(_int i)
transform an int into an expression and generate the corresponding entity if necessary; it is not cle...
Definition: expression.c:1188
expression make_op_exp(char *op_name, expression exp1, expression exp2)
================================================================
Definition: expression.c:2012
basic basic_of_expression(expression)
basic basic_of_expression(expression exp): Makes a basic of the same basic as the expression "exp".
Definition: type.c:1383
void AddLocalEntityToDeclarations(entity, entity, statement)
Add the variable entity e to the list of variables of the function module.
Definition: variable.c:233
entity make_new_scalar_variable(entity, basic)
Definition: variable.c:741
entity find_label_entity(const char *, const char *)
util.c
Definition: util.c:43
#define loop_body(x)
Definition: ri.h:1644
#define normalized_complex_p(x)
Definition: ri.h:1782
#define range_upper(x)
Definition: ri.h:2290
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define range_increment(x)
Definition: ri.h:2292
#define entity_undefined_p(x)
Definition: ri.h:2762
#define entity_undefined
Definition: ri.h:2761
#define expression_undefined
Definition: ri.h:1223
#define loop_label(x)
Definition: ri.h:1646
#define loop_locals(x)
Definition: ri.h:1650
#define expression_undefined_p(x)
Definition: ri.h:1224
#define range_lower(x)
Definition: ri.h:2288
#define loop_range(x)
Definition: ri.h:1642
#define statement_undefined_p(x)
Definition: ri.h:2420
#define loop_index(x)
Definition: ri.h:1640
#define statement_undefined
Definition: ri.h:2419
#define entity_initial(x)
Definition: ri.h:2796
void loop_normalize_statement(statement)
loop_normalize.c
statement find_loop_from_label(statement, entity)
Definition: util.c:218
bool loop_normalize(const string)
bool linearize_loop_range(const char *)