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