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