3 * File name: ir/ana/analyze_irg_agrs.c
4 * Purpose: read/write analyze of graph argument, which have mode reference.
5 * Author: Beyhan Veliev
8 * Copyright: (c) 1998-2005 Universität Karlsruhe
9 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
13 * @file analyze_irg_agrs.c
37 #include "analyze_irg_args.h"
40 static void *VISITED = &v;
43 * Walk recursive the successors of a graph argument
44 * with mode reference and mark if it will be read,
47 * @param arg The graph argument with mode reference,
48 * that must be checked.
50 static unsigned analyze_arg(ir_node *arg, unsigned bits)
55 /* We must visit a node once to avoid endless recursion.*/
56 set_irn_link(arg, VISITED);
58 for (i = get_irn_n_outs(arg) - 1; i >= 0; --i) {
59 succ = get_irn_out(arg, i);
62 if (get_irn_link(succ) == VISITED)
65 /* We should not walk over the memory edge.*/
66 if (get_irn_mode(succ) == mode_M)
69 /* If we reach with the recursion a Call node and our reference
70 isn't the address of this Call we accept that the reference will
71 be read and written if the graph of the method represented by
72 "Call" isn't computed else we analyze that graph. If our
73 reference is the address of this
74 Call node that mean the reference will be read.*/
75 switch (get_irn_opcode(succ)) {
78 ir_node *ptr = get_Call_ptr(succ);
81 /* Hmm: not sure what this is, most likely a read */
82 bits |= ptr_access_read;
85 ir_op *op = get_irn_op(ptr);
88 if (op == op_SymConst && get_SymConst_kind(ptr) == symconst_addr_ent) {
89 meth_ent = get_SymConst_entity(ptr);
91 for (p = get_Call_n_params(succ) - 1; p >= 0; --p) {
92 if (get_Call_param(succ, p) == arg) {
93 /* an arg can be used more than once ! */
94 bits |= get_method_param_access(meth_ent, p);
98 else if (op == op_Sel && get_irp_callee_info_state() == irg_callee_info_consistent) {
99 /* is be a polymorphic call but callee information is available */
100 int i, n_params = get_Call_n_params(succ);
102 /* simply look into ALL possible callees */
103 for (i = get_Call_n_callees(succ) - 1; i >= 0; --i) {
104 meth_ent = get_Call_callee(succ, i);
106 /* unknown_entity is used to signal that we don't know what is called */
107 if (meth_ent == unknown_entity) {
108 bits |= ptr_access_all;
112 for (p = n_params - 1; p >= 0; --p) {
113 if (get_Call_param(succ, p) == arg) {
114 /* an arg can be used more than once ! */
115 bits |= get_method_param_access(meth_ent, p);
120 else /* can do anything */
121 bits |= ptr_access_all;
124 /* search stops here anyway */
128 /* We have reached a Store node => the reference is written or stored. */
129 if (get_Store_ptr(succ) == arg) {
131 bits |= ptr_access_write;
135 bits |= ptr_access_store;
138 /* search stops here anyway */
142 /* We have reached a Load node => the reference is read. */
143 bits |= ptr_access_read;
145 /* search stops here anyway */
149 /* our address is casted into something unknown. Break our search. */
150 bits = ptr_access_all;
157 /* If we know that, the argument will be read, write and stored, we
158 can break the recursion.*/
159 if (bits == ptr_access_all) {
160 bits = ptr_access_all;
165 * A calculation that do not lead to a reference mode ends our search.
166 * This is dangerous: It would allow to cast into integer and that cast back ...
167 * so, when we detect a Conv we go mad, see the Conv case above.
169 if (!mode_is_reference(get_irn_mode(succ)))
172 /* follow further the address calculation */
173 bits = analyze_arg(succ, bits);
175 set_irn_link(arg, NULL);
180 * Check if a argument of the ir graph with mode
181 * reference is read, write or both.
183 * @param irg The ir graph to analyze.
185 static void analyze_ent_args(entity *ent)
188 ir_node *irg_args, *arg;
193 ptr_access_kind *rw_info;
195 mtp = get_entity_type(ent);
196 nparams = get_method_n_params(mtp);
198 ent->param_access = NEW_ARR_F(ptr_access_kind, nparams);
200 /* If the method haven't parameters we have
206 irg = get_entity_irg(ent);
208 /* we have not yet analyzed the graph, set ALL access for pointer args */
209 for (i = nparams - 1; i >= 0; --i)
210 ent->param_access[i] =
211 is_Pointer_type(get_method_param_type(mtp, i)) ? ptr_access_all : ptr_access_none;
214 /* no graph, no better info */
218 /* Call algorithm that computes the out edges */
219 if (get_irg_outs_state(irg) != outs_consistent)
222 irg_args = get_irg_args(irg);
224 /* A array to save the information for each argument with
226 NEW_ARR_A(ptr_access_kind, rw_info, nparams);
228 /* We initialize the element with none state. */
229 for (i = nparams - 1; i >= 0; --i)
230 rw_info[i] = ptr_access_none;
232 /* search for arguments with mode reference
234 for (i = get_irn_n_outs(irg_args) - 1; i >= 0; --i) {
235 arg = get_irn_out(irg_args, i);
236 arg_mode = get_irn_mode(arg);
237 proj_nr = get_Proj_proj(arg);
239 if (mode_is_reference(arg_mode))
240 rw_info[proj_nr] |= analyze_arg(arg, rw_info[proj_nr]);
243 /* copy the temporary info */
244 memcpy(ent->param_access, rw_info, nparams * sizeof(ent->param_access[0]));
246 printf("\n%s:\n", get_entity_name(ent));
247 for (i = 0; i < nparams; ++i) {
248 if (is_Pointer_type(get_method_param_type(mtp, i)))
249 if (ent->param_access[i] != ptr_access_none) {
250 printf(" Pointer Arg %d access: ", i);
251 if (ent->param_access[i] & ptr_access_read)
253 if (ent->param_access[i] & ptr_access_write)
255 if (ent->param_access[i] & ptr_access_store)
263 * Analyze how pointer arguments of a given
264 * ir graph are accessed.
266 * @param irg The ir graph to analyze.
268 void analyze_irg_args(ir_graph *irg)
272 if (irg == get_const_code_irg())
275 ent = get_irg_entity(irg);
279 if (! ent->param_access)
280 analyze_ent_args(ent);
284 * Compute for a method with pointer parameter(s)
285 * if they will be read or written.
287 ptr_access_kind get_method_param_access(entity *ent, int pos)
289 type *mtp = get_entity_type(ent);
290 int is_variadic = get_method_variadicity(mtp) == variadicity_variadic;
292 assert(0 <= pos && (is_variadic || pos < get_method_n_params(mtp)));
294 if (ent->param_access) {
295 if (pos < ARR_LEN(ent->param_access))
296 return ent->param_access[pos];
298 return ptr_access_all;
301 analyze_ent_args(ent);
303 if (pos < ARR_LEN(ent->param_access))
304 return ent->param_access[pos];
306 return ptr_access_all;
310 null_weight = 0, /**< If can't be anything optimized. */
311 binop_weight = 1, /**< If the argument have mode_weight and take part in binop. */
312 const_binop_weight = 1, /**< If the argument have mode_weight and take part in binop with a constant.*/
313 cmp_weight = 4, /**< If the argument take part in cmp. */
314 const_cmp_weight = 10 /**< If the argument take part in cmp with a constant. */
318 * Compute the weight of a method parameter
320 * @param arg The parameter them weight muss be computed.
322 static float calc_method_param_weight(ir_node *arg)
326 float weight = null_weight;
328 /* We mark the nodes to avoid endless recursion */
329 set_irn_link(arg, VISITED);
331 for (i = get_irn_n_outs(arg) - 1; i >= 0; i--) {
332 succ = get_irn_out(arg, i);
335 if (get_irn_link(succ) == VISITED)
338 /* We should not walk over the memory edge.*/
339 if (get_irn_mode(succ) == mode_M)
342 /* We have reached a cmp and we must increase the
343 weight with the cmp_weight.*/
344 if (get_irn_op(succ) == op_Cmp) {
346 if (get_Cmp_left(succ) == arg)
347 op = get_Cmp_right(succ);
349 op = get_Cmp_left(succ);
351 if (is_irn_constlike(op)) {
352 weight += const_cmp_weight;
355 weight += cmp_weight;
357 else if (is_binop(succ)) {
358 /* We have reached a binop and we must increase the
359 weight with the binop_weight. If the other operand of the
360 binop is a constant we increase the weight with const_binop_weight
361 and call the function recursive.
363 if (get_binop_left(succ) == arg)
364 op = get_binop_right(succ);
366 op = get_binop_left(succ);
368 if (is_irn_constlike(op)) {
369 weight += const_binop_weight;
370 weight += calc_method_param_weight(succ);
373 weight += binop_weight;
374 } else if (is_unop(succ)) {
375 /* We have reached a binop and we must increase the
376 weight with the const_binop_weight and call the function recursive.*/
377 weight += const_binop_weight;
378 weight += calc_method_param_weight(succ);
381 set_irn_link(arg, NULL);
386 * Set a weight for each argument of a ir_graph.
387 * The args with a greater weight are good for optimize.
389 * @param ent The entity of the ir_graph.
391 static void analyze_method_params_weight(entity *ent)
395 int nparams, i, proj_nr;
396 ir_node *irg_args, *arg;
398 mtp = get_entity_type(ent);
399 nparams = get_method_n_params(mtp);
401 /* allocate a new array. currently used as 'analysed' flag */
402 ent->param_weight = NEW_ARR_F(float, nparams);
404 /* If the method haven't parameters we have
410 irg = get_entity_irg(ent);
412 /* First we initialize the parameter weight with 0. */
413 for (i = nparams - 1; i >= 0; i--)
414 ent->param_weight[i] = null_weight;
417 /* no graph, no better info */
421 /* Call algorithm that computes the out edges */
422 if (get_irg_outs_state(irg) != outs_consistent)
425 irg_args = get_irg_args(irg);
427 for (i = get_irn_n_outs(irg_args) - 1; i >= 0; --i) {
428 arg = get_irn_out(irg_args, i);
429 proj_nr = get_Proj_proj(arg);
430 ent->param_weight[proj_nr] += calc_method_param_weight(arg);
434 printf("\n%s:\n", get_entity_name(ent));
435 for (i = nparams - 1; i >= 0; --i)
436 printf("The weight of argument %i is %f \n", i, ent->param_weight[i]);
441 * Compute for a method with pointer parameter(s)
442 * if they will be read or written.
444 float get_method_param_weight(entity *ent, int pos)
446 type *mtp = get_entity_type(ent);
447 int is_variadic = get_method_variadicity(mtp) == variadicity_variadic;
449 assert(0 <= pos && (is_variadic || pos < get_method_n_params(mtp)));
451 if (ent->param_weight) {
452 if (pos < ARR_LEN(ent->param_weight))
453 return ent->param_weight[pos];
458 analyze_method_params_weight(ent);
460 if (pos < ARR_LEN(ent->param_weight))
461 return ent->param_weight[pos];
468 * Analyze argument's weight of a given
471 * @param irg The ir graph to analyze.
473 void analyze_irg_args_weight(ir_graph *irg)
477 ent = get_irg_entity(irg);
481 if (! ent->param_weight)
482 analyze_method_params_weight(ent);