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