fixed bugs
[libfirm] / ir / ana / analyze_irg_args.c
1 /*
2  * Project:     libFIRM
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
6  * Created:
7  * CVS-ID:      $Id$
8  * Copyright:   (c) 1998-2005 Universität Karlsruhe
9  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
10  */
11
12 /**
13  * @file analyze_irg_agrs.c
14  *
15  */
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19
20 #ifdef HAVE_MALLOC_H
21 #include <malloc.h>
22 #endif
23 #ifdef HAVE_ALLOCA_H
24 #include <alloca.h>
25 #endif
26 #include <stdlib.h>
27
28 #include "irouts.h"
29 #include "irnode_t.h"
30 #include "irmode_t.h"
31 #include "array.h"
32 #include "irprog.h"
33 #include "entity_t.h"
34
35 #include "analyze_irg_args.h"
36
37 static char v;
38 static void *VISITED = &v;
39
40 /**
41  * Walk recursive the successors of a graph argument
42  * with mode reference and mark in the "irg_args" if it will be read,
43  * written or stored.
44  *
45  * @param arg   The graph argument with mode reference,
46  *             that must be checked.
47  */
48 static unsigned analyze_arg(ir_node *arg, unsigned bits)
49 {
50   int i, p;
51   ir_node *succ;
52
53   /* We must visit a node once to avoid endless recursion.*/
54   set_irn_link(arg, VISITED);
55
56   for (i = get_irn_n_outs(arg) - 1; i >= 0; --i) {
57     succ = get_irn_out(arg, i);
58
59     /* We was here.*/
60     if (get_irn_link(succ) == VISITED)
61       continue;
62
63     /* We should not walk over the memory edge.*/
64     if (get_irn_mode(succ) == mode_M)
65       continue;
66
67     /* If we reach with the recursion a Call node and our reference
68        isn't the address of this Call we accept that the reference will
69        be read and written if the graph of the method represented by
70        "Call" isn't computed else we analyze that graph. If our
71        reference is the address of this
72        Call node that mean the reference will be read.*/
73     if (get_irn_op(succ) == op_Call) {
74       ir_node *Call_ptr  = get_Call_ptr(succ);
75
76       if (Call_ptr == arg) {
77         /* Hmm: not sure what this is, most likely a read */
78         bits |= ptr_access_read;
79       }
80       else if (op_SymConst == get_irn_op(Call_ptr) &&
81               get_SymConst_kind(Call_ptr) == symconst_addr_ent) {
82         entity *meth_ent = get_SymConst_entity(Call_ptr);
83
84               for (p = get_Call_n_params(succ) - 1; p >= 0; --p){
85                 if (get_Call_param(succ, p) == arg) {
86             /* an arg can be used more than once ! */
87             bits |= get_method_param_access(meth_ent, p);
88                 }
89               }
90       } else /* can do anything */
91         bits |= ptr_access_all;
92
93       /* search stops here anyway */
94       continue;
95     }
96     else if (get_irn_op(succ) == op_Store) {
97       /* We have reached a Store node => the reference is written or stored. */
98       if (get_Store_ptr(succ) == arg) {
99         /* written to */
100         bits |= ptr_access_write;
101       }
102       else {
103         /* stored itself */
104         bits |= ptr_access_store;
105       }
106
107       /* search stops here anyway */
108       continue;
109    }
110     else if (get_irn_op(succ) == op_Load) {
111       /* We have reached a Load node => the reference is read. */
112       bits |= ptr_access_read;
113
114       /* search stops here anyway */
115       continue;
116     }
117     else if (get_irn_op(succ) == op_Conv) {
118       /* our address is casted into something unknown. Break our search. */
119       return ptr_access_all;
120     }
121
122     /* If we know that, the argument will be read, write and stored, we
123        can break the recursion.*/
124     if (bits == ptr_access_all)
125       return ptr_access_all;
126
127     /*
128      * A calculation that do not lead to a reference mode ends our search.
129      * This is dangerous: It would allow to cast into integer and that cast back ...
130      * so, when we detect a Conv we go mad, see the Conv case above.
131      */
132     if (!mode_is_reference(get_irn_mode(succ)))
133       continue;
134
135     /* follow further the address calculation */
136     bits = analyze_arg(succ, bits);
137   }
138   set_irn_link(arg, NULL);
139   return bits;
140 }
141
142
143 /**
144  * Check if a argument of the ir graph with mode
145  * reference is read, write or both.
146  *
147  * @param irg   The ir graph to analyze.
148  */
149 static void analyze_ent_args(entity *ent)
150 {
151   ir_graph *irg;
152   ir_node *irg_args, *arg;
153   ir_mode *arg_mode;
154   int nparams, i;
155   long proj_nr;
156   type *mtp;
157   ptr_access_kind *rw_info;
158
159   mtp     = get_entity_type(ent);
160   nparams = get_method_n_params(mtp);
161
162   ent->param_access = NEW_ARR_F(ptr_access_kind, nparams);
163
164   /* If the method haven't parameters we have
165    * nothing to do.
166    */
167   if (nparams <= 0)
168     return;
169
170   irg = get_entity_irg(ent);
171
172   /* we have not yet analysed the graph, set ALL access for pointer args */
173   for (i = nparams - 1; i >= 0; --i)
174     ent->param_access[i] =
175       is_Pointer_type(get_method_param_type(mtp, i)) ? ptr_access_all : ptr_access_none;
176
177   if (! irg) {
178     /* no graph, no better info */
179     return;
180   }
181
182   /* Call algorithm that computes the out edges */
183   if (get_irg_outs_state(irg) != outs_consistent)
184     compute_outs(irg);
185
186   irg_args = get_irg_args(irg);
187
188   /* A array to save the information for each argument with
189      mode reference.*/
190   NEW_ARR_A(ptr_access_kind, rw_info, nparams);
191
192   /* We initialize the element with none state. */
193   for (i = nparams - 1; i >= 0; --i)
194     rw_info[i] = ptr_access_none;
195
196   /* search for arguments with mode reference
197      to analyze them.*/
198   for (i = get_irn_n_outs(irg_args) - 1; i >= 0; --i) {
199     arg      = get_irn_out(irg_args, i);
200     arg_mode = get_irn_mode(arg);
201     proj_nr  = get_Proj_proj(arg);
202
203     if (mode_is_reference(arg_mode))
204       rw_info[proj_nr] |= analyze_arg(arg, rw_info[proj_nr]);
205   }
206
207   /* copy the temporary info */
208   memcpy(ent->param_access, rw_info, nparams * sizeof(ent->param_access[0]));
209
210   printf("\n%s:\n", get_entity_name(ent));
211   for (i = 0; i < nparams; ++i) {
212     if (is_Pointer_type(get_method_param_type(mtp, i)))
213       if (ent->param_access[i] != ptr_access_none) {
214         printf("  Pointer Arg %d access: ", i);
215         if (ent->param_access[i] & ptr_access_read)
216           printf("READ ");
217         if (ent->param_access[i] & ptr_access_write)
218           printf("WRITE ");
219         if (ent->param_access[i] & ptr_access_store)
220           printf("STORE ");
221         printf("\n");
222       }
223   }
224 }
225
226 /*
227  * Compute for a method with pointer parameter(s)
228  * if they will be read or written.
229  */
230 ptr_access_kind get_method_param_access(entity *ent, int pos)
231 {
232   type *mtp = get_entity_type(ent);
233   int  is_variadic = get_method_variadicity(mtp) == variadicity_variadic;
234
235   assert(0 <= pos && (is_variadic || pos < get_method_n_params(mtp)));
236
237   if (ent->param_access) {
238     if (pos < ARR_LEN(ent->param_access))
239       return ent->param_access[pos];
240     else
241       return ptr_access_all;
242   }
243
244   analyze_ent_args(ent);
245
246   if (pos < ARR_LEN(ent->param_access))
247     return ent->param_access[pos];
248   else
249     return ptr_access_all;
250 }
251
252 /**
253  * Analyze how pointer arguments of a given
254  * ir graph are accessed.
255  *
256  * @param irg   The ir graph to analyze.
257  */
258 void analyze_irg_args(ir_graph *irg)
259 {
260   entity *ent;
261
262   if (irg == get_const_code_irg())
263     return;
264
265   ent = get_irg_entity(irg);
266   if (! ent)
267     return;
268
269   if (! ent->param_access)
270     analyze_ent_args(ent);
271 }