added new accessers
[libfirm] / ir / ana / trouts.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ana/trouts.c
4  * Purpose:     Reverse edges that reference types/entities.
5  * Author:      Goetz Lindenmaier
6  * Modified by:
7  * Created:     29.10.2004
8  * CVS-ID:      $Id$
9  * Copyright:   (c) 2004 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12
13 #include "trouts.h"
14
15 #include "array.h"
16 #include "pmap.h"
17
18 #include "irprog.h"
19 #include "irgwalk.h"
20
21 /**------------------------------------------------------------------*/
22 /* We represent the fields in entities/types by hashmaps.            */
23 /**------------------------------------------------------------------*/
24
25 static pmap *entity_access_map = NULL;
26 static pmap *entity_reference_map = NULL;
27 static pmap *type_alloc_map = NULL;
28
29 static ir_node **get_entity_access_array(entity *ent) {
30   ir_node **res;
31   if (!entity_access_map) entity_access_map = pmap_create();
32
33   if (pmap_contains(entity_access_map, (void *)ent)) {
34     res = (ir_node **) pmap_get(entity_access_map, (void *)ent);
35   } else {
36     res = NEW_ARR_F(ir_node *, 0);
37     pmap_insert(entity_access_map, (void *)ent, (void *)res);
38   }
39
40   return res;
41 }
42 void set_entity_access_array(entity *ent, ir_node **accs) {
43   ir_node **old = pmap_get(entity_access_map, (void *)ent);
44   if (old != accs)
45     pmap_insert(entity_access_map, (void *)ent, (void *)accs);
46 }
47
48 static ir_node **get_entity_reference_array(entity *ent) {
49   ir_node **res;
50   if (!entity_reference_map) entity_reference_map = pmap_create();
51
52   if (pmap_contains(entity_reference_map, (void *)ent)) {
53     res = (ir_node **) pmap_get(entity_reference_map, (void *)ent);
54   } else {
55     res = NEW_ARR_F(ir_node *, 0);
56     pmap_insert(entity_reference_map, (void *)ent, (void *)res);
57   }
58
59   return res;
60 }
61 void set_entity_reference_array(entity *ent, ir_node **refs) {
62   ir_node **old = pmap_get(entity_reference_map, (void *)ent);
63   if (old != refs)
64     pmap_insert(entity_reference_map, (void *)ent, (void *)refs);
65 }
66
67 static ir_node **get_type_alloc_array(type *tp) {
68   ir_node **res;
69   if (!type_alloc_map) type_alloc_map = pmap_create();
70
71   if (pmap_contains(type_alloc_map, (void *)tp)) {
72     res = (ir_node **) pmap_get(type_alloc_map, (void *)tp);
73   } else {
74     res = NEW_ARR_F(ir_node *, 0);
75     pmap_insert(type_alloc_map, (void *)tp, (void *)res);
76   }
77
78   return res;
79 }
80 void set_type_alloc_array(type *tp, ir_node **alls) {
81   ir_node **old = pmap_get(type_alloc_map, (void *)tp);
82   if (old != alls)
83     pmap_insert(type_alloc_map, (void *)tp, (void *)alls);
84 }
85
86
87 /*------------------------------------------------------------------*/
88 /* Accessing the out datastructures.                                */
89 /* These routines only work properly if firm is in state            */
90 /* trouts_consistent or trouts_inconsistent.                        */
91 /*------------------------------------------------------------------*/
92
93 /**------------------------------------------------------------------*/
94 /*   Access routines for entities                                    */
95 /**------------------------------------------------------------------*/
96
97 int get_entity_n_accesses(entity *ent) {
98   assert(ent && is_entity(ent));
99
100   ir_node ** accs = (ir_node **)get_entity_access_array(ent);
101   return ARR_LEN(accs);
102 }
103
104 ir_node *get_entity_access(entity *ent, int pos) {
105   assert(0 <= pos && pos < get_entity_n_accesses(ent));
106
107   ir_node ** accs = (ir_node **)get_entity_access_array(ent);
108   return accs[pos];
109 }
110
111 void add_entity_access(entity *ent, ir_node *n) {
112   assert(ent && is_entity(ent));
113   assert(n && is_ir_node(n));
114
115   ir_node ** accs = (ir_node **)get_entity_access_array(ent);
116   ARR_APP1(ir_node *, accs, n);
117   set_entity_access_array(ent, accs);
118 }
119
120 void set_entity_access(entity *ent, int pos, ir_node *n) {
121   assert(0 <= pos && pos < get_entity_n_accesses(ent));
122   assert(n && is_ir_node(n));
123
124   ir_node ** accs = (ir_node **)get_entity_access_array(ent);
125   accs[pos] = n;
126 }
127
128 /**------------------------------------------------------------------*/
129
130 int get_entity_n_references(entity *ent) {
131   assert(ent && is_entity(ent));
132
133   ir_node ** refs = (ir_node **)get_entity_reference_array(ent);
134   return ARR_LEN(refs);
135 }
136
137 ir_node *get_entity_reference(entity *ent, int pos) {
138   assert(0 <= pos && pos < get_entity_n_references(ent));
139
140   ir_node ** refs = (ir_node **)get_entity_reference_array(ent);
141   return refs[pos];
142 }
143
144 void add_entity_reference(entity *ent, ir_node *n) {
145   assert(ent && is_entity(ent));
146   assert(n && is_ir_node(n));
147
148   ir_node ** refs = (ir_node **)get_entity_reference_array(ent);
149   ARR_APP1(ir_node *, refs, n);
150   set_entity_reference_array(ent, refs);
151 }
152
153 void set_entity_reference(entity *ent, int pos, ir_node *n) {
154   assert(0 <= pos && pos < get_entity_n_references(ent));
155   assert(n && is_ir_node(n));
156
157   ir_node ** refs = (ir_node **)get_entity_reference_array(ent);
158   refs[pos] = n;
159 }
160
161
162 /**------------------------------------------------------------------*/
163 /*   Access routines for types                                       */
164 /**------------------------------------------------------------------*/
165
166 /* Number of Alloc nodes that create an instance of this type */
167 int get_type_n_allocations(type *tp) {
168   assert(tp && is_type(tp));
169
170   ir_node **allocs = get_type_alloc_array(tp);
171   return ARR_LEN(allocs);
172 }
173
174 /* Alloc node that creates an instance of this type */
175 ir_node *get_type_allocation(type *tp, int pos) {
176   assert(0 <= pos && pos < get_type_n_allocations(tp));
177
178   ir_node **allocs = get_type_alloc_array(tp);
179   return allocs[pos];
180 }
181
182 void add_type_allocation(type *tp, ir_node *n) {
183   assert(tp && is_type(tp));
184   assert(n && is_ir_node(n));
185
186   ir_node **allocs = get_type_alloc_array(tp);
187   ARR_APP1(ir_node *, allocs, n);
188   set_type_alloc_array(tp, allocs);
189 }
190
191 void set_type_allocation(type *tp, int pos, ir_node *n) {
192   assert(0 <= pos && pos < get_type_n_allocations(tp));
193   assert(n && is_ir_node(n));
194
195   ir_node **allocs = get_type_alloc_array(tp);
196   allocs[pos] = n;
197 }
198
199 /*------------------------------------------------------------------*/
200 /* Building and Removing the out datastructure                      */
201 /*------------------------------------------------------------------*/
202
203 static void init_trouts(void) {
204 }
205
206 /* The entities that can be accessed by this Sel node. */
207 static int get_Sel_n_accessed_entities(ir_node *sel) {
208   return 1;
209 }
210
211 static entity *get_Sel_accessed_entity(ir_node *sel, int pos) {
212   return get_Sel_entity(sel);
213 }
214
215 /* An addr node is a SymConst or a Sel. */
216 static int get_addr_n_entities(ir_node *addr) {
217   int n_ents;
218
219   switch (get_irn_opcode(addr)) {
220   case iro_Sel:
221     /* Treat jack array sels? */
222     n_ents = get_Sel_n_accessed_entities(addr);
223     break;
224   case iro_SymConst:
225     if (get_SymConst_kind(addr) == symconst_addr_ent) {
226       n_ents = 1;
227       break;
228     }
229   default:
230     //assert(0 && "unexpected address expression");
231     n_ents = 0;
232   }
233
234   return n_ents;
235 }
236
237 /* An addr node is a SymConst or a Sel. */
238 static entity *get_addr_entity(ir_node *addr, int pos) {
239   entity *ent;
240
241   switch (get_irn_opcode(addr)) {
242   case iro_Sel:
243     /* Treat jack array sels? */
244     assert (0 <= pos && pos < get_Sel_n_accessed_entities(addr));
245     ent = get_Sel_accessed_entity(addr, pos);
246     break;
247   case iro_SymConst:
248     if (get_SymConst_kind(addr) == symconst_addr_ent) {
249       assert(pos == 0);
250       ent = get_SymConst_entity(addr);
251       break;
252     }
253   default:
254     ent = NULL;
255   }
256
257   return ent;
258 }
259
260 static void chain_accesses(ir_node *n, void *env) {
261   int i, n_ents;
262   ir_node *addr;
263
264   if (get_irn_op(n) == op_Alloc) {
265     add_type_allocation(get_Alloc_type(n), n);
266     return;
267   } else
268
269   if (get_irn_op(n) == op_Sel) {
270     add_entity_reference(get_Sel_entity(n), n);
271     return;
272   } else if (get_irn_op(n) == op_SymConst && (get_SymConst_kind(n) == symconst_addr_ent)) {
273     add_entity_reference(get_SymConst_entity(n), n);
274     return;
275   } else
276
277   if (is_memop(n)) {
278     addr = get_memop_ptr(n);
279   } else if (get_irn_op(n) == op_Call) {
280     addr = get_Call_ptr(n);
281     if (get_irn_op(addr) != op_Sel) return;  /* Sels before Calls mean a Load / polymorphic Call. */
282   } else {
283     return;
284   }
285
286   n_ents = get_addr_n_entities(addr);
287   for (i = 0; i < n_ents; ++i) {
288     entity *ent = get_addr_entity(addr, i);
289     if (ent)
290       add_entity_access(ent, n);
291     //else
292       //add_unrecognized_access(n);
293   }
294 }
295
296 /* compute the field temperature. */
297 void compute_trouts(void) {
298   int i, n_irgs = get_irp_n_irgs();
299
300   init_trouts();
301
302   for (i=0; i < n_irgs; i++) {
303     current_ir_graph = get_irp_irg(i);
304     irg_walk_graph(current_ir_graph, NULL, chain_accesses, NULL);
305   }
306   walk_const_code(NULL, chain_accesses, NULL);
307 }
308
309
310 void free_trouts(void) {
311   if (entity_access_map) {
312     ir_node **accs;
313     for (accs = (ir_node **)pmap_first(entity_access_map);
314          accs;
315          accs = (ir_node **)pmap_next(entity_access_map))
316       ; //DEL_ARR_F(accs);
317     pmap_destroy(entity_access_map);
318     entity_access_map = NULL;
319   }
320   if (entity_reference_map) {
321     ir_node **refs;
322     for (refs = (ir_node **)pmap_first(entity_reference_map);
323          refs;
324          refs = (ir_node **)pmap_next(entity_reference_map))
325       ; //DEL_ARR_F(refs);
326     pmap_destroy(entity_reference_map);
327     entity_reference_map = NULL;
328   }
329   if (type_alloc_map) {
330     ir_node **alls;
331     for (alls = (ir_node **)pmap_first(type_alloc_map);
332          alls;
333          alls = (ir_node **)pmap_next(type_alloc_map))
334       ; //DEL_ARR_F(alls);
335     pmap_destroy(type_alloc_map);
336     type_alloc_map = NULL;
337   }
338 }