make firm compilable with a c++ compiler
[libfirm] / ir / tr / compound_path.c
1 /*
2  * Copyright (C) 1995-2008 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 <assert.h>
29
30 #include "firm_types.h"
31 #include "typerep.h"
32 #include "compound_path_t.h"
33 #include "xmalloc.h"
34 #include "type_t.h"
35 #include "entity_t.h"
36 #include "irgraph_t.h"
37 #include "ircons.h"
38
39 compound_graph_path *new_compound_graph_path(ir_type *tp, int length)
40 {
41         compound_graph_path *res;
42
43         assert(is_compound_type(tp) || is_Array_type(tp));
44         assert(length > 0);
45
46         res = (compound_graph_path*)xmalloc(sizeof(*res) + (length-1) * sizeof(res->list[0]));
47         memset(res, 0, sizeof(*res) + (length-1) * sizeof(res->list[0]));
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, int pos)
68 {
69         int 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 int 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, int pos)
95 {
96         assert(gr && is_compound_graph_path(gr));
97         assert(pos >= 0 && pos < gr->len);
98         return gr->list[pos].node;
99 }
100
101 void set_compound_graph_path_node(compound_graph_path *gr, int pos,
102                                   ir_entity *node)
103 {
104         assert(gr && is_compound_graph_path(gr));
105         assert(pos >= 0 && pos < gr->len);
106         assert(is_entity(node));
107         gr->list[pos].node = node;
108         assert(is_proper_compound_graph_path(gr, pos));
109 }
110
111 int get_compound_graph_path_array_index(const compound_graph_path *gr, int pos)
112 {
113         assert(gr && is_compound_graph_path(gr));
114         assert(pos >= 0 && pos < gr->len);
115         return gr->list[pos].index;
116 }
117
118 void set_compound_graph_path_array_index(compound_graph_path *gr, int pos,
119                                          int index)
120 {
121         assert(gr && is_compound_graph_path(gr));
122         assert(pos >= 0 && pos < gr->len);
123         gr->list[pos].index = index;
124 }
125
126 ir_type *get_compound_graph_path_type(const compound_graph_path *gr)
127 {
128         assert(gr && is_compound_graph_path(gr));
129         return gr->tp;
130 }
131
132 static void allocate_values(ir_entity *ent)
133 {
134         if (ent->attr.cmpd_attr.values == NULL) {
135                 ent->attr.cmpd_attr.values = NEW_ARR_F(ir_node*, 0);
136                 assert(ent->attr.cmpd_attr.val_paths == NULL);
137                 ent->attr.cmpd_attr.val_paths = NEW_ARR_F(compound_graph_path*, 0);
138         }
139 }
140
141 void add_compound_ent_value_w_path(ir_entity *ent, ir_node *val,
142                                    compound_graph_path *path)
143 {
144         assert(is_compound_entity(ent));
145         assert(is_compound_graph_path(path));
146         allocate_values(ent);
147         ARR_APP1(ir_node *, ent->attr.cmpd_attr.values, val);
148         ARR_APP1(compound_graph_path *, ent->attr.cmpd_attr.val_paths, path);
149 }
150
151 void set_compound_ent_value_w_path(ir_entity *ent, ir_node *val,
152                                    compound_graph_path *path, int pos)
153 {
154         assert(is_compound_entity(ent));
155         assert(is_compound_graph_path(path));
156         assert(0 <= pos && pos < ARR_LEN(ent->attr.cmpd_attr.values));
157         ent->attr.cmpd_attr.values[pos]    = val;
158         ent->attr.cmpd_attr.val_paths[pos] = path;
159 }
160
161 compound_graph_path *get_compound_ent_value_path(const ir_entity *ent, int pos)
162 {
163         assert(is_compound_entity(ent));
164         assert(ent->initializer == NULL);
165         assert(0 <= pos && pos < ARR_LEN(ent->attr.cmpd_attr.val_paths));
166         return ent->attr.cmpd_attr.val_paths[pos];
167 }
168
169 /**
170  * Returns non-zero, if two compound_graph_pathes are equal
171  *
172  * @param path1            the first path
173  * @param path2            the second path
174  */
175 static int equal_paths(compound_graph_path *path1, compound_graph_path *path2)
176 {
177         int i;
178         int len1 = get_compound_graph_path_length(path1);
179         int len2 = get_compound_graph_path_length(path2);
180
181         if (len2 != len1) return 0;
182
183         for (i = 0; i < len1; i++) {
184                 ir_type *tp;
185                 ir_entity *node1 = get_compound_graph_path_node(path1, i);
186                 ir_entity *node2 = get_compound_graph_path_node(path2, i);
187
188                 if (node1 != node2) return 0;
189
190                 tp = get_entity_owner(node1);
191                 if (is_Array_type(tp)) {
192                         int index1 = get_compound_graph_path_array_index(path1, i);
193                         int index2 = get_compound_graph_path_array_index(path2, i);
194                         if (index1 != index2)
195                                 return 0;
196                 }
197         }
198         return 1;
199 }
200
201 /**
202  * Returns the position of a value with the given path.
203  * The path must contain array indices for all array element entities.
204  *
205  * @todo  This implementation is very slow (O(number of initializers * |path|)
206  *        and should be replaced when the new tree oriented
207  *        value representation is finally implemented.
208  */
209 static int get_compound_ent_pos_by_path(const ir_entity *ent,
210                                         compound_graph_path *path)
211 {
212         int i, n_paths = get_compound_ent_n_values(ent);
213
214         for (i = 0; i < n_paths; i ++) {
215                 compound_graph_path *gr = get_compound_ent_value_path(ent, i);
216                 if (equal_paths(gr, path))
217                         return i;
218         }
219         return -1;
220 }
221
222 ir_node *get_compound_ent_value_by_path(const ir_entity *ent,
223                                         compound_graph_path *path)
224 {
225         int pos = get_compound_ent_pos_by_path(ent, path);
226         if (pos >= 0)
227                 return get_compound_ent_value(ent, pos);
228         return NULL;
229 }
230
231 void remove_compound_ent_value(ir_entity *ent, ir_entity *value_ent)
232 {
233         int i, n;
234         assert(is_compound_entity(ent));
235
236         n = ARR_LEN(ent->attr.cmpd_attr.val_paths);
237         for (i = 0; i < n; ++i) {
238                 compound_graph_path *path = ent->attr.cmpd_attr.val_paths[i];
239                 if (path->list[path->len-1].node == value_ent) {
240                         for (; i < n - 1; ++i) {
241                                 ent->attr.cmpd_attr.val_paths[i] = ent->attr.cmpd_attr.val_paths[i+1];
242                                 ent->attr.cmpd_attr.values[i]    = ent->attr.cmpd_attr.values[i+1];
243                         }
244                         ARR_SETLEN(compound_graph_path*, ent->attr.cmpd_attr.val_paths, n - 1);
245                         ARR_SETLEN(ir_node*,             ent->attr.cmpd_attr.values,    n - 1);
246                         break;
247                 }
248         }
249 }
250
251 void add_compound_ent_value(ir_entity *ent, ir_node *val, ir_entity *member)
252 {
253         compound_graph_path *path;
254         ir_type *owner_tp = get_entity_owner(member);
255         assert(is_compound_entity(ent));
256         allocate_values(ent);
257         path = new_compound_graph_path(get_entity_type(ent), 1);
258         path->list[0].node = member;
259         if (is_Array_type(owner_tp)) {
260                 int max;
261                 int i, n;
262
263                 assert(get_array_n_dimensions(owner_tp) == 1 && has_array_lower_bound(owner_tp, 0));
264                 max = get_array_lower_bound_int(owner_tp, 0) -1;
265                 for (i = 0, n = get_compound_ent_n_values(ent); i < n; ++i) {
266                         int index = get_compound_graph_path_array_index(get_compound_ent_value_path(ent, i), 0);
267                         if (index > max) {
268                                 max = index;
269                         }
270                 }
271                 path->list[0].index = max + 1;
272         }
273         add_compound_ent_value_w_path(ent, val, path);
274 }
275
276 ir_entity *get_compound_ent_value_member(const ir_entity *ent, int pos)
277 {
278         compound_graph_path *path;
279         assert(is_compound_entity(ent));
280         path = get_compound_ent_value_path(ent, pos);
281
282         return get_compound_graph_path_node(path, get_compound_graph_path_length(path)-1);
283 }
284
285 void set_compound_ent_value(ir_entity *ent, ir_node *val, ir_entity *member,
286                             int pos)
287 {
288         compound_graph_path *path;
289         assert(is_compound_entity(ent));
290         path = get_compound_ent_value_path(ent, pos);
291         set_compound_graph_path_node(path, 0, member);
292         set_compound_ent_value_w_path(ent, val, path, pos);
293 }
294
295 void set_array_entity_values(ir_entity *ent, ir_tarval **values, int num_vals)
296 {
297         int i;
298         ir_type  *arrtp = get_entity_type(ent);
299         ir_node  *val;
300         ir_graph *irg = get_const_code_irg();
301
302         assert(is_Array_type(arrtp));
303         assert(get_array_n_dimensions(arrtp) == 1);
304         /* One bound is sufficient, the number of constant fields makes the
305            size. */
306         assert(get_array_lower_bound (arrtp, 0) || get_array_upper_bound (arrtp, 0));
307
308         for (i = 0; i < num_vals; i++) {
309                 val = new_r_Const(irg, values[i]);
310                 add_compound_ent_value(ent, val, get_array_element_entity(arrtp));
311                 set_compound_graph_path_array_index(get_compound_ent_value_path(ent, i), 0, i);
312         }
313 }
314
315 unsigned get_compound_ent_value_offset_bytes(const ir_entity *ent, int pos)
316 {
317         compound_graph_path *path;
318         int path_len, i;
319         unsigned offset = 0;
320         ir_type *curr_tp;
321
322         assert(get_type_state(get_entity_type(ent)) == layout_fixed);
323
324         path     = get_compound_ent_value_path(ent, pos);
325         path_len = get_compound_graph_path_length(path);
326         curr_tp  = path->tp;
327
328         for (i = 0; i < path_len; ++i) {
329                 if (is_Array_type(curr_tp)) {
330                         ir_type *elem_type = get_array_element_type(curr_tp);
331                         unsigned size      = get_type_size_bytes(elem_type);
332                         unsigned align     = get_type_alignment_bytes(elem_type);
333                         int      idx;
334
335                         assert(size > 0);
336                         if (size % align > 0) {
337                                 size += align - (size % align);
338                         }
339                         idx = get_compound_graph_path_array_index(path, i);
340                         assert(idx >= 0);
341                         offset += size * idx;
342                         curr_tp = elem_type;
343                 } else {
344                         ir_entity *node = get_compound_graph_path_node(path, i);
345                         offset += get_entity_offset(node);
346                         curr_tp = get_entity_type(node);
347                 }
348         }
349
350         return offset;
351 }
352
353 unsigned get_compound_ent_value_offset_bit_remainder(const ir_entity *ent,
354                                                      int pos)
355 {
356         compound_graph_path *path;
357         int path_len;
358         ir_entity *last_node;
359
360         assert(get_type_state(get_entity_type(ent)) == layout_fixed);
361
362         path      = get_compound_ent_value_path(ent, pos);
363         path_len  = get_compound_graph_path_length(path);
364         last_node = get_compound_graph_path_node(path, path_len - 1);
365
366         if (last_node == NULL)
367                 return 0;
368
369         return get_entity_offset_bits_remainder(last_node);
370 }
371
372 int get_compound_ent_n_values(const ir_entity *ent)
373 {
374         assert(ent->initializer == NULL);
375         assert(is_compound_entity(ent));
376         allocate_values((ir_entity*) ent);
377         return ARR_LEN(ent->attr.cmpd_attr.values);
378 }
379
380 ir_node *get_compound_ent_value(const ir_entity *ent, int pos)
381 {
382         assert(is_compound_entity(ent));
383         assert(ent->initializer == NULL);
384         assert(0 <= pos && pos < ARR_LEN(ent->attr.cmpd_attr.values));
385         return skip_Id(ent->attr.cmpd_attr.values[pos]);
386 }
387
388 int entity_has_compound_ent_values(const ir_entity *entity)
389 {
390         if (!is_compound_entity(entity))
391                 return 0;
392
393         return entity->attr.cmpd_attr.values != NULL;
394 }