add missing FP_USED()
[libfirm] / ir / be / ia32 / ia32_gen_decls.c
1 /**
2  * Dumps global variables and constants as ia32 assembler.
3  * @author Christian Wuerdig
4  * @date 04.11.2005
5  * @version $Id$
6  */
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <assert.h>
12
13 #include "obst.h"
14 #include "tv.h"
15 #include "irnode.h"
16 #include "entity.h"
17 #include "irprog.h"
18
19 #include "ia32_gen_decls.h"
20
21 /************************************************************************/
22
23 /*
24  * returns the highest bit value
25  */
26 static unsigned highest_bit(unsigned v)
27 {
28         int res = -1;
29
30         if (v >= (1U << 16U)) {
31                 res += 16;
32                 v >>= 16;
33         }
34         if (v >= (1U << 8U)) {
35                 res += 8;
36                 v >>= 8;
37         }
38         if (v >= (1U << 4U)) {
39                 res += 4;
40                 v >>= 4;
41         }
42         if (v >= (1U << 2U)) {
43                 res += 2;
44                 v >>= 2;
45         }
46         if (v >= (1U << 1U)) {
47                 res += 1;
48                 v >>= 1;
49         }
50         if (v >= 1)
51                 res += 1;
52
53         return res;
54 }
55
56 /*
57  * output the alignment
58  */
59 static void ia32_dump_align(struct obstack *obst, int align)
60 {
61         int h = highest_bit(align);
62
63         if ((1 << h) < align)
64                 ++h;
65         align = (1 << h);
66
67         if (align > 1)
68                 obstack_printf(obst, "\t.align %d\n", align);
69 }
70
71 static void dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
72 {
73         switch (bytes) {
74
75         case 1:
76                 obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0));
77                 break;
78
79         case 2:
80                 obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
81                 break;
82
83         case 4:
84                 obstack_printf(obst, "0x%02x%02x%02x%02x",
85                         get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
86                 break;
87
88         case 8:
89                 obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
90                         get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4),
91                         get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
92                 break;
93
94         case 10:
95         case 12:
96                 break;
97
98         default:
99                 fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
100                 assert(0);
101         }
102 }
103
104 /*
105  * dump an atomic value
106  */
107 static void do_dump_atomic_init(struct obstack *obst, ir_node *init)
108 {
109         ir_mode *mode = get_irn_mode(init);
110         int bytes     = get_mode_size_bytes(mode);
111         tarval *tv;
112
113         switch (get_irn_opcode(init)) {
114
115         case iro_Cast:
116                 do_dump_atomic_init(obst, get_Cast_op(init));
117                 return;
118
119         case iro_Conv:
120                 do_dump_atomic_init(obst, get_Conv_op(init));
121                 return;
122
123         case iro_Const:
124                 tv = get_Const_tarval(init);
125
126                 /* beware of old stuff */
127                 assert(! mode_is_reference(mode));
128
129                 /* it's a arithmetic value */
130                 dump_arith_tarval(obst, tv, bytes);
131                 return;
132
133         case iro_SymConst:
134                 switch (get_SymConst_kind(init)) {
135                 case symconst_addr_name:
136                         obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init)));
137                         break;
138
139                 case symconst_addr_ent:
140                         obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init)));
141                         break;
142
143                 case symconst_size:
144                         obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init)));
145                         break;
146
147                 default:
148                         assert(0 && "dump_atomic_init(): don't know how to init from this SymConst");
149                 }
150                 return;
151
152                 case iro_Add:
153                         do_dump_atomic_init(obst, get_Add_left(init));
154                         obstack_printf(obst, " + ");
155                         do_dump_atomic_init(obst, get_Add_right(init));
156                         return;
157
158                 case iro_Sub:
159                         do_dump_atomic_init(obst, get_Sub_left(init));
160                         obstack_printf(obst, " - ");
161                         do_dump_atomic_init(obst, get_Sub_right(init));
162                         return;
163
164                 case iro_Mul:
165                         do_dump_atomic_init(obst, get_Mul_left(init));
166                         obstack_printf(obst, " * ");
167                         do_dump_atomic_init(obst, get_Mul_right(init));
168                         return;
169
170                 default:
171                         assert(0 && "dump_atomic_init(): unknown IR-node");
172         }
173 }
174
175 /*
176  * dump an atomic value
177  */
178 static void dump_atomic_init(struct obstack *obst, ir_node *init)
179 {
180         ir_mode *mode = get_irn_mode(init);
181         int bytes     = get_mode_size_bytes(mode);
182
183         switch (bytes) {
184
185         case 1:
186                 obstack_printf(obst, "\t.byte\t");
187                 break;
188
189         case 2:
190                 obstack_printf(obst, "\t.value\t");
191                 break;
192
193         case 4:
194                 obstack_printf(obst, "\t.long\t");
195                 break;
196
197         case 8:
198                 obstack_printf(obst, "\t.quad\t");
199                 break;
200
201         case 10:
202         case 12:
203                 /* handled in arith */
204                 break;
205
206         default:
207                 fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
208                 assert(0);
209         }
210
211         do_dump_atomic_init(obst, init);
212         obstack_printf(obst, "\n");
213 }
214
215 /************************************************************************/
216 /* Routines to dump global variables                                    */
217 /************************************************************************/
218
219 /**
220  * Determine if an entity is a string constant
221  * @param ent The entity
222  * @return 1 if it is a string constant, 0 otherwise
223  */
224 static int ent_is_string_const(entity *ent)
225 {
226         int res = 0;
227         ir_type *ty;
228
229         ty = get_entity_type(ent);
230
231         /* if it's an array */
232         if (is_Array_type(ty)) {
233                 ir_type *elm_ty = get_array_element_type(ty);
234
235                 /* and the array's element type is primitive */
236                 if (is_Primitive_type(elm_ty)) {
237                         ir_mode *mode = get_type_mode(elm_ty);
238
239                         /*
240                         * and the mode of the element type is an int of
241                         * the same size as the byte mode
242                         */
243                         if (mode_is_int(mode)
244                                 && get_mode_size_bits(mode) == get_mode_size_bits(mode_Bs))
245                         {
246                                 int i, c, n;
247
248                                 n = get_compound_ent_n_values(ent);
249                                 for (i = 0; i < n; ++i) {
250                                         ir_node *irn = get_compound_ent_value(ent, i);
251                                         if(get_irn_opcode(irn) != iro_Const)
252                                                 return 0;
253
254                                         c = (int) get_tarval_long(get_Const_tarval(irn));
255
256                                         if((i < n - 1 && !(isgraph(c) || isspace(c)))
257                                                 || (i == n - 1 && c != '\0'))
258                                                 return 0;
259                                 }
260
261                                 res = 1;
262                         }
263                 }
264         }
265
266         return res;
267 }
268
269 /**
270  * Dump a atring constant.
271  * No checks are made!!
272  * @param obst The obst to dump on.
273  * @param ent The entity to dump.
274  */
275 static void dump_string_cst(struct obstack *obst, entity *ent)
276 {
277         int i, n;
278
279         obstack_printf(obst, "\t.string \"");
280         n = get_compound_ent_n_values(ent);
281
282         for (i = 0; i < n-1; ++i) {
283                 ir_node *irn;
284                 int c;
285
286                 irn = get_compound_ent_value(ent, i);
287                 c = (int) get_tarval_long(get_Const_tarval(irn));
288
289                 switch (c) {
290                 case '"' : obstack_printf(obst, "\\\""); break;
291                 case '\n': obstack_printf(obst, "\\n"); break;
292                 case '\r': obstack_printf(obst, "\\r"); break;
293                 case '\t': obstack_printf(obst, "\\t"); break;
294                 default  :
295                         if (isprint(c))
296                                 obstack_printf(obst, "%c", c);
297                         else
298                                 obstack_printf(obst, "%O", c);
299                         break;
300                 }
301         }
302         obstack_printf(obst, "\"\n");
303 }
304
305 struct arr_info {
306         int n_elems;
307         int visit_cnt;
308         int size;
309 };
310
311 static void dump_object_size(struct obstack *obst, const char *name, int size) {
312         obstack_printf(obst, "\t.type\t%s,@object\n", name);
313         obstack_printf(obst, "\t.size\t%s,%d\n", name, size);
314 }
315
316 /*
317  * Dumps the initialization of global variables that are not
318  * "uninitialized".
319  */
320 static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack, entity *ent)
321 {
322         ir_type *ty         = get_entity_type(ent);
323         const char *ld_name = get_entity_ld_name(ent);
324         int align, h;
325         struct obstack *obst = data_obstack;
326
327         /*
328         * FIXME: did NOT work for partly constant values
329         */
330         if (! is_Method_type(ty)) {
331                 ent_variability variability = get_entity_variability(ent);
332                 visibility visibility = get_entity_visibility(ent);
333
334                 if (variability == variability_constant) {
335                         /* a constant entity, put it on the rdata */
336                         obst = rdata_obstack;
337                 }
338
339                 /* check, whether it is initialized, if yes create data */
340                 if (variability != variability_uninitialized) {
341                         if (visibility == visibility_external_visible) {
342                                 obstack_printf(obst, ".globl\t%s\n", ld_name);
343                         }
344                         dump_object_size(obst, ld_name, (get_type_size_bits(ty) + 7) >> 3);
345
346                         align = get_type_alignment_bytes(ty);
347                         ia32_dump_align(obst, align);
348
349                         obstack_printf(obst, "%s:\n", ld_name);
350
351                         if (is_atomic_type(ty)) {
352                                 if (get_entity_visibility(ent) != visibility_external_allocated)
353                                         dump_atomic_init(obst, get_atomic_ent_value(ent));
354                         }
355                         else {
356                                 int i, size = 0;
357
358                                 if (ent_is_string_const(ent)) {
359                                         dump_string_cst(obst, ent);
360                                 }
361                                 else if (is_Array_type(ty)) {
362                                         int filler;
363
364                                         /* potential spare values should be already included! */
365                                         for (i = 0; i < get_compound_ent_n_values(ent); ++i) {
366                                                 entity *step = get_compound_ent_value_member(ent, i);
367                                                 ir_type *stype = get_entity_type(step);
368
369                                                 if (get_type_mode(stype)) {
370                                                         int align = (get_type_alignment_bits(stype) + 7) >> 3;
371                                                         int n     = size % align;
372
373                                                         if (n > 0) {
374                                                                 obstack_printf(obst, "\t.zero\t%d\n", align - n);
375                                                                 size += align - n;
376                                                         }
377                                                 }
378                                                 dump_atomic_init(obst, get_compound_ent_value(ent, i));
379                                                 size += get_type_size_bytes(stype);
380                                         }
381                                         filler = get_type_size_bytes(ty) - size;
382
383                                         if (filler > 0)
384                                                 obstack_printf(obst, "\t.zero\t%d\n", filler);
385                                 }
386                                 else if (is_compound_type(ty)) {
387                                         ir_node **vals;
388                                         int type_size, j;
389
390                                         /* Compound entities are NOT sorted.
391                                         * The sorting strategy used doesn't work for `value' compound fields nor
392                                         * for partially_constant entities.
393                                         */
394
395                                         /*
396                                         * in the worst case, every entity allocates one byte, so the type
397                                         * size should be equal or bigger the number of fields
398                                         */
399                                         type_size = get_type_size_bytes(ty);
400                                         vals      = xcalloc(type_size, sizeof(*vals));
401
402                                         /* collect the values and store them at the offsets */
403                                         for(i = 0; i < get_compound_ent_n_values(ent); ++i) {
404                                                 int                 graph_length, aipos, offset;
405                                                 struct arr_info     *ai;
406                                                 int                 all_n = 1;
407                                                 compound_graph_path *path = get_compound_ent_value_path(ent, i);
408
409                                                 /* get the access path to the costant value */
410                                                 graph_length = get_compound_graph_path_length(path);
411                                                 ai = xcalloc(graph_length, sizeof(struct arr_info));
412
413                                                 /* We wanna know how many arrays are on the path to the entity. We also have to know how
414                                                 * many elements each array holds to calculate the offset for the entity. */
415                                                 for (j = 0; j < graph_length; j++) {
416                                                         entity  *step      = get_compound_graph_path_node(path, j);
417                                                         ir_type *step_type = get_entity_type(step);
418                                                         int     ty_size    = (get_type_size_bits(step_type) + 7) >> 3;
419                                                         int     k, n       = 0;
420
421                                                         if (is_Array_type(step_type))
422                                                                 for (k = 0; k < get_array_n_dimensions(step_type); k++)
423                                                                         n += get_tarval_long(get_Const_tarval(get_array_upper_bound(step_type, k)));
424                                                                 if (n) all_n *= n;
425                                                                 ai[j].n_elems = n ? all_n + 1 : 0;
426                                                                 ai[j].visit_cnt = 0;
427                                                                 ai[j].size = ty_size;
428                                                 }
429
430                                                 aipos = graph_length - 1;
431                                                 if (aipos) aipos--;
432
433                                                 for (offset = j = 0; j < graph_length; j++) {
434                                                         entity *step       = get_compound_graph_path_node(path, j);
435                                                         ir_type *step_type = get_entity_type(step);
436                                                         int ent_ofs        = get_entity_offset_bytes(step);
437                                                         int stepsize       = 0;
438
439                                                         /* add all positive offsets (= offsets in structs) */
440                                                         if (ent_ofs >= 0) offset += ent_ofs;
441
442                                                         if (j == graph_length - 1) {
443                                                                 stepsize = (get_type_size_bits(step_type) + 7) >> 3;
444
445                                                                 /* Search the next free position in vals depending on the information from above (ai). */
446                                                                 while (vals[offset]) {
447                                                                         if (ai[aipos].visit_cnt < ai[aipos].n_elems) {
448                                                                                 offset += stepsize;
449                                                                                 ai[aipos].visit_cnt++;
450                                                                         }
451                                                                         else
452                                                                                 while (aipos >= 0 && ai[aipos].visit_cnt == ai[aipos].n_elems) {
453                                                                                         stepsize = ai[aipos--].size;
454                                                                                         offset  += stepsize;
455                                                                                 }
456                                                                 }
457
458                                                                 assert(aipos >= 0 && "couldn't store entity");
459                                                                 vals[offset] = get_compound_ent_value(ent, i);
460                                                         }
461                                                 }
462
463                                                 free(ai);
464                                         }
465
466                                         /* now write them sorted */
467                                         for(i = 0; i < type_size; ) {
468                                                 if (vals[i]) {
469                                                         dump_atomic_init(obst, vals[i]);
470                                                         i += (get_mode_size_bytes(get_irn_mode(vals[i])));
471                                                 }
472                                                 else {
473                                                         /* a gap */
474                                                         obstack_printf(obst, "\t.byte\t0\n");
475                                                         ++i;
476                                                 }
477                                         }
478                                         free(vals);
479                                 }
480                                 else {
481                                         assert(0 && "unsupported type");
482                                 }
483                         }
484                         obstack_printf(obst, "\n");
485                 }
486                 else if (visibility != visibility_external_allocated) {
487                         if (visibility == visibility_local) {
488                                 obstack_printf(comm_obstack, "\t.local\t%s\n", ld_name);
489                         }
490
491                         /* calculate the alignment */
492                         align = get_type_alignment_bytes(ty);
493                         h = highest_bit(align);
494
495                         if ((1 << h) < align)
496                                 ++h;
497                         align = (1 << h);
498
499                         if (align < 1)
500                                 align = 1;
501
502                         obstack_printf(comm_obstack, "\t.comm\t%s,%d,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3, align);
503                 }
504         }
505 }
506
507 /*
508  * Dumps declarations of global variables and the initialization code.
509  */
510 void ia32_dump_globals(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack)
511 {
512         ir_type *gt = get_glob_type();
513         int i, n = get_class_n_members(gt);
514
515         for (i = 0; i < n; i++)
516                 dump_global(rdata_obstack, data_obstack, comm_obstack, get_class_member(gt, i));
517 }
518
519 /************************************************************************/
520
521 void ia32_gen_decls(FILE *out) {
522         struct obstack rodata, data, comm;
523         int    size;
524         char   *cp;
525
526         obstack_init(&rodata);
527         obstack_init(&data);
528         obstack_init(&comm);
529
530         ia32_dump_globals(&rodata, &data, &comm);
531
532         size = obstack_object_size(&data);
533         cp   = obstack_finish(&data);
534         if (size > 0) {
535                 fprintf(out, "\t.data\n");
536                 fwrite(cp, 1, size, out);
537         }
538
539         size = obstack_object_size(&rodata);
540         cp   = obstack_finish(&rodata);
541         if (size > 0) {
542                 fprintf(out, "\t.section\t.rodata\n");
543                 fwrite(cp, 1, size, out);
544         }
545
546         size = obstack_object_size(&comm);
547         cp   = obstack_finish(&comm);
548         if (size > 0) {
549                 fprintf(out, "\t.text\n");
550                 fwrite(cp, 1, size, out);
551         }
552
553         obstack_free(&rodata, NULL);
554         obstack_free(&data, NULL);
555         obstack_free(&comm, NULL);
556 }