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