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