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