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