PIPS
if_conversion_init.c
Go to the documentation of this file.
1 /*
2 
3  $Id: if_conversion_init.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 #include <stdlib.h>
32 
33 #include "genC.h"
34 #include "linear.h"
35 #include "ri.h"
36 #include "effects.h"
37 #include "complexity_ri.h"
38 #include "text.h"
39 
40 #include "ri-util.h"
41 #include "prettyprint.h"
42 #include "effects-util.h"
43 #include "text-util.h"
44 #include "database.h"
45 #include "misc.h"
46 #include "pipsdbm.h"
47 #include "resources.h"
48 #include "control.h"
49 #include "transformations.h"
50 
51 #include "effects-generic.h"
52 #include "effects-simple.h"
53 #include "properties.h"
54 
55 #include "complexity.h"
56 #include "sac.h"
57 
58 
59 /**
60  * atomize the condition of a test and returns generated statements
61  *
62  * @param cs test statement
63  *
64  * @return generated statement
65  */
67 {
68  test t = statement_test(cs);
69  expression cond = test_condition(t);
70  if(!expression_reference_p(cond))
72  return statement_undefined;
73 }
74 
75 
76 /**
77  * accept if conversion if the call is an assignment call
78  */
79 static bool check_if_conv_call(call c, bool * success)
80 {
81  call tmp = copy_call(c);
82  split_update_call(tmp);
83  entity op = call_function(tmp);
85  free_call(tmp);
86  return *success;
87 }
88 
89 static bool check_if_conv_test(test t,bool *success);
91 {
92  switch(instruction_tag(i))
93  {
99  return true;
100  default:
101  return false;
102  };
103 }
104 
105 /**
106  * checks if a test statement is suitable for if conversion, that is
107  * it only contains sequence of assignments
108  *
109  */
110 static bool check_if_conv_test(test t, bool *success)
111 {
112  statement branches[2] = { test_true(t), test_false(t) };
113 
114  for(size_t i=0;i<2;i++)
115  gen_context_recurse(branches[i], success,
117  return false;
118 }
119 
120 /**
121  * checks if if conversion can be performed on test statement
122  *
123  * @param stat test statement
124  *
125  * @return true if conversion possible
126  */
127 static bool check_if_conv(statement stat)
128 {
130 
131  pips_assert("statement is a test", statement_test_p(stat));
132 
133  bool success = true;
135  return success;
136 }
137 
138 
139 /**
140  * adds @param cond to the condtion of @param t
141  */
143 {
145 }
146 
147 /**
148  * create a test statement with appropriate extension and a test under @a cond with a single true branch @a branch
149  */
151 {
154  make_test(cond,branch,make_empty_statement())));
156  return s;
157 }
158 
159 /**
160  * merge content of a test with the test itself
161  *
162  * @param branch content of the test
163  * @param cond condition of the test
164  *
165  * @return merged statements
166  */
167 static statement
169 {
170  // only add the condition if content is a test
171  if(statement_test_p(branch))
172  {
173  update_test_condition( statement_test(branch) ,cond);
174  return copy_statement(branch);
175  }
176  // the big part : merge tests into a single block
177  // the idea is too stack statements until a test is met.
178  // stacked statements are put under condition, then the test is added and so on
179  else if(statement_block_p(branch))
180  {
181  list block=NIL;
182  list curr_block = NIL;
183  FOREACH(STATEMENT,st,statement_block(branch))
184  {
185  if(statement_test_p(st))
186  {
188  if(!ENDP(curr_block))
191  curr_block=NIL;
192  }
193  else
194  {
195  curr_block=CONS(STATEMENT,copy_statement(st),curr_block);
196  }
197  }
198  if(!ENDP(curr_block))
201  }
202  // not much to do there, ony allpy test condition
203  else
205 }
206 
207 
208 /*
209  This function is called for each test statement in the code
210  */
211 static
213 {
214  // Only interested in the test statements
215  if(statement_test_p(stat))
216  {
217 
219  if (ancestor && INSTANCE_OF(control, ancestor)) {
220  // Hmmm, we are inside a control node
221  control c = (control) ancestor;
222  if (gen_length(control_successors(c)) == 2) {
223  // A control node with 2 successors is an unstructured test:
224  pips_user_warning("not converting a non structured test yet...\n");
225  return;
226  }
227  }
228 
229  complexity stat_comp = load_statement_complexity(stat);
230  if(stat_comp != (complexity) HASH_UNDEFINED_VALUE)
231  {
232 
233  Ppolynome poly = complexity_polynome(stat_comp);
234  if(polynome_constant_p(poly))
235  {
236  clean_up_sequences(stat);
237  pips_debug(2,"analyzing statement:\n");
238  ifdebug(2) {
239  print_statement(stat);
240  }
241 
242  // Get the number of calls in the if statement
243  int cost = polynome_TCST(poly);
244  pips_debug(3,"cost %d\n", cost);
245 
246  // ensure the statement is valid
247  bool success = check_if_conv(stat);
248 
249  // If the number of calls is smaller than IF_CONV_THRESH
250  if(success && cost < get_int_property("IF_CONVERSION_INIT_THRESHOLD"))
251  {
252  test t = statement_test(stat);
253 
254  // Atomize the condition
256 
257  expression not_test_condition=
261  );
262  list block =
265  do_transform_if_statements(test_false(t),not_test_condition)
266  );
270  ifdebug(3) {
271  pips_debug(3,"new test:\n");
272  print_statement(stat);
273  }
274  }
275  }
276  else
277  pips_user_warning("not converting a test, complexity too ... complex \n");
278 
279  }
280  else
281  pips_user_warning("not converting a test, complexity not available\n");
282  }
283 }
284 
285 /*
286  This phase changes:
287 
288  if(a > 0)
289  {
290  i = 3;
291  if(b == 3)
292  {
293  x = 5;
294  }
295  }
296  else
297  {
298  if(b < 3)
299  {
300  x = 6;
301  }
302  j = 3;
303  }
304 
305 into:
306 
307 L0 = (a > 0);
308 #pragma IF_TO_CONVERT
309 if(L0)
310 {
311 i = 3;
312 }
313 L1 = (b == 3);
314 #pragma IF_TO_CONVERT
315 if(L0 && L1)
316 {
317 x = 5;
318 }
319 L2 = (b < 3);
320 #pragma IF_TO_CONVERT
321 if(!L0 && L2)
322 {
323 x = 6;
324 }
325 #pragma IF_TO_CONVERT
326 if(!L0)
327 {
328 j = 3;
329 }
330 
331 This transformation is done if:
332 - there is only call- or sequence-
333 statements in the imbricated if-statements
334 - the number of calls in the imbricated if-statements
335 is smaller than IF_CONV_THRESH
336 */
337 bool if_conversion_init(char * mod_name)
338 {
339  // get the resources
341  statement root = (statement) db_get_memory_resource(DBR_CODE, mod_name, true);
343 
344  set_current_module_statement(fake);// to prevent a complex bug with gen_recurse and AddEntityToCurrentModule
345  set_complexity_map( (statement_mapping) db_get_memory_resource(DBR_COMPLEXITIES, mod_name, true));
346 
347  debug_on("IF_CONVERSION_INIT_DEBUG_LEVEL");
348 
349  ifdebug(1) {
350  pips_debug(1, "Code before if_conversion_init:\n");
351  print_statement(root);
352  }
353 
354  // Now do the job
356 
357  ifdebug(1) {
358  pips_debug(1, "Code after if_conv_init_statement:\n");
359  print_statement(root);
360  }
361 
362  // and share decl
365  free_statement(fake);
366 
367  ifdebug(1) {
368  pips_debug(1, "Code after copying from fake statement:\n");
369  print_statement(root);
370  }
371 
372  // Reorder the module, because new statements have been added
373  module_reorder(root);
374  DB_PUT_MEMORY_RESOURCE(DBR_CODE, mod_name, root);
375 
376  // update/release resources
380 
381  debug_off();
382 
383  return true;
384 }
int get_int_property(const string)
expression copy_expression(expression p)
EXPRESSION.
Definition: ri.c:850
statement copy_statement(statement p)
STATEMENT.
Definition: ri.c:2186
test make_test(expression a1, statement a2, statement a3)
Definition: ri.c:2607
extension make_extension_pragma(pragma _field_)
Definition: ri.c:938
instruction make_instruction_test(test _field_)
Definition: ri.c:1172
call copy_call(call p)
CALL.
Definition: ri.c:233
void free_call(call p)
Definition: ri.c:236
pragma make_pragma_string(string _field_)
Definition: ri.c:1775
void free_statement(statement p)
Definition: ri.c:2189
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
Ppolynome complexity_polynome(complexity comp)
Because complexity is composed of two elements, we use this function to get the first element : polyn...
Definition: comp_math.c:506
complexity load_statement_complexity(statement)
void reset_complexity_map(void)
void set_complexity_map(statement_mapping)
void split_update_call(call c)
Definition: flatten_code.c:772
#define call_constant_p(C)
Definition: flint_check.c:51
#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
bool success
Definition: gpips-local.h:59
statement make_block_statement(list)
Make a block statement from a list of statement.
Definition: statement.c:616
statement instruction_to_statement(instruction)
Build a statement from a give instruction.
Definition: statement.c:597
statement make_empty_block_statement(void)
Build an empty statement (block/sequence)
Definition: statement.c:625
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
entity set_current_module_entity(entity)
static.c
Definition: static.c:66
gen_chunk * gen_get_recurse_current_ancestor(void)
Get the ancestor of the current object.
Definition: genClib.c:3526
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_true(__attribute__((unused)) gen_chunk *unused)
Return true and ignore the argument.
Definition: genClib.c:2780
instruction make_instruction_block(list statements)
Build an instruction block from a list of statements.
Definition: instruction.c:106
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
size_t gen_length(const list l)
Definition: list.c:150
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
#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
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
test statement_test(statement)
Get the test of a statement.
Definition: statement.c:1348
bool statement_test_p(statement)
Definition: statement.c:343
statement update_statement_instruction(statement, instruction)
Replace the instruction in statement s by instruction i.
Definition: statement.c:3039
void insert_statement_no_matter_what(statement, statement, bool)
Break the IR consistency or, at the very least, do not insert new declarations at the usual place,...
Definition: statement.c:2581
static void update_test_condition(test t, expression cond)
adds
static statement atomize_condition(statement cs)
atomize the condition of a test and returns generated statements
static bool check_if_conv_test(test t, bool *success)
checks if a test statement is suitable for if conversion, that is it only contains sequence of assign...
static statement do_transform_if_statements(statement branch, expression cond)
merge content of a test with the test itself
static statement make_if_converted_test_statement(expression cond, statement branch)
create a test statement with appropriate extension and a test under cond with a single true branch br...
static void if_conv_init_statement(statement stat)
static bool check_if_conv_call(call c, bool *success)
accept if conversion if the call is an assignment call
static bool check_if_conv_walker(instruction i, bool *success)
static bool check_if_conv(statement stat)
checks if if conversion can be performed on test statement
bool if_conversion_init(char *mod_name)
if_conversion_init.c
struct _newgen_struct_control_ * control
#define debug_on(env)
Definition: misc-local.h:157
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_user_warning
Definition: misc-local.h:146
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define debug_off()
Definition: misc-local.h:160
#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
float polynome_TCST(Ppolynome pp)
float polynome_TCST(Ppolynome pp) returns the constant term of polynomial pp.
Definition: pnome-reduc.c:156
bool polynome_constant_p(Ppolynome pp)
bool polynome_constant_p(Ppolynome pp) return true if pp is a constant polynomial (including null pol...
Definition: pnome-reduc.c:180
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 ENTITY_ASSIGN_P(e)
#define statement_block_p(stat)
#define INSTANCE_OF(type, value)
polymorhism thanks to newgen !
#define ENTITY_CONTINUE_P(e)
#define AND_OPERATOR_NAME
FI: intrinsics are defined at a third place after bootstrap and effects! I guess the name should be d...
#define is_instruction_block
soft block->sequence transition
#define make_statement_list(stats...)
easy list constructor
#define NOT_OPERATOR_NAME
#define make_empty_statement
An alias for make_empty_block_statement.
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
entity entity_intrinsic(const char *name)
FI: I do not understand this function name (see next one!).
Definition: entity.c:1292
expression MakeBinaryCall(entity f, expression eg, expression ed)
Creates a call expression to a function with 2 arguments.
Definition: expression.c:354
expression MakeUnaryCall(entity f, expression a)
Creates a call expression to a function with one argument.
Definition: expression.c:342
bool expression_reference_p(expression e)
Test if an expression is a reference.
Definition: expression.c:528
entity make_new_scalar_variable(entity, basic)
Definition: variable.c:741
#define call_function(x)
Definition: ri.h:709
#define test_false(x)
Definition: ri.h:2837
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
#define instruction_domain
newgen_functional_domain_defined
Definition: ri.h:202
#define EXTENSION(x)
EXTENSION.
Definition: ri.h:1253
@ is_instruction_test
Definition: ri.h:1470
@ is_instruction_call
Definition: ri.h:1474
#define instruction_tag(x)
Definition: ri.h:1511
#define test_true(x)
Definition: ri.h:2835
#define statement_extensions(x)
Definition: ri.h:2464
#define control_successors(x)
Definition: ri.h:945
#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 extensions_extension(x)
Definition: ri.h:1330
#define instruction_test(x)
Definition: ri.h:1517
#define statement_undefined_p(x)
Definition: ri.h:2420
#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
statement simd_atomize_this_expression(entity(*create)(entity, basic), expression e)
returns the assignment statement if moved, or NULL if not.
Definition: atomizer.c:87
char * strdup()
#define ifdebug(n)
Definition: sg.c:47
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
A gen_chunk is used to store every object.
Definition: genC.h:58