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