2004-02-29 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / jit / helpers.c
1 /*
2  * helpers.c: architecture independent helper functions
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <mono/os/gc_wrapper.h>
12 #include <glib.h>
13
14 #include "codegen.h"
15 #include "helpers.h"
16
17 int
18 mono_map_store_svt_type (int svt)
19 {
20         switch (svt) {
21         case VAL_I32:
22                 return MB_TERM_STIND_I4;
23         case VAL_POINTER:
24                 return MB_TERM_STIND_REF;
25         case VAL_I64:
26                 return MB_TERM_STIND_I8;
27         case VAL_DOUBLE:
28                 return MB_TERM_STIND_R8;
29         default:
30                 g_assert_not_reached ();
31         }
32
33         return 0;
34 }
35
36 void
37 mono_get_val_sizes (MonoValueType type, int *size, int *align) 
38
39         switch (type) {
40         case VAL_I32:
41                 *size = *align = sizeof (gint32);
42                 break;
43         case VAL_I64:
44                 *size = *align = sizeof (gint64);
45                 break;
46         case VAL_POINTER:
47                 *size = *align = sizeof (gpointer);
48                 break;
49         case VAL_DOUBLE:
50                 *size = *align = sizeof (double);
51                 break;
52         default:
53                 g_assert_not_reached ();
54         }
55 }
56
57 /**
58  * mono_map_stind_type:
59  * @type: the type to map
60  *
61  * Translates the MonoType @type into the corresponding store opcode 
62  * for the code generator.
63  */
64 int
65 mono_map_stind_type (MonoType *type)
66 {
67         if (type->byref) 
68                 return MB_TERM_STIND_REF;
69
70         switch (type->type) {
71         case MONO_TYPE_I1:
72         case MONO_TYPE_U1:
73         case MONO_TYPE_BOOLEAN:
74                 return MB_TERM_STIND_I1;        
75         case MONO_TYPE_I2:
76         case MONO_TYPE_U2:
77         case MONO_TYPE_CHAR:
78                 return MB_TERM_STIND_I2;        
79 #if SIZEOF_VOID_P == 4
80         case MONO_TYPE_I:
81         case MONO_TYPE_U:
82 #endif
83         case MONO_TYPE_I4:
84         case MONO_TYPE_U4:
85                 return MB_TERM_STIND_I4;        
86         case MONO_TYPE_CLASS:
87         case MONO_TYPE_OBJECT:
88         case MONO_TYPE_STRING:
89         case MONO_TYPE_PTR:
90         case MONO_TYPE_SZARRAY:
91         case MONO_TYPE_ARRAY:    
92                 return MB_TERM_STIND_REF;
93         case MONO_TYPE_I8:
94         case MONO_TYPE_U8:
95 #if SIZEOF_VOID_P == 8
96         case MONO_TYPE_I:
97         case MONO_TYPE_U:
98 #endif
99                 return MB_TERM_STIND_I8;
100         case MONO_TYPE_R4:
101                 return MB_TERM_STIND_R4;
102         case MONO_TYPE_R8:
103                 return MB_TERM_STIND_R8;
104         case MONO_TYPE_VALUETYPE: 
105                 if (type->data.klass->enumtype)
106                         return mono_map_stind_type (type->data.klass->enum_basetype);
107                 else
108                         return MB_TERM_STIND_OBJ;
109         default:
110                 g_warning ("unknown type %02x", type->type);
111                 g_assert_not_reached ();
112         }
113
114         g_assert_not_reached ();
115         return -1;
116 }
117
118 /**
119  * mono_map_remote_stind_type:
120  * @type: the type to map
121  *
122  * Translates the MonoType @type into the corresponding remote store opcode 
123  * for the code generator.
124  */
125 int
126 mono_map_remote_stind_type (MonoType *type)
127 {
128         if (type->byref) {
129                 return MB_TERM_REMOTE_STIND_REF;
130         }
131
132         switch (type->type) {
133         case MONO_TYPE_I1:
134         case MONO_TYPE_U1:
135         case MONO_TYPE_BOOLEAN:
136                 return MB_TERM_REMOTE_STIND_I1; 
137         case MONO_TYPE_I2:
138         case MONO_TYPE_U2:
139         case MONO_TYPE_CHAR:
140                 return MB_TERM_REMOTE_STIND_I2; 
141 #if SIZEOF_VOID_P == 4
142         case MONO_TYPE_I:
143         case MONO_TYPE_U:
144 #endif
145         case MONO_TYPE_I4:
146         case MONO_TYPE_U4:
147                 return MB_TERM_REMOTE_STIND_I4; 
148         case MONO_TYPE_CLASS:
149         case MONO_TYPE_OBJECT:
150         case MONO_TYPE_STRING:
151         case MONO_TYPE_PTR:
152         case MONO_TYPE_SZARRAY:
153         case MONO_TYPE_ARRAY:    
154                 return MB_TERM_REMOTE_STIND_REF;
155 #if SIZEOF_VOID_P == 8
156         case MONO_TYPE_I:
157         case MONO_TYPE_U:
158 #endif
159         case MONO_TYPE_I8:
160         case MONO_TYPE_U8:
161                 return MB_TERM_REMOTE_STIND_I8;
162         case MONO_TYPE_R4:
163                 return MB_TERM_REMOTE_STIND_R4;
164         case MONO_TYPE_R8:
165                 return MB_TERM_REMOTE_STIND_R8;
166         case MONO_TYPE_VALUETYPE: 
167                 if (type->data.klass->enumtype)
168                         return mono_map_remote_stind_type (type->data.klass->enum_basetype);
169                 else
170                         return MB_TERM_REMOTE_STIND_OBJ;
171         default:
172                 g_warning ("unknown type %02x", type->type);
173                 g_assert_not_reached ();
174         }
175
176         g_assert_not_reached ();
177         return -1;
178 }
179
180 int
181 mono_map_starg_type (MonoType *type)
182 {
183         if (type->byref) 
184                 return MB_TERM_STIND_REF;
185
186         switch (type->type) {
187         case MONO_TYPE_I1:
188         case MONO_TYPE_U1:
189         case MONO_TYPE_BOOLEAN:
190         case MONO_TYPE_I2:
191         case MONO_TYPE_U2:
192         case MONO_TYPE_CHAR:
193 #if SIZEOF_VOID_P == 4
194         case MONO_TYPE_I:
195         case MONO_TYPE_U:
196 #endif
197         case MONO_TYPE_I4:
198         case MONO_TYPE_U4:
199                 return MB_TERM_STIND_I4;
200         case MONO_TYPE_CLASS:
201         case MONO_TYPE_OBJECT:
202         case MONO_TYPE_STRING:
203         case MONO_TYPE_PTR:
204         case MONO_TYPE_SZARRAY:
205         case MONO_TYPE_ARRAY:    
206                 return MB_TERM_STIND_REF;
207 #if SIZEOF_VOID_P == 8
208         case MONO_TYPE_I:
209         case MONO_TYPE_U:
210 #endif
211         case MONO_TYPE_I8:
212         case MONO_TYPE_U8:
213                 return MB_TERM_STIND_I8;
214         case MONO_TYPE_R4:
215                 return MB_TERM_STIND_R4;
216         case MONO_TYPE_R8:
217                 return MB_TERM_STIND_R8;
218         case MONO_TYPE_VALUETYPE: 
219                 if (type->data.klass->enumtype)
220                         return mono_map_starg_type (type->data.klass->enum_basetype);
221                 else
222                         return MB_TERM_STIND_OBJ;
223         default:
224                 g_warning ("unknown type %02x", type->type);
225                 g_assert_not_reached ();
226         }
227
228         g_assert_not_reached ();
229         return -1;
230 }
231
232 int
233 mono_map_arg_type (MonoType *type)
234 {
235         if (type->byref) 
236                 return MB_TERM_ARG_I4;
237
238         switch (type->type) {
239         case MONO_TYPE_I1:
240         case MONO_TYPE_U1:
241         case MONO_TYPE_BOOLEAN:
242         case MONO_TYPE_I2:
243         case MONO_TYPE_U2:
244         case MONO_TYPE_CHAR:
245 #if SIZEOF_VOID_P == 4
246         case MONO_TYPE_I:
247         case MONO_TYPE_U:
248 #endif
249         case MONO_TYPE_I4:
250         case MONO_TYPE_U4:
251                 return MB_TERM_ARG_I4;
252         case MONO_TYPE_CLASS:
253         case MONO_TYPE_OBJECT:
254         case MONO_TYPE_PTR:
255         case MONO_TYPE_SZARRAY:
256         case MONO_TYPE_ARRAY:    
257         case MONO_TYPE_STRING:
258 #if SIZEOF_VOID_P == 8
259                 return MB_TERM_ARG_I8;
260 #else
261                 return MB_TERM_ARG_I4;
262 #endif
263         case MONO_TYPE_I8:
264         case MONO_TYPE_U8:
265 #if SIZEOF_VOID_P == 8
266         case MONO_TYPE_I:
267         case MONO_TYPE_U:
268 #endif
269                 return MB_TERM_ARG_I8;
270         case MONO_TYPE_R4:
271                 return MB_TERM_ARG_R4;
272         case MONO_TYPE_R8:
273                 return MB_TERM_ARG_R8;
274         case MONO_TYPE_VALUETYPE:
275                 if (type->data.klass->enumtype)
276                         return mono_map_arg_type (type->data.klass->enum_basetype);
277                 else
278                         return MB_TERM_ARG_OBJ;
279         default:
280                 g_warning ("unknown type %02x", type->type);
281                 g_assert_not_reached ();
282         }
283
284         g_assert_not_reached ();
285         return -1;
286 }
287
288 /**
289  * mono_map_ldind_type:
290  * @type: the type to map
291  *
292  * Translates the MonoType @type into the corresponding load opcode 
293  * for the code generator.
294  */
295 int
296 mono_map_ldind_type (MonoType *type, MonoValueType *svt)
297 {
298         if (type->byref) {
299                 *svt = VAL_POINTER;
300                 return MB_TERM_LDIND_REF;
301         }
302
303         switch (type->type) {
304         case MONO_TYPE_I1:
305                 *svt = VAL_I32;
306                 return MB_TERM_LDIND_I1;
307         case MONO_TYPE_U1:
308         case MONO_TYPE_BOOLEAN:
309                 *svt = VAL_I32;
310                 return MB_TERM_LDIND_U1;
311         case MONO_TYPE_I2:
312                 *svt = VAL_I32;
313                 return MB_TERM_LDIND_I2;
314         case MONO_TYPE_U2:
315         case MONO_TYPE_CHAR:
316                 *svt = VAL_I32;
317                 return MB_TERM_LDIND_U2;
318 #if SIZEOF_VOID_P == 4
319         case MONO_TYPE_I:
320 #endif
321         case MONO_TYPE_I4:
322                 *svt = VAL_I32;
323                 return MB_TERM_LDIND_I4;
324 #if SIZEOF_VOID_P == 4
325         case MONO_TYPE_U:
326 #endif
327         case MONO_TYPE_U4:
328                 *svt = VAL_I32;
329                 return MB_TERM_LDIND_U4;
330         case MONO_TYPE_CLASS:
331         case MONO_TYPE_OBJECT:
332         case MONO_TYPE_STRING:
333         case MONO_TYPE_PTR:
334         case MONO_TYPE_SZARRAY:
335         case MONO_TYPE_ARRAY:    
336                 *svt = VAL_POINTER;
337                 return MB_TERM_LDIND_REF;
338 #if SIZEOF_VOID_P == 8
339         case MONO_TYPE_I:
340         case MONO_TYPE_U:
341 #endif
342         case MONO_TYPE_I8:
343         case MONO_TYPE_U8:
344                 *svt = VAL_I64;
345                 return MB_TERM_LDIND_I8;
346         case MONO_TYPE_R4:
347                 *svt = VAL_DOUBLE;
348                 return MB_TERM_LDIND_R4;
349         case MONO_TYPE_R8:
350                 *svt = VAL_DOUBLE;
351                 return MB_TERM_LDIND_R8;
352         case MONO_TYPE_VALUETYPE:
353                 if (type->data.klass->enumtype) {
354                         return mono_map_ldind_type (type->data.klass->enum_basetype, svt);
355                 } else {
356                         *svt = VAL_UNKNOWN;
357                         return MB_TERM_LDIND_OBJ;
358                 }
359         default:
360                 g_warning ("unknown type %02x", type->type);
361                 g_assert_not_reached ();
362         }
363
364         g_assert_not_reached ();
365         return -1;
366 }
367
368 int
369 mono_map_ldarg_type (MonoType *type, MonoValueType *svt)
370 {
371         if (type->byref) {
372                 *svt = VAL_POINTER;
373                 return MB_TERM_LDIND_REF;
374         }
375
376         switch (type->type) {
377         case MONO_TYPE_I1:
378         case MONO_TYPE_U1:
379         case MONO_TYPE_BOOLEAN:
380         case MONO_TYPE_I2:
381         case MONO_TYPE_U2:
382         case MONO_TYPE_CHAR:
383 #if SIZEOF_VOID_P == 4
384         case MONO_TYPE_I:
385         case MONO_TYPE_U:
386 #endif
387         case MONO_TYPE_I4:
388         case MONO_TYPE_U4:
389                 *svt = VAL_I32;
390                 return MB_TERM_LDIND_U4;
391         case MONO_TYPE_CLASS:
392         case MONO_TYPE_OBJECT:
393         case MONO_TYPE_STRING:
394         case MONO_TYPE_PTR:
395         case MONO_TYPE_SZARRAY:
396         case MONO_TYPE_ARRAY:    
397                 *svt = VAL_POINTER;
398                 return MB_TERM_LDIND_REF;
399         case MONO_TYPE_I8:
400         case MONO_TYPE_U8:
401 #if SIZEOF_VOID_P == 8
402         case MONO_TYPE_I:
403         case MONO_TYPE_U:
404 #endif
405                 *svt = VAL_I64;
406                 return MB_TERM_LDIND_I8;
407         case MONO_TYPE_R4:
408                 *svt = VAL_DOUBLE;
409                 return MB_TERM_LDIND_R4;
410         case MONO_TYPE_R8:
411                 *svt = VAL_DOUBLE;
412                 return MB_TERM_LDIND_R8;
413         case MONO_TYPE_VALUETYPE:
414                 if (type->data.klass->enumtype) {
415                         return mono_map_ldarg_type (type->data.klass->enum_basetype, svt);
416                 } else {
417                         *svt = VAL_UNKNOWN;
418                         return MB_TERM_LDIND_OBJ;
419                 }
420         default:
421                 g_warning ("unknown type %02x", type->type);
422                 g_assert_not_reached ();
423         }
424
425         g_assert_not_reached ();
426         return -1;
427 }
428
429 /**
430  * mono_map_call_type:
431  * @type: the type to map
432  *
433  * Translates the MonoType @type into the corresponding call opcode 
434  * for the code generator.
435  */
436 int
437 mono_map_call_type (MonoType *type, MonoValueType *svt)
438 {
439         if (type->byref) 
440                 return MB_TERM_CALL_I4;
441
442         switch (type->type) {
443         case MONO_TYPE_VOID:
444                 *svt = VAL_UNKNOWN;
445                 return MB_TERM_CALL_VOID;
446         case MONO_TYPE_I1:
447         case MONO_TYPE_U1:
448         case MONO_TYPE_BOOLEAN:
449         case MONO_TYPE_I2:
450         case MONO_TYPE_U2:
451         case MONO_TYPE_CHAR:
452 #if SIZEOF_VOID_P == 4
453         case MONO_TYPE_I:
454         case MONO_TYPE_U:
455 #endif
456         case MONO_TYPE_I4:
457         case MONO_TYPE_U4:
458                 *svt = VAL_I32;
459                 return MB_TERM_CALL_I4;
460         case MONO_TYPE_VALUETYPE:
461                 if (type->data.klass->enumtype) {
462                         return mono_map_call_type (type->data.klass->enum_basetype, svt);
463                 } else {
464                         *svt = VAL_I32;
465                         return MB_TERM_CALL_VOID;
466                 }
467         case MONO_TYPE_CLASS:
468         case MONO_TYPE_OBJECT:
469         case MONO_TYPE_STRING:
470         case MONO_TYPE_PTR:
471         case MONO_TYPE_SZARRAY: 
472         case MONO_TYPE_ARRAY: 
473                 *svt = VAL_POINTER;
474 #if SIZEOF_VOID_P == 8
475                 return MB_TERM_CALL_I8;
476 #else
477                 return MB_TERM_CALL_I4;
478 #endif
479         case MONO_TYPE_I8:
480         case MONO_TYPE_U8:
481 #if SIZEOF_VOID_P == 8
482         case MONO_TYPE_I:
483         case MONO_TYPE_U:
484 #endif
485                 *svt = VAL_I64;
486                 return MB_TERM_CALL_I8;
487         case MONO_TYPE_R4:
488         case MONO_TYPE_R8:
489                 *svt = VAL_DOUBLE;
490                 return MB_TERM_CALL_R8;
491         default:
492                 g_warning ("unknown type %02x", type->type);
493                 g_assert_not_reached ();
494         }
495
496         g_assert_not_reached ();
497         return -1;
498 }
499
500 MBTree *
501 mono_ctree_new (MonoMemPool *mp, int op, MBTree *left, MBTree *right)
502 {
503         MBTree *t = mono_mempool_alloc0 (mp, sizeof (MBTree));
504
505         t->op = op;
506         t->left = left;
507         t->right = right;
508         t->reg1 = -1;
509         t->reg2 = -1;
510         t->reg3 = -1;
511         t->svt = VAL_UNKNOWN;
512         t->cli_addr = -1;
513         return t;
514 }
515
516 MBTree *
517 mono_ctree_new_leaf (MonoMemPool *mp, int op)
518 {
519         return mono_ctree_new (mp, op, NULL, NULL);
520 }
521
522 MBTree *
523 mono_ctree_new_icon4 (MonoMemPool *mp, gint32 data)
524 {
525         MBTree *t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
526         t1->data.i = data;
527         return t1;
528 }
529
530 /*
531  * prints the tree to stdout
532  */
533 void
534 mono_print_ctree (MonoFlowGraph *cfg, MBTree *tree)
535 {
536         int arity;
537
538         if (!tree)
539                 return;
540
541         arity = (tree->left != NULL) + (tree->right != NULL);
542
543         if (arity)
544                 printf (" (%s", mono_burg_term_string [tree->op]);
545         else 
546                 printf (" %s", mono_burg_term_string [tree->op]);
547
548         switch (tree->op) {
549         case MB_TERM_CONST_I4:
550                 printf ("[%d]", tree->data.i);
551                 break;
552         case MB_TERM_ADDR_L:
553                 if (VARINFO (cfg, tree->data.i).reg >= 0)
554                         printf ("[%s|%d]", arch_get_reg_name (VARINFO (cfg, tree->data.i).reg), 
555                                 tree->data.i);
556                 else
557                         printf ("[%d]", tree->data.i);
558                 break;
559         }
560
561         g_assert (!(tree->right && !tree->left));
562
563         mono_print_ctree (cfg, tree->left);
564         mono_print_ctree (cfg, tree->right);
565
566         if (arity)
567                 printf (")");
568 }
569
570 /*
571  * prints the whole forest to stdout
572  */
573 void
574 mono_print_forest (MonoFlowGraph *cfg, GPtrArray *forest)
575 {
576         const int top = forest->len;
577         int i;
578
579         for (i = 0; i < top; i++) {
580                 MBTree *t = (MBTree *) g_ptr_array_index (forest, i);
581                 printf ("       ");
582                 mono_print_ctree (cfg, t);
583                 printf ("\n");
584         }
585
586 }
587
588 /**
589  * mono_disassemble_code:
590  * @code: a pointer to the code
591  * @size: the code size in bytes
592  *
593  * Disassemble to code to stdout.
594  */
595 void
596 mono_disassemble_code (guint8 *code, int size, char *id)
597 {
598         int i;
599         FILE *ofd;
600
601         if (!(ofd = fopen ("/tmp/test.s", "w")))
602                 g_assert_not_reached ();
603
604         fprintf (ofd, "%s:\n", id);
605
606         for (i = 0; i < size; ++i) 
607                 fprintf (ofd, ".byte %d\n", (unsigned int) code [i]);
608
609         fclose (ofd);
610
611         system ("as /tmp/test.s -o /tmp/test.o;objdump -d /tmp/test.o"); 
612 }
613