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