reformatted/improved some testapps
[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 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <assert.h>
16
17 #include "obst.h"
18 #include "tv.h"
19 #include "irnode.h"
20 #include "entity.h"
21 #include "irprog.h"
22 #include "error.h"
23
24 #include "../be.h"
25
26 #include "ia32_emitter.h"
27 #include "ia32_gen_decls.h"
28
29 typedef struct obstack obstack_t;
30
31 typedef struct _ia32_decl_env {
32         obstack_t *rodata_obst;
33         obstack_t *data_obst;
34         obstack_t *bss_obst;
35         obstack_t *ctor_obst;
36         const be_main_env_t *main_env;
37 } ia32_decl_env_t;
38
39 /************************************************************************/
40
41 /**
42  * output a tarval
43  */
44 static void dump_arith_tarval(obstack_t *obst, tarval *tv, int bytes)
45 {
46         switch (bytes) {
47
48         case 1:
49                 obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0));
50                 break;
51
52         case 2:
53                 obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
54                 break;
55
56         case 4:
57                 obstack_printf(obst, "0x%02x%02x%02x%02x",
58                         get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
59                 break;
60
61         case 8:
62                 obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
63                         get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4),
64                         get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
65                 break;
66
67         case 10:
68         case 12:
69                 break;
70
71         default:
72                 fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
73                 assert(0);
74         }
75 }
76
77 /**
78  * Return the tarval of an atomic initializer.
79  */
80 static tarval *get_atomic_init_tv(ir_node *init)
81 {
82         for (;;) {
83                 ir_mode *mode = get_irn_mode(init);
84
85                 switch (get_irn_opcode(init)) {
86
87                 case iro_Cast:
88                         init = get_Cast_op(init);
89                         continue;
90
91                 case iro_Conv:
92                         init = get_Conv_op(init);
93                         continue;
94
95                 case iro_Const:
96                         return get_Const_tarval(init);
97
98                 case iro_SymConst:
99                         switch (get_SymConst_kind(init)) {
100                         case symconst_ofs_ent:
101                                 return new_tarval_from_long(get_entity_offset(get_SymConst_entity(init)), mode);
102
103                         case symconst_type_size:
104                                 return new_tarval_from_long(get_type_size_bytes(get_SymConst_type(init)), mode);
105
106                         case symconst_type_align:
107                                 return new_tarval_from_long(get_type_alignment_bytes(get_SymConst_type(init)), mode);
108
109                         case symconst_enum_const:
110                                 return get_enumeration_value(get_SymConst_enum(init));
111
112                         default:
113                                 return NULL;
114                         }
115
116                 default:
117                         return NULL;
118                 }
119         }
120 }
121
122 /**
123  * dump an atomic value
124  */
125 static void do_dump_atomic_init(obstack_t *obst, ir_node *init)
126 {
127         ir_mode *mode = get_irn_mode(init);
128         int bytes     = get_mode_size_bytes(mode);
129         tarval *tv;
130
131         switch (get_irn_opcode(init)) {
132
133         case iro_Cast:
134                 do_dump_atomic_init(obst, get_Cast_op(init));
135                 return;
136
137         case iro_Conv:
138                 do_dump_atomic_init(obst, get_Conv_op(init));
139                 return;
140
141         case iro_Const:
142                 tv = get_Const_tarval(init);
143
144                 /* beware of old stuff */
145                 //assert(! mode_is_reference(mode));
146
147                 /* it's a arithmetic value */
148                 dump_arith_tarval(obst, tv, bytes);
149                 return;
150
151         case iro_SymConst:
152                 switch (get_SymConst_kind(init)) {
153                 case symconst_addr_name:
154                         obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init)));
155                         break;
156
157                 case symconst_addr_ent:
158                         obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init)));
159                         break;
160
161                 case symconst_ofs_ent:
162                         obstack_printf(obst, "%d", get_entity_offset(get_SymConst_entity(init)));
163                         break;
164
165                 case symconst_type_size:
166                         obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init)));
167                         break;
168
169                 case symconst_type_align:
170                         obstack_printf(obst, "%d", get_type_alignment_bytes(get_SymConst_type(init)));
171                         break;
172
173                 case symconst_enum_const:
174                         tv = get_enumeration_value(get_SymConst_enum(init));
175                         dump_arith_tarval(obst, tv, bytes);
176                         break;
177
178                 default:
179                         assert(!"dump_atomic_init(): don't know how to init from this SymConst");
180                 }
181                 return;
182
183                 case iro_Add:
184                         do_dump_atomic_init(obst, get_Add_left(init));
185                         obstack_printf(obst, " + ");
186                         do_dump_atomic_init(obst, get_Add_right(init));
187                         return;
188
189                 case iro_Sub:
190                         do_dump_atomic_init(obst, get_Sub_left(init));
191                         obstack_printf(obst, " - ");
192                         do_dump_atomic_init(obst, get_Sub_right(init));
193                         return;
194
195                 case iro_Mul:
196                         do_dump_atomic_init(obst, get_Mul_left(init));
197                         obstack_printf(obst, " * ");
198                         do_dump_atomic_init(obst, get_Mul_right(init));
199                         return;
200
201                 default:
202                         assert(0 && "dump_atomic_init(): unknown IR-node");
203         }
204 }
205
206 /**
207  * dumps the type for given size (.byte, .long, ...)
208  */
209 static void dump_size_type(obstack_t *obst, int size) {
210         switch (size) {
211
212         case 1:
213                 obstack_printf(obst, "\t.byte\t");
214                 break;
215
216         case 2:
217                 obstack_printf(obst, "\t.value\t");
218                 break;
219
220         case 4:
221                 obstack_printf(obst, "\t.long\t");
222                 break;
223
224         case 8:
225                 obstack_printf(obst, "\t.quad\t");
226                 break;
227
228         case 10:
229         case 12:
230                 /* handled in arith */
231                 break;
232
233         default:
234                 fprintf(stderr, "Try to dump a type with %d bytes\n", size);
235                 assert(0);
236         }
237 }
238
239 /**
240  * dump an atomic value to an obstack
241  */
242 static void dump_atomic_init(obstack_t *obst, ir_node *init)
243 {
244         ir_mode *mode = get_irn_mode(init);
245         int bytes     = get_mode_size_bytes(mode);
246
247         dump_size_type(obst, bytes);
248         do_dump_atomic_init(obst, init);
249         obstack_printf(obst, "\n");
250 }
251
252 /************************************************************************/
253 /* Routines to dump global variables                                    */
254 /************************************************************************/
255
256 /**
257  * Determine if an entity is a string constant
258  * @param ent The entity
259  * @return 1 if it is a string constant, 0 otherwise
260  */
261 static int ent_is_string_const(ir_entity *ent)
262 {
263         int res = 0;
264         ir_type *ty;
265
266         ty = get_entity_type(ent);
267
268         /* if it's an array */
269         if (is_Array_type(ty)) {
270                 ir_type *elm_ty = get_array_element_type(ty);
271
272                 /* and the array's element type is primitive */
273                 if (is_Primitive_type(elm_ty)) {
274                         ir_mode *mode = get_type_mode(elm_ty);
275
276                         /*
277                          * and the mode of the element type is an int of
278                          * the same size as the byte mode
279                          */
280                         if (mode_is_int(mode)
281                                 && get_mode_size_bits(mode) == get_mode_size_bits(mode_Bs))
282                         {
283                                 int i, c, n;
284
285                                 n = get_compound_ent_n_values(ent);
286                                 for (i = 0; i < n; ++i) {
287                                         ir_node *irn = get_compound_ent_value(ent, i);
288                                         if(get_irn_opcode(irn) != iro_Const)
289                                                 return 0;
290
291                                         c = (int) get_tarval_long(get_Const_tarval(irn));
292
293                                         if((i < n - 1 && !(isgraph(c) || isspace(c)))
294                                                 || (i == n - 1 && c != '\0'))
295                                                 return 0;
296                                 }
297
298                                 res = 1;
299                         }
300                 }
301         }
302
303         return res;
304 }
305
306 /**
307  * Dump a string constant.
308  * No checks are made!!
309  * @param obst The obst to dump on.
310  * @param ent The entity to dump.
311  */
312 static void dump_string_cst(obstack_t *obst, ir_entity *ent)
313 {
314         int i, n;
315
316         obstack_printf(obst, "\t.string \"");
317         n = get_compound_ent_n_values(ent);
318
319         for (i = 0; i < n-1; ++i) {
320                 ir_node *irn;
321                 int c;
322
323                 irn = get_compound_ent_value(ent, i);
324                 c = (int) get_tarval_long(get_Const_tarval(irn));
325
326                 switch (c) {
327                 case '"' : obstack_printf(obst, "\\\""); break;
328                 case '\n': obstack_printf(obst, "\\n"); break;
329                 case '\r': obstack_printf(obst, "\\r"); break;
330                 case '\t': obstack_printf(obst, "\\t"); break;
331                 case '\\': obstack_printf(obst, "\\\\"); break;
332                 default  :
333                         if (isprint(c))
334                                 obstack_printf(obst, "%c", c);
335                         else
336                                 obstack_printf(obst, "\\%o", c);
337                         break;
338                 }
339         }
340         obstack_printf(obst, "\"\n");
341 }
342
343 static void dump_array_init(obstack_t *obst, ir_entity *ent)
344 {
345         const ir_type *ty = get_entity_type(ent);
346         int i;
347         int filler;
348         int size = 0;
349
350         /* potential spare values should be already included! */
351         for (i = 0; i < get_compound_ent_n_values(ent); ++i) {
352                 ir_entity *step = get_compound_ent_value_member(ent, i);
353                 ir_type *stype = get_entity_type(step);
354
355                 if (get_type_mode(stype)) {
356                         int align = (get_type_alignment_bits(stype) + 7) >> 3;
357                         int n     = size % align;
358
359                         if (n > 0) {
360                                 obstack_printf(obst, "\t.zero\t%d\n", align - n);
361                                 size += align - n;
362                         }
363                 }
364                 dump_atomic_init(obst, get_compound_ent_value(ent, i));
365                 size += get_type_size_bytes(stype);
366         }
367         filler = get_type_size_bytes(ty) - size;
368
369         if (filler > 0)
370                 obstack_printf(obst, "\t.skip\t%d\n", filler);
371 }
372
373 enum normal_or_bitfield_kind {
374         NORMAL = 0,
375         BITFIELD
376 };
377
378 typedef struct {
379         enum normal_or_bitfield_kind kind;
380         union {
381                 ir_node *value;
382                 unsigned char bf_val;
383         } v;
384 } normal_or_bitfield;
385
386 /**
387  * Dump an initializer for a compound entity.
388  */
389 static void dump_compound_init(obstack_t *obst, ir_entity *ent)
390 {
391         normal_or_bitfield *vals;
392         int i, j, n = get_compound_ent_n_values(ent);
393         int last_ofs;
394
395         /* Find the initializer size. Sorrily gcc support a nasty feature:
396            The last filed of a compound may be a flexible array. This allows
397            initializers bigger than the type size. */
398         last_ofs = 0;
399         for (i = 0; i < n; ++i) {
400                 int offset = get_compound_ent_value_offset_bytes(ent, i);
401                 int bits_remainder = get_compound_ent_value_offset_bit_remainder(ent, i);
402                 const compound_graph_path *path = get_compound_ent_value_path(ent, i);
403                 int path_len = get_compound_graph_path_length(path);
404                 ir_entity *last_ent = get_compound_graph_path_node(path, path_len - 1);
405                 int value_len = get_type_size_bits(get_entity_type(last_ent));
406
407                 offset += (value_len + bits_remainder + 7) >> 3;
408
409                 if (offset > last_ofs) {
410                         last_ofs = offset;
411                 }
412         }
413
414         /*
415          * In the worst case, every initializer allocates one byte.
416          * Moreover, initializer might be big, do not allocate an stack.
417          */
418         vals = xcalloc(last_ofs, sizeof(vals[0]));
419
420         /* collect the values and store them at the offsets */
421         for (i = 0; i < n; ++i) {
422                 const compound_graph_path *path = get_compound_ent_value_path(ent, i);
423                 int path_len = get_compound_graph_path_length(path);
424                 int offset = get_compound_ent_value_offset_bytes(ent, i);
425                 int offset_bits = get_compound_ent_value_offset_bit_remainder(ent, i);
426                 ir_node *value = get_compound_ent_value(ent, i);
427                 ir_entity *last_ent = get_compound_graph_path_node(path, path_len - 1);
428                 int value_len = get_type_size_bits(get_entity_type(last_ent));
429                 assert(offset >= 0);
430                 assert(offset_bits >= 0);
431
432                 if (offset_bits != 0 || value_len % 8 != 0) {
433                         tarval *shift, *shifted;
434                         tarval *tv = get_atomic_init_tv(value);
435                         if (tv == NULL) {
436                                 panic("Couldn't get numeric value for bitfield initializer '%s'\n",
437                                       get_entity_ld_name(ent));
438                         }
439                         shift = new_tarval_from_long(offset_bits, mode_Is);
440                         shifted = tarval_shl(tv, shift);
441                         if (shifted == tarval_bad || shifted == tarval_undefined) {
442                                 panic("Couldn't shift numeric value for bitfield initializer '%s'\n",
443                                       get_entity_ld_name(ent));
444                         }
445
446                         for (j = 0; j < 4 && value_len > 0; ++j) {
447                                 assert(offset + j < last_ofs);
448                                 assert(vals[offset + j].kind == BITFIELD || vals[offset + j].v.value == NULL);
449                                 vals[offset + j].kind = BITFIELD;
450                                 vals[offset + j].v.bf_val |= get_tarval_sub_bits(shifted, j);
451                                 value_len -= 8 - offset_bits;
452                                 offset_bits = 0;
453                         }
454                 } else {
455                         assert(offset < last_ofs);
456                         assert(vals[offset].kind == NORMAL);
457                         assert(vals[offset].v.value == NULL);
458                         vals[offset].v.value = value;
459                 }
460         }
461
462         /* now write them sorted */
463         for (i = 0; i < last_ofs; ) {
464                 int space = 0, skip = 0;
465                 if (vals[i].kind == NORMAL) {
466                    if(vals[i].v.value != NULL) {
467                            dump_atomic_init(obst, vals[i].v.value);
468                            skip = get_mode_size_bytes(get_irn_mode(vals[i].v.value)) - 1;
469                    } else {
470                            space = 1;
471                    }
472                 } else {
473                         obstack_printf(obst, "\t.byte\t%d\n", vals[i].v.bf_val);
474                 }
475
476                 ++i;
477                 space = 0;
478                 while (i < last_ofs && vals[i].kind == NORMAL && vals[i].v.value == NULL) {
479                         ++space;
480                         ++i;
481                 }
482                 space -= skip;
483                 assert(space >= 0);
484
485                 /* a gap */
486                 if (space > 0)
487                         obstack_printf(obst, "\t.skip\t%d\n", space);
488         }
489         xfree(vals);
490 }
491
492 /**
493  * Dump a global entity.
494  */
495 static void dump_global(ia32_decl_env_t *env, ir_entity *ent)
496 {
497         obstack_t *obst;
498         ir_type *type = get_entity_type(ent);
499         const char *ld_name = get_entity_ld_name(ent);
500         ir_variability variability = get_entity_variability(ent);
501         ir_visibility visibility = get_entity_visibility(ent);
502         int align = get_type_alignment_bytes(type);
503
504         obst = env->data_obst;
505         if (is_Method_type(type)) {
506                 if (get_method_img_section(ent) == section_constructors) {
507                         obst = env->ctor_obst;
508                         obstack_printf(obst, ".balign\t%d\n", align);
509                         dump_size_type(obst, align);
510                         obstack_printf(obst, "%s\n", ld_name);
511                 }
512                 return;
513         } else if (variability == variability_constant) {
514                 /* a constant entity, put it on the rdata */
515                 obst = env->rodata_obst;
516         } else if (variability == variability_uninitialized) {
517                 /* uninitialized entity put it in bss segment */
518                 obst = env->bss_obst;
519         }
520
521         be_dbg_variable(env->main_env->db_handle, obst, ent);
522
523         /* global or not global */
524         if(visibility == visibility_external_visible) {
525                 obstack_printf(obst, ".global\t%s\n", ld_name);
526         } else if(visibility == visibility_external_allocated) {
527                 obstack_printf(obst, ".global\t%s\n", ld_name);
528                 /* we can return now... */
529                 return;
530         }
531         /* alignment */
532         if(align > 1) {
533                 obstack_printf(obst, ".balign\t%d\n", align);
534         }
535
536         obstack_printf(obst, "%s:\n", ld_name);
537
538         if (variability == variability_uninitialized) {
539                 obstack_printf(obst, "\t.zero %d\n", get_type_size_bytes(type));
540         } else if (is_atomic_type(type)) {
541                 dump_atomic_init(obst, get_atomic_ent_value(ent));
542         } else if (ent_is_string_const(ent)) {
543                 dump_string_cst(obst, ent);
544         } else if (is_Array_type(type)) {
545                 dump_array_init(obst, ent);
546         } else if (is_compound_type(type)) {
547                 dump_compound_init(obst, ent);
548         } else
549                 assert(0 && "unsupported type");
550 }
551
552 /**
553  * Dumps declarations of global variables and the initialization code.
554  */
555 static void ia32_dump_globals(ir_type *gt, ia32_decl_env_t *env)
556 {
557         int i, n = get_compound_n_members(gt);
558
559         for (i = 0; i < n; i++) {
560                 ir_entity *ent = get_compound_member(gt, i);
561                 dump_global(env, ent);
562         }
563 }
564
565 /************************************************************************/
566
567 void ia32_gen_decls(FILE *out, const be_main_env_t *main_env) {
568         ia32_decl_env_t env;
569         obstack_t rodata, data, bss, ctor;
570         int    size;
571         char   *cp;
572
573         /* dump the global type */
574         obstack_init(&rodata);
575         obstack_init(&data);
576         obstack_init(&bss);
577
578         if (main_env->options->opt_profile)
579                 obstack_init(&ctor);
580
581         env.rodata_obst = &rodata;
582         env.data_obst   = &data;
583         env.bss_obst    = &bss;
584         env.ctor_obst   = main_env->options->opt_profile ? &ctor : NULL;
585         env.main_env    = main_env;
586
587         ia32_dump_globals(get_glob_type(), &env);
588
589         size = obstack_object_size(&data);
590         cp   = obstack_finish(&data);
591         if (size > 0) {
592                 ia32_switch_section(out, SECTION_DATA);
593                 fwrite(cp, 1, size, out);
594         }
595
596         size = obstack_object_size(&rodata);
597         cp   = obstack_finish(&rodata);
598         if (size > 0) {
599                 ia32_switch_section(out, SECTION_RODATA);
600                 fwrite(cp, 1, size, out);
601         }
602
603         size = obstack_object_size(&bss);
604         cp   = obstack_finish(&bss);
605         if (size > 0) {
606                 ia32_switch_section(out, SECTION_COMMON);
607                 fwrite(cp, 1, size, out);
608         }
609
610         if (main_env->options->opt_profile) {
611                 size = obstack_object_size(&ctor);
612                 cp   = obstack_finish(&ctor);
613                 if (size > 0) {
614                         ia32_switch_section(out, SECTION_CTOR);
615                         fwrite(cp, 1, size, out);
616                 }
617                 obstack_free(&ctor, NULL);
618         }
619
620         obstack_free(&rodata, NULL);
621         obstack_free(&data, NULL);
622         obstack_free(&bss, NULL);
623
624         /* dump the Thread Local Storage */
625         obstack_init(&data);
626
627         env.rodata_obst = &data;
628         env.data_obst   = &data;
629         env.bss_obst   = &data;
630         env.ctor_obst   = NULL;
631
632         ia32_dump_globals(get_tls_type(), &env);
633
634         size = obstack_object_size(&data);
635         cp   = obstack_finish(&data);
636         if (size > 0) {
637                 ia32_switch_section(out, SECTION_TLS);
638                 fprintf(out, ".balign\t%d\n", 32);
639                 fwrite(cp, 1, size, out);
640         }
641
642         obstack_free(&data, NULL);
643 }