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