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