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