a const parameter is enough for get_method_XXX()
[libfirm] / ir / tr / compound_path.c
1 /*
2  * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @author  Martin Trapp, Christian Schaefer, Goetz Lindenmaier, Michael Beck
23  * @version $Id$
24  */
25 #include "config.h"
26
27 #include <stdlib.h>
28 #include <stdbool.h>
29 #include <assert.h>
30
31 #include "firm_types.h"
32 #include "typerep.h"
33 #include "compound_path_t.h"
34 #include "xmalloc.h"
35 #include "type_t.h"
36 #include "entity_t.h"
37 #include "irgraph_t.h"
38 #include "ircons.h"
39
40 compound_graph_path *new_compound_graph_path(ir_type *tp, size_t length)
41 {
42         compound_graph_path *res;
43
44         assert(is_compound_type(tp) || is_Array_type(tp));
45         assert(length > 0);
46
47         res = XMALLOCFZ(compound_graph_path, list, length);
48         res->kind = k_ir_compound_graph_path;
49         res->tp   = tp;
50         res->len  = length;
51
52         return res;
53 }
54
55 void free_compound_graph_path(compound_graph_path *gr)
56 {
57         assert(gr && is_compound_graph_path(gr));
58         gr->kind = k_BAD;
59         free(gr);
60 }
61
62 int is_compound_graph_path(const void *thing)
63 {
64         return get_kind(thing) == k_ir_compound_graph_path;
65 }
66
67 int is_proper_compound_graph_path(compound_graph_path *gr, size_t pos)
68 {
69         size_t i;
70         ir_entity *node;
71         ir_type *owner = gr->tp;
72
73         for (i = 0; i <= pos; i++) {
74                 node = get_compound_graph_path_node(gr, i);
75                 if (node == NULL)
76                         /* Path not yet complete. */
77                         return 1;
78                 if (get_entity_owner(node) != owner)
79                         return 0;
80                 owner = get_entity_type(node);
81         }
82         if (pos == get_compound_graph_path_length(gr))
83                 if (!is_atomic_type(owner))
84                         return 0;
85                 return 1;
86 }
87
88 size_t get_compound_graph_path_length(const compound_graph_path *gr)
89 {
90         assert(gr && is_compound_graph_path(gr));
91         return gr->len;
92 }
93
94 ir_entity *get_compound_graph_path_node(const compound_graph_path *gr,
95                                         size_t pos)
96 {
97         assert(gr && is_compound_graph_path(gr));
98         assert(pos < gr->len);
99         return gr->list[pos].node;
100 }
101
102 void set_compound_graph_path_node(compound_graph_path *gr, size_t pos,
103                                   ir_entity *node)
104 {
105         assert(gr && is_compound_graph_path(gr));
106         assert(pos < gr->len);
107         assert(is_entity(node));
108         gr->list[pos].node = node;
109         assert(is_proper_compound_graph_path(gr, pos));
110 }
111
112 long get_compound_graph_path_array_index(const compound_graph_path *gr, size_t pos)
113 {
114         assert(gr && is_compound_graph_path(gr));
115         assert(pos < gr->len);
116         return gr->list[pos].index;
117 }
118
119 void set_compound_graph_path_array_index(compound_graph_path *gr, size_t pos,
120                                          long index)
121 {
122         assert(gr && is_compound_graph_path(gr));
123         assert(pos < gr->len);
124         gr->list[pos].index = index;
125 }
126
127 ir_type *get_compound_graph_path_type(const compound_graph_path *gr)
128 {
129         assert(gr && is_compound_graph_path(gr));
130         return gr->tp;
131 }
132
133 static void allocate_values(ir_entity *ent)
134 {
135         if (ent->attr.cmpd_attr.values == NULL) {
136                 ent->attr.cmpd_attr.values = NEW_ARR_F(ir_node*, 0);
137                 assert(ent->attr.cmpd_attr.val_paths == NULL);
138                 ent->attr.cmpd_attr.val_paths = NEW_ARR_F(compound_graph_path*, 0);
139         }
140 }
141
142 void add_compound_ent_value_w_path(ir_entity *ent, ir_node *val,
143                                    compound_graph_path *path)
144 {
145         assert(is_compound_entity(ent));
146         assert(is_compound_graph_path(path));
147         allocate_values(ent);
148         ARR_APP1(ir_node *, ent->attr.cmpd_attr.values, val);
149         ARR_APP1(compound_graph_path *, ent->attr.cmpd_attr.val_paths, path);
150 }
151
152 void set_compound_ent_value_w_path(ir_entity *ent, ir_node *val,
153                                    compound_graph_path *path, size_t pos)
154 {
155         assert(is_compound_entity(ent));
156         assert(is_compound_graph_path(path));
157         assert(pos < ARR_LEN(ent->attr.cmpd_attr.values));
158         ent->attr.cmpd_attr.values[pos]    = val;
159         ent->attr.cmpd_attr.val_paths[pos] = path;
160 }
161
162 compound_graph_path *get_compound_ent_value_path(const ir_entity *ent,
163                                                  size_t pos)
164 {
165         assert(is_compound_entity(ent));
166         assert(ent->initializer == NULL);
167         assert(pos < ARR_LEN(ent->attr.cmpd_attr.val_paths));
168         return ent->attr.cmpd_attr.val_paths[pos];
169 }
170
171 /**
172  * Returns non-zero, if two compound_graph_pathes are equal
173  *
174  * @param path1            the first path
175  * @param path2            the second path
176  */
177 static bool equal_paths(compound_graph_path *path1, compound_graph_path *path2)
178 {
179         size_t i;
180         size_t len1 = get_compound_graph_path_length(path1);
181         size_t len2 = get_compound_graph_path_length(path2);
182
183         if (len2 != len1) return false;
184
185         for (i = 0; i < len1; i++) {
186                 ir_type *tp;
187                 ir_entity *node1 = get_compound_graph_path_node(path1, i);
188                 ir_entity *node2 = get_compound_graph_path_node(path2, i);
189
190                 if (node1 != node2) return false;
191
192                 tp = get_entity_owner(node1);
193                 if (is_Array_type(tp)) {
194                         size_t index1 = get_compound_graph_path_array_index(path1, i);
195                         size_t index2 = get_compound_graph_path_array_index(path2, i);
196                         if (index1 != index2)
197                                 return false;
198                 }
199         }
200         return true;
201 }
202
203 /**
204  * Returns the position of a value with the given path.
205  * The path must contain array indices for all array element entities.
206  *
207  * @todo  This implementation is very slow (O(number of initializers * |path|)
208  *        and should be replaced when the new tree oriented
209  *        value representation is finally implemented.
210  */
211 static size_t get_compound_ent_pos_by_path(const ir_entity *ent,
212                                            compound_graph_path *path)
213 {
214         size_t i, n_paths = get_compound_ent_n_values(ent);
215
216         for (i = 0; i < n_paths; i ++) {
217                 compound_graph_path *gr = get_compound_ent_value_path(ent, i);
218                 if (equal_paths(gr, path))
219                         return i;
220         }
221         return (size_t)-1;
222 }
223
224 ir_node *get_compound_ent_value_by_path(const ir_entity *ent,
225                                         compound_graph_path *path)
226 {
227         size_t pos = get_compound_ent_pos_by_path(ent, path);
228         if (pos != (size_t)-1)
229                 return get_compound_ent_value(ent, pos);
230         return NULL;
231 }
232
233 void remove_compound_ent_value(ir_entity *ent, ir_entity *value_ent)
234 {
235         size_t i, n;
236         assert(is_compound_entity(ent));
237
238         n = ARR_LEN(ent->attr.cmpd_attr.val_paths);
239         for (i = 0; i < n; ++i) {
240                 compound_graph_path *path = ent->attr.cmpd_attr.val_paths[i];
241                 if (path->list[path->len-1].node == value_ent) {
242                         for (; i < n - 1; ++i) {
243                                 ent->attr.cmpd_attr.val_paths[i] = ent->attr.cmpd_attr.val_paths[i+1];
244                                 ent->attr.cmpd_attr.values[i]    = ent->attr.cmpd_attr.values[i+1];
245                         }
246                         ARR_SETLEN(compound_graph_path*, ent->attr.cmpd_attr.val_paths, n - 1);
247                         ARR_SETLEN(ir_node*,             ent->attr.cmpd_attr.values,    n - 1);
248                         break;
249                 }
250         }
251 }
252
253 void add_compound_ent_value(ir_entity *ent, ir_node *val, ir_entity *member)
254 {
255         compound_graph_path *path;
256         ir_type *owner_tp = get_entity_owner(member);
257         assert(is_compound_entity(ent));
258         allocate_values(ent);
259         path = new_compound_graph_path(get_entity_type(ent), 1);
260         path->list[0].node = member;
261         if (is_Array_type(owner_tp)) {
262                 long max;
263                 size_t i, n;
264
265                 assert(get_array_n_dimensions(owner_tp) == 1 && has_array_lower_bound(owner_tp, 0));
266                 max = get_array_lower_bound_int(owner_tp, 0) -1;
267                 for (i = 0, n = get_compound_ent_n_values(ent); i < n; ++i) {
268                         long index = get_compound_graph_path_array_index(get_compound_ent_value_path(ent, i), 0);
269                         if (index > max) {
270                                 max = index;
271                         }
272                 }
273                 path->list[0].index = max + 1;
274         }
275         add_compound_ent_value_w_path(ent, val, path);
276 }
277
278 ir_entity *get_compound_ent_value_member(const ir_entity *ent, size_t pos)
279 {
280         compound_graph_path *path;
281         assert(is_compound_entity(ent));
282         path = get_compound_ent_value_path(ent, pos);
283
284         return get_compound_graph_path_node(path, get_compound_graph_path_length(path)-1);
285 }
286
287 void set_compound_ent_value(ir_entity *ent, ir_node *val, ir_entity *member,
288                             size_t pos)
289 {
290         compound_graph_path *path;
291         assert(is_compound_entity(ent));
292         path = get_compound_ent_value_path(ent, pos);
293         set_compound_graph_path_node(path, 0, member);
294         set_compound_ent_value_w_path(ent, val, path, pos);
295 }
296
297 void set_array_entity_values(ir_entity *ent, ir_tarval **values, size_t num_vals)
298 {
299         size_t i;
300         ir_type  *arrtp = get_entity_type(ent);
301         ir_node  *val;
302         ir_graph *irg = get_const_code_irg();
303
304         assert(is_Array_type(arrtp));
305         assert(get_array_n_dimensions(arrtp) == 1);
306         /* One bound is sufficient, the number of constant fields makes the
307            size. */
308         assert(get_array_lower_bound (arrtp, 0) || get_array_upper_bound (arrtp, 0));
309
310         for (i = 0; i < num_vals; i++) {
311                 val = new_r_Const(irg, values[i]);
312                 add_compound_ent_value(ent, val, get_array_element_entity(arrtp));
313                 set_compound_graph_path_array_index(get_compound_ent_value_path(ent, i), 0, i);
314         }
315 }
316
317 unsigned get_compound_ent_value_offset_bytes(const ir_entity *ent, size_t pos)
318 {
319         compound_graph_path *path;
320         size_t path_len, i;
321         unsigned offset = 0;
322         ir_type *curr_tp;
323
324         assert(get_type_state(get_entity_type(ent)) == layout_fixed);
325
326         path     = get_compound_ent_value_path(ent, pos);
327         path_len = get_compound_graph_path_length(path);
328         curr_tp  = path->tp;
329
330         for (i = 0; i < path_len; ++i) {
331                 if (is_Array_type(curr_tp)) {
332                         ir_type *elem_type = get_array_element_type(curr_tp);
333                         unsigned size      = get_type_size_bytes(elem_type);
334                         unsigned align     = get_type_alignment_bytes(elem_type);
335                         size_t   idx;
336
337                         assert(size > 0);
338                         if (size % align > 0) {
339                                 size += align - (size % align);
340                         }
341                         idx = get_compound_graph_path_array_index(path, i);
342                         assert(idx != (size_t)-1);
343                         offset += size * idx;
344                         curr_tp = elem_type;
345                 } else {
346                         ir_entity *node = get_compound_graph_path_node(path, i);
347                         offset += get_entity_offset(node);
348                         curr_tp = get_entity_type(node);
349                 }
350         }
351
352         return offset;
353 }
354
355 unsigned get_compound_ent_value_offset_bit_remainder(const ir_entity *ent,
356                                                      size_t pos)
357 {
358         compound_graph_path *path;
359         size_t path_len;
360         ir_entity *last_node;
361
362         assert(get_type_state(get_entity_type(ent)) == layout_fixed);
363
364         path      = get_compound_ent_value_path(ent, pos);
365         path_len  = get_compound_graph_path_length(path);
366         last_node = get_compound_graph_path_node(path, path_len - 1);
367
368         if (last_node == NULL)
369                 return 0;
370
371         return get_entity_offset_bits_remainder(last_node);
372 }
373
374 size_t get_compound_ent_n_values(const ir_entity *ent)
375 {
376         assert(ent->initializer == NULL);
377         assert(is_compound_entity(ent));
378         allocate_values((ir_entity*) ent);
379         return ARR_LEN(ent->attr.cmpd_attr.values);
380 }
381
382 ir_node *get_compound_ent_value(const ir_entity *ent, size_t pos)
383 {
384         assert(is_compound_entity(ent));
385         assert(ent->initializer == NULL);
386         assert(pos < ARR_LEN(ent->attr.cmpd_attr.values));
387         return skip_Id(ent->attr.cmpd_attr.values[pos]);
388 }
389
390 int entity_has_compound_ent_values(const ir_entity *entity)
391 {
392         if (!is_compound_entity(entity))
393                 return 0;
394
395         return entity->attr.cmpd_attr.values != NULL;
396 }