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