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