2003-12-06 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / mini / mini-ppc.c
1 /*
2  * mini-ppc.c: PowerPC backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2003 Ximian, Inc.
9  */
10 #include "mini.h"
11 #include <string.h>
12
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
15
16 #include "mini-ppc.h"
17 #include "inssel.h"
18 #include "cpu-g4.h"
19
20 int mono_exc_esp_offset = 0;
21
22 const char*
23 mono_arch_regname (int reg) {
24         static const char * rnames[] = {
25                 "ppc_r0", "ppc_sp", "ppc_r2", "ppc_r3", "ppc_r4",
26                 "ppc_r5", "ppc_r6", "ppc_r7", "ppc_r8", "ppc_r9",
27                 "ppc_r10", "ppc_r11", "ppc_r12", "ppc_r13", "ppc_r14",
28                 "ppc_r15", "ppc_r16", "ppc_r17", "ppc_r18", "ppc_r19",
29                 "ppc_r20", "ppc_r21", "ppc_r22", "ppc_r23", "ppc_r24",
30                 "ppc_r25", "ppc_r26", "ppc_r27", "ppc_r28", "ppc_r29",
31                 "ppc_r30", "ppc_r31"
32         };
33         if (reg >= 0 && reg < 32)
34                 return rnames [reg];
35         return "unknown";
36 }
37
38 typedef struct {
39         guint16 size;
40         guint16 offset;
41         guint8  pad;
42 } MonoJitArgumentInfo;
43
44 /*
45  * arch_get_argument_info:
46  * @csig:  a method signature
47  * @param_count: the number of parameters to consider
48  * @arg_info: an array to store the result infos
49  *
50  * Gathers information on parameters such as size, alignment and
51  * padding. arg_info should be large enought to hold param_count + 1 entries. 
52  *
53  * Returns the size of the activation frame.
54  */
55 static int
56 arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
57 {
58         int k, frame_size = 0;
59         int size, align, pad;
60         int offset = 8;
61
62         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
63                 frame_size += sizeof (gpointer);
64                 offset += 4;
65         }
66
67         arg_info [0].offset = offset;
68
69         if (csig->hasthis) {
70                 frame_size += sizeof (gpointer);
71                 offset += 4;
72         }
73
74         arg_info [0].size = frame_size;
75
76         for (k = 0; k < param_count; k++) {
77                 
78                 if (csig->pinvoke)
79                         size = mono_type_native_stack_size (csig->params [k], &align);
80                 else
81                         size = mono_type_stack_size (csig->params [k], &align);
82
83                 /* ignore alignment for now */
84                 align = 1;
85
86                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
87                 arg_info [k].pad = pad;
88                 frame_size += size;
89                 arg_info [k + 1].pad = 0;
90                 arg_info [k + 1].size = size;
91                 offset += pad;
92                 arg_info [k + 1].offset = offset;
93                 offset += size;
94         }
95
96         align = MONO_ARCH_FRAME_ALIGNMENT;
97         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
98         arg_info [k].pad = pad;
99
100         return frame_size;
101 }
102
103 static int indent_level = 0;
104
105 static void indent (int diff) {
106         int v = indent_level;
107         while (v-- > 0) {
108                 printf (". ");
109         }
110         indent_level += diff;
111 }
112
113 static void
114 enter_method (MonoMethod *method, char *ebp)
115 {
116         int i, j;
117         MonoClass *class;
118         MonoObject *o;
119         MonoJitArgumentInfo *arg_info;
120         MonoMethodSignature *sig;
121         char *fname;
122
123         fname = mono_method_full_name (method, TRUE);
124         indent (1);
125         printf ("ENTER: %s(", fname);
126         g_free (fname);
127
128         if (!ebp) {
129                 printf (") ip: %p\n", __builtin_return_address (1));
130                 return;
131         }
132         if (((int)ebp & (MONO_ARCH_FRAME_ALIGNMENT - 1)) != 0) {
133                 g_error ("unaligned stack detected (%p)", ebp);
134         }
135
136         sig = method->signature;
137
138         arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
139
140         arch_get_argument_info (sig, sig->param_count, arg_info);
141
142         if (MONO_TYPE_ISSTRUCT (method->signature->ret)) {
143                 g_assert (!method->signature->ret->byref);
144
145                 printf ("VALUERET:%p, ", *((gpointer *)(ebp + 8)));
146         }
147
148         if (method->signature->hasthis) {
149                 gpointer *this = (gpointer *)(ebp + arg_info [0].offset);
150                 if (method->klass->valuetype) {
151                         printf ("value:%p, ", *this);
152                 } else {
153                         o = *((MonoObject **)this);
154
155                         if (o) {
156                                 class = o->vtable->klass;
157
158                                 if (class == mono_defaults.string_class) {
159                                         printf ("this:[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
160                                 } else {
161                                         printf ("this:%p[%s.%s], ", o, class->name_space, class->name);
162                                 }
163                         } else 
164                                 printf ("this:NULL, ");
165                 }
166         }
167
168         for (i = 0; i < method->signature->param_count; ++i) {
169                 gpointer *cpos = (gpointer *)(ebp + arg_info [i + 1].offset);
170                 int size = arg_info [i + 1].size;
171
172                 MonoType *type = method->signature->params [i];
173                 
174                 if (type->byref) {
175                         printf ("[BYREF:%p], ", *cpos); 
176                 } else switch (type->type) {
177                         
178                 case MONO_TYPE_I:
179                 case MONO_TYPE_U:
180                         printf ("%p, ", (gpointer)*((int *)(cpos)));
181                         break;
182                 case MONO_TYPE_BOOLEAN:
183                 case MONO_TYPE_CHAR:
184                 case MONO_TYPE_I1:
185                 case MONO_TYPE_U1:
186                 case MONO_TYPE_I2:
187                 case MONO_TYPE_U2:
188                 case MONO_TYPE_I4:
189                 case MONO_TYPE_U4:
190                         printf ("%d, ", *((int *)(cpos)));
191                         break;
192                 case MONO_TYPE_STRING: {
193                         MonoString *s = *((MonoString **)cpos);
194                         if (s) {
195                                 g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
196                                 printf ("[STRING:%p:%s], ", s, mono_string_to_utf8 (s));
197                         } else 
198                                 printf ("[STRING:null], ");
199                         break;
200                 }
201                 case MONO_TYPE_CLASS:
202                 case MONO_TYPE_OBJECT: {
203                         o = *((MonoObject **)cpos);
204                         if (o) {
205                                 class = o->vtable->klass;
206                     
207                                 if (class == mono_defaults.string_class) {
208                                         printf ("[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
209                                 } else if (class == mono_defaults.int32_class) {
210                                         printf ("[INT32:%p:%d], ", o, *(gint32 *)((char *)o + sizeof (MonoObject)));
211                                 } else
212                                         printf ("[%s.%s:%p], ", class->name_space, class->name, o);
213                         } else {
214                                 printf ("%p, ", *((gpointer *)(cpos)));                         
215                         }
216                         break;
217                 }
218                 case MONO_TYPE_PTR:
219                 case MONO_TYPE_FNPTR:
220                 case MONO_TYPE_ARRAY:
221                 case MONO_TYPE_SZARRAY:
222                         printf ("%p, ", *((gpointer *)(cpos)));
223                         break;
224                 case MONO_TYPE_I8:
225                         printf ("%lld, ", *((gint64 *)(cpos)));
226                         break;
227                 case MONO_TYPE_R4:
228                         printf ("%f, ", *((float *)(cpos)));
229                         break;
230                 case MONO_TYPE_R8:
231                         printf ("%f, ", *((double *)(cpos)));
232                         break;
233                 case MONO_TYPE_VALUETYPE: 
234                         printf ("[");
235                         for (j = 0; j < size; j++)
236                                 printf ("%02x,", *((guint8*)cpos +j));
237                         printf ("], ");
238                         break;
239                 default:
240                         printf ("XX, ");
241                 }
242         }
243
244         printf (")\n");
245 }
246
247 static void
248 leave_method (MonoMethod *method, ...)
249 {
250         MonoType *type;
251         char *fname;
252         va_list ap;
253
254         va_start(ap, method);
255
256         fname = mono_method_full_name (method, TRUE);
257         indent (-1);
258         printf ("LEAVE: %s", fname);
259         g_free (fname);
260
261         type = method->signature->ret;
262
263 handle_enum:
264         switch (type->type) {
265         case MONO_TYPE_VOID:
266                 break;
267         case MONO_TYPE_BOOLEAN: {
268                 int eax = va_arg (ap, int);
269                 if (eax)
270                         printf ("TRUE:%d", eax);
271                 else 
272                         printf ("FALSE");
273                         
274                 break;
275         }
276         case MONO_TYPE_CHAR:
277         case MONO_TYPE_I1:
278         case MONO_TYPE_U1:
279         case MONO_TYPE_I2:
280         case MONO_TYPE_U2:
281         case MONO_TYPE_I4:
282         case MONO_TYPE_U4:
283         case MONO_TYPE_I:
284         case MONO_TYPE_U: {
285                 int eax = va_arg (ap, int);
286                 printf ("EAX=%d", eax);
287                 break;
288         }
289         case MONO_TYPE_STRING: {
290                 MonoString *s = va_arg (ap, MonoString *);
291 ;
292                 if (s) {
293                         g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
294                         printf ("[STRING:%p:%s]", s, mono_string_to_utf8 (s));
295                 } else 
296                         printf ("[STRING:null], ");
297                 break;
298         }
299         case MONO_TYPE_CLASS: 
300         case MONO_TYPE_OBJECT: {
301                 MonoObject *o = va_arg (ap, MonoObject *);
302
303                 if (o) {
304                         if (o->vtable->klass == mono_defaults.boolean_class) {
305                                 printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject)));            
306                         } else if  (o->vtable->klass == mono_defaults.int32_class) {
307                                 printf ("[INT32:%p:%d]", o, *((gint32 *)((char *)o + sizeof (MonoObject))));    
308                         } else if  (o->vtable->klass == mono_defaults.int64_class) {
309                                 printf ("[INT64:%p:%lld]", o, *((gint64 *)((char *)o + sizeof (MonoObject))));  
310                         } else
311                                 printf ("[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o);
312                 } else
313                         printf ("[OBJECT:%p]", o);
314                
315                 break;
316         }
317         case MONO_TYPE_PTR:
318         case MONO_TYPE_FNPTR:
319         case MONO_TYPE_ARRAY:
320         case MONO_TYPE_SZARRAY: {
321                 gpointer p = va_arg (ap, gpointer);
322                 printf ("result=%p", p);
323                 break;
324         }
325         case MONO_TYPE_I8: {
326                 gint64 l =  va_arg (ap, gint64);
327                 printf ("lresult=%lld", l);
328                 break;
329         }
330         case MONO_TYPE_R8: {
331                 double f = va_arg (ap, double);
332                 printf ("FP=%f\n", f);
333                 break;
334         }
335         case MONO_TYPE_VALUETYPE: 
336                 if (type->data.klass->enumtype) {
337                         type = type->data.klass->enum_basetype;
338                         goto handle_enum;
339                 } else {
340                         guint8 *p = va_arg (ap, gpointer);
341                         int j, size, align;
342                         size = mono_type_size (type, &align);
343                         printf ("[");
344                         for (j = 0; p && j < size; j++)
345                                 printf ("%02x,", p [j]);
346                         printf ("]");
347                 }
348                 break;
349         default:
350                 printf ("(unknown return type %x)", method->signature->ret->type);
351         }
352
353         printf (" ip: %p\n", __builtin_return_address (1));
354 }
355
356 /*
357  * Initialize the cpu to execute managed code.
358  */
359 void
360 mono_arch_cpu_init (void)
361 {
362 }
363
364 /*
365  * This function returns the optimizations supported on this cpu.
366  */
367 guint32
368 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
369 {
370         guint32 opts = 0;
371
372         /* no ppc-specific optimizations yet */
373         *exclude_mask = 0;
374         return opts;
375 }
376
377 static gboolean
378 is_regsize_var (MonoType *t) {
379         if (t->byref)
380                 return TRUE;
381         switch (t->type) {
382         case MONO_TYPE_I4:
383         case MONO_TYPE_U4:
384         case MONO_TYPE_I:
385         case MONO_TYPE_U:
386                 return TRUE;
387         case MONO_TYPE_OBJECT:
388         case MONO_TYPE_STRING:
389         case MONO_TYPE_CLASS:
390         case MONO_TYPE_SZARRAY:
391         case MONO_TYPE_ARRAY:
392                 return FALSE;
393         case MONO_TYPE_VALUETYPE:
394                 if (t->data.klass->enumtype)
395                         return is_regsize_var (t->data.klass->enum_basetype);
396                 return FALSE;
397         }
398         return FALSE;
399 }
400
401 GList *
402 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
403 {
404         GList *vars = NULL;
405         int i;
406
407         for (i = 0; i < cfg->num_varinfo; i++) {
408                 MonoInst *ins = cfg->varinfo [i];
409                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
410
411                 /* unused vars */
412                 if (vmv->range.first_use.abs_pos > vmv->range.last_use.abs_pos)
413                         continue;
414
415                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
416                         continue;
417
418                 /* we can only allocate 32 bit values */
419                 if (is_regsize_var (ins->inst_vtype)) {
420                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
421                         g_assert (i == vmv->idx);
422                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
423                 }
424         }
425
426         return vars;
427 }
428
429 GList *
430 mono_arch_get_global_int_regs (MonoCompile *cfg)
431 {
432         GList *regs = NULL;
433         int i, top = 32;
434         if (cfg->flags & MONO_CFG_HAS_ALLOCA)
435                 top = 31;
436         for (i = 13; i < top; ++i)
437                 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
438
439         return regs;
440 }
441
442 // code from ppc/tramp.c, try to keep in sync
443 #define MIN_CACHE_LINE 8
444
445 void
446 mono_arch_flush_icache (guint8 *code, gint size)
447 {
448         guint i;
449         guint8 *p;
450
451         p = code;
452         for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
453                 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
454         }
455         asm ("sync");
456         p = code;
457         for (i = 0; i < size; i += MIN_CACHE_LINE, p += MIN_CACHE_LINE) {
458                 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
459         }
460         asm ("sync");
461         asm ("isync");
462 }
463
464 #define NOT_IMPLEMENTED(x) \
465                 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
466
467 #define PROLOG_INS 8
468 #define CALL_INS   2
469 #define EPILOG_INS 6
470 #define FLOAT_REGS 8
471 #define GENERAL_REGS 8
472 #ifdef __APPLE__
473 #define MINIMAL_STACK_SIZE 10
474 #define ALWAYS_ON_STACK(s) s
475 #define FP_ALSO_IN_REG(s) s
476 #define RET_ADDR_OFFSET 8
477 #define STACK_PARAM_OFFSET 24
478 #else
479 #define MINIMAL_STACK_SIZE 5
480 #define ALWAYS_ON_STACK(s)
481 #define FP_ALSO_IN_REG(s) s
482 #define ALIGN_DOUBLES
483 #define RET_ADDR_OFFSET 4
484 #define STACK_PARAM_OFFSET 8
485 #endif
486
487 enum {
488         RegTypeGeneral,
489         RegTypeBase,
490         RegTypeFP
491 };
492
493 typedef struct {
494         gint16 offset;
495         gint8  reg;
496         guint8  regtype : 2; /* 0 general, 1 basereg, 2 floating point register */
497         guint8  size    : 6; /* 1, 2, 4, 8 */
498 } ArgInfo;
499
500 typedef struct {
501         int nargs;
502         guint32 stack_usage;
503         guint32 struct_ret;
504         ArgInfo ret;
505         ArgInfo args [1];
506 } CallInfo;
507
508 #define DEBUG(a)
509
510 static void inline
511 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
512 {
513         if (simple) {
514                 if (*gr >= 3 + GENERAL_REGS) {
515                         ainfo->offset = *stack_size;
516                         ainfo->reg = ppc_sp; /* in the caller */
517                         ainfo->regtype = RegTypeBase;
518                         *stack_size += 4;
519                 } else {
520                         ALWAYS_ON_STACK (*stack_size += 4);
521                         ainfo->reg = *gr;
522                 }
523         } else {
524                 if (*gr >= 3 + GENERAL_REGS - 1) {
525                         ainfo->offset = *stack_size;
526                         ainfo->reg = ppc_sp; /* in the caller */
527                         ainfo->regtype = RegTypeBase;
528                         *stack_size += 8;
529 #ifdef ALIGN_DOUBLES
530                         *stack_size += (*stack_size % 8);
531 #endif
532                 } else {
533                         ALWAYS_ON_STACK (*stack_size += 8);
534                         ainfo->reg = *gr;
535                 }
536 #ifdef ALIGN_DOUBLES
537                 if ((*gr) & 1)
538                         (*gr) ++;
539 #endif
540                 (*gr) ++;
541         }
542         (*gr) ++;
543 }
544
545 static CallInfo*
546 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
547 {
548         guint i, fr, gr;
549         int n = sig->hasthis + sig->param_count;
550         guint32 simpletype;
551         guint32 stack_size = 0;
552         CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
553
554         fr = 1;
555         gr = 3;
556
557         /* FIXME: handle returning a struct */
558         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
559                 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
560                 cinfo->struct_ret = ppc_r3;
561         }
562
563         n = 0;
564         if (sig->hasthis) {
565                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
566                 n++;
567         }
568         DEBUG(printf("params: %d\n", sig->param_count));
569         for (i = 0; i < sig->param_count; ++i) {
570                 DEBUG(printf("param %d: ", i));
571                 if (sig->params [i]->byref) {
572                         DEBUG(printf("byref\n"));
573                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
574                         n++;
575                         continue;
576                 }
577                 simpletype = sig->params [i]->type;
578         enum_calc_size:
579                 switch (simpletype) {
580                 case MONO_TYPE_BOOLEAN:
581                 case MONO_TYPE_I1:
582                 case MONO_TYPE_U1:
583                         cinfo->args [n].size = 1;
584                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
585                         n++;
586                         break;
587                 case MONO_TYPE_CHAR:
588                 case MONO_TYPE_I2:
589                 case MONO_TYPE_U2:
590                         cinfo->args [n].size = 2;
591                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
592                         n++;
593                         break;
594                 case MONO_TYPE_I4:
595                 case MONO_TYPE_U4:
596                         cinfo->args [n].size = 4;
597                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
598                         n++;
599                         break;
600                 case MONO_TYPE_I:
601                 case MONO_TYPE_U:
602                 case MONO_TYPE_PTR:
603                 case MONO_TYPE_CLASS:
604                 case MONO_TYPE_OBJECT:
605                 case MONO_TYPE_STRING:
606                 case MONO_TYPE_SZARRAY:
607                 case MONO_TYPE_ARRAY:
608                         cinfo->args [n].size = sizeof (gpointer);
609                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
610                         n++;
611                         break;
612                 case MONO_TYPE_VALUETYPE: {
613                         gint size;
614                         if (sig->params [i]->data.klass->enumtype) {
615                                 simpletype = sig->params [i]->data.klass->enum_basetype->type;
616                                 goto enum_calc_size;
617                         }
618                         size = mono_class_value_size (sig->params [i]->data.klass, NULL);
619                         DEBUG(printf ("load %d bytes struct\n",
620                                       mono_class_value_size (sig->params [i]->data.klass, NULL)));
621                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
622                         n++;
623                         break;
624                 }
625                 case MONO_TYPE_U8:
626                 case MONO_TYPE_I8:
627                         cinfo->args [n].size = 8;
628                         add_general (&gr, &stack_size, cinfo->args + n, FALSE);
629                         n++;
630                         break;
631                 case MONO_TYPE_R4:
632                         cinfo->args [n].size = 4;
633                         if (fr < 7) {
634                                 cinfo->args [n].regtype = RegTypeFP;
635                                 cinfo->args [n].reg = fr;
636                                 fr ++;
637                                 FP_ALSO_IN_REG (gr ++);
638                                 ALWAYS_ON_STACK (stack_size += 4);
639                         } else {
640                                 NOT_IMPLEMENTED ("R4 arg");
641                         }
642                         n++;
643                         break;
644                 case MONO_TYPE_R8:
645                         cinfo->args [n].size = 8;
646                         if (fr < 7) {
647                                 cinfo->args [n].regtype = RegTypeFP;
648                                 cinfo->args [n].reg = fr;
649                                 fr ++;
650                                 FP_ALSO_IN_REG (gr += 2);
651                                 ALWAYS_ON_STACK (stack_size += 8);
652                         } else {
653                                 NOT_IMPLEMENTED ("R8 arg");
654                         }
655                         n++;
656                         break;
657                 default:
658                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
659                 }
660         }
661
662         {
663                 simpletype = sig->ret->type;
664 enum_retvalue:
665                 switch (simpletype) {
666                 case MONO_TYPE_BOOLEAN:
667                 case MONO_TYPE_I1:
668                 case MONO_TYPE_U1:
669                 case MONO_TYPE_I2:
670                 case MONO_TYPE_U2:
671                 case MONO_TYPE_CHAR:
672                 case MONO_TYPE_I4:
673                 case MONO_TYPE_U4:
674                 case MONO_TYPE_I:
675                 case MONO_TYPE_U:
676                 case MONO_TYPE_CLASS:
677                 case MONO_TYPE_OBJECT:
678                 case MONO_TYPE_SZARRAY:
679                 case MONO_TYPE_ARRAY:
680                 case MONO_TYPE_STRING:
681                         cinfo->ret.reg = ppc_r3;
682                         break;
683                 case MONO_TYPE_U8:
684                 case MONO_TYPE_I8:
685                         cinfo->ret.reg = ppc_r3;
686                         break;
687                 case MONO_TYPE_R4:
688                 case MONO_TYPE_R8:
689                         cinfo->ret.reg = ppc_f1;
690                         cinfo->ret.regtype = RegTypeFP;
691                         break;
692                 case MONO_TYPE_VALUETYPE:
693                         if (sig->ret->data.klass->enumtype) {
694                                 simpletype = sig->ret->data.klass->enum_basetype->type;
695                                 goto enum_retvalue;
696                         }
697                         break;
698                 case MONO_TYPE_VOID:
699                         break;
700                 default:
701                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
702                 }
703         }
704
705         /* align stack size to 16 */
706         DEBUG (printf ("      stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
707         stack_size = (stack_size + 15) & ~15;
708
709         cinfo->stack_usage = stack_size;
710         return cinfo;
711 }
712
713
714 /*
715  * Set var information according to the calling convention. ppc version.
716  * The locals var stuff should most likely be split in another method.
717  */
718 void
719 mono_arch_allocate_vars (MonoCompile *m)
720 {
721         MonoMethodSignature *sig;
722         MonoMethodHeader *header;
723         MonoInst *inst;
724         int i, offset, size, align, curinst;
725         int frame_reg = ppc_sp;
726  
727         if (m->flags & MONO_CFG_HAS_ALLOCA)
728                 frame_reg = ppc_r31;
729         m->frame_reg = frame_reg;
730
731         header = ((MonoMethodNormal *)m->method)->header;
732
733         sig = m->method->signature;
734         
735         offset = 0;
736         curinst = 0;
737         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
738                 m->ret->opcode = OP_REGVAR;
739                 m->ret->inst_c0 = ppc_r3;
740         } else {
741                 /* FIXME: handle long and FP values */
742                 switch (sig->ret->type) {
743                 case MONO_TYPE_VOID:
744                         break;
745                 default:
746                         m->ret->opcode = OP_REGVAR;
747                         m->ret->inst_c0 = ppc_r3;
748                         break;
749                 }
750         }
751         /* local vars are at a positive offset from the stack pointer */
752         /* 
753          * also note that if the function uses alloca, we use ppc_r31
754          * to point at the local variables.
755          */
756         offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
757         /* align the offset to 16 bytes: not sure this is needed here  */
758         //offset += 16 - 1;
759         //offset &= ~(16 - 1);
760
761         /* add parameter area size for called functions */
762         offset += m->param_area;
763         offset += 16 - 1;
764         offset &= ~(16 - 1);
765
766         /* FIXME: check how to handle this stuff... reserve space to save LMF and caller saved registers */
767         offset += sizeof (MonoLMF);
768
769 #if 0
770         /* this stuff should not be needed on ppc and the new jit,
771          * because a call on ppc to the handlers doesn't change the 
772          * stack pointer and the jist doesn't manipulate the stack pointer
773          * for operations involving valuetypes.
774          */
775         /* reserve space to store the esp */
776         offset += sizeof (gpointer);
777
778         /* this is a global constant */
779         mono_exc_esp_offset = offset;
780 #endif
781
782         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
783                 inst = m->ret;
784                 offset += sizeof(gpointer) - 1;
785                 offset &= ~(sizeof(gpointer) - 1);
786                 inst->inst_offset = offset;
787                 inst->opcode = OP_REGOFFSET;
788                 inst->inst_basereg = frame_reg;
789                 offset += sizeof(gpointer);
790         }
791         curinst = m->locals_start;
792         for (i = curinst; i < m->num_varinfo; ++i) {
793                 inst = m->varinfo [i];
794                 if (inst->opcode == OP_REGVAR)
795                         continue;
796
797                 /* inst->unused indicates native sized value types, this is used by the
798                 * pinvoke wrappers when they call functions returning structure */
799                 if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype))
800                         size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
801                 else
802                         size = mono_type_size (inst->inst_vtype, &align);
803
804                 offset += align - 1;
805                 offset &= ~(align - 1);
806                 inst->inst_offset = offset;
807                 inst->opcode = OP_REGOFFSET;
808                 inst->inst_basereg = frame_reg;
809                 offset += size;
810                 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
811         }
812
813         curinst = 0;
814         if (sig->hasthis) {
815                 inst = m->varinfo [curinst];
816                 if (inst->opcode != OP_REGVAR) {
817                         inst->opcode = OP_REGOFFSET;
818                         inst->inst_basereg = frame_reg;
819                         offset += sizeof (gpointer) - 1;
820                         offset &= ~(sizeof (gpointer) - 1);
821                         inst->inst_offset = offset;
822                         offset += sizeof (gpointer);
823                 }
824                 curinst++;
825         }
826
827         for (i = 0; i < sig->param_count; ++i) {
828                 inst = m->varinfo [curinst];
829                 if (inst->opcode != OP_REGVAR) {
830                         inst->opcode = OP_REGOFFSET;
831                         inst->inst_basereg = frame_reg;
832                         size = mono_type_size (sig->params [i], &align);
833                         offset += align - 1;
834                         offset &= ~(align - 1);
835                         inst->inst_offset = offset;
836                         offset += size;
837                 }
838                 curinst++;
839         }
840
841         /* align the offset to 16 bytes */
842         offset += 16 - 1;
843         offset &= ~(16 - 1);
844
845         /* change sign? */
846         m->stack_offset = offset;
847
848 }
849
850 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
851  * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
852  */
853
854 /* 
855  * take the arguments and generate the arch-specific
856  * instructions to properly call the function in call.
857  * This includes pushing, moving arguments to the right register
858  * etc.
859  * Issue: who does the spilling if needed, and when?
860  */
861 MonoCallInst*
862 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
863         MonoInst *arg, *in;
864         MonoMethodSignature *sig;
865         int i, n, type;
866         MonoType *ptype;
867         CallInfo *cinfo;
868         ArgInfo *ainfo;
869
870         sig = call->signature;
871         n = sig->param_count + sig->hasthis;
872         
873         cinfo = calculate_sizes (sig, sig->pinvoke);
874         if (cinfo->struct_ret)
875                 call->used_iregs |= 1 << cinfo->struct_ret;
876
877         for (i = 0; i < n; ++i) {
878                 ainfo = cinfo->args + i;
879                 if (is_virtual && i == 0) {
880                         /* the argument will be attached to the call instrucion */
881                         in = call->args [i];
882                         call->used_iregs |= 1 << ainfo->reg;
883                 } else {
884                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
885                         in = call->args [i];
886                         arg->cil_code = in->cil_code;
887                         arg->inst_left = in;
888                         arg->type = in->type;
889                         /* prepend, we'll need to reverse them later */
890                         arg->next = call->out_args;
891                         call->out_args = arg;
892                         if (ainfo->regtype == RegTypeGeneral) {
893                                 arg->unused = ainfo->reg;
894                                 call->used_iregs |= 1 << ainfo->reg;
895                                 if (arg->type == STACK_I8)
896                                         call->used_iregs |= 1 << (ainfo->reg + 1);
897                         } else if (ainfo->regtype == RegTypeBase) {
898                                 g_assert_not_reached ();
899                         } else if (ainfo->regtype == RegTypeFP) {
900                                 arg->opcode = OP_OUTARG_R8;
901                                 arg->unused = ainfo->reg;
902                                 call->used_fregs |= 1 << ainfo->reg;
903                                 if (ainfo->size == 4) {
904                                         /* we reduce the precision */
905                                         MonoInst *conv;
906                                         MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
907                                         conv->inst_left = arg->inst_left;
908                                         arg->inst_left = conv;
909                                 }
910                         } else {
911                                 g_assert_not_reached ();
912                         }
913                 }
914         }
915         /*
916          * Reverse the call->out_args list.
917          */
918         {
919                 MonoInst *prev = NULL, *list = call->out_args, *next;
920                 while (list) {
921                         next = list->next;
922                         list->next = prev;
923                         prev = list;
924                         list = next;
925                 }
926                 call->out_args = prev;
927         }
928         call->stack_usage = cinfo->stack_usage;
929         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
930         cfg->flags |= MONO_CFG_HAS_CALLS;
931         /* 
932          * should set more info in call, such as the stack space
933          * used by the args that needs to be added back to esp
934          */
935
936         g_free (cinfo);
937         return call;
938 }
939
940 /*
941  * Allow tracing to work with this interface (with an optional argument)
942  */
943
944 /*
945  * This may be needed on some archs or for debugging support.
946  */
947 void
948 mono_arch_instrument_mem_needs (MonoMethod *method, int *stack, int *code)
949 {
950         /* no stack room needed now (may be needed for FASTCALL-trace support) */
951         *stack = 0;
952         /* split prolog-epilog requirements? */
953         *code = 50; /* max bytes needed: check this number */
954 }
955
956 void*
957 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
958 {
959         guchar *code = p;
960
961         ppc_load (code, ppc_r3, cfg->method);
962         ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
963         ppc_load (code, ppc_r0, func);
964         ppc_mtlr (code, ppc_r0);
965         ppc_blrl (code);
966         return code;
967 }
968
969 enum {
970         SAVE_NONE,
971         SAVE_STRUCT,
972         SAVE_ONE,
973         SAVE_TWO,
974         SAVE_FP
975 };
976
977 void*
978 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
979 {
980         guchar *code = p;
981         int save_mode = SAVE_NONE;
982         MonoMethod *method = cfg->method;
983         int rtype = method->signature->ret->type;
984         
985 handle_enum:
986         switch (rtype) {
987         case MONO_TYPE_VOID:
988                 /* special case string .ctor icall */
989                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
990                         save_mode = SAVE_ONE;
991                 else
992                         save_mode = SAVE_NONE;
993                 break;
994         case MONO_TYPE_I8:
995         case MONO_TYPE_U8:
996                 save_mode = SAVE_TWO;
997                 break;
998         case MONO_TYPE_R4:
999         case MONO_TYPE_R8:
1000                 save_mode = SAVE_FP;
1001                 break;
1002         case MONO_TYPE_VALUETYPE:
1003                 if (method->signature->ret->data.klass->enumtype) {
1004                         rtype = method->signature->ret->data.klass->enum_basetype->type;
1005                         goto handle_enum;
1006                 }
1007                 save_mode = SAVE_STRUCT;
1008                 break;
1009         default:
1010                 save_mode = SAVE_ONE;
1011                 break;
1012         }
1013
1014         switch (save_mode) {
1015         case SAVE_TWO:
1016                 ppc_stw (code, ppc_r3, cfg->stack_usage - 8, cfg->frame_reg);
1017                 ppc_stw (code, ppc_r4, cfg->stack_usage - 4, cfg->frame_reg);
1018                 if (enable_arguments) {
1019                         ppc_mr (code, ppc_r5, ppc_r4);
1020                         ppc_mr (code, ppc_r4, ppc_r3);
1021                 }
1022                 break;
1023         case SAVE_ONE:
1024                 ppc_stw (code, ppc_r3, cfg->stack_usage - 8, cfg->frame_reg);
1025                 if (enable_arguments) {
1026                         ppc_mr (code, ppc_r4, ppc_r3);
1027                 }
1028                 break;
1029         case SAVE_FP:
1030                 ppc_stfd (code, ppc_f1, cfg->stack_usage - 8, cfg->frame_reg);
1031                 if (enable_arguments) {
1032                         /* FIXME: what reg?  */
1033                         ppc_fmr (code, ppc_f3, ppc_f1);
1034                 }
1035                 break;
1036         case SAVE_STRUCT:
1037                 if (enable_arguments) {
1038                         /* FIXME: get the actual address  */
1039                         ppc_mr (code, ppc_r4, ppc_r3);
1040                 }
1041                 break;
1042         case SAVE_NONE:
1043         default:
1044                 break;
1045         }
1046
1047         ppc_load (code, ppc_r3, cfg->method);
1048         ppc_load (code, ppc_r0, func);
1049         ppc_mtlr (code, ppc_r0);
1050         ppc_blrl (code);
1051
1052         switch (save_mode) {
1053         case SAVE_TWO:
1054                 ppc_lwz (code, ppc_r3, cfg->stack_usage - 8, cfg->frame_reg);
1055                 ppc_lwz (code, ppc_r4, cfg->stack_usage - 4, cfg->frame_reg);
1056                 break;
1057         case SAVE_ONE:
1058                 ppc_lwz (code, ppc_r3, cfg->stack_usage - 8, cfg->frame_reg);
1059                 break;
1060         case SAVE_FP:
1061                 ppc_lfd (code, ppc_f1, cfg->stack_usage - 8, cfg->frame_reg);
1062                 break;
1063         case SAVE_NONE:
1064         default:
1065                 break;
1066         }
1067
1068         return code;
1069 }
1070
1071 #define EMIT_COND_BRANCH(ins,cond) \
1072 if (ins->flags & MONO_INST_BRLABEL) { \
1073         if (ins->inst_i0->inst_c0) { \
1074                 ppc_bc (code, branch_b0_table [cond], branch_b1_table [cond], (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff);      \
1075         } else { \
1076                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1077                 ppc_bc (code, branch_b0_table [cond], branch_b1_table [cond], 0);       \
1078         } \
1079 } else { \
1080         if (0 && ins->inst_true_bb->native_offset) { \
1081                 ppc_bc (code, branch_b0_table [cond], branch_b1_table [cond], (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1082         } else { \
1083                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1084                 ppc_bc (code, branch_b0_table [cond], branch_b1_table [cond], 0);       \
1085         } \
1086 }
1087
1088 /* emit an exception if condition is fail */
1089 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)            \
1090         do {                                                        \
1091                 mono_add_patch_info (cfg, code - cfg->native_code,   \
1092                                     MONO_PATCH_INFO_EXC, exc_name);  \
1093                 x86_branch32 (code, cond, 0, signed);               \
1094         } while (0); 
1095
1096 static void
1097 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1098 {
1099         MonoInst *ins, *last_ins = NULL;
1100         ins = bb->code;
1101
1102         while (ins) {
1103
1104                 switch (ins->opcode) {
1105                 case OP_MUL_IMM: 
1106                         /* remove unnecessary multiplication with 1 */
1107                         if (ins->inst_imm == 1) {
1108                                 if (ins->dreg != ins->sreg1) {
1109                                         ins->opcode = OP_MOVE;
1110                                 } else {
1111                                         last_ins->next = ins->next;                             
1112                                         ins = ins->next;                                
1113                                         continue;
1114                                 }
1115                         }
1116                         break;
1117                 case OP_LOAD_MEMBASE:
1118                 case OP_LOADI4_MEMBASE:
1119                         /* 
1120                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1121                          * OP_LOAD_MEMBASE offset(basereg), reg
1122                          */
1123                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1124                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1125                             ins->inst_basereg == last_ins->inst_destbasereg &&
1126                             ins->inst_offset == last_ins->inst_offset) {
1127                                 if (ins->dreg == last_ins->sreg1) {
1128                                         last_ins->next = ins->next;                             
1129                                         ins = ins->next;                                
1130                                         continue;
1131                                 } else {
1132                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1133                                         ins->opcode = OP_MOVE;
1134                                         ins->sreg1 = last_ins->sreg1;
1135                                 }
1136
1137                         /* 
1138                          * Note: reg1 must be different from the basereg in the second load
1139                          * OP_LOAD_MEMBASE offset(basereg), reg1
1140                          * OP_LOAD_MEMBASE offset(basereg), reg2
1141                          * -->
1142                          * OP_LOAD_MEMBASE offset(basereg), reg1
1143                          * OP_MOVE reg1, reg2
1144                          */
1145                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1146                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1147                               ins->inst_basereg != last_ins->dreg &&
1148                               ins->inst_basereg == last_ins->inst_basereg &&
1149                               ins->inst_offset == last_ins->inst_offset) {
1150
1151                                 if (ins->dreg == last_ins->dreg) {
1152                                         last_ins->next = ins->next;                             
1153                                         ins = ins->next;                                
1154                                         continue;
1155                                 } else {
1156                                         ins->opcode = OP_MOVE;
1157                                         ins->sreg1 = last_ins->dreg;
1158                                 }
1159
1160                                 //g_assert_not_reached ();
1161
1162 #if 0
1163                         /* 
1164                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1165                          * OP_LOAD_MEMBASE offset(basereg), reg
1166                          * -->
1167                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1168                          * OP_ICONST reg, imm
1169                          */
1170                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1171                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1172                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1173                                    ins->inst_offset == last_ins->inst_offset) {
1174                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1175                                 ins->opcode = OP_ICONST;
1176                                 ins->inst_c0 = last_ins->inst_imm;
1177                                 g_assert_not_reached (); // check this rule
1178 #endif
1179                         }
1180                         break;
1181                 case OP_LOADU1_MEMBASE:
1182                 case OP_LOADI1_MEMBASE:
1183                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1184                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1185                                         ins->inst_offset == last_ins->inst_offset) {
1186                                 if (ins->dreg == last_ins->sreg1) {
1187                                         last_ins->next = ins->next;                             
1188                                         ins = ins->next;                                
1189                                         continue;
1190                                 } else {
1191                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1192                                         ins->opcode = OP_MOVE;
1193                                         ins->sreg1 = last_ins->sreg1;
1194                                 }
1195                         }
1196                         break;
1197                 case OP_LOADU2_MEMBASE:
1198                 case OP_LOADI2_MEMBASE:
1199                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1200                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1201                                         ins->inst_offset == last_ins->inst_offset) {
1202                                 if (ins->dreg == last_ins->sreg1) {
1203                                         last_ins->next = ins->next;                             
1204                                         ins = ins->next;                                
1205                                         continue;
1206                                 } else {
1207                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1208                                         ins->opcode = OP_MOVE;
1209                                         ins->sreg1 = last_ins->sreg1;
1210                                 }
1211                         }
1212                         break;
1213                 case CEE_CONV_I4:
1214                 case CEE_CONV_U4:
1215                 case OP_MOVE:
1216                         /* 
1217                          * OP_MOVE reg, reg 
1218                          */
1219                         if (ins->dreg == ins->sreg1) {
1220                                 if (last_ins)
1221                                         last_ins->next = ins->next;                             
1222                                 ins = ins->next;
1223                                 continue;
1224                         }
1225                         /* 
1226                          * OP_MOVE sreg, dreg 
1227                          * OP_MOVE dreg, sreg
1228                          */
1229                         if (last_ins && last_ins->opcode == OP_MOVE &&
1230                             ins->sreg1 == last_ins->dreg &&
1231                             ins->dreg == last_ins->sreg1) {
1232                                 last_ins->next = ins->next;                             
1233                                 ins = ins->next;                                
1234                                 continue;
1235                         }
1236                         break;
1237                 }
1238                 last_ins = ins;
1239                 ins = ins->next;
1240         }
1241         bb->last_ins = last_ins;
1242 }
1243
1244 /* 
1245  * the branch_b0_table should maintain the order of these
1246  * opcodes.
1247 case CEE_BEQ:
1248 case CEE_BGE:
1249 case CEE_BGT:
1250 case CEE_BLE:
1251 case CEE_BLT:
1252 case CEE_BNE_UN:
1253 case CEE_BGE_UN:
1254 case CEE_BGT_UN:
1255 case CEE_BLE_UN:
1256 case CEE_BLT_UN:
1257  */
1258 static const guchar 
1259 branch_b0_table [] = {
1260         PPC_BR_TRUE, 
1261         PPC_BR_FALSE, 
1262         PPC_BR_TRUE, 
1263         PPC_BR_FALSE, 
1264         PPC_BR_TRUE, 
1265         
1266         PPC_BR_FALSE, 
1267         PPC_BR_FALSE, 
1268         PPC_BR_TRUE, 
1269         PPC_BR_FALSE,
1270         PPC_BR_TRUE
1271 };
1272
1273 static const guchar 
1274 branch_b1_table [] = {
1275         PPC_BR_EQ, 
1276         PPC_BR_LT, 
1277         PPC_BR_GT, 
1278         PPC_BR_GT,
1279         PPC_BR_LT, 
1280         
1281         PPC_BR_EQ, 
1282         PPC_BR_LT, 
1283         PPC_BR_GT, 
1284         PPC_BR_GT,
1285         PPC_BR_LT 
1286 };
1287
1288 /*
1289  * returns the offset used by spillvar. It allocates a new
1290  * spill variable if necessary. 
1291  */
1292 static int
1293 mono_spillvar_offset (MonoCompile *cfg, int spillvar)
1294 {
1295         MonoSpillInfo **si, *info;
1296         int i = 0;
1297
1298         si = &cfg->spill_info; 
1299         
1300         while (i <= spillvar) {
1301
1302                 if (!*si) {
1303                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1304                         info->next = NULL;
1305                         info->offset = cfg->stack_offset;
1306                         cfg->stack_offset += sizeof (gpointer);
1307                 }
1308
1309                 if (i == spillvar)
1310                         return (*si)->offset;
1311
1312                 i++;
1313                 si = &(*si)->next;
1314         }
1315
1316         g_assert_not_reached ();
1317         return 0;
1318 }
1319
1320 static int
1321 mono_spillvar_offset_float (MonoCompile *cfg, int spillvar)
1322 {
1323         MonoSpillInfo **si, *info;
1324         int i = 0;
1325
1326         si = &cfg->spill_info_float; 
1327         
1328         while (i <= spillvar) {
1329
1330                 if (!*si) {
1331                         *si = info = mono_mempool_alloc (cfg->mempool, sizeof (MonoSpillInfo));
1332                         info->next = NULL;
1333                         cfg->stack_offset += 7;
1334                         cfg->stack_offset &= ~7;
1335                         info->offset = cfg->stack_offset;
1336                         cfg->stack_offset += sizeof (double);
1337                 }
1338
1339                 if (i == spillvar)
1340                         return (*si)->offset;
1341
1342                 i++;
1343                 si = &(*si)->next;
1344         }
1345
1346         g_assert_not_reached ();
1347         return 0;
1348 }
1349
1350 #undef DEBUG
1351 #define DEBUG(a) if (cfg->verbose_level > 1) a
1352 //#define DEBUG(a)
1353 #define reg_is_freeable(r) ((r) >= 3 && (r) <= 10)
1354 #define freg_is_freeable(r) ((r) >= 1 && (r) <= 14)
1355
1356 typedef struct {
1357         int born_in;
1358         int killed_in;
1359         int last_use;
1360         int prev_use;
1361 } RegTrack;
1362
1363 static const char*const * ins_spec = ppcg4;
1364
1365 static void
1366 print_ins (int i, MonoInst *ins)
1367 {
1368         const char *spec = ins_spec [ins->opcode];
1369         g_print ("\t%-2d %s", i, mono_inst_name (ins->opcode));
1370         if (spec [MONO_INST_DEST]) {
1371                 if (ins->dreg >= MONO_MAX_IREGS)
1372                         g_print (" R%d <-", ins->dreg);
1373                 else
1374                         g_print (" %s <-", mono_arch_regname (ins->dreg));
1375         }
1376         if (spec [MONO_INST_SRC1]) {
1377                 if (ins->sreg1 >= MONO_MAX_IREGS)
1378                         g_print (" R%d", ins->sreg1);
1379                 else
1380                         g_print (" %s", mono_arch_regname (ins->sreg1));
1381         }
1382         if (spec [MONO_INST_SRC2]) {
1383                 if (ins->sreg2 >= MONO_MAX_IREGS)
1384                         g_print (" R%d", ins->sreg2);
1385                 else
1386                         g_print (" %s", mono_arch_regname (ins->sreg2));
1387         }
1388         if (spec [MONO_INST_CLOB])
1389                 g_print (" clobbers: %c", spec [MONO_INST_CLOB]);
1390         g_print ("\n");
1391 }
1392
1393 static void
1394 print_regtrack (RegTrack *t, int num)
1395 {
1396         int i;
1397         char buf [32];
1398         const char *r;
1399         
1400         for (i = 0; i < num; ++i) {
1401                 if (!t [i].born_in)
1402                         continue;
1403                 if (i >= MONO_MAX_IREGS) {
1404                         g_snprintf (buf, sizeof(buf), "R%d", i);
1405                         r = buf;
1406                 } else
1407                         r = mono_arch_regname (i);
1408                 g_print ("liveness: %s [%d - %d]\n", r, t [i].born_in, t[i].last_use);
1409         }
1410 }
1411
1412 typedef struct InstList InstList;
1413
1414 struct InstList {
1415         InstList *prev;
1416         InstList *next;
1417         MonoInst *data;
1418 };
1419
1420 static inline InstList*
1421 inst_list_prepend (MonoMemPool *pool, InstList *list, MonoInst *data)
1422 {
1423         InstList *item = mono_mempool_alloc (pool, sizeof (InstList));
1424         item->data = data;
1425         item->prev = NULL;
1426         item->next = list;
1427         if (list)
1428                 list->prev = item;
1429         return item;
1430 }
1431
1432 /*
1433  * Force the spilling of the variable in the symbolic register 'reg'.
1434  */
1435 static int
1436 get_register_force_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, int reg)
1437 {
1438         MonoInst *load;
1439         int i, sel, spill;
1440         
1441         sel = cfg->rs->iassign [reg];
1442         /*i = cfg->rs->isymbolic [sel];
1443         g_assert (i == reg);*/
1444         i = reg;
1445         spill = ++cfg->spill_count;
1446         cfg->rs->iassign [i] = -spill - 1;
1447         mono_regstate_free_int (cfg->rs, sel);
1448         /* we need to create a spill var and insert a load to sel after the current instruction */
1449         MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1450         load->dreg = sel;
1451         load->inst_basereg = cfg->frame_reg;
1452         load->inst_offset = mono_spillvar_offset (cfg, spill);
1453         if (item->prev) {
1454                 while (ins->next != item->prev->data)
1455                         ins = ins->next;
1456         }
1457         load->next = ins->next;
1458         ins->next = load;
1459         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1460         i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1461         g_assert (i == sel);
1462
1463         return sel;
1464 }
1465
1466 static int
1467 get_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1468 {
1469         MonoInst *load;
1470         int i, sel, spill;
1471
1472         DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
1473         /* exclude the registers in the current instruction */
1474         if (reg != ins->sreg1 && (reg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg1] >= 0))) {
1475                 if (ins->sreg1 >= MONO_MAX_IREGS)
1476                         regmask &= ~ (1 << cfg->rs->iassign [ins->sreg1]);
1477                 else
1478                         regmask &= ~ (1 << ins->sreg1);
1479                 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1480         }
1481         if (reg != ins->sreg2 && (reg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_IREGS && cfg->rs->iassign [ins->sreg2] >= 0))) {
1482                 if (ins->sreg2 >= MONO_MAX_IREGS)
1483                         regmask &= ~ (1 << cfg->rs->iassign [ins->sreg2]);
1484                 else
1485                         regmask &= ~ (1 << ins->sreg2);
1486                 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1487         }
1488         if (reg != ins->dreg && reg_is_freeable (ins->dreg)) {
1489                 regmask &= ~ (1 << ins->dreg);
1490                 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
1491         }
1492
1493         DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
1494         g_assert (regmask); /* need at least a register we can free */
1495         sel = -1;
1496         /* we should track prev_use and spill the register that's farther */
1497         for (i = 0; i < MONO_MAX_IREGS; ++i) {
1498                 if (regmask & (1 << i)) {
1499                         sel = i;
1500                         DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->iassign [sel]));
1501                         break;
1502                 }
1503         }
1504         i = cfg->rs->isymbolic [sel];
1505         spill = ++cfg->spill_count;
1506         cfg->rs->iassign [i] = -spill - 1;
1507         mono_regstate_free_int (cfg->rs, sel);
1508         /* we need to create a spill var and insert a load to sel after the current instruction */
1509         MONO_INST_NEW (cfg, load, OP_LOAD_MEMBASE);
1510         load->dreg = sel;
1511         load->inst_basereg = cfg->frame_reg;
1512         load->inst_offset = mono_spillvar_offset (cfg, spill);
1513         if (item->prev) {
1514                 while (ins->next != item->prev->data)
1515                         ins = ins->next;
1516         }
1517         load->next = ins->next;
1518         ins->next = load;
1519         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1520         i = mono_regstate_alloc_int (cfg->rs, 1 << sel);
1521         g_assert (i == sel);
1522         
1523         return sel;
1524 }
1525
1526 static int
1527 get_float_register_spilling (MonoCompile *cfg, InstList *item, MonoInst *ins, guint32 regmask, int reg)
1528 {
1529         MonoInst *load;
1530         int i, sel, spill;
1531
1532         DEBUG (g_print ("start regmask to assign R%d: 0x%08x (R%d <- R%d R%d)\n", reg, regmask, ins->dreg, ins->sreg1, ins->sreg2));
1533         /* exclude the registers in the current instruction */
1534         if (reg != ins->sreg1 && (freg_is_freeable (ins->sreg1) || (ins->sreg1 >= MONO_MAX_FREGS && cfg->rs->fassign [ins->sreg1] >= 0))) {
1535                 if (ins->sreg1 >= MONO_MAX_FREGS)
1536                         regmask &= ~ (1 << cfg->rs->fassign [ins->sreg1]);
1537                 else
1538                         regmask &= ~ (1 << ins->sreg1);
1539                 DEBUG (g_print ("excluding sreg1 %s\n", mono_arch_regname (ins->sreg1)));
1540         }
1541         if (reg != ins->sreg2 && (freg_is_freeable (ins->sreg2) || (ins->sreg2 >= MONO_MAX_FREGS && cfg->rs->fassign [ins->sreg2] >= 0))) {
1542                 if (ins->sreg2 >= MONO_MAX_FREGS)
1543                         regmask &= ~ (1 << cfg->rs->fassign [ins->sreg2]);
1544                 else
1545                         regmask &= ~ (1 << ins->sreg2);
1546                 DEBUG (g_print ("excluding sreg2 %s %d\n", mono_arch_regname (ins->sreg2), ins->sreg2));
1547         }
1548         if (reg != ins->dreg && freg_is_freeable (ins->dreg)) {
1549                 regmask &= ~ (1 << ins->dreg);
1550                 DEBUG (g_print ("excluding dreg %s\n", mono_arch_regname (ins->dreg)));
1551         }
1552
1553         DEBUG (g_print ("available regmask: 0x%08x\n", regmask));
1554         g_assert (regmask); /* need at least a register we can free */
1555         sel = -1;
1556         /* we should track prev_use and spill the register that's farther */
1557         for (i = 0; i < MONO_MAX_FREGS; ++i) {
1558                 if (regmask & (1 << i)) {
1559                         sel = i;
1560                         DEBUG (g_print ("selected register %s has assignment %d\n", mono_arch_regname (sel), cfg->rs->fassign [sel]));
1561                         break;
1562                 }
1563         }
1564         i = cfg->rs->fsymbolic [sel];
1565         spill = ++cfg->spill_count;
1566         cfg->rs->fassign [i] = -spill - 1;
1567         mono_regstate_free_float(cfg->rs, sel);
1568         /* we need to create a spill var and insert a load to sel after the current instruction */
1569         MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
1570         load->dreg = sel;
1571         load->inst_basereg = cfg->frame_reg;
1572         load->inst_offset = mono_spillvar_offset_float (cfg, spill);
1573         if (item->prev) {
1574                 while (ins->next != item->prev->data)
1575                         ins = ins->next;
1576         }
1577         load->next = ins->next;
1578         ins->next = load;
1579         DEBUG (g_print ("SPILLED LOAD (%d at 0x%08x(%%sp)) R%d (freed %s)\n", spill, load->inst_offset, i, mono_arch_regname (sel)));
1580         i = mono_regstate_alloc_float (cfg->rs, 1 << sel);
1581         g_assert (i == sel);
1582         
1583         return sel;
1584 }
1585
1586 static MonoInst*
1587 create_copy_ins (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1588 {
1589         MonoInst *copy;
1590         MONO_INST_NEW (cfg, copy, OP_MOVE);
1591         copy->dreg = dest;
1592         copy->sreg1 = src;
1593         if (ins) {
1594                 copy->next = ins->next;
1595                 ins->next = copy;
1596         }
1597         DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1598         return copy;
1599 }
1600
1601 static MonoInst*
1602 create_copy_ins_float (MonoCompile *cfg, int dest, int src, MonoInst *ins)
1603 {
1604         MonoInst *copy;
1605         MONO_INST_NEW (cfg, copy, OP_FMOVE);
1606         copy->dreg = dest;
1607         copy->sreg1 = src;
1608         if (ins) {
1609                 copy->next = ins->next;
1610                 ins->next = copy;
1611         }
1612         DEBUG (g_print ("\tforced copy from %s to %s\n", mono_arch_regname (src), mono_arch_regname (dest)));
1613         return copy;
1614 }
1615
1616 static MonoInst*
1617 create_spilled_store (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1618 {
1619         MonoInst *store;
1620         MONO_INST_NEW (cfg, store, OP_STORE_MEMBASE_REG);
1621         store->sreg1 = reg;
1622         store->inst_destbasereg = cfg->frame_reg;
1623         store->inst_offset = mono_spillvar_offset (cfg, spill);
1624         if (ins) {
1625                 store->next = ins->next;
1626                 ins->next = store;
1627         }
1628         DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
1629         return store;
1630 }
1631
1632 static MonoInst*
1633 create_spilled_store_float (MonoCompile *cfg, int spill, int reg, int prev_reg, MonoInst *ins)
1634 {
1635         MonoInst *store;
1636         MONO_INST_NEW (cfg, store, OP_STORER8_MEMBASE_REG);
1637         store->sreg1 = reg;
1638         store->inst_destbasereg = cfg->frame_reg;
1639         store->inst_offset = mono_spillvar_offset_float (cfg, spill);
1640         if (ins) {
1641                 store->next = ins->next;
1642                 ins->next = store;
1643         }
1644         DEBUG (g_print ("SPILLED STORE (%d at 0x%08x(%%sp)) R%d (from %s)\n", spill, store->inst_offset, prev_reg, mono_arch_regname (reg)));
1645         return store;
1646 }
1647
1648 static void
1649 insert_before_ins (MonoInst *ins, InstList *item, MonoInst* to_insert)
1650 {
1651         MonoInst *prev;
1652         g_assert (item->next);
1653         prev = item->next->data;
1654
1655         while (prev->next != ins)
1656                 prev = prev->next;
1657         to_insert->next = ins;
1658         prev->next = to_insert;
1659         /* 
1660          * needed otherwise in the next instruction we can add an ins to the 
1661          * end and that would get past this instruction.
1662          */
1663         item->data = to_insert; 
1664 }
1665
1666 static int
1667 alloc_int_reg (MonoCompile *cfg, InstList *curinst, MonoInst *ins, int sym_reg, guint32 allow_mask)
1668 {
1669         int val = cfg->rs->iassign [sym_reg];
1670         if (val < 0) {
1671                 int spill = 0;
1672                 if (val < -1) {
1673                         /* the register gets spilled after this inst */
1674                         spill = -val -1;
1675                 }
1676                 val = mono_regstate_alloc_int (cfg->rs, allow_mask);
1677                 if (val < 0)
1678                         val = get_register_spilling (cfg, curinst, ins, allow_mask, sym_reg);
1679                 cfg->rs->iassign [sym_reg] = val;
1680                 /* add option to store before the instruction for src registers */
1681                 if (spill)
1682                         create_spilled_store (cfg, spill, val, sym_reg, ins);
1683         }
1684         cfg->rs->isymbolic [val] = sym_reg;
1685         return val;
1686 }
1687
1688 /* use ppc_r3-ppc_10 as temp registers */
1689 #define PPC_CALLER_REGS (0xff<<3)
1690 #define PPC_CALLER_FREGS (0xff<<2)
1691
1692 /*
1693  * Local register allocation.
1694  * We first scan the list of instructions and we save the liveness info of
1695  * each register (when the register is first used, when it's value is set etc.).
1696  * We also reverse the list of instructions (in the InstList list) because assigning
1697  * registers backwards allows for more tricks to be used.
1698  */
1699 void
1700 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1701 {
1702         MonoInst *ins;
1703         MonoRegState *rs = cfg->rs;
1704         int i, val;
1705         RegTrack *reginfo, *reginfof;
1706         RegTrack *reginfo1, *reginfo2, *reginfod;
1707         InstList *tmp, *reversed = NULL;
1708         const char *spec;
1709         guint32 src1_mask, src2_mask, dest_mask;
1710         guint32 cur_iregs, cur_fregs;
1711
1712         if (!bb->code)
1713                 return;
1714         rs->next_vireg = bb->max_ireg;
1715         rs->next_vfreg = bb->max_freg;
1716         mono_regstate_assign (rs);
1717         reginfo = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vireg);
1718         reginfof = mono_mempool_alloc0 (cfg->mempool, sizeof (RegTrack) * rs->next_vfreg);
1719         rs->ifree_mask = PPC_CALLER_REGS;
1720         rs->ffree_mask = PPC_CALLER_FREGS;
1721
1722         ins = bb->code;
1723         i = 1;
1724         DEBUG (g_print ("LOCAL regalloc: basic block: %d\n", bb->block_num));
1725         /* forward pass on the instructions to collect register liveness info */
1726         while (ins) {
1727                 spec = ins_spec [ins->opcode];
1728                 DEBUG (print_ins (i, ins));
1729                 if (spec [MONO_INST_CLOB] == 'c') {
1730                         MonoCallInst * call = (MonoCallInst*)ins;
1731                         int j;
1732                 }
1733                 if (spec [MONO_INST_SRC1]) {
1734                         if (spec [MONO_INST_SRC1] == 'f')
1735                                 reginfo1 = reginfof;
1736                         else
1737                                 reginfo1 = reginfo;
1738                         reginfo1 [ins->sreg1].prev_use = reginfo1 [ins->sreg1].last_use;
1739                         reginfo1 [ins->sreg1].last_use = i;
1740                 } else {
1741                         ins->sreg1 = -1;
1742                 }
1743                 if (spec [MONO_INST_SRC2]) {
1744                         if (spec [MONO_INST_SRC2] == 'f')
1745                                 reginfo2 = reginfof;
1746                         else
1747                                 reginfo2 = reginfo;
1748                         reginfo2 [ins->sreg2].prev_use = reginfo2 [ins->sreg2].last_use;
1749                         reginfo2 [ins->sreg2].last_use = i;
1750                 } else {
1751                         ins->sreg2 = -1;
1752                 }
1753                 if (spec [MONO_INST_DEST]) {
1754                         if (spec [MONO_INST_DEST] == 'f')
1755                                 reginfod = reginfof;
1756                         else
1757                                 reginfod = reginfo;
1758                         if (spec [MONO_INST_DEST] != 'b') /* it's not just a base register */
1759                                 reginfod [ins->dreg].killed_in = i;
1760                         reginfod [ins->dreg].prev_use = reginfod [ins->dreg].last_use;
1761                         reginfod [ins->dreg].last_use = i;
1762                         if (reginfod [ins->dreg].born_in == 0 || reginfod [ins->dreg].born_in > i)
1763                                 reginfod [ins->dreg].born_in = i;
1764                         if (spec [MONO_INST_DEST] == 'l') {
1765                                 /* result in eax:edx, the virtual register is allocated sequentially */
1766                                 reginfod [ins->dreg + 1].prev_use = reginfod [ins->dreg + 1].last_use;
1767                                 reginfod [ins->dreg + 1].last_use = i;
1768                                 if (reginfod [ins->dreg + 1].born_in == 0 || reginfod [ins->dreg + 1].born_in > i)
1769                                         reginfod [ins->dreg + 1].born_in = i;
1770                         }
1771                 } else {
1772                         ins->dreg = -1;
1773                 }
1774                 reversed = inst_list_prepend (cfg->mempool, reversed, ins);
1775                 ++i;
1776                 ins = ins->next;
1777         }
1778
1779         cur_iregs = PPC_CALLER_REGS;
1780         cur_fregs = PPC_CALLER_FREGS;
1781
1782         DEBUG (print_regtrack (reginfo, rs->next_vireg));
1783         DEBUG (print_regtrack (reginfof, rs->next_vfreg));
1784         tmp = reversed;
1785         while (tmp) {
1786                 int prev_dreg, prev_sreg1, prev_sreg2;
1787                 --i;
1788                 ins = tmp->data;
1789                 spec = ins_spec [ins->opcode];
1790                 DEBUG (g_print ("processing:"));
1791                 DEBUG (print_ins (i, ins));
1792                 /* make the register available for allocation: FIXME add fp reg */
1793                 if (ins->opcode == OP_SETREG) {
1794                         cur_iregs |= 1 << ins->dreg;
1795                         DEBUG (g_print ("adding %d to cur_iregs\n", ins->dreg));
1796                 } else if (ins->opcode == OP_SETFREG) {
1797                         cur_fregs |= 1 << ins->dreg;
1798                         DEBUG (g_print ("adding %d to cur_fregs\n", ins->dreg));
1799                 } else if (spec [MONO_INST_CLOB] == 'c') {
1800                         MonoCallInst *cinst = (MonoCallInst*)ins;
1801                         DEBUG (g_print ("excluding regs 0x%x from cur_iregs (0x%x)\n", cinst->used_iregs, cur_iregs));
1802                         cur_iregs &= ~cinst->used_iregs;
1803                         cur_fregs &= ~cinst->used_fregs;
1804                         DEBUG (g_print ("available cur_iregs: 0x%x\n", cur_iregs));
1805                         /* registers used by the calling convention are excluded from 
1806                          * allocation: they will be selectively enabled when they are 
1807                          * assigned by the special SETREG opcodes.
1808                          */
1809                 }
1810                 dest_mask = src1_mask = src2_mask = cur_iregs;
1811                 /* update for use with FP regs... */
1812                 if (spec [MONO_INST_DEST] == 'f') {
1813                         if (ins->dreg >= MONO_MAX_FREGS) {
1814                                 val = rs->fassign [ins->dreg];
1815                                 prev_dreg = ins->dreg;
1816                                 if (val < 0) {
1817                                         int spill = 0;
1818                                         if (val < -1) {
1819                                                 /* the register gets spilled after this inst */
1820                                                 spill = -val -1;
1821                                         }
1822                                         val = mono_regstate_alloc_float (rs, dest_mask);
1823                                         if (val < 0)
1824                                                 val = get_float_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1825                                         rs->fassign [ins->dreg] = val;
1826                                         if (spill)
1827                                                 create_spilled_store_float (cfg, spill, val, prev_dreg, ins);
1828                                 }
1829                                 DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1830                                 rs->fsymbolic [val] = prev_dreg;
1831                                 ins->dreg = val;
1832                                 if (spec [MONO_INST_CLOB] == 'c' && ins->dreg != ppc_f1) {
1833                                         /* this instruction only outputs to ppc_f3, need to copy */
1834                                         create_copy_ins_float (cfg, ins->dreg, ppc_f1, ins);
1835                                 }
1836                         } else {
1837                                 prev_dreg = -1;
1838                         }
1839                         if (freg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i || !(cur_fregs & (1 << ins->dreg)))) {
1840                                 DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
1841                                 mono_regstate_free_float (rs, ins->dreg);
1842                         }
1843                 } else if (ins->dreg >= MONO_MAX_IREGS) {
1844                         val = rs->iassign [ins->dreg];
1845                         prev_dreg = ins->dreg;
1846                         if (val < 0) {
1847                                 int spill = 0;
1848                                 if (val < -1) {
1849                                         /* the register gets spilled after this inst */
1850                                         spill = -val -1;
1851                                 }
1852                                 val = mono_regstate_alloc_int (rs, dest_mask);
1853                                 if (val < 0)
1854                                         val = get_register_spilling (cfg, tmp, ins, dest_mask, ins->dreg);
1855                                 rs->iassign [ins->dreg] = val;
1856                                 if (spill)
1857                                         create_spilled_store (cfg, spill, val, prev_dreg, ins);
1858                         }
1859                         DEBUG (g_print ("\tassigned dreg %s to dest R%d\n", mono_arch_regname (val), ins->dreg));
1860                         rs->isymbolic [val] = prev_dreg;
1861                         ins->dreg = val;
1862                         if (spec [MONO_INST_DEST] == 'l') {
1863                                 int hreg = prev_dreg + 1;
1864                                 val = rs->iassign [hreg];
1865                                 if (val < 0) {
1866                                         int spill = 0;
1867                                         if (val < -1) {
1868                                                 /* the register gets spilled after this inst */
1869                                                 spill = -val -1;
1870                                         }
1871                                         val = mono_regstate_alloc_int (rs, dest_mask);
1872                                         if (val < 0)
1873                                                 val = get_register_spilling (cfg, tmp, ins, dest_mask, hreg);
1874                                         rs->iassign [hreg] = val;
1875                                         if (spill)
1876                                                 create_spilled_store (cfg, spill, val, hreg, ins);
1877                                 }
1878                                 DEBUG (g_print ("\tassigned hreg %s to dest R%d\n", mono_arch_regname (val), hreg));
1879                                 rs->isymbolic [val] = hreg;
1880                                 /* FIXME:? ins->dreg = val; */
1881                                 if (ins->dreg == ppc_r4) {
1882                                         if (val != ppc_r3)
1883                                                 create_copy_ins (cfg, val, ppc_r3, ins);
1884                                 } else if (ins->dreg == ppc_r3) {
1885                                         if (val == ppc_r4) {
1886                                                 /* swap */
1887                                                 create_copy_ins (cfg, ppc_r4, ppc_r0, ins);
1888                                                 create_copy_ins (cfg, ppc_r3, ppc_r4, ins);
1889                                                 create_copy_ins (cfg, ppc_r0, ppc_r3, ins);
1890                                         } else {
1891                                                 /* two forced copies */
1892                                                 create_copy_ins (cfg, val, ppc_r3, ins);
1893                                                 create_copy_ins (cfg, ins->dreg, ppc_r4, ins);
1894                                         }
1895                                 } else {
1896                                         if (val == ppc_r3) {
1897                                                 create_copy_ins (cfg, ins->dreg, ppc_r4, ins);
1898                                         } else {
1899                                                 /* two forced copies */
1900                                                 create_copy_ins (cfg, val, ppc_r3, ins);
1901                                                 create_copy_ins (cfg, ins->dreg, ppc_r4, ins);
1902                                         }
1903                                 }
1904                                 if (reg_is_freeable (val) && hreg >= 0 && (reginfo [hreg].born_in >= i && !(cur_iregs & (1 << val)))) {
1905                                         DEBUG (g_print ("\tfreeable %s (R%d)\n", mono_arch_regname (val), hreg));
1906                                         mono_regstate_free_int (rs, val);
1907                                 }
1908                         } else if (spec [MONO_INST_DEST] == 'a' && ins->dreg != ppc_r3 && spec [MONO_INST_CLOB] != 'd') {
1909                                 /* this instruction only outputs to ppc_r3, need to copy */
1910                                 create_copy_ins (cfg, ins->dreg, ppc_r3, ins);
1911                         }
1912                 } else {
1913                         prev_dreg = -1;
1914                 }
1915                 if (spec [MONO_INST_DEST] != 'f' && reg_is_freeable (ins->dreg) && prev_dreg >= 0 && (reginfo [prev_dreg].born_in >= i)) {
1916                         DEBUG (g_print ("\tfreeable %s (R%d) (born in %d)\n", mono_arch_regname (ins->dreg), prev_dreg, reginfo [prev_dreg].born_in));
1917                         mono_regstate_free_int (rs, ins->dreg);
1918                 }
1919                 if (spec [MONO_INST_SRC1] == 'f') {
1920                         if (ins->sreg1 >= MONO_MAX_FREGS) {
1921                                 val = rs->fassign [ins->sreg1];
1922                                 prev_sreg1 = ins->sreg1;
1923                                 if (val < 0) {
1924                                         int spill = 0;
1925                                         if (val < -1) {
1926                                                 /* the register gets spilled after this inst */
1927                                                 spill = -val -1;
1928                                         }
1929                                         //g_assert (val == -1); /* source cannot be spilled */
1930                                         val = mono_regstate_alloc_float (rs, src1_mask);
1931                                         if (val < 0)
1932                                                 val = get_float_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
1933                                         rs->fassign [ins->sreg1] = val;
1934                                         DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1935                                         if (spill) {
1936                                                 MonoInst *store = create_spilled_store_float (cfg, spill, val, prev_sreg1, NULL);
1937                                                 insert_before_ins (ins, tmp, store);
1938                                         }
1939                                 }
1940                                 rs->fsymbolic [val] = prev_sreg1;
1941                                 ins->sreg1 = val;
1942                         } else {
1943                                 prev_sreg1 = -1;
1944                         }
1945                 } else if (ins->sreg1 >= MONO_MAX_IREGS) {
1946                         val = rs->iassign [ins->sreg1];
1947                         prev_sreg1 = ins->sreg1;
1948                         if (val < 0) {
1949                                 int spill = 0;
1950                                 if (val < -1) {
1951                                         /* the register gets spilled after this inst */
1952                                         spill = -val -1;
1953                                 }
1954                                 if (0 && ins->opcode == OP_MOVE) {
1955                                         /* 
1956                                          * small optimization: the dest register is already allocated
1957                                          * but the src one is not: we can simply assign the same register
1958                                          * here and peephole will get rid of the instruction later.
1959                                          * This optimization may interfere with the clobbering handling:
1960                                          * it removes a mov operation that will be added again to handle clobbering.
1961                                          * There are also some other issues that should with make testjit.
1962                                          */
1963                                         mono_regstate_alloc_int (rs, 1 << ins->dreg);
1964                                         val = rs->iassign [ins->sreg1] = ins->dreg;
1965                                         //g_assert (val >= 0);
1966                                         DEBUG (g_print ("\tfast assigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1967                                 } else {
1968                                         //g_assert (val == -1); /* source cannot be spilled */
1969                                         val = mono_regstate_alloc_int (rs, src1_mask);
1970                                         if (val < 0)
1971                                                 val = get_register_spilling (cfg, tmp, ins, src1_mask, ins->sreg1);
1972                                         rs->iassign [ins->sreg1] = val;
1973                                         DEBUG (g_print ("\tassigned sreg1 %s to R%d\n", mono_arch_regname (val), ins->sreg1));
1974                                 }
1975                                 if (spill) {
1976                                         MonoInst *store = create_spilled_store (cfg, spill, val, prev_sreg1, NULL);
1977                                         insert_before_ins (ins, tmp, store);
1978                                 }
1979                         }
1980                         rs->isymbolic [val] = prev_sreg1;
1981                         ins->sreg1 = val;
1982                 } else {
1983                         prev_sreg1 = -1;
1984                 }
1985                 if (spec [MONO_INST_SRC2] == 'f') {
1986                         if (ins->sreg2 >= MONO_MAX_FREGS) {
1987                                 val = rs->fassign [ins->sreg2];
1988                                 prev_sreg2 = ins->sreg2;
1989                                 if (val < 0) {
1990                                         int spill = 0;
1991                                         if (val < -1) {
1992                                                 /* the register gets spilled after this inst */
1993                                                 spill = -val -1;
1994                                         }
1995                                         val = mono_regstate_alloc_float (rs, src2_mask);
1996                                         if (val < 0)
1997                                                 val = get_float_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
1998                                         rs->fassign [ins->sreg2] = val;
1999                                         DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
2000                                         if (spill)
2001                                                 create_spilled_store_float (cfg, spill, val, prev_sreg2, ins);
2002                                 }
2003                                 rs->fsymbolic [val] = prev_sreg2;
2004                                 ins->sreg2 = val;
2005                         } else {
2006                                 prev_sreg2 = -1;
2007                         }
2008                 } else if (ins->sreg2 >= MONO_MAX_IREGS) {
2009                         val = rs->iassign [ins->sreg2];
2010                         prev_sreg2 = ins->sreg2;
2011                         if (val < 0) {
2012                                 int spill = 0;
2013                                 if (val < -1) {
2014                                         /* the register gets spilled after this inst */
2015                                         spill = -val -1;
2016                                 }
2017                                 val = mono_regstate_alloc_int (rs, src2_mask);
2018                                 if (val < 0)
2019                                         val = get_register_spilling (cfg, tmp, ins, src2_mask, ins->sreg2);
2020                                 rs->iassign [ins->sreg2] = val;
2021                                 DEBUG (g_print ("\tassigned sreg2 %s to R%d\n", mono_arch_regname (val), ins->sreg2));
2022                                 if (spill)
2023                                         create_spilled_store (cfg, spill, val, prev_sreg2, ins);
2024                         }
2025                         rs->isymbolic [val] = prev_sreg2;
2026                         ins->sreg2 = val;
2027                 } else {
2028                         prev_sreg2 = -1;
2029                 }
2030
2031                 if (spec [MONO_INST_CLOB] == 'c') {
2032                         int j, s;
2033                         guint32 clob_mask = PPC_CALLER_REGS;
2034                         for (j = 0; j < MONO_MAX_IREGS; ++j) {
2035                                 s = 1 << j;
2036                                 if ((clob_mask & s) && !(rs->ifree_mask & s) && j != ins->sreg1) {
2037                                         //g_warning ("register %s busy at call site\n", mono_arch_regname (j));
2038                                 }
2039                         }
2040                 }
2041                 /*if (reg_is_freeable (ins->sreg1) && prev_sreg1 >= 0 && reginfo [prev_sreg1].born_in >= i) {
2042                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg1)));
2043                         mono_regstate_free_int (rs, ins->sreg1);
2044                 }
2045                 if (reg_is_freeable (ins->sreg2) && prev_sreg2 >= 0 && reginfo [prev_sreg2].born_in >= i) {
2046                         DEBUG (g_print ("freeable %s\n", mono_arch_regname (ins->sreg2)));
2047                         mono_regstate_free_int (rs, ins->sreg2);
2048                 }*/
2049                 
2050                 //DEBUG (print_ins (i, ins));
2051                 tmp = tmp->next;
2052         }
2053 }
2054
2055 static guchar*
2056 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2057 {
2058         /* sreg is a float, dreg is an integer reg. ppc_f1 is used a scratch */
2059         ppc_fctiwz (code, ppc_f1, sreg);
2060         ppc_stfd (code, ppc_f1, -8, ppc_sp);
2061         ppc_lwz (code, dreg, -4, ppc_sp);
2062         if (!is_signed) {
2063                 if (size == 1)
2064                         ppc_andid (code, dreg, dreg, 0xff);
2065                 else if (size == 2)
2066                         ppc_andid (code, dreg, dreg, 0xffff);
2067         } else {
2068                 if (size == 1)
2069                         ppc_extsb (code, dreg, dreg);
2070                 else if (size == 2)
2071                         ppc_extsh (code, dreg, dreg);
2072         }
2073         return code;
2074 }
2075
2076 static unsigned char*
2077 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
2078 {
2079 #if 0
2080         int sreg = tree->sreg1;
2081         x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
2082         if (tree->flags & MONO_INST_INIT) {
2083                 int offset = 0;
2084                 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
2085                         x86_push_reg (code, X86_EAX);
2086                         offset += 4;
2087                 }
2088                 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
2089                         x86_push_reg (code, X86_ECX);
2090                         offset += 4;
2091                 }
2092                 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
2093                         x86_push_reg (code, X86_EDI);
2094                         offset += 4;
2095                 }
2096                 
2097                 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
2098                 if (sreg != X86_ECX)
2099                         x86_mov_reg_reg (code, X86_ECX, sreg, 4);
2100                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
2101                                 
2102                 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
2103                 x86_cld (code);
2104                 x86_prefix (code, X86_REP_PREFIX);
2105                 x86_stosl (code);
2106                 
2107                 if (tree->dreg != X86_EDI && sreg != X86_EDI)
2108                         x86_pop_reg (code, X86_EDI);
2109                 if (tree->dreg != X86_ECX && sreg != X86_ECX)
2110                         x86_pop_reg (code, X86_ECX);
2111                 if (tree->dreg != X86_EAX && sreg != X86_EAX)
2112                         x86_pop_reg (code, X86_EAX);
2113         }
2114 #endif
2115         return code;
2116 }
2117
2118 void
2119 ppc_patch (guchar *code, guchar *target)
2120 {
2121         guint32 ins = *(guint32*)code;
2122         guint32 prim = ins >> 26;
2123
2124 //      g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2125         if (prim == 18) {
2126                 // absolute address
2127                 if (ins & 2) {
2128                         guint32 li = (guint32)target;
2129                         ins = prim << 26 | (ins & 3);
2130                         ins |= li;
2131                         // FIXME: assert the top bits of li are 0
2132                 } else {
2133                         gint diff = target - code;
2134                         ins = prim << 26 | (ins & 3);
2135                         diff &= ~3;
2136                         diff &= ~(63 << 26);
2137                         ins |= diff;
2138                 }
2139                 *(guint32*)code = ins;
2140         } else if (prim == 16) {
2141                 // absolute address
2142                 if (ins & 2) {
2143                         guint32 li = (guint32)target;
2144                         ins = (ins & 0xffff0000) | (ins & 3);
2145                         li &= 0xffff;
2146                         ins |= li;
2147                         // FIXME: assert the top bits of li are 0
2148                 } else {
2149                         gint diff = target - code;
2150                         ins = (ins & 0xffff0000) | (ins & 3);
2151                         diff &= 0xffff;
2152                         ins |= diff;
2153                 }
2154                 *(guint32*)code = ins;
2155         } else {
2156                 g_assert_not_reached ();
2157         }
2158 //      g_print ("patched with 0x%08x\n", ins);
2159 }
2160
2161 void
2162 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2163 {
2164         MonoInst *ins;
2165         MonoCallInst *call;
2166         guint offset;
2167         guint8 *code = cfg->native_code + cfg->code_len;
2168         MonoInst *last_ins = NULL;
2169         guint last_offset = 0;
2170         int max_len, cpos;
2171
2172         if (cfg->opt & MONO_OPT_PEEPHOLE)
2173                 peephole_pass (cfg, bb);
2174
2175         /* we don't align basic blocks of loops on ppc */
2176
2177         if (cfg->verbose_level > 2)
2178                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2179
2180         cpos = bb->max_offset;
2181
2182         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2183                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2184                 //g_assert (!mono_compile_aot);
2185                 //cpos += 6;
2186                 //if (bb->cil_code)
2187                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2188                 /* this is not thread save, but good enough */
2189                 /* fixme: howto handle overflows? */
2190                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
2191         }
2192
2193         ins = bb->code;
2194         while (ins) {
2195                 offset = code - cfg->native_code;
2196
2197                 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2198
2199                 if (offset > (cfg->code_size - max_len - 16)) {
2200                         cfg->code_size *= 2;
2201                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2202                         code = cfg->native_code + offset;
2203                 }
2204         //      if (ins->cil_code)
2205         //              g_print ("cil code\n");
2206
2207                 switch (ins->opcode) {
2208                 case OP_STOREI1_MEMBASE_IMM:
2209                         ppc_li (code, ppc_r11, ins->inst_imm);
2210                         g_assert (ppc_is_imm16 (ins->inst_offset));
2211                         ppc_stb (code, ppc_r11, ins->inst_offset, ins->inst_destbasereg);
2212                         break;
2213                 case OP_STOREI2_MEMBASE_IMM:
2214                         ppc_li (code, ppc_r11, ins->inst_imm);
2215                         g_assert (ppc_is_imm16 (ins->inst_offset));
2216                         ppc_sth (code, ppc_r11, ins->inst_offset, ins->inst_destbasereg);
2217                         break;
2218                 case OP_STORE_MEMBASE_IMM:
2219                 case OP_STOREI4_MEMBASE_IMM:
2220                         ppc_load (code, ppc_r11, ins->inst_imm);
2221                         g_assert (ppc_is_imm16 (ins->inst_offset));
2222                         ppc_stw (code, ppc_r11, ins->inst_offset, ins->inst_destbasereg);
2223                         break;
2224                 case OP_STOREI1_MEMBASE_REG:
2225                         g_assert (ppc_is_imm16 (ins->inst_offset));
2226                         ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2227                         break;
2228                 case OP_STOREI2_MEMBASE_REG:
2229                         g_assert (ppc_is_imm16 (ins->inst_offset));
2230                         ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2231                         break;
2232                 case OP_STORE_MEMBASE_REG:
2233                 case OP_STOREI4_MEMBASE_REG:
2234                         g_assert (ppc_is_imm16 (ins->inst_offset));
2235                         ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2236                         break;
2237                 case CEE_LDIND_I:
2238                 case CEE_LDIND_I4:
2239                 case CEE_LDIND_U4:
2240                         g_assert_not_reached ();
2241                         //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2242                         break;
2243                 case OP_LOADU4_MEM:
2244                         g_assert_not_reached ();
2245                         //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
2246                         //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
2247                         break;
2248                 case OP_LOAD_MEMBASE:
2249                 case OP_LOADI4_MEMBASE:
2250                 case OP_LOADU4_MEMBASE:
2251                         if (ppc_is_imm16 (ins->inst_offset)) {
2252                                 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2253                         } else {
2254                                 ppc_load (code, ppc_r11, ins->inst_offset);
2255                                 ppc_lwzx (code, ins->dreg, ppc_r11, ins->inst_basereg);
2256                         }
2257                         break;
2258                 case OP_LOADU1_MEMBASE:
2259                         g_assert (ppc_is_imm16 (ins->inst_offset));
2260                         ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2261                         break;
2262                 case OP_LOADI1_MEMBASE:
2263                         g_assert (ppc_is_imm16 (ins->inst_offset));
2264                         // FIXME: sign extend
2265                         ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2266                         break;
2267                 case OP_LOADU2_MEMBASE:
2268                         g_assert (ppc_is_imm16 (ins->inst_offset));
2269                         ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2270                         break;
2271                 case OP_LOADI2_MEMBASE:
2272                         g_assert (ppc_is_imm16 (ins->inst_offset));
2273                         ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2274                         break;
2275                 case CEE_CONV_I1:
2276                         ppc_extsb (code, ins->dreg, ins->sreg1);
2277                         break;
2278                 case CEE_CONV_I2:
2279                         ppc_extsh (code, ins->dreg, ins->sreg1);
2280                         break;
2281                 case CEE_CONV_U1:
2282                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2283                         break;
2284                 case CEE_CONV_U2:
2285                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2286                         break;
2287                 case OP_COMPARE:
2288                         if (ins->next && (ins->next->opcode >= CEE_BNE_UN && ins->next->opcode <= CEE_BLT_UN))
2289                                 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2290                         else
2291                                 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2292                         break;
2293                 case OP_COMPARE_IMM:
2294                         if (ins->next && ins->next->opcode >= CEE_BNE_UN && ins->next->opcode <= CEE_BLT_UN) {
2295                                 if (ppc_is_uimm16 (ins->inst_imm)) {
2296                                         ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2297                                 } else {
2298                                         ppc_load (code, ppc_r11, ins->inst_imm);
2299                                         ppc_cmpl (code, 0, 0, ins->sreg1, ppc_r11);
2300                                 }
2301                         } else {
2302                                 if (ppc_is_imm16 (ins->inst_imm)) {
2303                                         ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2304                                 } else {
2305                                         ppc_load (code, ppc_r11, ins->inst_imm);
2306                                         ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2307                                 }
2308                         }
2309                         break;
2310                 case OP_X86_TEST_NULL:
2311                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2312                         break;
2313                 case CEE_BREAK:
2314                         ppc_break (code);
2315                         break;
2316                 case OP_ADDCC:
2317                         ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2318                         break;
2319                 case CEE_ADD:
2320                         ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2321                         break;
2322                 case OP_ADC:
2323                         ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2324                         break;
2325                 case OP_ADD_IMM:
2326                         if (ppc_is_imm16 (ins->inst_imm)) {
2327                                 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2328                         } else {
2329                                 ppc_load (code, ppc_r11, ins->inst_imm);
2330                                 ppc_add (code, ins->dreg, ins->sreg1, ppc_r11);
2331                         }
2332                         break;
2333                 case OP_ADC_IMM:
2334                         ppc_load (code, ppc_r11, ins->inst_imm);
2335                         ppc_adde (code, ins->dreg, ins->sreg1, ppc_r11);
2336                         break;
2337                 case OP_SUBCC:
2338                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2339                         break;
2340                 case CEE_SUB:
2341                         ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2342                         break;
2343                 case OP_SBB:
2344                         ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2345                         break;
2346                 case OP_SUB_IMM:
2347                         // we add the negated value
2348                         if (ppc_is_imm16 (-ins->inst_imm))
2349                                 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2350                         else {
2351                                 ppc_load (code, ppc_r11, ins->inst_imm);
2352                                 ppc_sub (code, ins->dreg, ins->sreg1, ppc_r11);
2353                         }
2354                         break;
2355                 case OP_SBB_IMM:
2356                         ppc_load (code, ppc_r11, ins->inst_imm);
2357                         ppc_subfe (code, ins->dreg, ins->sreg2, ppc_r11);
2358                         break;
2359                 case OP_PPC_SUBFIC:
2360                         g_assert (ppc_is_imm16 (ins->inst_imm));
2361                         ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2362                         break;
2363                 case OP_PPC_SUBFZE:
2364                         ppc_subfze (code, ins->dreg, ins->sreg1);
2365                         break;
2366                 case CEE_AND:
2367                         /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2368                         ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2369                         break;
2370                 case OP_AND_IMM:
2371                         if (!(ins->inst_imm & 0xffff0000)) {
2372                                 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2373                         } else if (!(ins->inst_imm & 0xffff)) {
2374                                 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2375                         } else {
2376                                 ppc_load (code, ppc_r11, ins->inst_imm);
2377                                 ppc_and (code, ins->sreg1, ins->dreg, ppc_r11);
2378                         }
2379                         break;
2380                 case CEE_DIV:
2381                         ppc_divw (code, ins->dreg, ins->sreg1, ins->sreg2);
2382                         break;
2383                 case CEE_DIV_UN:
2384                         ppc_divwu (code, ins->dreg, ins->sreg1, ins->sreg2);
2385                         break;
2386                 case OP_DIV_IMM:
2387                         ppc_load (code, ppc_r11, ins->inst_imm);
2388                         ppc_divw (code, ins->dreg, ins->sreg1, ppc_r11);
2389                         break;
2390                 case CEE_REM:
2391                         ppc_divw (code, ppc_r11, ins->sreg1, ins->sreg2);
2392                         ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2393                         ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2394                         break;
2395                 case CEE_REM_UN:
2396                         ppc_divwu (code, ppc_r11, ins->sreg1, ins->sreg2);
2397                         ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2398                         ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2399                         break;
2400                 case OP_REM_IMM:
2401                         ppc_load (code, ppc_r11, ins->inst_imm);
2402                         ppc_divw (code, ins->dreg, ins->sreg1, ppc_r11);
2403                         ppc_mullw (code, ins->dreg, ins->dreg, ppc_r11);
2404                         ppc_subf (code, ins->dreg, ins->dreg, ins->sreg1);
2405                         break;
2406                 case CEE_OR:
2407                         ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2408                         break;
2409                 case OP_OR_IMM:
2410                         if (!(ins->inst_imm & 0xffff0000)) {
2411                                 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2412                         } else if (!(ins->inst_imm & 0xffff)) {
2413                                 ppc_oris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2414                         } else {
2415                                 ppc_load (code, ppc_r11, ins->inst_imm);
2416                                 ppc_or (code, ins->sreg1, ins->dreg, ppc_r11);
2417                         }
2418                         break;
2419                 case CEE_XOR:
2420                         ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2421                         break;
2422                 case OP_XOR_IMM:
2423                         if (!(ins->inst_imm & 0xffff0000)) {
2424                                 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2425                         } else if (!(ins->inst_imm & 0xffff)) {
2426                                 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2427                         } else {
2428                                 ppc_load (code, ppc_r11, ins->inst_imm);
2429                                 ppc_xor (code, ins->sreg1, ins->dreg, ppc_r11);
2430                         }
2431                         break;
2432                 case CEE_SHL:
2433                         ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2434                         break;
2435                 case OP_SHL_IMM:
2436                         ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0xf), 0, (31 - (ins->inst_imm & 0xf)));
2437                         //ppc_load (code, ppc_r11, ins->inst_imm);
2438                         //ppc_slw (code, ins->sreg1, ins->dreg, ppc_r11);
2439                         break;
2440                 case CEE_SHR:
2441                         ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2442                         break;
2443                 case OP_SHR_IMM:
2444                         // there is also ppc_srawi
2445                         //ppc_load (code, ppc_r11, ins->inst_imm);
2446                         //ppc_sraw (code, ins->dreg, ins->sreg1, ppc_r11);
2447                         ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2448                         break;
2449                 case OP_SHR_UN_IMM:
2450                         ppc_load (code, ppc_r11, ins->inst_imm);
2451                         ppc_srw (code, ins->dreg, ins->sreg1, ppc_r11);
2452                         //ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0xf)), (ins->inst_imm & 0xf), 31);
2453                         break;
2454                 case CEE_SHR_UN:
2455                         ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2456                         break;
2457                 case CEE_NOT:
2458                         ppc_not (code, ins->dreg, ins->sreg1);
2459                         break;
2460                 case CEE_NEG:
2461                         ppc_neg (code, ins->dreg, ins->sreg1);
2462                         break;
2463                 case CEE_MUL:
2464                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2465                         break;
2466                 case OP_MUL_IMM:
2467                         ppc_load (code, ppc_r11, ins->inst_imm);
2468                         ppc_mullw (code, ins->dreg, ins->sreg1, ppc_r11);
2469                         break;
2470                 case CEE_MUL_OVF:
2471                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2472                         //g_assert_not_reached ();
2473                         //x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2474                         //EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2475                         break;
2476                 case CEE_MUL_OVF_UN:
2477                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2478                         //FIXME: g_assert_not_reached ();
2479                         break;
2480                 case OP_ICONST:
2481                 case OP_SETREGIMM:
2482                         ppc_load (code, ins->dreg, ins->inst_c0);
2483                         break;
2484                 /*case OP_CLASS:
2485                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_CLASS, (gpointer)ins->inst_c0);
2486                         ppc_load (code, ins->dreg, 0xff00ff00);
2487                         break;
2488                 case OP_IMAGE:
2489                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_IMAGE, (gpointer)ins->inst_c0);
2490                         ppc_load (code, ins->dreg, 0xff00ff00);
2491                         break;*/
2492                 case CEE_CONV_I4:
2493                 case CEE_CONV_U4:
2494                 case OP_MOVE:
2495                 case OP_SETREG:
2496                         ppc_mr (code, ins->dreg, ins->sreg1);
2497                         break;
2498                 case OP_SETLRET: {
2499                         int saved = ins->sreg1;
2500                         if (ins->sreg1 == ppc_r3) {
2501                                 ppc_mr (code, ppc_r0, ins->sreg1);
2502                                 saved = ppc_r0;
2503                         }
2504                         if (ins->sreg2 != ppc_r3)
2505                                 ppc_mr (code, ppc_r3, ins->sreg2);
2506                         if (saved != ppc_r4)
2507                                 ppc_mr (code, ppc_r4, saved);
2508                         break;
2509                 }
2510                 case OP_SETFREG:
2511                 case OP_FMOVE:
2512                         ppc_fmr (code, ins->dreg, ins->sreg1);
2513                         break;
2514                 case OP_FCONV_TO_R4:
2515                         ppc_frsp (code, ins->dreg, ins->sreg1);
2516                         break;
2517                 case CEE_JMP:
2518                         g_assert_not_reached ();
2519                         break;
2520                 case OP_CHECK_THIS:
2521                         /* ensure ins->sreg1 is not NULL */
2522                         ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2523                         break;
2524                 case OP_FCALL:
2525                 case OP_LCALL:
2526                 case OP_VCALL:
2527                 case OP_VOIDCALL:
2528                 case CEE_CALL:
2529                         call = (MonoCallInst*)ins;
2530                         if (ins->flags & MONO_INST_HAS_METHOD)
2531                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2532                         else
2533                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2534                         ppc_bl (code, 0);
2535                         break;
2536                 case OP_FCALL_REG:
2537                 case OP_LCALL_REG:
2538                 case OP_VCALL_REG:
2539                 case OP_VOIDCALL_REG:
2540                 case OP_CALL_REG:
2541                         ppc_mtlr (code, ins->sreg1);
2542                         ppc_blrl (code);
2543                         break;
2544                 case OP_FCALL_MEMBASE:
2545                 case OP_LCALL_MEMBASE:
2546                 case OP_VCALL_MEMBASE:
2547                 case OP_VOIDCALL_MEMBASE:
2548                 case OP_CALL_MEMBASE:
2549                         ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2550                         ppc_mtlr (code, ppc_r0);
2551                         ppc_blrl (code);
2552                         break;
2553                 case OP_OUTARG:
2554                         g_assert_not_reached ();
2555                         break;
2556                 case OP_LOCALLOC:
2557                         g_assert_not_reached ();
2558                         /* keep alignment */
2559 #define MONO_FRAME_ALIGNMENT 32
2560                         ppc_addi (code, ppc_r0, ins->sreg1, MONO_FRAME_ALIGNMENT-1);
2561                         ppc_rlwinm (code, ppc_r0, ppc_r0, 0, 0, 27);
2562                         ppc_lwz (code, ppc_r11, 0, ppc_sp);
2563                         ppc_neg (code, ppc_r0, ppc_r0);
2564                         ppc_stwux (code, ppc_sp, ppc_r0, ppc_sp);
2565                         ppc_mr (code, ins->dreg, ppc_sp);
2566                         break;
2567                 case CEE_RET:
2568                         ppc_blr (code);
2569                         break;
2570                 case CEE_THROW: {
2571                         ppc_mr (code, ppc_r3, ins->sreg1);
2572                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2573                                              (gpointer)"mono_arch_throw_exception");
2574                         ppc_bl (code, 0);
2575                         break;
2576                 }
2577                 case OP_START_HANDLER:
2578                         ppc_mflr (code, ppc_r0);
2579                         ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2580                         break;
2581                 case OP_ENDFILTER:
2582                         if (ins->sreg1 != ppc_r3)
2583                                 ppc_mr (code, ppc_r3, ins->sreg1);
2584                         ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2585                         ppc_mtlr (code, ppc_r0);
2586                         ppc_blr (code);
2587                         break;
2588                 case CEE_ENDFINALLY:
2589                         ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2590                         ppc_mtlr (code, ppc_r0);
2591                         ppc_blr (code);
2592                         break;
2593                 case OP_CALL_HANDLER: 
2594                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2595                         ppc_bl (code, 0);
2596                         break;
2597                 case OP_LABEL:
2598                         ins->inst_c0 = code - cfg->native_code;
2599                         break;
2600                 case CEE_BR:
2601                         //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2602                         //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2603                         //break;
2604                         if (ins->flags & MONO_INST_BRLABEL) {
2605                                 /*if (ins->inst_i0->inst_c0) {
2606                                         ppc_b (code, 0);
2607                                         //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2608                                 } else*/ {
2609                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2610                                         ppc_b (code, 0);
2611                                 }
2612                         } else {
2613                                 /*if (ins->inst_target_bb->native_offset) {
2614                                         ppc_b (code, 0);
2615                                         //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2616                                 } else*/ {
2617                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2618                                         ppc_b (code, 0);
2619                                 } 
2620                         }
2621                         break;
2622                 case OP_BR_REG:
2623                         ppc_mtctr (code, ins->sreg1);
2624                         ppc_bcctr (code, 20, 0);
2625                         break;
2626                 case OP_CEQ:
2627                         ppc_li (code, ins->dreg, 0);
2628                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2629                         ppc_li (code, ins->dreg, 1);
2630                         break;
2631                 case OP_CLT:
2632                 case OP_CLT_UN:
2633                         ppc_li (code, ins->dreg, 1);
2634                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2635                         ppc_li (code, ins->dreg, 0);
2636                         break;
2637                 case OP_CGT:
2638                 case OP_CGT_UN:
2639                         ppc_li (code, ins->dreg, 1);
2640                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2641                         ppc_li (code, ins->dreg, 0);
2642                         break;
2643                 case OP_COND_EXC_EQ:
2644                 case OP_COND_EXC_NE_UN:
2645                 case OP_COND_EXC_LT:
2646                 case OP_COND_EXC_LT_UN:
2647                 case OP_COND_EXC_GT:
2648                 case OP_COND_EXC_GT_UN:
2649                 case OP_COND_EXC_GE:
2650                 case OP_COND_EXC_GE_UN:
2651                 case OP_COND_EXC_LE:
2652                 case OP_COND_EXC_LE_UN:
2653                 case OP_COND_EXC_OV:
2654                 case OP_COND_EXC_NO:
2655                 case OP_COND_EXC_C:
2656                 case OP_COND_EXC_NC:
2657                         //EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], 
2658                         //                          (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
2659                         break;
2660                 case CEE_BEQ:
2661                 case CEE_BNE_UN:
2662                 case CEE_BLT:
2663                 case CEE_BLT_UN:
2664                 case CEE_BGT:
2665                 case CEE_BGT_UN:
2666                 case CEE_BGE:
2667                 case CEE_BGE_UN:
2668                 case CEE_BLE:
2669                 case CEE_BLE_UN:
2670                         EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2671                         break;
2672
2673                 /* floating point opcodes */
2674                 case OP_R8CONST:
2675                         ppc_load (code, ppc_r11, ins->inst_p0);
2676                         ppc_lfd (code, ins->dreg, 0, ppc_r11);
2677                         break;
2678                 case OP_R4CONST:
2679                         ppc_load (code, ppc_r11, ins->inst_p0);
2680                         ppc_lfs (code, ins->dreg, 0, ppc_r11);
2681                         break;
2682                 case OP_STORER8_MEMBASE_REG:
2683                         ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2684                         break;
2685                 case OP_LOADR8_MEMBASE:
2686                         ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2687                         break;
2688                 case OP_STORER4_MEMBASE_REG:
2689                         ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2690                         break;
2691                 case OP_LOADR4_MEMBASE:
2692                         ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2693                         break;
2694                 case CEE_CONV_R4: /* FIXME: change precision */
2695                 case CEE_CONV_R8: {
2696                         static const guint64 adjust_val = 0x4330000000000000UL;
2697                         ppc_li (code, ppc_r0, 0);
2698                         ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2699                         ppc_stw (code, ins->sreg1, -8, ppc_sp);
2700                         ppc_xoris (code, ppc_r11, ins->sreg1, 0x8000);
2701                         ppc_stw (code, ppc_r11, -4, ppc_sp);
2702                         ppc_lfd (code, ins->dreg, -8, ppc_sp);
2703                         ppc_li (code, ppc_r11, &adjust_val);
2704                         ppc_lfd (code, ppc_f0, 0, ppc_r11);
2705                         ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2706                         break;
2707                 }
2708                 case OP_X86_FP_LOAD_I8:
2709                         g_assert_not_reached ();
2710                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
2711                         break;
2712                 case OP_X86_FP_LOAD_I4:
2713                         g_assert_not_reached ();
2714                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
2715                         break;
2716                 case OP_FCONV_TO_I1:
2717                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2718                         break;
2719                 case OP_FCONV_TO_U1:
2720                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2721                         break;
2722                 case OP_FCONV_TO_I2:
2723                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2724                         break;
2725                 case OP_FCONV_TO_U2:
2726                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2727                         break;
2728                 case OP_FCONV_TO_I4:
2729                 case OP_FCONV_TO_I:
2730                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2731                         break;
2732                 case OP_FCONV_TO_U4:
2733                 case OP_FCONV_TO_U:
2734                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2735                         break;
2736                 case OP_FCONV_TO_I8:
2737                 case OP_FCONV_TO_U8:
2738                         g_assert_not_reached ();
2739                         /* Implemented as helper calls */
2740                         break;
2741                 case OP_LCONV_TO_R_UN:
2742                         g_assert_not_reached ();
2743                         /* Implemented as helper calls */
2744                         break;
2745                 case OP_LCONV_TO_OVF_I: {
2746 #if 0
2747                         guint8 *br [3], *label [1];
2748
2749                         /* 
2750                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
2751                          */
2752                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
2753
2754                         /* If the low word top bit is set, see if we are negative */
2755                         br [0] = code; x86_branch8 (code, X86_CC_LT, 0, TRUE);
2756                         /* We are not negative (no top bit set, check for our top word to be zero */
2757                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
2758                         br [1] = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
2759                         label [0] = code;
2760
2761                         /* throw exception */
2762                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException");
2763                         x86_jump32 (code, 0);
2764         
2765                         x86_patch (br [0], code);
2766                         /* our top bit is set, check that top word is 0xfffffff */
2767                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0xffffffff);
2768                 
2769                         x86_patch (br [1], code);
2770                         /* nope, emit exception */
2771                         br [2] = code; x86_branch8 (code, X86_CC_NE, 0, TRUE);
2772                         x86_patch (br [2], label [0]);
2773
2774                         if (ins->dreg != ins->sreg1)
2775                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2776 #endif
2777                         g_assert_not_reached ();
2778                         break;
2779                 }
2780                 case OP_FADD:
2781                         ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2782                         break;
2783                 case OP_FSUB:
2784                         ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2785                         break;          
2786                 case OP_FMUL:
2787                         ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2788                         break;          
2789                 case OP_FDIV:
2790                         ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2791                         break;          
2792                 case OP_FNEG:
2793                         ppc_fneg (code, ins->dreg, ins->sreg1);
2794                         break;          
2795                 case OP_FREM:
2796                         /* emulated */
2797                         g_assert_not_reached ();
2798                         break;
2799                 case OP_FCOMPARE:
2800                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2801                         break;
2802                 case OP_FCEQ:
2803                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2804                         ppc_li (code, ins->dreg, 0);
2805                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2806                         ppc_li (code, ins->dreg, 1);
2807                         break;
2808                 case OP_FCLT:
2809                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2810                         ppc_li (code, ins->dreg, 1);
2811                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2812                         ppc_li (code, ins->dreg, 0);
2813                         break;
2814                 case OP_FCLT_UN:
2815                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2816                         ppc_li (code, ins->dreg, 1);
2817                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2818                         ppc_li (code, ins->dreg, 0);
2819                         break;
2820                 case OP_FCGT:
2821                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2822                         ppc_li (code, ins->dreg, 1);
2823                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2824                         ppc_li (code, ins->dreg, 0);
2825                         break;
2826                 case OP_FCGT_UN:
2827                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2828                         ppc_li (code, ins->dreg, 1);
2829                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2830                         ppc_li (code, ins->dreg, 0);
2831                         break;
2832                 case OP_FBEQ:
2833                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2834                         break;
2835                 case OP_FBNE_UN:
2836                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2837                         break;
2838                 case OP_FBLT:
2839                         EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
2840                         break;
2841                 case OP_FBLT_UN:
2842                         EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
2843                         break;
2844                 case OP_FBGT:
2845                         EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
2846                         break;
2847                 case OP_FBGT_UN:
2848                         EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
2849                         break;
2850                 case OP_FBGE:
2851                         EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
2852                         break;
2853                 case OP_FBGE_UN:
2854                         EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
2855                         break;
2856                 case OP_FBLE:
2857                         EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
2858                         break;
2859                 case OP_FBLE_UN:
2860                         EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
2861                         break;
2862                 case CEE_CKFINITE: {
2863                         ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2864                         ppc_lwz (code, ppc_r0, -8, ppc_sp);
2865                         ppc_rlwinm (code, ppc_r0, ppc_r0, 0, 1, 31);
2866                         ppc_xoris (code, ppc_r11, ppc_r0, 0x7ff0);
2867                         ppc_neg (code, ppc_r0, ppc_r11);
2868                         ppc_rlwinm (code, ppc_r0, ppc_r0, 1, 31, 31);
2869                         g_assert_not_reached ();
2870                         x86_push_reg (code, X86_EAX);
2871                         x86_fxam (code);
2872                         x86_fnstsw (code);
2873                         x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4100);
2874                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x0100);
2875                         x86_pop_reg (code, X86_EAX);
2876                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "ArithmeticException");
2877                         break;
2878                 }
2879                 default:
2880                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2881                         g_assert_not_reached ();
2882                 }
2883
2884                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
2885                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2886                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
2887                         g_assert_not_reached ();
2888                 }
2889                
2890                 cpos += max_len;
2891
2892                 last_ins = ins;
2893                 last_offset = offset;
2894                 
2895                 ins = ins->next;
2896         }
2897
2898         cfg->code_len = code - cfg->native_code;
2899 }
2900
2901 void
2902 mono_arch_register_lowlevel_calls (void)
2903 {
2904         mono_register_jit_icall (enter_method, "mono_enter_method", NULL, TRUE);
2905         mono_register_jit_icall (leave_method, "mono_leave_method", NULL, TRUE);
2906 }
2907
2908 void
2909 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji)
2910 {
2911         MonoJumpInfo *patch_info;
2912
2913         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
2914                 unsigned char *ip = patch_info->ip.i + code;
2915                 const unsigned char *target = NULL;
2916
2917                 switch (patch_info->type) {
2918                 case MONO_PATCH_INFO_BB:
2919                         target = patch_info->data.bb->native_offset + code;
2920                         break;
2921                 case MONO_PATCH_INFO_ABS:
2922                         target = patch_info->data.target;
2923                         break;
2924                 case MONO_PATCH_INFO_LABEL:
2925                         target = patch_info->data.inst->inst_c0 + code;
2926                         break;
2927                 case MONO_PATCH_INFO_IP:
2928                         *((gpointer *)(ip)) = ip;
2929                         continue;
2930                 case MONO_PATCH_INFO_METHOD_REL:
2931                         *((gpointer *)(ip)) = code + patch_info->data.offset;
2932                         continue;
2933                 case MONO_PATCH_INFO_INTERNAL_METHOD: {
2934                         MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
2935                         if (!mi) {
2936                                 g_warning ("unknown MONO_PATCH_INFO_INTERNAL_METHOD %s", patch_info->data.name);
2937                                 g_assert_not_reached ();
2938                         }
2939                         target = mi->wrapper;
2940                         break;
2941                 }
2942                 case MONO_PATCH_INFO_METHOD_JUMP:
2943                         g_assert_not_reached ();
2944                         break;
2945                 case MONO_PATCH_INFO_METHOD:
2946                         if (patch_info->data.method == method) {
2947                                 target = code;
2948                         } else {
2949                                 /* get the trampoline to the method from the domain */
2950                                 target = mono_arch_create_jit_trampoline (patch_info->data.method);
2951                         }
2952                         break;
2953                 case MONO_PATCH_INFO_SWITCH: {
2954                         gpointer *table = (gpointer *)patch_info->data.target;
2955                         int i;
2956
2957                         // FIXME: inspect code to get the register
2958                         ppc_load (ip, ppc_r11, patch_info->data.target);
2959                         //*((gconstpointer *)(ip + 2)) = patch_info->data.target;
2960
2961                         for (i = 0; i < patch_info->table_size; i++) {
2962                                 table [i] = (int)patch_info->data.table [i] + code;
2963                         }
2964                         /* we put into the table the absolute address, no need for ppc_patch in this case */
2965                         continue;
2966                 }
2967                 case MONO_PATCH_INFO_METHODCONST:
2968                 case MONO_PATCH_INFO_CLASS:
2969                 case MONO_PATCH_INFO_IMAGE:
2970                 case MONO_PATCH_INFO_FIELD:
2971                         g_assert_not_reached ();
2972                         *((gconstpointer *)(ip + 1)) = patch_info->data.target;
2973                         continue;
2974                 case MONO_PATCH_INFO_R4:
2975                 case MONO_PATCH_INFO_R8:
2976                         g_assert_not_reached ();
2977                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
2978                         continue;
2979                 case MONO_PATCH_INFO_IID:
2980                         g_assert_not_reached ();
2981                         mono_class_init (patch_info->data.klass);
2982                         *((guint32 *)(ip + 1)) = patch_info->data.klass->interface_id;
2983                         continue;                       
2984                 case MONO_PATCH_INFO_VTABLE:
2985                         g_assert_not_reached ();
2986                         *((gconstpointer *)(ip + 1)) = mono_class_vtable (domain, patch_info->data.klass);
2987                         continue;
2988                 case MONO_PATCH_INFO_CLASS_INIT:
2989                         target = mono_create_class_init_trampoline (mono_class_vtable (domain, patch_info->data.klass));
2990                         break;
2991                 case MONO_PATCH_INFO_SFLDA: {
2992                         MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
2993                         if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && mono_class_needs_cctor_run (vtable->klass, method))
2994                                 /* Done by the generated code */
2995                                 ;
2996                         else {
2997                                 mono_runtime_class_init (vtable);
2998                         }
2999                         g_assert_not_reached ();
3000                         *((gconstpointer *)(ip + 1)) = 
3001                                 (char*)vtable->data + patch_info->data.field->offset;
3002                         continue;
3003                 }
3004                 case MONO_PATCH_INFO_EXC_NAME:
3005                         g_assert_not_reached ();
3006                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3007                         continue;
3008                 case MONO_PATCH_INFO_LDSTR:
3009                         g_assert_not_reached ();
3010                         *((gconstpointer *)(ip + 1)) = 
3011                                 mono_ldstr (domain, patch_info->data.token->image, 
3012                                                         mono_metadata_token_index (patch_info->data.token->token));
3013                         continue;
3014                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
3015                         gpointer handle;
3016                         MonoClass *handle_class;
3017
3018                         handle = mono_ldtoken (patch_info->data.token->image, 
3019                                                                    patch_info->data.token->token, &handle_class);
3020                         mono_class_init (handle_class);
3021                         mono_class_init (mono_class_from_mono_type (handle));
3022
3023                         g_assert_not_reached ();
3024                         *((gconstpointer *)(ip + 1)) = 
3025                                 mono_type_get_object (domain, handle);
3026                         continue;
3027                 }
3028                 case MONO_PATCH_INFO_LDTOKEN: {
3029                         gpointer handle;
3030                         MonoClass *handle_class;
3031
3032                         handle = mono_ldtoken (patch_info->data.token->image,
3033                                                                    patch_info->data.token->token, &handle_class);
3034                         mono_class_init (handle_class);
3035
3036                         g_assert_not_reached ();
3037                         *((gconstpointer *)(ip + 1)) = handle;
3038                         continue;
3039                 }
3040                 default:
3041                         g_assert_not_reached ();
3042                 }
3043                 ppc_patch (ip, target);
3044         }
3045 }
3046
3047 int
3048 mono_arch_max_epilog_size (MonoCompile *cfg)
3049 {
3050         int exc_count = 0, max_epilog_size = 16 + 20*4;
3051         MonoJumpInfo *patch_info;
3052         
3053         if (cfg->method->save_lmf)
3054                 max_epilog_size += 128;
3055         
3056         if (mono_jit_trace_calls != NULL)
3057                 max_epilog_size += 50;
3058
3059         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3060                 max_epilog_size += 50;
3061
3062         /* count the number of exception infos */
3063      
3064         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3065                 if (patch_info->type == MONO_PATCH_INFO_EXC)
3066                         exc_count++;
3067         }
3068
3069         /* 
3070          * make sure we have enough space for exceptions
3071          * 16 is the size of two push_imm instructions and a call
3072          */
3073         max_epilog_size += exc_count*16;
3074
3075         return max_epilog_size;
3076 }
3077
3078 guint8 *
3079 mono_arch_emit_prolog (MonoCompile *cfg)
3080 {
3081         MonoMethod *method = cfg->method;
3082         MonoBasicBlock *bb;
3083         MonoMethodSignature *sig;
3084         MonoInst *inst;
3085         int alloc_size, pos, max_offset, i;
3086         guint8 *code;
3087         CallInfo *cinfo;
3088         int tracing = 0;
3089
3090         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3091                 tracing = 1;
3092
3093         cfg->code_size = 256;
3094         code = cfg->native_code = g_malloc (cfg->code_size);
3095
3096         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3097                 ppc_mflr (code, ppc_r0);
3098                 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3099         }
3100         if (cfg->flags & MONO_CFG_HAS_ALLOCA) {
3101                 cfg->used_int_regs |= 1 << 31;
3102         }
3103
3104         alloc_size = cfg->stack_offset;
3105         pos = 0;
3106         /* reserve room to save return value */
3107         if (tracing)
3108                 pos += 8;
3109
3110         if (method->save_lmf) {
3111 #if 0
3112                 pos += sizeof (MonoLMF);
3113                 
3114                 /* save the current IP */
3115                 mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3116                 x86_push_imm (code, 0);
3117
3118                 /* save all caller saved regs */
3119                 x86_push_reg (code, X86_EBX);
3120                 x86_push_reg (code, X86_EDI);
3121                 x86_push_reg (code, X86_ESI);
3122                 x86_push_reg (code, X86_EBP);
3123
3124                 /* save method info */
3125                 x86_push_imm (code, method);
3126         
3127                 /* get the address of lmf for the current thread */
3128                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3129                                      (gpointer)"get_lmf_addr");
3130                 x86_call_code (code, 0);
3131
3132                 /* push lmf */
3133                 x86_push_reg (code, X86_EAX); 
3134                 /* push *lfm (previous_lmf) */
3135                 x86_push_membase (code, X86_EAX, 0);
3136                 /* *(lmf) = ESP */
3137                 x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
3138 #endif
3139         } else {
3140
3141                 for (i = 13; i < 32; ++i) {
3142                         if (cfg->used_int_regs & (1 << i)) {
3143                                 pos += 4;
3144                                 ppc_stw (code, i, -pos, ppc_sp);
3145                         }
3146                 }
3147         }
3148
3149         alloc_size += pos;
3150         // align to PPC_STACK_ALIGNMENT bytes
3151         if (alloc_size & (PPC_STACK_ALIGNMENT - 1))
3152                 alloc_size += PPC_STACK_ALIGNMENT - (alloc_size & (PPC_STACK_ALIGNMENT - 1));
3153
3154         cfg->stack_usage = alloc_size;
3155         if (alloc_size)
3156                 ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3157         if (cfg->flags & MONO_CFG_HAS_ALLOCA)
3158                 ppc_mr (code, ppc_r31, ppc_sp);
3159
3160         /* compute max_offset in order to use short forward jumps */
3161         max_offset = 0;
3162         if (cfg->opt & MONO_OPT_BRANCH) {
3163                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3164                         MonoInst *ins = bb->code;
3165                         bb->max_offset = max_offset;
3166
3167                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3168                                 max_offset += 6; 
3169
3170                         while (ins) {
3171                                 max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
3172                                 ins = ins->next;
3173                         }
3174                 }
3175         }
3176
3177         /* load arguments allocated to register from the stack */
3178         sig = method->signature;
3179         pos = 0;
3180
3181         cinfo = calculate_sizes (sig, sig->pinvoke);
3182
3183         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3184                 ArgInfo *ainfo = &cinfo->ret;
3185                 inst = cfg->ret;
3186                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3187         }
3188         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3189                 ArgInfo *ainfo = cinfo->args + i;
3190                 inst = cfg->varinfo [pos];
3191                 
3192                 if (inst->opcode == OP_REGVAR) {
3193                         if (ainfo->regtype == RegTypeGeneral)
3194                                 ppc_mr (code, inst->dreg, ainfo->reg);
3195                         else if (ainfo->regtype == RegTypeFP)
3196                                 ppc_fmr (code, inst->dreg, ainfo->reg);
3197                         else
3198                                 g_assert_not_reached ();
3199                         if (cfg->verbose_level > 2)
3200                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3201                 } else {
3202                         /* the argument should be put on the stack: FIXME handle size != word  */
3203                         if (ainfo->regtype == RegTypeGeneral) {
3204                                 switch (ainfo->size) {
3205                                 case 1:
3206                                         ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3207                                         break;
3208                                 case 2:
3209                                         ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3210                                         break;
3211                                 case 8:
3212                                         ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3213                                         ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3214                                         break;
3215                                 default:
3216                                         ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3217                                 }
3218                         } else if (ainfo->regtype == RegTypeFP) {
3219                                 if (ainfo->size == 8)
3220                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3221                                 else if (ainfo->size == 4)
3222                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3223                                 else
3224                                         g_assert_not_reached ();
3225                         } else
3226                                 g_assert_not_reached ();
3227                 }
3228                 pos++;
3229         }
3230
3231         if (tracing)
3232                 code = mono_arch_instrument_prolog (cfg, enter_method, code, TRUE);
3233
3234         cfg->code_len = code - cfg->native_code;
3235         g_free (cinfo);
3236
3237         return code;
3238 }
3239
3240 void
3241 mono_arch_emit_epilog (MonoCompile *cfg)
3242 {
3243         MonoJumpInfo *patch_info;
3244         MonoMethod *method = cfg->method;
3245         int pos, i;
3246         guint8 *code;
3247
3248         code = cfg->native_code + cfg->code_len;
3249
3250         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3251                 code = mono_arch_instrument_epilog (cfg, leave_method, code, TRUE);
3252                 pos = 8;
3253         } else {
3254                 pos = 0;
3255         }
3256         
3257         if (method->save_lmf) {
3258                 pos = -sizeof (MonoLMF);
3259         }
3260
3261         if (method->save_lmf) {
3262 #if 0
3263                 /* ebx = previous_lmf */
3264                 x86_pop_reg (code, X86_EBX);
3265                 /* edi = lmf */
3266                 x86_pop_reg (code, X86_EDI);
3267                 /* *(lmf) = previous_lmf */
3268                 x86_mov_membase_reg (code, X86_EDI, 0, X86_EBX, 4);
3269
3270                 /* discard method info */
3271                 x86_pop_reg (code, X86_ESI);
3272
3273                 /* restore caller saved regs */
3274                 x86_pop_reg (code, X86_EBP);
3275                 x86_pop_reg (code, X86_ESI);
3276                 x86_pop_reg (code, X86_EDI);
3277                 x86_pop_reg (code, X86_EBX);
3278 #endif
3279         }
3280
3281         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3282                 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3283                 ppc_mtlr (code, ppc_r0);
3284         }
3285         ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3286         for (i = 13; i < 32; ++i) {
3287                 if (cfg->used_int_regs & (1 << i)) {
3288                         pos += 4;
3289                         ppc_lwz (code, i, -pos, cfg->frame_reg);
3290                 }
3291         }
3292         ppc_blr (code);
3293
3294         /* add code to raise exceptions */
3295         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3296                 switch (patch_info->type) {
3297                 case MONO_PATCH_INFO_EXC:
3298                         /*x86_patch (patch_info->ip.i + cfg->native_code, code);
3299                         x86_push_imm (code, patch_info->data.target);
3300                         x86_push_imm (code, patch_info->ip.i + cfg->native_code);
3301                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3302                         patch_info->data.name = "mono_arch_throw_exception_by_name";
3303                         patch_info->ip.i = code - cfg->native_code;
3304                         x86_jump_code (code, 0);*/
3305                         break;
3306                 default:
3307                         /* do nothing */
3308                         break;
3309                 }
3310         }
3311
3312         cfg->code_len = code - cfg->native_code;
3313
3314         g_assert (cfg->code_len < cfg->code_size);
3315
3316 }
3317
3318 void
3319 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3320 {
3321 }
3322
3323 void
3324 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3325 {
3326         int this_dreg = ppc_r3;
3327         
3328         if (vt_reg != -1)
3329                 this_dreg = ppc_r4;
3330
3331         /* add the this argument */
3332         if (this_reg != -1) {
3333                 MonoInst *this;
3334                 MONO_INST_NEW (cfg, this, OP_SETREG);
3335                 this->type = this_type;
3336                 this->sreg1 = this_reg;
3337                 this->dreg = this_dreg;
3338                 mono_bblock_add_inst (cfg->cbb, this);
3339         }
3340
3341         if (vt_reg != -1) {
3342                 MonoInst *vtarg;
3343                 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3344                 vtarg->type = STACK_MP;
3345                 vtarg->sreg1 = vt_reg;
3346                 vtarg->dreg = ppc_r3;
3347                 mono_bblock_add_inst (cfg->cbb, vtarg);
3348         }
3349 }
3350