added doxygen comments
[libfirm] / ir / be / ppc32 / ppc32_gen_decls.c
1 /*
2  * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Dumps global variables and constants as ppc assembler.
23  * @author  Moritz Kroll, Jens Mueller
24  * @date    14.02.2006
25  * @version $Id$
26  */
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <assert.h>
35
36 #include "xmalloc.h"
37 #include "obst.h"
38
39 #include "tv.h"
40 #include "irnode.h"
41 #include "entity.h"
42 #include "irprog.h"
43 #include "pset.h"
44
45 #include "ppc32_gen_decls.h"
46
47 extern pset *symbol_pset;
48
49 /************************************************************************/
50
51 /*
52  * returns the highest bit value
53  */
54 static unsigned highest_bit(unsigned v)
55 {
56   int res = -1;
57
58   if (v >= (1U << 16U)) {
59     res += 16;
60     v >>= 16;
61   }
62   if (v >= (1U << 8U)) {
63     res += 8;
64     v >>= 8;
65   }
66   if (v >= (1U << 4U)) {
67     res += 4;
68     v >>= 4;
69   }
70   if (v >= (1U << 2U)) {
71     res += 2;
72     v >>= 2;
73   }
74   if (v >= (1U << 1U)) {
75     res += 1;
76     v >>= 1;
77   }
78   if (v >= 1)
79     res += 1;
80
81   return res;
82 }
83
84 /*
85  * output the alignment
86  */
87 static void ppc32_dump_align(struct obstack *obst, int align)
88 {
89   int h = highest_bit(align);
90
91   if ((1 << h) < align)
92     ++h;
93   align = (1 << h);
94
95   if (align > 1)
96     obstack_printf(obst, "\t.align %d\n", align);
97 }
98
99 static void dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
100 {
101   switch (bytes) {
102
103   case 1:
104     obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0));
105     break;
106
107   case 2:
108     obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
109     break;
110
111   case 4:
112     obstack_printf(obst, "0x%02x%02x%02x%02x",
113     get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
114     break;
115
116   case 8:
117     obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
118     get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4),
119     get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
120     break;
121
122   case 10:
123   case 12:
124     break;
125
126   default:
127     fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
128     assert(0);
129   }
130 }
131
132 #if 0
133 /*
134  * dump an arithmetic tarval
135  */
136 static void ppc32_dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
137 {
138   switch (bytes) {
139
140   case 1:
141     obstack_printf(obst, "\t.byte\t");
142     break;
143
144   case 2:
145     obstack_printf(obst, "\t.value\t");
146     break;
147
148   case 4:
149     obstack_printf(obst, "\t.long\t");
150     break;
151
152   case 8:
153     obstack_printf(obst, "\t.quad\t");
154     break;
155
156   case 10:
157   case 12:
158     break;
159
160   default:
161     fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
162     assert(0);
163   }
164   dump_arith_tarval(obst, tv, bytes);
165 }
166 #endif
167
168 /*
169  * dump an atomic value
170  */
171 static void do_dump_atomic_init(struct obstack *obst, ir_node *init)
172 {
173   ir_mode *mode = get_irn_mode(init);
174   int bytes     = get_mode_size_bytes(mode);
175   tarval *tv;
176
177   switch (get_irn_opcode(init)) {
178
179   case iro_Cast:
180     do_dump_atomic_init(obst, get_Cast_op(init));
181     return;
182
183   case iro_Conv:
184     do_dump_atomic_init(obst, get_Conv_op(init));
185     return;
186
187   case iro_Const:
188     tv = get_Const_tarval(init);
189
190     /* beware of old stuff */
191     assert(! mode_is_reference(mode));
192
193     /* it's a arithmetic value */
194     dump_arith_tarval(obst, tv, bytes);
195     return;
196
197   case iro_SymConst:
198     switch (get_SymConst_kind(init)) {
199     case symconst_addr_name:
200       obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init)));
201       break;
202
203     case symconst_addr_ent:
204       obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init)));
205       break;
206
207     case symconst_ofs_ent:
208       obstack_printf(obst, "%d", get_entity_offset(get_SymConst_entity(init)));
209       break;
210
211     case symconst_type_size:
212       obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init)));
213       break;
214
215     case symconst_type_align:
216       obstack_printf(obst, "%d", get_type_alignment_bytes(get_SymConst_type(init)));
217       break;
218
219     case symconst_enum_const:
220       tv = get_enumeration_value(get_SymConst_enum(init));
221       dump_arith_tarval(obst, tv, bytes);
222       break;
223
224     default:
225       assert(!"dump_atomic_init(): don't know how to init from this SymConst");
226     }
227     return;
228
229   case iro_Add:
230     do_dump_atomic_init(obst, get_Add_left(init));
231     obstack_printf(obst, " + ");
232     do_dump_atomic_init(obst, get_Add_right(init));
233     return;
234
235   case iro_Sub:
236     do_dump_atomic_init(obst, get_Sub_left(init));
237     obstack_printf(obst, " - ");
238     do_dump_atomic_init(obst, get_Sub_right(init));
239     return;
240
241   case iro_Mul:
242     do_dump_atomic_init(obst, get_Mul_left(init));
243     obstack_printf(obst, " * ");
244     do_dump_atomic_init(obst, get_Mul_right(init));
245     return;
246
247   default:
248     assert(0 && "dump_atomic_init(): unknown IR-node");
249   }
250 }
251
252 /*
253  * dump an atomic value
254  */
255 static void dump_atomic_init(struct obstack *obst, ir_node *init)
256 {
257   ir_mode *mode = get_irn_mode(init);
258   int bytes     = get_mode_size_bytes(mode);
259
260   switch (bytes) {
261
262   case 1:
263     obstack_printf(obst, "\t.byte\t");
264     break;
265
266   case 2:
267     obstack_printf(obst, "\t.value\t");
268     break;
269
270   case 4:
271     obstack_printf(obst, "\t.long\t");
272     break;
273
274   case 8:
275     obstack_printf(obst, "\t.quad\t");
276     break;
277
278   case 10:
279   case 12:
280     /* handled in arith */
281     break;
282
283   default:
284     fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
285     assert(0);
286   }
287
288   do_dump_atomic_init(obst, init);
289   obstack_printf(obst, "\n");
290 }
291
292 /************************************************************************/
293 /* Routines to dump global variables                                    */
294 /************************************************************************/
295
296 /**
297  * Determine if an entity is a string constant
298  * @param ent The entity
299  * @return 1 if it is a string constant, 0 otherwise
300  */
301 static int ent_is_string_const(ir_entity *ent)
302 {
303   int res = 0;
304   ir_type *ty;
305
306   ty = get_entity_type(ent);
307
308   /* if it's an array */
309   if (is_Array_type(ty)) {
310     ir_type *elm_ty = get_array_element_type(ty);
311
312     /* and the array's element type is primitive */
313     if (is_Primitive_type(elm_ty)) {
314       ir_mode *mode = get_type_mode(elm_ty);
315
316       /*
317        * and the mode of the element type is an int of
318        * the same size as the byte mode
319        */
320       if (mode_is_int(mode)
321          && get_mode_size_bits(mode) == get_mode_size_bits(mode_Bs))
322       {
323         int i, c, n;
324
325         n = get_compound_ent_n_values(ent);
326         for (i = 0; i < n; ++i) {
327           ir_node *irn = get_compound_ent_value(ent, i);
328           if(get_irn_opcode(irn) != iro_Const)
329             return 0;
330
331           c = (int) get_tarval_long(get_Const_tarval(irn));
332
333           if((i < n - 1 && !(isgraph(c) || isspace(c)))
334              || (i == n - 1 && c != '\0'))
335             return 0;
336         }
337
338         res = 1;
339       }
340     }
341   }
342
343   return res;
344 }
345
346 /**
347  * Dump a atring constant.
348  * No checks are made!!
349  * @param obst The obst to dump on.
350  * @param ent The entity to dump.
351  */
352 static void dump_string_cst(struct obstack *obst, ir_entity *ent)
353 {
354   int i, n;
355
356   obstack_printf(obst, "\t.asciz \"");
357   n = get_compound_ent_n_values(ent);
358
359   for (i = 0; i < n-1; ++i) {
360     ir_node *irn;
361     int c;
362
363     irn = get_compound_ent_value(ent, i);
364     c = (int) get_tarval_long(get_Const_tarval(irn));
365
366     switch (c) {
367     case '"' : obstack_printf(obst, "\\\""); break;
368     case '\n': obstack_printf(obst, "\\n"); break;
369     case '\r': obstack_printf(obst, "\\r"); break;
370     case '\t': obstack_printf(obst, "\\t"); break;
371     default  :
372       if (isprint(c))
373         obstack_printf(obst, "%c", c);
374       else
375         obstack_printf(obst, "\\%o", c);
376       break;
377     }
378   }
379   obstack_printf(obst, "\"\n");
380 }
381
382 struct arr_info {
383   int n_elems;
384   int visit_cnt;
385   int size;
386 };
387
388 /*
389  * Dumps the initialization of global variables that are not
390  * "uninitialized".
391  */
392 static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack, ir_entity *ent)
393 {
394   ir_type *ty         = get_entity_type(ent);
395   const char *ld_name = get_entity_ld_name(ent);
396   int align; //, h;
397   struct obstack *obst = data_obstack;
398
399   /*
400    * FIXME: did NOT work for partly constant values
401    */
402   if (! is_Method_type(ty)) {
403     ir_variability variability = get_entity_variability(ent);
404     ir_visibility visibility = get_entity_visibility(ent);
405
406     if (variability == variability_constant) {
407       /* a constant entity, put it on the rdata */
408       obst = rdata_obstack;
409     }
410
411     /* check, whether it is initialized, if yes create data */
412     if (variability != variability_uninitialized) {
413       if (visibility == visibility_external_visible) {
414         obstack_printf(obst, ".globl\t%s\n", ld_name);
415       }
416 //      obstack_printf(obst, "\t.type\t%s,@object\n", ld_name);
417 //      obstack_printf(obst, "\t.size\t%s,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3);
418
419       align = get_type_alignment_bytes(ty);
420       ppc32_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             ir_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               ir_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               ir_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(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]) {
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       if (visibility == visibility_local) {
561         obstack_printf(comm_obstack, "\t.local\t%s\n", ld_name);
562       }
563
564       /* calculate the alignment */
565 /*      align = get_type_alignment_bytes(ty);
566       h = highest_bit(align);
567
568       if ((1 << h) < align)
569         ++h;
570       align = (1 << h);
571
572       if (align < 1)
573         align = 1;
574
575       obstack_printf(comm_obstack, "\t.comm\t%s,%d,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3, align);*/
576       obstack_printf(comm_obstack, "\t.comm\t%s,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3);
577     }
578   }
579 }
580
581 /*
582  * Dumps declarations of global variables and the initialization code.
583  */
584 void ppc32_dump_globals(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack)
585 {
586   ir_type *gt = get_glob_type();
587   int i, n = get_class_n_members(gt);
588
589   for (i = 0; i < n; i++)
590     dump_global(rdata_obstack, data_obstack, comm_obstack, get_class_member(gt, i));
591 }
592
593 void ppc32_dump_indirect_symbols(struct obstack *isyms)
594 {
595   ir_entity *ent;
596
597   foreach_pset(symbol_pset, ent) {
598     const char *ld_name = get_entity_ld_name(ent);
599     obstack_printf(isyms, ".non_lazy_symbol_pointer\n%s:\n\t.indirect_symbol _%s\n\t.long 0\n\n",ld_name,ld_name);
600   }
601 }
602
603 /************************************************************************/
604
605 void ppc32_gen_decls(FILE *out) {
606   struct obstack rodata, data, comm, isyms;
607   int    size;
608   char   *cp;
609
610   obstack_init(&rodata);
611   obstack_init(&data);
612   obstack_init(&comm);
613
614   ppc32_dump_globals(&rodata, &data, &comm);
615
616   size = obstack_object_size(&data);
617   cp   = obstack_finish(&data);
618   if (size > 0) {
619     fprintf(out, "\t.data\n");
620     fwrite(cp, 1, size, out);
621   }
622
623   size = obstack_object_size(&rodata);
624   cp   = obstack_finish(&rodata);
625   if (size > 0) {
626     fprintf(out, "\t.const_data\n");
627     fwrite(cp, 1, size, out);
628   }
629
630   size = obstack_object_size(&comm);
631   cp   = obstack_finish(&comm);
632   if (size > 0) {
633 //    fprintf(out, "\t.common\n");
634     fwrite(cp, 1, size, out);
635     fprintf(out, "\n");
636   }
637
638   obstack_free(&rodata, NULL);
639   obstack_free(&data, NULL);
640   obstack_free(&comm, NULL);
641
642   obstack_init(&isyms);
643
644   ppc32_dump_indirect_symbols(&isyms);
645
646   size = obstack_object_size(&isyms);
647   cp   = obstack_finish(&isyms);
648   if (size > 0) {
649           fprintf(out, "\t.data\n");
650           fwrite(cp, 1, size, out);
651   }
652
653   obstack_free(&isyms,NULL);
654 }