PIPS
if_conversion.c
Go to the documentation of this file.
1 /*
2 
3  $Id: if_conversion.c 23495 2018-10-24 09:19:47Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 #ifdef HAVE_CONFIG_H
25  #include "pips_config.h"
26 #endif
27 
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 
32 #include "genC.h"
33 #include "linear.h"
34 #include "ri.h"
35 #include "effects.h"
36 
37 #include "ri-util.h"
38 #include "prettyprint.h"
39 #include "effects-util.h"
40 #include "text-util.h"
41 #include "database.h"
42 #include "misc.h"
43 #include "pipsdbm.h"
44 #include "resources.h"
45 #include "control.h"
46 #include "transformations.h"
47 
48 #include "effects-generic.h"
49 #include "effects-simple.h"
50 #include "properties.h"
51 
52 #include "callgraph.h"
53 
54 #include "sac.h"
55 
56 
57 /**
58  * creates a phi-instruction using the entity given in property
59  * the generated instruction as the form
60  * @a lRef = PHI(@a cond,@a ref1, @a ref2)
61  * all parameters are copied
62  */
63 static instruction
65  expression ref1, expression ref2)
66 {
67  entity phiEntity = module_name_to_runtime_entity(get_string_property("IF_CONVERSION_PHI"));
68  expression phiExp = MakeTernaryCall(
69  phiEntity,
70  copy_expression(cond),
71  copy_expression(ref1),
72  copy_expression(ref2)
73  );
74 
76 }
77 
78 /*
79  The if_conversion phase only supports assign statement whose right
80  expression does not have any write effect.
81 
82  So, this function returns true if the statement stat is supported.
83  */
85 {
87  {
89  split_update_call(c); // this will take car of splitting a+=2 into a = a+2
90  entity op = call_function(c);
91  // Only the assign statements with no side effects are supported
92  if(ENTITY_ASSIGN_P(op) )
93  {
96  bool has_write_effect_p = effects_write_at_least_once_p(effects);
97  free(effects);
98  return !has_write_effect_p;
99  }
100  }
101  return false;
102 }
103 
104 /**
105  * converts statement @a stat into a phi-statement if possible
106  *
107  * @param cond condition of the potential new phi - statement
108  * @param stat statement to check
109  *
110  * @return true if processing was ok (sg:unclean, event to me :))
111  */
112 static bool
114 {
115 
116  // Only the assign statements with no side effects are supported
117  if(simd_supported_stat_p(stat))
118  {
120 
121  // lRef is the left reference of the assign call
122  expression lhs = binary_call_lhs(c);
123  reference lhs_ref = expression_reference(lhs);
124  lhs=copy_expression(lhs); /* to prevent side effect from further inplace modification */
125  entity e = reference_variable(lhs_ref);
126 
127  basic newBas = basic_of_reference(lhs_ref);
128 
129  if(!basic_undefined_p(newBas))
130  {
131  ifdebug(1) {
132  pips_debug(1,"converting statement\n");
133  print_statement(stat);
134  }
135  // Create a new entity if rhs is not a reference or a constant itself
136  expression rhs = binary_call_rhs(c);
140  ref = rhs;
141  else {
144  newBas);
145  AddEntityToCurrentModule(newVar);
146 
149  to_add = call_to_statement(c);
150  }
151  // Make an assign statement to insert before the phi-statement
152  instruction assign = make_phi_assign_instruction(lhs_ref, cond, ref, lhs);
153  update_statement_instruction(stat,assign);
154  if(!statement_undefined_p(to_add))
155  insert_statement(stat,to_add,true);
156  ifdebug(1) {
157  pips_debug(1,"into statement\n");
158  print_statement(stat);
159  }
160  free_expression(lhs);
161  return true;
162  }
163  free_expression(lhs);
164 
165  }
166  else if(declaration_statement_p(stat))
167  return true;// leave statement untouched
168  return false;
169 }
170 
171 /*
172  This function changes the true statement stat in two list.
173 
174  For example, if the true statement stat is:
175 
176  A(I) = I + 1
177  J = J + 1
178 
179  then outStat will be:
180 
181  A0 = I + 1
182  J0 = J + 1
183 
184  and postlude will be:
185 
186  A(I) = PHI(COND, A0, A(I))
187  J = J0
188  */
189 static void process_true_stat(statement parent, expression cond, statement stat)
190 {
191 
192  // It must have been verified in the if_conversion_init phase
193  pips_assert("stat is a call or a sequence statement",
196  statement_loop_p(stat)));
197 
198  // If stat is a call statement, ...
200  {
201  if(process_true_call_stat(cond, stat))
202  {
206  free_statement(stat);
207  }
208 
209  }
210  // recurse for for loops
211  else if( statement_loop_p(stat))
212  process_true_stat(stat,cond,loop_body(statement_loop(stat)));
213 
214  // If stat is a sequence statement, ...
215  else if(statement_block_p(stat))
216  {
217  // first split initalizations
219 
220  // then do the processing
221  bool something_bad_p=false;
222  if(statement_block_p(stat))
223  {
225  {
226  something_bad_p|=!process_true_call_stat(cond, st);
227  }
228  }
229  else
230  something_bad_p|=!process_true_call_stat(cond, stat);
231  if(!something_bad_p)
232  {
236  free_statement(stat);
237  }
238  }
239 }
240 
241 /*
242  This function is called for each code statement.
243  */
245 {
246  // If the statement comment contains the string IF_TO_CONVERT,
247  // then it means that this statement must be converted ...
248  extension ex;
250  {
251  // remove the pragma
253 
254  // Process the "true statements" (test_false(t) is empty because if_conversion
255  // phase is done after if_conversion_init phase).
258  }
259 }
260 
261 /*
262  This phase do the actual if conversion.
263  It changes:
264 
265  c IF_TO_CONVERT
266  if(L1) then
267  A(I) = I + 1
268  J = J + 1
269  endif
270 
271 into:
272 
273 A0 = I + 1
274 J0 = J + 1
275 A(I) = PHI(L1, A0, A(I))
276 J = PHI(L1, J0, J)
277 
278 This phase MUST be used after if_conversion_init phase
279 
280 */
281 bool if_conversion(char * mod_name)
282 {
283  // get the resources
284  statement mod_stmt = (statement)
285  db_get_memory_resource(DBR_CODE, mod_name, true);
286 
289 
290  debug_on("IF_CONVERSION_DEBUG_LEVEL");
291  // Now do the job
292 
294 
295  // Reorder the module, because new statements have been added
296  module_reorder(mod_stmt);
297  DB_PUT_MEMORY_RESOURCE(DBR_CODE, mod_name, mod_stmt);
298  DB_PUT_MEMORY_RESOURCE(DBR_CALLEES, mod_name,
299  compute_callees(mod_stmt));
300 
301  // update/release resources
304 
305  debug_off();
306 
307  return true;
308 }
309 
311  if(ENDP(conditions)) {
313  statement eve = clone_statement(adam,cc);
314  free_clone_context(cc);
315  return eve;
316  }
319  make_test(
320  copy_expression(EXPRESSION(CAR(conditions))),
321  do_loop_nest_unswitching_purge(adam,CDR(conditions)),
322  do_loop_nest_unswitching_purge(adam,CDR(conditions))
323  )
324  )
325  );
326  return eve;
327 }
328 
329 static void do_loop_nest_unswitching(statement st,list *conditions) {
330  if(statement_loop_p(st)) {
331  loop l =statement_loop(st);
332  range r = loop_range(l);
333  expression u = range_upper(r);
334  if(expression_minmax_p(u)) {//only handle the case of two args right now ... */
335  call c = expression_call(u);
336  if(gen_length(call_arguments(c)) > 2 ) pips_internal_error("do not handle more than 2 args");
337  expression hs[]= {
338  binary_call_lhs(c),
339  binary_call_rhs(c)
340  };
341  for(int i=0;i<(int)(sizeof(hs)/sizeof(hs[0]));i++) {
342  expression hss = hs[i];
343  hs[i]=copy_expression(hs[i]);
344  NORMALIZE_EXPRESSION(hs[i]);
346  /* will help for partial eval later */
349  hs[i]=make_assign_expression(entity_to_expression(etmp),hs[i]);
351  }
352  }
353 
354  *conditions=
357  *conditions);
358  }
359 
361  /* some conditions left */
362  if(!ENDP(*conditions) && (!statement_loop_p(sparent) || !sparent)) {
363  *st = *(do_loop_nest_unswitching_purge(st,*conditions));
364  //add_pragma_str_to_statement(st,get_string_property("OUTLINE_PRAGMA"),true);
365  gen_full_free_list(*conditions);
366  *conditions=NIL;
367  }
368  /* parent is a loop : check for a conflict */
369  else {
370  list toremove=NIL;
371  list tconditions=gen_copy_seq(*conditions);
372  FOREACH(EXPRESSION,cond,tconditions) {
373  set s = get_referenced_entities(cond);
374  if(set_belong_p(s,loop_index(statement_loop(sparent)))) {
375  toremove=CONS(EXPRESSION,cond,toremove);
376  gen_remove_once(conditions,cond);
377  }
378  set_free(s);
379  }
380  gen_free_list(tconditions);
381  if(!ENDP(toremove)) {
382  *st = *(do_loop_nest_unswitching_purge(st,toremove));
383  //add_pragma_str_to_statement(st,get_string_property("OUTLINE_PRAGMA"),true);
384  }
385  gen_full_free_list(toremove);
386  }
387  }
388  else pips_assert("everything is ok",ENDP(*conditions));
389 }
390 
394 
395  list l=NIL;
398  pips_assert("everything went well\n",ENDP(l));
399 
400 
401  // Reorder the module, because new statements have been added
404 
407  return true;
408 }
clone_context make_clone_context(entity a1, entity a2, list a3, statement a4)
Definition: cloning.c:52
void free_clone_context(clone_context p)
Definition: cloning.c:19
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
reference make_reference(entity a1, list a2)
Definition: ri.c:2083
test make_test(expression a1, statement a2, statement a3)
Definition: ri.c:2607
instruction make_instruction_test(test _field_)
Definition: ri.c:1172
call copy_call(call p)
CALL.
Definition: ri.c:233
void free_expression(expression p)
Definition: ri.c:853
reference copy_reference(reference p)
REFERENCE.
Definition: ri.c:2047
void free_statement(statement p)
Definition: ri.c:2189
static reference ref
Current stmt (an integer)
Definition: adg_read_paf.c:163
void const char const char const int
callees compute_callees(const statement stat)
Recompute the callees of a module statement.
Definition: callgraph.c:355
statement clone_statement(statement s, clone_context cc)
clone_statement.c
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
bool effects_write_at_least_once_p(list)
list expression_to_proper_effects(expression)
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 *)
void statement_split_initializations(statement s)
Recurse through the statements of s and split local declarations.
Definition: flatten_code.c:733
void split_update_call(call c)
Definition: flatten_code.c:772
#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 gen_full_free_list(list l)
Definition: genClib.c:1023
void free(void *)
statement instruction_to_statement(instruction)
Build a statement from a give instruction.
Definition: statement.c:597
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
gen_chunk * gen_get_ancestor(int, const void *)
return the first ancestor object found of the given type.
Definition: genClib.c:3560
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
instruction make_assign_instruction(expression l, expression r)
Definition: instruction.c:87
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
void gen_remove(list *cpp, const void *o)
remove all occurences of item o from list *cpp, which is thus modified.
Definition: list.c:685
void gen_remove_once(list *pl, const void *o)
Remove the first occurence of o in list pl:
Definition: list.c:691
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
list gen_copy_seq(list l)
Copy a list structure.
Definition: list.c:501
size_t gen_length(const list l)
Definition: list.c:150
#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
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
loop statement_loop(statement)
Get the loop of a statement.
Definition: statement.c:1374
bool statement_loop_p(statement)
Definition: statement.c:349
statement update_statement_instruction(statement, instruction)
Replace the instruction in statement s by instruction i.
Definition: statement.c:3039
void insert_statement(statement, statement, bool)
This is the normal entry point.
Definition: statement.c:2570
extension get_extension_from_statement_with_pragma(statement, const char *)
Get the extension of a statement with pragma beginning with a prefix.
Definition: statement.c:3871
bool declaration_statement_p(statement)
Had to be optimized according to Beatrice Creusillet.
Definition: statement.c:224
bool expression_constant_p(expression)
HPFC module by Fabien COELHO.
Definition: expression.c:2453
static void if_conv_statement(statement cs)
static void do_loop_nest_unswitching(statement st, list *conditions)
bool loop_nest_unswitching(const char *module_name)
static bool process_true_call_stat(expression cond, statement stat)
converts statement stat into a phi-statement if possible
static void process_true_stat(statement parent, expression cond, statement stat)
static statement do_loop_nest_unswitching_purge(statement adam, list conditions)
bool if_conversion(char *mod_name)
if_conversion.c
static instruction make_phi_assign_instruction(reference lRef, expression cond, expression ref1, expression ref2)
creates a phi-instruction using the entity given in property the generated instruction as the form lR...
Definition: if_conversion.c:64
static bool simd_supported_stat_p(statement stat)
Definition: if_conversion.c:84
#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_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
void set_free(set)
Definition: set.c:332
bool set_belong_p(const set, const void *)
Definition: set.c:194
void print_statement(statement)
Print a statement on stderr.
Definition: statement.c:98
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define GREATER_THAN_OPERATOR_NAME
#define binary_call_rhs(c)
#define ENTITY_ASSIGN_P(e)
#define NORMALIZE_EXPRESSION(e)
#define statement_block_p(stat)
#define binary_intrinsic_expression(name, e1, e2)
#define call_to_statement(c)
#define binary_call_lhs(c)
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 module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
entity module_name_to_runtime_entity(const char *name)
similar to module_name_to_entity but generates a warning and a stub if the entity is not found
Definition: entity.c:1485
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
expression reference_to_expression(reference r)
Definition: expression.c:196
bool expression_minmax_p(expression e)
Definition: expression.c:3882
expression entity_to_expression(entity e)
if v is a constant, returns a constant call.
Definition: expression.c:165
call expression_call(expression e)
Definition: expression.c:445
void update_expression_syntax(expression e, syntax s)
frees expression syntax of e and replace it by the new syntax s
Definition: expression.c:3564
bool expression_reference_p(expression e)
Test if an expression is a reference.
Definition: expression.c:528
expression make_assign_expression(expression lhs, expression rhs)
Make an assign expression, since in C the assignment is a side effect operator.
Definition: expression.c:390
reference expression_reference(expression e)
Short cut, meaningful only if expression_reference_p(e) holds.
Definition: expression.c:1832
expression MakeTernaryCall(entity f, expression e1, expression e2, expression e3)
Creates a call expression to a function with 3 arguments.
Definition: expression.c:367
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
entity make_new_scalar_variable(entity, basic)
Definition: variable.c:741
void AddEntityToCurrentModule(entity)
Add a variable entity to the current module declarations.
Definition: variable.c:260
entity make_new_scalar_variable_with_prefix(const char *, entity, basic)
Create a new scalar variable of type b in the given module.
Definition: variable.c:592
basic basic_of_reference(reference)
Retrieves the basic of a reference in a newly allocated basic object.
Definition: type.c:1459
#define loop_body(x)
Definition: ri.h:1644
#define instruction_sequence_p(x)
Definition: ri.h:1512
#define syntax_reference(x)
Definition: ri.h:2730
#define normalized_complex_p(x)
Definition: ri.h:1782
#define call_function(x)
Definition: ri.h:709
#define reference_variable(x)
Definition: ri.h:2326
#define range_upper(x)
Definition: ri.h:2290
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define basic_undefined_p(x)
Definition: ri.h:557
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define instruction_undefined
Definition: ri.h:1454
#define expression_undefined
Definition: ri.h:1223
#define expression_normalized(x)
Definition: ri.h:1249
#define test_true(x)
Definition: ri.h:2835
#define statement_extensions(x)
Definition: ri.h:2464
#define instruction_call_p(x)
Definition: ri.h:1527
#define test_condition(x)
Definition: ri.h:2833
#define statement_instruction(x)
Definition: ri.h:2458
#define instruction_call(x)
Definition: ri.h:1529
#define loop_range(x)
Definition: ri.h:1642
#define extensions_extension(x)
Definition: ri.h:1330
#define call_arguments(x)
Definition: ri.h:711
#define instruction_test(x)
Definition: ri.h:1517
#define statement_undefined_p(x)
Definition: ri.h:2420
#define expression_syntax(x)
Definition: ri.h:1247
#define loop_index(x)
Definition: ri.h:1640
#define statement_undefined
Definition: ri.h:2419
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
#define IF_TO_CONVERT
if conversion
Definition: sac-local.h:43
#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