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(ir_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->attr.mtd_attr.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->attr.mtd_attr.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 assure_irg_outs(irg);
220 irg_args = get_irg_args(irg);
222 /* A array to save the information for each argument with
224 NEW_ARR_A(ptr_access_kind, rw_info, nparams);
226 /* We initialize the element with none state. */
227 for (i = nparams - 1; i >= 0; --i)
228 rw_info[i] = ptr_access_none;
230 /* search for arguments with mode reference
232 for (i = get_irn_n_outs(irg_args) - 1; i >= 0; --i) {
233 arg = get_irn_out(irg_args, i);
234 arg_mode = get_irn_mode(arg);
235 proj_nr = get_Proj_proj(arg);
237 if (mode_is_reference(arg_mode))
238 rw_info[proj_nr] |= analyze_arg(arg, rw_info[proj_nr]);
241 /* copy the temporary info */
242 memcpy(ent->attr.mtd_attr.param_access, rw_info,
243 nparams * sizeof(ent->attr.mtd_attr.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->attr.mtd_attr.param_access[i] != ptr_access_none) {
250 printf(" Pointer Arg %d access: ", i);
251 if (ent->attr.mtd_attr.param_access[i] & ptr_access_read)
253 if (ent->attr.mtd_attr.param_access[i] & ptr_access_write)
255 if (ent->attr.mtd_attr.param_access[i] & ptr_access_store)
264 * Analyze how pointer arguments of a given
265 * ir graph are accessed.
267 * @param irg The ir graph to analyze.
269 void analyze_irg_args(ir_graph *irg)
273 if (irg == get_const_code_irg())
276 ent = get_irg_entity(irg);
280 if (! ent->attr.mtd_attr.param_access)
281 analyze_ent_args(ent);
285 * Compute for a method with pointer parameter(s)
286 * if they will be read or written.
288 ptr_access_kind get_method_param_access(ir_entity *ent, int pos)
290 ir_type *mtp = get_entity_type(ent);
292 int is_variadic = get_method_variadicity(mtp) == variadicity_variadic;
294 assert(0 <= pos && (is_variadic || pos < get_method_n_params(mtp)));
297 if (ent->attr.mtd_attr.param_access) {
298 if (pos < ARR_LEN(ent->attr.mtd_attr.param_access))
299 return ent->attr.mtd_attr.param_access[pos];
301 return ptr_access_all;
304 analyze_ent_args(ent);
306 if (pos < ARR_LEN(ent->attr.mtd_attr.param_access))
307 return ent->attr.mtd_attr.param_access[pos];
309 return ptr_access_all;
313 null_weight = 0, /**< If can't be anything optimized. */
314 binop_weight = 1, /**< If the argument have mode_weight and take part in binop. */
315 const_binop_weight = 1, /**< If the argument have mode_weight and take part in binop with a constant.*/
316 cmp_weight = 4, /**< If the argument take part in cmp. */
317 const_cmp_weight = 10 /**< If the argument take part in cmp with a constant. */
321 * Compute the weight of a method parameter
323 * @param arg The parameter them weight muss be computed.
325 static float calc_method_param_weight(ir_node *arg)
329 float weight = null_weight;
331 /* We mark the nodes to avoid endless recursion */
332 set_irn_link(arg, VISITED);
334 for (i = get_irn_n_outs(arg) - 1; i >= 0; i--) {
335 succ = get_irn_out(arg, i);
338 if (get_irn_link(succ) == VISITED)
341 /* We should not walk over the memory edge.*/
342 if (get_irn_mode(succ) == mode_M)
345 /* We have reached a cmp and we must increase the
346 weight with the cmp_weight.*/
347 if (get_irn_op(succ) == op_Cmp) {
349 if (get_Cmp_left(succ) == arg)
350 op = get_Cmp_right(succ);
352 op = get_Cmp_left(succ);
354 if (is_irn_constlike(op)) {
355 weight += const_cmp_weight;
358 weight += cmp_weight;
360 else if (is_binop(succ)) {
361 /* We have reached a binop and we must increase the
362 weight with the binop_weight. If the other operand of the
363 binop is a constant we increase the weight with const_binop_weight
364 and call the function recursive.
366 if (get_binop_left(succ) == arg)
367 op = get_binop_right(succ);
369 op = get_binop_left(succ);
371 if (is_irn_constlike(op)) {
372 weight += const_binop_weight;
373 weight += calc_method_param_weight(succ);
376 weight += binop_weight;
377 } else if (is_unop(succ)) {
378 /* We have reached a binop and we must increase the
379 weight with the const_binop_weight and call the function recursive.*/
380 weight += const_binop_weight;
381 weight += calc_method_param_weight(succ);
384 set_irn_link(arg, NULL);
389 * Set a weight for each argument of a ir_graph.
390 * The args with a greater weight are good for optimize.
392 * @param ent The entity of the ir_graph.
394 static void analyze_method_params_weight(ir_entity *ent)
398 int nparams, i, proj_nr;
399 ir_node *irg_args, *arg;
401 mtp = get_entity_type(ent);
402 nparams = get_method_n_params(mtp);
404 /* allocate a new array. currently used as 'analysed' flag */
405 ent->attr.mtd_attr.param_weight = NEW_ARR_F(float, nparams);
407 /* If the method haven't parameters we have
413 irg = get_entity_irg(ent);
415 /* First we initialize the parameter weight with 0. */
416 for (i = nparams - 1; i >= 0; i--)
417 ent->attr.mtd_attr.param_weight[i] = null_weight;
420 /* no graph, no better info */
424 /* Call algorithm that computes the out edges */
425 assure_irg_outs(irg);
427 irg_args = get_irg_args(irg);
429 for (i = get_irn_n_outs(irg_args) - 1; i >= 0; --i) {
430 arg = get_irn_out(irg_args, i);
431 proj_nr = get_Proj_proj(arg);
432 ent->attr.mtd_attr.param_weight[proj_nr] += calc_method_param_weight(arg);
436 printf("\n%s:\n", get_entity_name(ent));
437 for (i = nparams - 1; i >= 0; --i)
438 printf("The weight of argument %i is %f \n", i, ent->param_weight[i]);
443 * Compute for a method with pointer parameter(s)
444 * if they will be read or written.
446 float get_method_param_weight(ir_entity *ent, int pos)
448 ir_type *mtp = get_entity_type(ent);
451 int is_variadic = get_method_variadicity(mtp) == variadicity_variadic;
452 assert(0 <= pos && (is_variadic || pos < get_method_n_params(mtp)));
455 if (ent->attr.mtd_attr.param_weight) {
456 if (pos < ARR_LEN(ent->attr.mtd_attr.param_weight))
457 return ent->attr.mtd_attr.param_weight[pos];
462 analyze_method_params_weight(ent);
464 if (pos < ARR_LEN(ent->attr.mtd_attr.param_weight))
465 return ent->attr.mtd_attr.param_weight[pos];
472 * Analyze argument's weight of a given
475 * @param irg The ir graph to analyze.
477 void analyze_irg_args_weight(ir_graph *irg)
481 ent = get_irg_entity(irg);
485 if (! ent->attr.mtd_attr.param_weight)
486 analyze_method_params_weight(ent);