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