PIPS
rice.c
Go to the documentation of this file.
1 /*
2 
3  $Id: rice.c 23065 2016-03-02 09:05:50Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23  */
24 #ifdef HAVE_CONFIG_H
25 #include "pips_config.h"
26 #endif
27 /* Remi Triolet
28  *
29  * Modifications:
30  *
31  * - Bruno Baron:
32  *
33  * - Francois Irigoin: I do not understand why regions of statements are
34  * implemented as set of statements instead of set of statement orderings
35  * since the dependence graph refers to statement orderings.
36  *
37  * - Francois Irigoin: use a copy of the code statement to generate
38  * the parallel code, instead of using side effects on the sequential
39  * code statement. This works because the dependence graph uses
40  * persistent pointers towards statement, statement_ordeging, and because
41  * the references are the same in the sequential code and in its copy.
42  * So references are still accessible, although it may be useless for
43  * parallelization.
44  */
45 
46 /* FI: I want misc.h and I end up with the other ones as well? */
47 #include "linear.h"
48 
49 #include "genC.h"
50 #include "ri.h"
51 #include "effects.h"
52 
53 #include "misc.h"
54 
55 #include "local.h"
56 #include "prettyprint.h"
57 
58 /* the dependence graph of the current loop nest */
60 
61 /* to know if do loop parallelization must be done */
63 
64 /* This is an horrendous hack. ENCLOSING should be passed as an
65  argument, but I don't have the courage to make the changes . */
66 
67 int enclosing = 0;
68 
70  int l,
71  statement(*codegen_fun)(statement,graph,set,int,bool)) {
72  cons *blocs = NIL;
73 
74  CONTROL_MAP(c, {
75  statement st = rice_statement(control_statement(c),l,codegen_fun);
76  control_statement(c) = st;
77  }, unstructured_control(u), blocs);
78 
79  gen_free_list(blocs);
80 }
81 
83  int l,
84  statement(*codegen_fun)(statement,
85  graph,
86  set,
87  int,
88  bool)) {
89  instruction istat = statement_instruction(stat);
90  statement new_stat = stat; // Most statements are modified by side effects
91 
92  switch(instruction_tag(istat)) {
93  case is_instruction_block: {
94  MAPL(pc, {
95  statement st = STATEMENT(CAR(pc));
96  STATEMENT_(CAR(pc)) = rice_statement(st,l,codegen_fun);
97  }, instruction_block(istat));
98  break;
99  }
100  case is_instruction_test: {
101  test obj_test = instruction_test(istat);
102  test_true(obj_test) = rice_statement(test_true(obj_test), l, codegen_fun);
103  test_false(obj_test) = rice_statement(test_false(obj_test),
104  l,
105  codegen_fun);
106  break;
107  }
108  case is_instruction_loop: {
109  new_stat = rice_loop(stat, l, codegen_fun);
110  ifdebug(7) {
111  if(statement_loop_p(new_stat))
112  pips_debug(7, "regenerated loop is %s:",
114  "sequential" : "parallel");
115  else
116  pips_debug(7, "regenerated code:");
117  if(statement_consistent_p(new_stat))
118  fprintf(stderr, " consistent\n");
119  print_parallel_statement(new_stat);
120  }
121  break;
122  }
124  whileloop wl = instruction_whileloop(istat);
125 
126  whileloop_body(wl) = rice_statement(whileloop_body(wl), l, codegen_fun);
127  break;
128  }
129  case is_instruction_forloop: {
130  forloop wl = instruction_forloop(istat);
131 
132  forloop_body(wl) = rice_statement(forloop_body(wl), l, codegen_fun);
133  break;
134  }
135  case is_instruction_goto:
136  pips_internal_error("Unexpected go to instruction in parsed code");
137  break;
138  case is_instruction_call:
140  break;
142  unstructured obj_unstructured = instruction_unstructured(istat);
143  rice_unstructured(obj_unstructured, l, codegen_fun);
144  break;
145  }
146  default:
147  pips_internal_error("default case reached with tag %d",
148  instruction_tag(istat));
149  }
150 
151  return (new_stat);
152 }
153 
154 /* Eventually parallelize a do-loop with à la Rice algorithm.
155 
156  @return a statement with the same loop (not parallelized), a statement
157  with a parallelized do-loop or an empty statement (the loop body was
158  empty so it is trivially parallelized in this way).
159  */
161  int l,
162  statement(*codegen_fun)(statement, graph, set, int, bool)) {
163  statement nstat;
164  instruction istat = statement_instruction(stat);
165  loop lstat = instruction_loop(istat);
166  set region;
167  //statement b = statement_undefined;
168  ifdebug(1) {
169  pips_debug(1, "original nest of loops:\n\n");
170  print_statement(stat);
171  }
172 
173  if((region = distributable_loop(stat)) == set_undefined) {
174  int so = statement_ordering(stat);
175  user_warning("rice_loop",
176  "Cannot apply Allen & Kennedy's algorithm on "
177  "loop %s with index %s at Statement %d (%d, %d)"
178  " because it contains either tests or goto statements"
179  " which prohibit loop distribution. You could activate the"
180  " coarse_grain_parallelization rule.\n",
183  statement_number(stat),
184  ORDERING_NUMBER(so),
185  ORDERING_STATEMENT(so));
186  goto skip_parallelization_of_this_loop;
187  }
188 
189  if(!get_bool_property("PARALLELIZE_AGAIN_PARALLEL_CODE")
190  && parallel_loop_statement_p(stat))
191  /* Well the loop is already parallel and we are asked not to do the
192  job again that may lead to less optimal code for the target: */
193  goto skip_parallelization_of_this_loop;
194 
195  ifdebug(2) {
196  debug(2, "rice_loop", "applied on region:\n");
197  print_statement_set(stderr, region);
198  }
199 
201  nstat = codegen_fun(stat, dg, region, l, true);
202 
203  ifdebug(7) {
204  pips_debug(7, "consistency checking for CodeGenerate output: ");
205  if(statement_consistent_p(nstat))
206  fprintf(stderr, " gen consistent\n");
207  }
208 
209  if(nstat == statement_undefined)
210  /* The code generation did not generate anything, probably because the
211  loop body was empty ("CONTINUE"/";", "{ }"), so no loop is
212  generated: */
213  nstat = make_empty_statement();
214 
215  /* FI: I'd rather not return a block when a unique loop statement has to
216  * be wrapped.
217  */pips_assert("block or loop",
220  /* try to keep label */
221  if(statement_loop_p(nstat))
222  statement_label(nstat) = statement_label(stat);
223  else {
225  if(statement_loop_p(s)) {
226  statement_label(s) = statement_label(stat);
227  break;
228  }
229  }
230  statement_number(nstat)
232  : statement_number(stat));
233  statement_ordering(nstat) = statement_ordering(stat);
234  statement_comments(nstat) = statement_comments(stat);
235  /* Do not forget to move forbidden information associated with
236  block: */
238  ifdebug(1) {
239  fprintf(stderr, "final nest of loops:\n\n");
241  }
242 
243  /* StatementToContext should be freed here. but it is not easy. */
244  set_free(region);
245 
247 
248  return nstat;
249 
250  /* Skip the parallelization of this loop but go on recursion for
251  eventual loops in this loop body: */
252  skip_parallelization_of_this_loop: enclosing++;
253  loop_body(lstat) = rice_statement(loop_body(lstat), l + 1, codegen_fun);
254  enclosing--;
255  return (stat);
256 }
257 
258 /*
259  * RICE_DEBUG_LEVEL (properly?) included, FC 23/09/93
260  */
261 bool do_it(string mod_name,
262  bool distribute_p,
263  string what,
264  statement(*codegen_fun)(statement, graph, set, int, bool)) {
267 
269  /* In spite of its name, the new statement "mod_parallel_stat"
270  * may be sequential if distribute_p is true
271  */
272  statement mod_parallel_stat = statement_undefined;
273 
275  mod_name,
276  true));
278 
279  debug_on("RICE_DEBUG_LEVEL");
280 
281  print_parallelization_statistics(mod_name, "ante", mod_stat);
282 
283  ifdebug(7) {
284  pips_debug(7, "\nTesting NewGen consistency for initial code %s:\n",
285  mod_name);
287  fprintf(stderr, " NewGen consistent statement\n");
288  }
289 
290  ifdebug(1) {
291  debug(1, "do_it", "original sequential code:\n\n");
293  }
294 
295  mod_parallel_stat = copy_statement(mod_stat);
296 
297  ifdebug(7) {
298  debug(7,
299  "do_it",
300  "\nTesting NewGen consistency for copy code %s:",
301  mod_name);
302  if(statement_consistent_p((statement)mod_parallel_stat))
303  fprintf(stderr, " NewGen consistent statement copy\n");
304  }
305 
306  ifdebug(1) {
307  debug(1, "do_it", "copy of sequential code:\n\n");
309  }
310 
311  if(graph_undefined_p(dg)) {
312  dg = (graph)db_get_memory_resource(DBR_DG, mod_name, true);
313  } else {
314  pips_internal_error("dg should be undefined");
315  }
316 
317  /* Make sure the dependence graph points towards the code copy */
318  set_ordering_to_statement(mod_parallel_stat);
319 
320  rice_distribute_only = distribute_p;
321  enclosing = 0;
322  // rice_statement works by side effects, most of the times, but
323  // not for loops
324  mod_parallel_stat = rice_statement(mod_parallel_stat, 1, codegen_fun);
325 
326  /* Regenerate statement_ordering for the parallel code */
328  module_body_reorder(mod_parallel_stat);
330 
331  (void)update_loops_locals(mod_name, mod_parallel_stat);
332 
333  ifdebug(7) {
334  pips_debug(7, "\nparallelized code for module %s:", mod_name);
335  if(statement_consistent_p(mod_parallel_stat))
336  fprintf(stderr, " gen consistent\n");
337  print_parallel_statement(mod_parallel_stat);
338  }
339 
340  debug_off();
341  clean_up_sequences(mod_parallel_stat);
342 
343  /* FI: This may be parallel or sequential code */DB_PUT_MEMORY_RESOURCE(what, mod_name, mod_parallel_stat);
344 
345  print_parallelization_statistics(mod_name, "post", mod_parallel_stat);
346 
349  return true;
350 }
351 
352 /****************************************************** PIPSMAKE INTERFACE */
353 
354 bool distributer(string mod_name) {
355  bool success;
356 
357  debug_on("RICE_DEBUG_LEVEL");
358 
360  /*
361  * For C code, this pass requires that effects are calculated with property
362  * MEMORY_EFFECTS_ONLY set to false because we need that the Chains includes
363  * arcs for declarations as these latter are separate statements now.
364  */
365  bool memory_effects_only_p = get_bool_property("MEMORY_EFFECTS_ONLY");
366  if(c_module_p(module) && memory_effects_only_p) {
367  // user error? internal error?
368  pips_user_warning("Distributer should be run with property "
369  "MEMORY_EFFECTS_ONLY set to FALSE.");
370  return false; // return to pass manager with a failure code
371  }
372 
373  success = do_it(mod_name, true, DBR_CODE, &CodeGenerate);
374 
375  debug_off();
376 
377  return success;
378 }
379 
380 static bool rice(string mod_name)
381 {
382  bool success = true;
384 
385  /*
386  * For C code, this pass requires that effects are calculated with property
387  * MEMORY_EFFECTS_ONLY set to false because we need that the Chains includes
388  * arcs for declarations as these latter are separate statements now.
389  */
390  if (c_module_p(module) &&
391  get_bool_property("MEMORY_EFFECTS_ONLY"))
392  pips_user_error("Rice parallelization should be run with property "
393  "MEMORY_EFFECTS_ONLY set to FALSE.\n");
394 
395  success = do_it(mod_name, false, DBR_PARALLELIZED_CODE, &CodeGenerate);
396 
397  return success;
398 }
399 
400 bool rice_all_dependence(string mod_name) {
401  set_bool_property("GENERATE_NESTED_PARALLEL_LOOPS", true);
402  set_bool_property("RICE_DATAFLOW_DEPENDENCE_ONLY", false);
403  return rice(mod_name);
404 }
405 
406 bool rice_data_dependence(string mod_name) {
407  set_bool_property("GENERATE_NESTED_PARALLEL_LOOPS", true);
408  set_bool_property("RICE_DATAFLOW_DEPENDENCE_ONLY", true);
409  pips_user_warning("This phase is designed for experimental purposes only. The generated code is most likely to be illegal, especially if a privatization phase was performed before.\n");
410  return rice(mod_name);
411 }
412 
413 bool rice_cray(string mod_name) {
414  set_bool_property("GENERATE_NESTED_PARALLEL_LOOPS", false);
415  set_bool_property("RICE_DATAFLOW_DEPENDENCE_ONLY", false);
416  return rice(mod_name);
417 }
statement copy_statement(statement p)
STATEMENT.
Definition: ri.c:2186
bool statement_consistent_p(statement p)
Definition: ri.c:2195
bool clean_up_sequences(statement s)
Recursively clean up the statement sequences by fusing them if possible and by removing useless one.
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
#define region
simulation of the type region
bool update_loops_locals(const char *, statement)
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
bool success
Definition: gpips-local.h:59
struct _newgen_struct_graph_ * graph
Definition: graph.h:31
#define graph_undefined_p(x)
Definition: graph.h:61
#define graph_undefined
Definition: graph.h:60
#define CONTROL_MAP(ctl, code, c, list)
Macro to walk through all the controls reachable from a given control node of an unstructured.
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
set distributable_loop(statement l)
this functions checks if Kennedy's algorithm can be applied on the loop passed as argument.
Definition: loop.c:221
bool parallel_loop_statement_p(statement s)
Test if a statement is a parallel loop.
Definition: loop.c:420
void clean_enclosing_loops(void)
Definition: loop.c:58
void print_parallelization_statistics(const char *module, const char *msg, statement s)
Print out the number of sequential versus parallel loops.
Definition: loop.c:814
statement_mapping loops_mapping_of_statement(statement stat)
Definition: loop.c:155
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
#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 MAPL(_map_list_cp, _code, _l)
Apply some code on the addresses of all the elements of a list.
Definition: newgen_list.h:203
string db_get_memory_resource(const char *rname, const char *oname, bool pure)
Return the pointer to the resource, whatever it is.
Definition: database.c:755
#define DB_PUT_MEMORY_RESOURCE(res_name, own_name, res_val)
conform to old interface.
Definition: pipsdbm-local.h:66
list statement_block(statement)
Get the list of block statements of a statement sequence.
Definition: statement.c:1338
bool statement_loop_p(statement)
Definition: statement.c:349
void fix_statement_attributes_if_sequence(statement)
Apply fix_sequence_statement_attributes() on the statement only if it really a sequence.
Definition: statement.c:2078
static statement mod_stat
We want to keep track of the current statement inside the recurse.
Definition: impact_check.c:41
#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 user_warning(fn,...)
Definition: misc-local.h:262
#define pips_user_error
Definition: misc-local.h:147
void debug(const int the_expected_debug_level, const char *calling_function_name, const char *a_message_format,...)
ARARGS0.
Definition: debug.c:189
#define set_undefined
Definition: newgen_set.h:48
void set_free(set)
Definition: set.c:332
hash_table set_ordering_to_statement(statement s)
To be used instead of initialize_ordering_to_statement() to make sure that the hash table ots is in s...
Definition: ordering.c:172
void reset_ordering_to_statement(void)
Reset the mapping from ordering to statement.
Definition: ordering.c:185
static char * module
Definition: pips.c:74
void print_statement_set(FILE *, set)
statement.c
Definition: statement.c:49
void print_parallel_statement(statement)
Definition: statement.c:156
void print_statement(statement)
Print a statement on stderr.
Definition: statement.c:98
void set_bool_property(const char *, bool)
bool module_body_reorder(statement body)
Reorder a module.
Definition: reorder.c:211
#define instruction_block_p(i)
#define ORDERING_NUMBER(o)
#define ORDERING_STATEMENT(o)
#define statement_block_p(stat)
#define STATEMENT_NUMBER_UNDEFINED
default values
#define unstructured_control
After the modification in Newgen: unstructured = entry:control x exit:control we have create a macro ...
#define is_instruction_block
soft block->sequence transition
#define instruction_block(i)
#define make_empty_statement
An alias for make_empty_block_statement.
const char * entity_local_name(entity e)
entity_local_name modified so that it does not core when used in vect_fprint, since someone thought t...
Definition: entity.c:453
entity local_name_to_top_level_entity(const char *n)
This function try to find a top-level entity from a local name.
Definition: entity.c:1450
bool c_module_p(entity m)
Test if a module "m" is written in C.
Definition: entity.c:2777
const char * label_local_name(entity e)
END_EOLE.
Definition: entity.c:604
void set_enclosing_loops_map(statement_mapping)
#define STATEMENT_(x)
Definition: ri.h:2416
#define loop_body(x)
Definition: ri.h:1644
#define loop_execution(x)
Definition: ri.h:1648
#define instruction_loop_p(x)
Definition: ri.h:1518
#define instruction_loop(x)
Definition: ri.h:1520
#define statement_ordering(x)
Definition: ri.h:2454
#define test_false(x)
Definition: ri.h:2837
#define statement_label(x)
Definition: ri.h:2450
@ is_instruction_goto
Definition: ri.h:1473
@ is_instruction_unstructured
Definition: ri.h:1475
@ is_instruction_whileloop
Definition: ri.h:1472
@ is_instruction_expression
Definition: ri.h:1478
@ is_instruction_test
Definition: ri.h:1470
@ is_instruction_call
Definition: ri.h:1474
@ is_instruction_forloop
Definition: ri.h:1477
@ is_instruction_loop
Definition: ri.h:1471
#define instruction_tag(x)
Definition: ri.h:1511
#define execution_sequential_p(x)
Definition: ri.h:1208
#define test_true(x)
Definition: ri.h:2835
#define instruction_forloop(x)
Definition: ri.h:1538
#define loop_label(x)
Definition: ri.h:1646
#define instruction_whileloop(x)
Definition: ri.h:1523
#define whileloop_body(x)
Definition: ri.h:3162
#define statement_instruction(x)
Definition: ri.h:2458
#define statement_comments(x)
Definition: ri.h:2456
#define control_statement(x)
Definition: ri.h:941
#define instruction_test(x)
Definition: ri.h:1517
#define statement_number(x)
Definition: ri.h:2452
#define forloop_body(x)
Definition: ri.h:1372
#define instruction_unstructured(x)
Definition: ri.h:1532
#define loop_index(x)
Definition: ri.h:1640
#define statement_undefined
Definition: ri.h:2419
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
statement CodeGenerate(statement __attribute__((unused)) stat, graph g, set region, int l, bool task_parallelize_p)
This function implements Allen & Kennedy's algorithm.
Definition: codegen.c:393
bool rice_distribute_only
to know if do loop parallelization must be done
Definition: rice.c:62
int enclosing
This is an horrendous hack.
Definition: rice.c:67
statement rice_loop(statement stat, int l, statement(*codegen_fun)(statement, graph, set, int, bool))
Eventually parallelize a do-loop with Ã&#160; la Rice algorithm.
Definition: rice.c:160
statement rice_statement(statement stat, int l, statement(*codegen_fun)(statement, graph, set, int, bool))
Definition: rice.c:82
bool rice_data_dependence(string mod_name)
Definition: rice.c:406
void rice_unstructured(unstructured u, int l, statement(*codegen_fun)(statement, graph, set, int, bool))
Definition: rice.c:69
bool rice_cray(string mod_name)
Definition: rice.c:413
bool do_it(string mod_name, bool distribute_p, string what, statement(*codegen_fun)(statement, graph, set, int, bool))
Definition: rice.c:261
bool rice_all_dependence(string mod_name)
Definition: rice.c:400
bool distributer(string mod_name)
Definition: rice.c:354
static bool rice(string mod_name)
Definition: rice.c:380
graph dg
Remi Triolet.
Definition: rice.c:59
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
#define ifdebug(n)
Definition: sg.c:47
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