a simple analysys which determines which pointer arguments are read/write
[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 /**
38  * A struct to save if a graph argument with mode reference is
39  * read/write or both.
40  */
41 typedef struct {
42   unsigned char read;
43   unsigned char write;
44 } rw_info_t;
45
46 enum access {
47   ACC_UNKNOWN,
48   ACC_ACCESSED,
49   ACC_NOT_ACCESSED
50 };
51
52 #define ACCESS(a)       if ((a) == ACC_UNKNOWN) (a) = ACC_ACCESSED
53 #define NOT_ACCESS(a)   if ((a) == ACC_UNKNOWN) (a) = ACC_NOT_ACCESSED
54
55 static char v;
56 static void *VISITED = &v;
57
58 /**
59  * Walk recursive the successors of a graph argument
60  * with mode reference and mark in the "irg_args" if it will be read,
61  * written or both.
62  *
63  * @param arg   The graph argument with mode reference,
64  *             that must be checked.
65  */
66 static unsigned analyze_arg(ir_node *arg, unsigned bits)
67 {
68   int i, p;
69   ir_node *succ;
70
71   /* We must visit a node once to avoid endless recursion.*/
72   set_irn_link(arg, VISITED);
73
74   for (i = get_irn_n_outs(arg) - 1; i >= 0; --i) {
75     succ = get_irn_out(arg, i);
76
77     /* We was here.*/
78     if (get_irn_link(succ) == VISITED)
79       continue;
80
81     /* We should not walk over the memory edge.*/
82     if (get_irn_mode(succ) == mode_M)
83       continue;
84
85     /* A addition or subtraction of the argument with output, that
86        isn't with mode reference must not be checked.*/
87     if ((get_irn_op(succ) == op_Add || get_irn_op(succ) == op_Sub) &&
88         !mode_is_reference(get_irn_mode(succ)))
89       continue;
90
91     /* A Block as successor isn't interesting.*/
92     if (get_irn_op(succ) == op_Block)
93       continue;
94
95     /* If we reach with the recursion a Call node and our reference
96        isn't the address of this Call we accept that the reference will
97        be read and written if the graph of the method represented by
98        "Call" isn't computed else we analyze that graph. If our
99        reference is the address of this
100        Call node that mean the reference will be read.*/
101     if (get_irn_op(succ) == op_Call) {
102       ir_node *Call_ptr  = get_Call_ptr(succ);
103
104       if (Call_ptr == arg)
105         return bits | ptr_access_read;
106       else if (op_SymConst == get_irn_op(Call_ptr) &&
107               get_SymConst_kind(Call_ptr) == symconst_addr_ent) {
108         entity *meth_ent = get_SymConst_entity(Call_ptr);
109
110               for (p = get_Call_n_params(succ) - 1; p >= 0; --p){
111                 if (get_Call_param(succ, p) == arg) {
112             /* an arg can be used more than once ! */
113             bits |= get_method_param_access(meth_ent, p);
114                 }
115               }
116       } else
117         bits |= ptr_access_rw;
118     }
119     else if (get_irn_op(succ) == op_Store) {
120       /* We have reached a Store node => the reference is written. */
121       bits |= ptr_access_write;
122     }
123     else if (get_irn_op(succ) == op_Load) {
124       /* We have reached a Load node => the reference is read. */
125       bits |= ptr_access_read;
126     }
127
128     /* If we know that, the argument will be read and written, we
129        can break the recursion.*/
130     if (bits == ptr_access_rw)
131       return ptr_access_rw;
132
133     bits = analyze_arg(succ, bits);
134   }
135   set_irn_link(arg, NULL);
136   return bits;
137 }
138
139
140 /**
141  * Check if a argument of the ir graph with mode
142  * reference is read, write or both.
143  *
144  * @param irg   The ir graph to analyze.
145  */
146 static void analyze_ent_args(entity *ent)
147 {
148   ir_graph *irg;
149   ir_node *irg_args, *arg;
150   ir_mode *arg_mode;
151   int nparams, i;
152   long proj_nr;
153   type *mtp;
154   unsigned bits;
155   rw_info_t *rw_info;
156
157   mtp     = get_entity_type(ent);
158   nparams = get_method_n_params(mtp);
159
160   ent->param_access = NEW_ARR_F(ptr_access_kind, nparams);
161
162   /* If the method haven't parameters we have
163    * nothing to do.*/
164   if (nparams <= 0)
165     return;
166
167   irg = get_entity_irg(ent);
168
169   if (! irg) {
170     /* if we could not determine the graph, set RW access */
171     for (i = nparams - 1; i >= 0; --i)
172       ent->param_access[i] =
173         is_Pointer_type(get_method_param_type(mtp, i)) ? ptr_access_rw : ptr_access_none;
174
175     return;
176   }
177
178   /* Call algorithm that computes the out edges */
179   if (get_irg_outs_state(irg) != outs_consistent)
180     compute_outs(irg);
181
182   irg_args = get_irg_args(irg);
183
184   /* A array to save the information for each argument with
185      mode reference.*/
186   NEW_ARR_A(rw_info_t, rw_info, nparams);
187
188   /* We initialize the element with UNKNOWN state. */
189   for (i = nparams - 1; i >= 0; --i) {
190     rw_info[i].read  = ACC_UNKNOWN;
191     rw_info[i].write = ACC_UNKNOWN;
192   }
193
194   /* search for arguments with mode reference
195      to analyze them.*/
196   for (i = get_irn_n_outs(irg_args) - 1; i >= 0; --i) {
197     arg      = get_irn_out(irg_args, i);
198     arg_mode = get_irn_mode(arg);
199     proj_nr  = get_Proj_proj(arg);
200
201     if (mode_is_reference(arg_mode)) {
202       bits = analyze_arg(arg, ptr_access_none);
203
204       if (bits & ptr_access_read)
205         ACCESS(rw_info[proj_nr].read);
206       if (bits & ptr_access_write)
207         ACCESS(rw_info[proj_nr].write);
208     }
209   }
210
211   /* set all unknown values to NOT_ACCESSED */
212   for (i = nparams - 1; i >= 0; --i) {
213     NOT_ACCESS(rw_info[i].read);
214     NOT_ACCESS(rw_info[i].write);
215
216     ent->param_access[i] = (rw_info[i].read  == ACC_ACCESSED ? ptr_access_read : ptr_access_none) |
217                            (rw_info[i].write == ACC_ACCESSED ? ptr_access_write : ptr_access_none);
218   }
219
220   printf("%s:\n", get_entity_name(ent));
221   for (i = 0; i < nparams; ++i) {
222     if (is_Pointer_type(get_method_param_type(mtp, i)))
223       printf("Pointer Arg %i wird %s %s\n", i,
224         ent->param_access[i] & ptr_access_read  ? "gelesen" : "",
225         ent->param_access[i] & ptr_access_write ? "geschrieben" : "");
226   }
227 }
228
229 /*
230  * Compute for a method with pointer parameter(s)
231  * if they will be read or written.
232  */
233 ptr_access_kind get_method_param_access(entity *ent, int pos)
234 {
235   type *mtp = get_entity_type(ent);
236   int  is_variadic = get_method_variadicity(mtp) == variadicity_variadic;
237
238   assert(0 <= pos && (is_variadic || pos < get_method_n_params(mtp)));
239
240   if (ent->param_access) {
241     if (pos < ARR_LEN(ent->param_access))
242       return ent->param_access[pos];
243     else
244       return ptr_access_rw;
245   }
246
247   analyze_ent_args(ent);
248
249   if (pos < ARR_LEN(ent->param_access))
250     return ent->param_access[pos];
251   else
252     return ptr_access_rw;
253 }
254
255 /**
256  * Analyze how pointer arguments of a given
257  * ir graph are accessed.
258  *
259  * @param irg   The ir graph to analyze.
260  */
261 void analyze_irg_args(ir_graph *irg)
262 {
263   entity *ent;
264
265   if (irg == get_const_code_irg())
266     return;
267
268   ent = get_irg_entity(irg);
269   if (! ent)
270     return;
271
272   if (! ent->param_access)
273     analyze_ent_args(ent);
274 }