PIPS
registers.c
Go to the documentation of this file.
1 /*
2  $Id: registers.c 23495 2018-10-24 09:19:47Z coelho $
3 
4  Copyright 1989-2016 MINES ParisTech
5 
6  This file is part of PIPS.
7 
8  PIPS is free software: you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  any later version.
12 
13  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
14  WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  FITNESS FOR A PARTICULAR PURPOSE.
16 
17  See the GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 // do not compile unless required
25 #include "phases.h"
26 #ifdef BUILDER_FORCE_REGISTER_DECLARATIONS
27 
28 #ifdef HAVE_CONFIG_H
29  #include "pips_config.h"
30 #endif
31 
32 #include <stdlib.h>
33 #include <stdio.h>
34 
35 #include "genC.h"
36 #include "linear.h"
37 
38 #include "misc.h"
39 #include "pipsdbm.h"
40 #include "properties.h"
41 
42 #include "ri.h"
43 #include "ri-util.h"
44 
45 #include "control.h" // module_reorder
46 
47 /************************************************* DETECT REGISTER VARIABLES */
48 
49 // formal parameters and local variables can be declared registers
50 // for registers, the cannot be referenced (&i)
51 // for arrays, the address cannot be used, a[i] and not a, but on sizeof(a)
52 
53 typedef struct {
54  set invalidated; // of entities, which cannot be declared "register"
55 } drv_context;
56 
57 // return first possible variable, or NULL
58 static entity expression_to_variable(const expression e)
59 {
61  if (syntax_reference_p(s))
63  else if (syntax_call_p(s))
64  {
66  if (la)
67  return expression_to_variable(EXPRESSION(CAR(la)));
68  else
69  return NULL;
70  }
71  else
72  return NULL;
73 }
74 
75 // loop indexes are ok as registers.
76 
77 // detect explicit address-of operators
78 static bool drv_call_flt(const call c, drv_context * ctx)
79 {
80  entity fun = call_function(c);
81  pips_debug(8, "considering call to %s\n", entity_name(fun));
82  if (ENTITY_ADDRESS_OF_P(fun)) // & ...
83  {
84  list la = call_arguments(c);
85  pips_assert("one argument to &", gen_length(la)==1);
86  entity var = expression_to_variable(EXPRESSION(CAR(la)));
87  if (var)
88  {
89  pips_debug(7, "invalidating variable %s\n", entity_name(var));
90  set_add_element(ctx->invalidated, ctx->invalidated, var);
91  }
92  // else no variable found... should it be allowed?
93  }
94  return true;
95 }
96 
97 // detect implicit address-of for arrays
98 static bool drv_reference_flt(const reference r, drv_context * ctx)
99 {
100  entity var = reference_variable(r);
101  if (entity_array_p(var))
102  {
103  list dims =
105  if (gen_length(dims) != gen_length(reference_indices(r)))
106  set_add_element(ctx->invalidated, ctx->invalidated, var);
107  }
108  return true;
109 }
110 
111 /* recurse in object to detect which variables cannot be declared register
112  */
113 static void drv_collect(gen_chunk * object, drv_context * ctx)
114 {
115  gen_context_multi_recurse(object, ctx,
116  call_domain, drv_call_flt, gen_null,
117  reference_domain, drv_reference_flt, gen_null,
118  // ignore sizeof
120  NULL);
121 }
122 
123 /********************************************************** CUT DECLARATIONS */
124 
125 typedef struct {
126  // entities switched to "register"
127  set switched;
128  // statement -> list of declaration statements to insert before it
129  hash_table newdecls;
130  // statement -> direct enclosing sequence
131  hash_table outside;
132 } cd_context;
133 
134 static bool cut_declarations_flt(statement s, cd_context * ctx)
135 {
136  // argh! do not strust statement_declarations necessarily
137  if (!declaration_statement_p(s))
138  return true;
139 
140  list decls = statement_declarations(s);
141  int ndecls = gen_length(decls);
142 
143  pips_debug(3, "at statement %"_intFMT", %d declarations\n",
144  statement_number(s), ndecls);
145  ifdebug(7) {
146  // show details...
147  FOREACH(entity, vs, decls)
148  pips_debug(7, " - variable: %s\n", entity_name(vs));
149  }
150 
151  // check IR consistency
153  pips_assert("declaration statement is in a sequence",
154  sq && gen_in_list_p(s, sequence_statements(sq)));
155 
156  if (ndecls>1)
157  {
158  // built list of declaration statements
159  list lds = NIL;
160  // current list of variables
161  list nl = NIL;
162  // whether statements in nl are switched or not
163  bool nswitched = false;
164  FOREACH(entity, v, decls)
165  {
166  pips_debug(4, "%s (%sregister) in statement %"_intFMT"\n",
167  entity_name(v), set_belong_p(ctx->switched, v)? "": "NOT ",
168  statement_number(s));
169 
170  if (set_belong_p(ctx->switched, v))
171  {
172  if (nl) // a current list is being constructed
173  {
174  if (nswitched) // it already contains switched variables
175  nl = CONS(entity, v, nl);
176  else
177  {
178  pips_debug(5, "cutting on %s\n", entity_name(v));
179  // cut list
180  ndecls -= gen_length(nl);
181  lds =
182  CONS(statement,
185  lds);
186  // restart
187  nl = CONS(entity, v, NIL), nswitched = true;
188  }
189  }
190  else // first new list
191  nl = CONS(entity, v, NIL), nswitched = true;
192  }
193  else // another unchanged variable
194  {
195  if (nl)
196  {
197  if (nswitched) // current list contains switched vars
198  {
199  pips_debug(5, "cutting S on %s\n", entity_name(v));
200  // cut list
201  ndecls -= gen_length(nl);
202  lds =
203  CONS(statement,
206  lds);
207  // restart
208  nl = CONS(entity, v, NIL), nswitched = false;
209  }
210  else // non switched vars, insert in homogeneous list
211  nl = CONS(entity, v, nl);
212  }
213  else // first new list
214  nl = CONS(entity, v, NIL), nswitched = false;
215  }
216  }
217 
218  pips_assert("all declarations are managed", ndecls==(int) gen_length(nl));
219 
220  // store lds for later insertions
221  // I do not that now because we are still recurring in the statements...
222  if (lds)
223  {
224  hash_put(ctx->newdecls, s, gen_nreverse(lds));
225  hash_put(ctx->outside, s, sq);
226  // last list kept in current statement
229  }
230  else // no change
231  gen_free_list(nl);
232  }
233  return true;
234 }
235 
236 // C99 6.7.1 2: variable can be at most in 1 storage class in
237 // auto, extern, static, register, (typedef)
238 static bool variable_can_switch_to_register(entity var)
239 {
240  if ((!get_bool_property("FORCE_REGISTER_POINTER") && entity_pointer_p(var)) ||
241  (!get_bool_property("FORCE_REGISTER_ARRAY") && entity_array_p(var)) ||
242  (!get_bool_property("FORCE_REGISTER_FORMAL") && entity_formal_p(var)))
243  return false;
244  else if (top_level_entity_p(var) || // extern
245  entity_static_variable_p(var)) // static
246  return false;
247  else if (entity_variable_p(var)) // others
248  {
250  if (qualifier_register_p(q))
251  return false;
252 
253  return true;
254  }
255  else
256  return false;
257 }
258 
259 /* @brief modify list of qualifiers so that it includes register and *not* auto
260  * @param lq initial list, which is freed on the fly
261  * @return a newly allocated qualifier list
262  */
263 static list make_it_register(list lq)
264 {
265  list nlq = NIL;
266  FOREACH(qualifier, q, lq)
267  {
268  if (!qualifier_register_p(q) && !qualifier_auto_p(q))
269  nlq = CONS(qualifier, q, nlq);
270  else
271  free_qualifier(q);
272  }
273  gen_free_list(lq);
275 }
276 
277 bool force_register_declarations(const char * module_name)
278 {
279  statement stat = (statement)
280  db_get_memory_resource(DBR_CODE, module_name, true);
282 
285 
286  debug_on("PIPS_REGISTERS_DEBUG_LEVEL");
287 
288  // collect variables that cannot be registers
289  drv_context ctx = { set_make(set_pointer) };
290  set switched = set_make(set_pointer);
291 
292  // in the code
293  drv_collect((void *) stat, &ctx);
294 
295  // and in variable initializations
297 
298  FOREACH(entity, var, vars)
299  drv_collect((void *) entity_initial(var), &ctx);
300 
301  // now switch those variables that could be
302  FOREACH(entity, var, vars)
303  {
304  if (entity_variable_p(var) &&
305  (entity_formal_p(var) || storage_ram_p(entity_storage(var))) &&
306  !set_belong_p(ctx.invalidated, var) &&
307  variable_can_switch_to_register(var))
308  {
309  pips_debug(2, "force %s as register\n", entity_name(var));
311  variable_qualifiers(v) = make_it_register(variable_qualifiers(v));
312  set_add_element(switched, switched, var);
313  }
314  else
315  pips_debug(3, "variable %s kept\n", entity_name(var));
316  }
317 
318  // now we have to possibly cut declaration lists as they must be homogeneous
319  // think of "int i1, r1, i2;" where only r1 switched to register.
320  cd_context cd = {
322  };
323  gen_context_recurse(stat, &cd,
324  statement_domain, cut_declarations_flt, gen_null2);
325 
326  // perform actual insertions.
327  HASH_FOREACH(statement, s, list, l, cd.newdecls)
328  {
329  pips_assert("sequence of statement", hash_defined_p(cd.outside, s));
330  sequence sq = (sequence) hash_get(cd.outside, s);
331 
332  // put initial comment on the front statement
333  statement front = STATEMENT(CAR(l));
336 
337  // link into the sequence
338  sequence_statements(sq) =
339  gen_insert_list(l, s, sequence_statements(sq), true);
340  }
341 
342  // cleanup allocated stuff
343  set_free(ctx.invalidated), ctx.invalidated = NULL;
344  set_free(switched), switched = NULL;
345  hash_table_free(cd.newdecls);
346  hash_table_free(cd.outside);
347 
348  debug_off();
349 
350  // return result to pipsdbm
351  // should not be needed: clean_up_sequences(stat);
352  module_reorder(stat);
353  DB_PUT_MEMORY_RESOURCE(DBR_CODE, module_name, stat);
354 
355  // cleanup
358  return true;
359 }
360 
361 #endif // BUILDER_FORCE_REGISTER_DECLARATIONS
void free_qualifier(qualifier p)
Definition: ri.c:1871
qualifier make_qualifier_register(void)
Definition: ri.c:1933
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
const char * module_name(const char *s)
Return the module part of an entity name.
Definition: entity_names.c:296
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_get_ancestor_type(i, o)
Definition: genC.h:276
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
void gen_context_multi_recurse(void *o, void *context,...)
Multi-recursion with context function visitor.
Definition: genClib.c:3373
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_false(__attribute__((unused)) gen_chunk *unused)
Return false and ignore the argument.
Definition: genClib.c:2796
void gen_null(__attribute__((unused)) void *unused)
Ignore the argument.
Definition: genClib.c:2752
list gen_insert_list(list nl, const void *item, list l, bool before)
insert nl before or after item in list l, both initial lists are consumed
Definition: list.c:269
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 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
bool gen_in_list_p(const void *vo, const list lx)
tell whether vo belongs to lx
Definition: list.c:734
#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
statement make_declarations_statement(list, int, string)
Make a declaration(s) statement.
Definition: statement.c:990
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
bool hash_defined_p(const hash_table htp, const void *key)
true if key has e value in htp.
Definition: hash.c:484
#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 debug_off()
Definition: misc-local.h:160
@ hash_pointer
Definition: newgen_hash.h:32
#define HASH_FOREACH(key_type, k, value_type, v, ht)
Definition: newgen_hash.h:71
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
#define string_undefined
Definition: newgen_types.h:40
#define _intFMT
Definition: newgen_types.h:57
static char * module
Definition: pips.c:74
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define entity_declarations(e)
MISC: newgen shorthands.
#define entity_variable_p(e)
An entity_variable_p(e) may hide a typedef and hence a functional type.
#define ENTITY_ADDRESS_OF_P(e)
bool entity_formal_p(entity p)
is p a formal parameter?
Definition: entity.c:1935
bool entity_array_p(entity e)
Is e a variable with an array type?
Definition: entity.c:754
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
bool top_level_entity_p(entity e)
Check if the scope of entity e is global.
Definition: entity.c:1130
bool entity_pointer_p(entity e)
Definition: entity.c:745
type ultimate_type(type)
Definition: type.c:3466
bool entity_static_variable_p(entity)
return true if the entity is declared with the keyword static
Definition: variable.c:1146
#define qualifier_register_p(x)
Definition: ri.h:2185
#define syntax_reference_p(x)
Definition: ri.h:2728
struct _newgen_struct_sequence_ * sequence
Definition: ri.h:351
#define syntax_reference(x)
Definition: ri.h:2730
#define call_function(x)
Definition: ri.h:709
#define reference_variable(x)
Definition: ri.h:2326
#define syntax_call_p(x)
Definition: ri.h:2734
#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 qualifier_auto_p(x)
Definition: ri.h:2188
#define call_domain
newgen_callees_domain_defined
Definition: ri.h:58
#define EXPRESSION(x)
EXPRESSION.
Definition: ri.h:1217
#define reference_domain
newgen_range_domain_defined
Definition: ri.h:338
#define entity_name(x)
Definition: ri.h:2790
#define sizeofexpression_domain
newgen_sequence_domain_defined
Definition: ri.h:354
#define sequence_statements(x)
Definition: ri.h:2360
#define reference_indices(x)
Definition: ri.h:2328
#define syntax_call(x)
Definition: ri.h:2736
#define variable_qualifiers(x)
Definition: ri.h:3124
#define variable_dimensions(x)
Definition: ri.h:3122
#define statement_declarations(x)
Definition: ri.h:2460
#define statement_comments(x)
Definition: ri.h:2456
#define call_arguments(x)
Definition: ri.h:711
#define entity_type(x)
Definition: ri.h:2792
#define statement_number(x)
Definition: ri.h:2452
#define expression_syntax(x)
Definition: ri.h:1247
#define sequence_domain
newgen_reference_domain_defined
Definition: ri.h:346
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
#define entity_initial(x)
Definition: ri.h:2796
#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
bool force_register_declarations(const char *)
registers.c
A gen_chunk is used to store every object.
Definition: genC.h:58