2008-10-21 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / mini-ppc.c
1 /*
2  * mini-ppc.c: PowerPC backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2003 Ximian, Inc.
9  */
10 #include "mini.h"
11 #include <string.h>
12
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
15
16 #include "mini-ppc.h"
17 #include "inssel.h"
18 #include "cpu-ppc.h"
19 #include "trace.h"
20 #ifdef __APPLE__
21 #include <sys/sysctl.h>
22 #endif
23
24 /* From ir-emit.h */
25 static inline guint32
26 alloc_ireg (MonoCompile *cfg)
27 {
28         return cfg->next_vreg ++;
29 }
30
31 static inline guint32
32 alloc_lreg (MonoCompile *cfg)
33 {
34 #if SIZEOF_VOID_P == 8
35         return cfg->next_vreg ++;
36 #else
37         /* Use a pair of consecutive vregs */
38         guint32 res = cfg->next_vreg;
39
40         cfg->next_vreg += 3;
41
42         return res;
43 #endif
44 }
45
46 static inline guint32
47 alloc_freg (MonoCompile *cfg)
48 {
49 #ifdef MONO_ARCH_SOFT_FLOAT
50         /* Allocate an lvreg so float ops can be decomposed into long ops */
51         return alloc_lreg (cfg);
52 #else
53         /* Allocate these from the same pool as the int regs */
54         return cfg->next_vreg ++;
55 #endif
56 }
57
58 static inline guint32
59 alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
60 {
61         switch (stack_type) {
62         case STACK_I4:
63         case STACK_PTR:
64         case STACK_MP:
65         case STACK_OBJ:
66                 return alloc_ireg (cfg);
67         case STACK_R8:
68                 return alloc_freg (cfg);
69         case STACK_I8:
70                 return alloc_lreg (cfg);
71         case STACK_VTYPE:
72                 return alloc_ireg (cfg);
73         default:
74                 g_assert_not_reached ();
75         }
76 }
77
78 #ifdef MONO_ARCH_SOFT_FLOAT
79 #define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8 || (stack_type) == STACK_R8)
80 #else
81 #define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8)
82 #endif
83
84 #define NEW_VARLOADA(cfg,dest,var,vartype) do { \
85         MONO_INST_NEW ((cfg), (dest), OP_LDADDR); \
86                 (dest)->inst_p0 = (var); \
87                 (var)->flags |= MONO_INST_INDIRECT;     \
88                 (dest)->type = STACK_MP;        \
89                 (dest)->klass = (var)->klass;   \
90         (dest)->dreg = alloc_dreg ((cfg), STACK_MP); \
91                 if (SIZEOF_VOID_P == 4 && DECOMPOSE_INTO_REGPAIR ((var)->type)) { MonoInst *var1 = get_vreg_to_inst (cfg, (var)->dreg + 1); MonoInst *var2 = get_vreg_to_inst (cfg, (var)->dreg + 2); g_assert (var1); g_assert (var2); var1->flags |= MONO_INST_INDIRECT; var2->flags |= MONO_INST_INDIRECT; } \
92         } while (0)
93
94 #define EMIT_NEW_VARLOADA(cfg,dest,var,vartype) do { NEW_VARLOADA ((cfg), (dest), (var), (vartype)); MONO_ADD_INS ((cfg)->cbb, (dest)); } while (0)
95
96 #define FORCE_INDIR_CALL 1
97
98 enum {
99         TLS_MODE_DETECT,
100         TLS_MODE_FAILED,
101         TLS_MODE_LTHREADS,
102         TLS_MODE_NPTL,
103         TLS_MODE_DARWIN_G4,
104         TLS_MODE_DARWIN_G5
105 };
106
107 /* This mutex protects architecture specific caches */
108 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
109 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
110 static CRITICAL_SECTION mini_arch_mutex;
111
112 int mono_exc_esp_offset = 0;
113 static int tls_mode = TLS_MODE_DETECT;
114 static int lmf_pthread_key = -1;
115 static int monothread_key = -1;
116 static int monodomain_key = -1;
117
118 static int
119 offsets_from_pthread_key (guint32 key, int *offset2)
120 {
121         int idx1 = key / 32;
122         int idx2 = key % 32;
123         *offset2 = idx2 * sizeof (gpointer);
124         return 284 + idx1 * sizeof (gpointer);
125 }
126
127 #define emit_linuxthreads_tls(code,dreg,key) do {\
128                 int off1, off2; \
129                 off1 = offsets_from_pthread_key ((key), &off2); \
130                 ppc_lwz ((code), (dreg), off1, ppc_r2); \
131                 ppc_lwz ((code), (dreg), off2, (dreg)); \
132         } while (0);
133
134 #define emit_darwing5_tls(code,dreg,key) do {\
135                 int off1 = 0x48 + key * sizeof (gpointer);      \
136                 ppc_mfspr ((code), (dreg), 104);        \
137                 ppc_lwz ((code), (dreg), off1, (dreg)); \
138         } while (0);
139
140 /* FIXME: ensure the sc call preserves all but r3 */
141 #define emit_darwing4_tls(code,dreg,key) do {\
142                 int off1 = 0x48 + key * sizeof (gpointer);      \
143                 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
144                 ppc_li ((code), ppc_r0, 0x7FF2);        \
145                 ppc_sc ((code));        \
146                 ppc_lwz ((code), (dreg), off1, ppc_r3); \
147                 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
148         } while (0);
149
150 #define emit_tls_access(code,dreg,key) do {     \
151                 switch (tls_mode) {     \
152                 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break;    \
153                 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break;       \
154                 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break;       \
155                 default: g_assert_not_reached ();       \
156                 }       \
157         } while (0)
158
159 const char*
160 mono_arch_regname (int reg) {
161         static const char rnames[][4] = {
162                 "r0", "sp", "r2", "r3", "r4",
163                 "r5", "r6", "r7", "r8", "r9",
164                 "r10", "r11", "r12", "r13", "r14",
165                 "r15", "r16", "r17", "r18", "r19",
166                 "r20", "r21", "r22", "r23", "r24",
167                 "r25", "r26", "r27", "r28", "r29",
168                 "r30", "r31"
169         };
170         if (reg >= 0 && reg < 32)
171                 return rnames [reg];
172         return "unknown";
173 }
174
175 const char*
176 mono_arch_fregname (int reg) {
177         static const char rnames[][4] = {
178                 "f0", "f1", "f2", "f3", "f4",
179                 "f5", "f6", "f7", "f8", "f9",
180                 "f10", "f11", "f12", "f13", "f14",
181                 "f15", "f16", "f17", "f18", "f19",
182                 "f20", "f21", "f22", "f23", "f24",
183                 "f25", "f26", "f27", "f28", "f29",
184                 "f30", "f31"
185         };
186         if (reg >= 0 && reg < 32)
187                 return rnames [reg];
188         return "unknown";
189 }
190
191 /* this function overwrites r0, r11, r12 */
192 static guint8*
193 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
194 {
195         /* unrolled, use the counter in big */
196         if (size > sizeof (gpointer) * 5) {
197                 int shifted = size >> 2;
198                 guint8 *copy_loop_start, *copy_loop_jump;
199
200                 ppc_load (code, ppc_r0, shifted);
201                 ppc_mtctr (code, ppc_r0);
202                 g_assert (sreg == ppc_r11);
203                 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
204                 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
205                 copy_loop_start = code;
206                 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
207                 ppc_stwu (code, ppc_r0, 4, ppc_r12);
208                 copy_loop_jump = code;
209                 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
210                 ppc_patch (copy_loop_jump, copy_loop_start);
211                 size -= shifted * 4;
212                 doffset = soffset = 0;
213                 dreg = ppc_r12;
214         }
215         while (size >= 4) {
216                 ppc_lwz (code, ppc_r0, soffset, sreg);
217                 ppc_stw (code, ppc_r0, doffset, dreg);
218                 size -= 4;
219                 soffset += 4;
220                 doffset += 4;
221         }
222         while (size >= 2) {
223                 ppc_lhz (code, ppc_r0, soffset, sreg);
224                 ppc_sth (code, ppc_r0, doffset, dreg);
225                 size -= 2;
226                 soffset += 2;
227                 doffset += 2;
228         }
229         while (size >= 1) {
230                 ppc_lbz (code, ppc_r0, soffset, sreg);
231                 ppc_stb (code, ppc_r0, doffset, dreg);
232                 size -= 1;
233                 soffset += 1;
234                 doffset += 1;
235         }
236         return code;
237 }
238
239 /*
240  * mono_arch_get_argument_info:
241  * @csig:  a method signature
242  * @param_count: the number of parameters to consider
243  * @arg_info: an array to store the result infos
244  *
245  * Gathers information on parameters such as size, alignment and
246  * padding. arg_info should be large enought to hold param_count + 1 entries. 
247  *
248  * Returns the size of the activation frame.
249  */
250 int
251 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
252 {
253         int k, frame_size = 0;
254         int size, align, pad;
255         int offset = 8;
256
257         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
258                 frame_size += sizeof (gpointer);
259                 offset += 4;
260         }
261
262         arg_info [0].offset = offset;
263
264         if (csig->hasthis) {
265                 frame_size += sizeof (gpointer);
266                 offset += 4;
267         }
268
269         arg_info [0].size = frame_size;
270
271         for (k = 0; k < param_count; k++) {
272                 
273                 if (csig->pinvoke)
274                         size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
275                 else
276                         size = mini_type_stack_size (NULL, csig->params [k], &align);
277
278                 /* ignore alignment for now */
279                 align = 1;
280
281                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
282                 arg_info [k].pad = pad;
283                 frame_size += size;
284                 arg_info [k + 1].pad = 0;
285                 arg_info [k + 1].size = size;
286                 offset += pad;
287                 arg_info [k + 1].offset = offset;
288                 offset += size;
289         }
290
291         align = MONO_ARCH_FRAME_ALIGNMENT;
292         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
293         arg_info [k].pad = pad;
294
295         return frame_size;
296 }
297
298 gpointer
299 mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
300 {
301         char *o = NULL;
302         int reg, offset = 0;
303         guint32* code = (guint32*)code_ptr;
304
305         *displacement = 0;
306
307         /* This is the 'blrl' instruction */
308         --code;
309
310         /* Sanity check: instruction must be 'blrl' */
311         if (*code != 0x4e800021)
312                 return NULL;
313
314         /* the thunk-less direct call sequence: lis/ori/mtlr/blrl */
315         if ((code [-1] >> 26) == 31 && (code [-2] >> 26) == 24 && (code [-3] >> 26) == 15) {
316                 return NULL;
317         }
318
319         /* OK, we're now at the 'blrl' instruction. Now walk backwards
320         till we get to a 'mtlr rA' */
321         for (; --code;) {
322                 if((*code & 0x7c0803a6) == 0x7c0803a6) {
323                         gint16 soff;
324                         /* Here we are: we reached the 'mtlr rA'.
325                         Extract the register from the instruction */
326                         reg = (*code & 0x03e00000) >> 21;
327                         --code;
328                         /* ok, this is a lwz reg, offset (vtreg) 
329                          * it is emitted with:
330                          * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
331                          */
332                         soff = (*code & 0xffff);
333                         offset = soff;
334                         reg = (*code >> 16) & 0x1f;
335                         g_assert (reg != ppc_r1);
336                         /*g_print ("patching reg is %d\n", reg);*/
337                         if (reg >= 13) {
338                                 MonoLMF *lmf = (MonoLMF*)((char*)regs + (14 * sizeof (double)) + (13 * sizeof (gulong)));
339                                 /* saved in the MonoLMF structure */
340                                 o = (gpointer)lmf->iregs [reg - 13];
341                         } else {
342                                 o = regs [reg];
343                         }
344                         break;
345                 }
346         }
347         *displacement = offset;
348         return o;
349 }
350
351 gpointer*
352 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
353 {
354         gpointer vt;
355         int displacement;
356         vt = mono_arch_get_vcall_slot (code, regs, &displacement);
357         if (!vt)
358                 return NULL;
359         return (gpointer*)((char*)vt + displacement);
360 }
361
362 #define MAX_ARCH_DELEGATE_PARAMS 7
363
364 gpointer
365 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
366 {
367         guint8 *code, *start;
368
369         /* FIXME: Support more cases */
370         if (MONO_TYPE_ISSTRUCT (sig->ret))
371                 return NULL;
372
373         if (has_target) {
374                 static guint8* cached = NULL;
375                 mono_mini_arch_lock ();
376                 if (cached) {
377                         mono_mini_arch_unlock ();
378                         return cached;
379                 }
380                 
381                 start = code = mono_global_codeman_reserve (16);
382
383                 /* Replace the this argument with the target */
384                 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
385                 ppc_mtctr (code, ppc_r0);
386                 ppc_lwz (code, ppc_r3, G_STRUCT_OFFSET (MonoDelegate, target), ppc_r3);
387                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
388
389                 g_assert ((code - start) <= 16);
390
391                 mono_arch_flush_icache (start, 16);
392                 cached = start;
393                 mono_mini_arch_unlock ();
394                 return cached;
395         } else {
396                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
397                 int size, i;
398
399                 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
400                         return NULL;
401                 for (i = 0; i < sig->param_count; ++i)
402                         if (!mono_is_regsize_var (sig->params [i]))
403                                 return NULL;
404
405                 mono_mini_arch_lock ();
406                 code = cache [sig->param_count];
407                 if (code) {
408                         mono_mini_arch_unlock ();
409                         return code;
410                 }
411
412                 size = 12 + sig->param_count * 4;
413                 start = code = mono_global_codeman_reserve (size);
414
415                 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET (MonoDelegate, method_ptr), ppc_r3);
416                 ppc_mtctr (code, ppc_r0);
417                 /* slide down the arguments */
418                 for (i = 0; i < sig->param_count; ++i) {
419                         ppc_mr (code, (ppc_r3 + i), (ppc_r3 + i + 1));
420                 }
421                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
422
423                 g_assert ((code - start) <= size);
424
425                 mono_arch_flush_icache (start, size);
426                 cache [sig->param_count] = start;
427                 mono_mini_arch_unlock ();
428                 return start;
429         }
430         return NULL;
431 }
432
433 gpointer
434 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
435 {
436         /* FIXME: handle returning a struct */
437         if (MONO_TYPE_ISSTRUCT (sig->ret))
438                 return (gpointer)regs [ppc_r4];
439         return (gpointer)regs [ppc_r3];
440 }
441
442 /*
443  * Initialize the cpu to execute managed code.
444  */
445 void
446 mono_arch_cpu_init (void)
447 {
448 }
449
450 /*
451  * Initialize architecture specific code.
452  */
453 void
454 mono_arch_init (void)
455 {
456         InitializeCriticalSection (&mini_arch_mutex);   
457 }
458
459 /*
460  * Cleanup architecture specific code.
461  */
462 void
463 mono_arch_cleanup (void)
464 {
465         DeleteCriticalSection (&mini_arch_mutex);
466 }
467
468 /*
469  * This function returns the optimizations supported on this cpu.
470  */
471 guint32
472 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
473 {
474         guint32 opts = 0;
475
476         /* no ppc-specific optimizations yet */
477         *exclude_mask = 0;
478         return opts;
479 }
480
481 static gboolean
482 is_regsize_var (MonoType *t) {
483         if (t->byref)
484                 return TRUE;
485         t = mini_type_get_underlying_type (NULL, t);
486         switch (t->type) {
487         case MONO_TYPE_I4:
488         case MONO_TYPE_U4:
489         case MONO_TYPE_I:
490         case MONO_TYPE_U:
491         case MONO_TYPE_PTR:
492         case MONO_TYPE_FNPTR:
493                 return TRUE;
494         case MONO_TYPE_OBJECT:
495         case MONO_TYPE_STRING:
496         case MONO_TYPE_CLASS:
497         case MONO_TYPE_SZARRAY:
498         case MONO_TYPE_ARRAY:
499                 return TRUE;
500         case MONO_TYPE_GENERICINST:
501                 if (!mono_type_generic_inst_is_valuetype (t))
502                         return TRUE;
503                 return FALSE;
504         case MONO_TYPE_VALUETYPE:
505                 return FALSE;
506         }
507         return FALSE;
508 }
509
510 GList *
511 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
512 {
513         GList *vars = NULL;
514         int i;
515
516         for (i = 0; i < cfg->num_varinfo; i++) {
517                 MonoInst *ins = cfg->varinfo [i];
518                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
519
520                 /* unused vars */
521                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
522                         continue;
523
524                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
525                         continue;
526
527                 /* we can only allocate 32 bit values */
528                 if (is_regsize_var (ins->inst_vtype)) {
529                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
530                         g_assert (i == vmv->idx);
531                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
532                 }
533         }
534
535         return vars;
536 }
537
538 GList *
539 mono_arch_get_global_int_regs (MonoCompile *cfg)
540 {
541         GList *regs = NULL;
542         int i, top = 32;
543         if (cfg->frame_reg != ppc_sp)
544                 top = 31;
545         /* ppc_r13 is used by the system on PPC EABI */
546         for (i = 14; i < top; ++i)
547                 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
548
549         return regs;
550 }
551
552 /*
553  * mono_arch_regalloc_cost:
554  *
555  *  Return the cost, in number of memory references, of the action of 
556  * allocating the variable VMV into a register during global register
557  * allocation.
558  */
559 guint32
560 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
561 {
562         /* FIXME: */
563         return 2;
564 }
565
566 typedef struct {
567         long int type;
568         long int value;
569 } AuxVec;
570
571 void
572 mono_arch_flush_icache (guint8 *code, gint size)
573 {
574         guint8 *p, *endp, *start;
575         static int cachelinesize = 0;
576         static int cachelineinc = 16;
577
578         if (!cachelinesize) {
579 #ifdef __APPLE__
580                 int mib [3];
581                 size_t len;
582                 mib [0] = CTL_HW;
583                 mib [1] = HW_CACHELINE;
584                 len = sizeof (cachelinesize);
585                 if (sysctl(mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
586                         perror ("sysctl");
587                         cachelinesize = 128;
588                 } else {
589                         cachelineinc = cachelinesize;
590                         /*g_print ("setting cl size to %d\n", cachelinesize);*/
591                 }
592 #elif defined(__linux__)
593                 /* sadly this will work only with 2.6 kernels... */
594                 FILE* f = fopen ("/proc/self/auxv", "rb");
595                 if (f) {
596                         AuxVec vec;
597                         while (fread (&vec, sizeof (vec), 1, f) == 1) {
598                                 if (vec.type == 19) {
599                                         cachelinesize = vec.value;
600                                         break;
601                                 }
602                         }
603                         fclose (f);
604                 }
605                 if (!cachelinesize)
606                         cachelinesize = 128;
607 #else
608 #warning Need a way to get cache line size
609                 cachelinesize = 128;
610 #endif
611         }
612         p = start = code;
613         endp = p + size;
614         start = (guint8*)((gsize)start & ~(cachelinesize - 1));
615         /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
616         if (1) {
617                 for (p = start; p < endp; p += cachelineinc) {
618                         asm ("dcbf 0,%0;" : : "r"(p) : "memory");
619                 }
620         } else {
621                 for (p = start; p < endp; p += cachelineinc) {
622                         asm ("dcbst 0,%0;" : : "r"(p) : "memory");
623                 }
624         }
625         asm ("sync");
626         p = code;
627         for (p = start; p < endp; p += cachelineinc) {
628                 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
629         }
630         asm ("sync");
631         asm ("isync");
632 }
633
634 void
635 mono_arch_flush_register_windows (void)
636 {
637 }
638
639 #ifdef __APPLE__
640 #define ALWAYS_ON_STACK(s) s
641 #define FP_ALSO_IN_REG(s) s
642 #else
643 #define ALWAYS_ON_STACK(s)
644 #define FP_ALSO_IN_REG(s)
645 #define ALIGN_DOUBLES
646 #endif
647
648 enum {
649         RegTypeGeneral,
650         RegTypeBase,
651         RegTypeFP,
652         RegTypeStructByVal,
653         RegTypeStructByAddr
654 };
655
656 typedef struct {
657         gint32  offset;
658         guint32 vtsize; /* in param area */
659         guint8  reg;
660         guint8  regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
661         guint8  size    : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
662 } ArgInfo;
663
664 typedef struct {
665         int nargs;
666         guint32 stack_usage;
667         guint32 struct_ret;
668         ArgInfo ret;
669         ArgInfo sig_cookie;
670         ArgInfo args [1];
671 } CallInfo;
672
673 #define DEBUG(a)
674
675 static void inline
676 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
677 {
678         if (simple) {
679                 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
680                         ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
681                         ainfo->reg = ppc_sp; /* in the caller */
682                         ainfo->regtype = RegTypeBase;
683                         *stack_size += 4;
684                 } else {
685                         ALWAYS_ON_STACK (*stack_size += 4);
686                         ainfo->reg = *gr;
687                 }
688         } else {
689                 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
690 #ifdef ALIGN_DOUBLES
691                         //*stack_size += (*stack_size % 8);
692 #endif
693                         ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
694                         ainfo->reg = ppc_sp; /* in the caller */
695                         ainfo->regtype = RegTypeBase;
696                         *stack_size += 8;
697                 } else {
698 #ifdef ALIGN_DOUBLES
699                 if (!((*gr) & 1))
700                         (*gr) ++;
701 #endif
702                         ALWAYS_ON_STACK (*stack_size += 8);
703                         ainfo->reg = *gr;
704                 }
705                 (*gr) ++;
706         }
707         (*gr) ++;
708 }
709
710 #if __APPLE__
711 static gboolean
712 has_only_a_r48_field (MonoClass *klass)
713 {
714         gpointer iter;
715         MonoClassField *f;
716         gboolean have_field = FALSE;
717         iter = NULL;
718         while ((f = mono_class_get_fields (klass, &iter))) {
719                 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
720                         if (have_field)
721                                 return FALSE;
722                         if (!f->type->byref && (f->type->type == MONO_TYPE_R4 || f->type->type == MONO_TYPE_R8))
723                                 have_field = TRUE;
724                         else
725                                 return FALSE;
726                 }
727         }
728         return have_field;
729 }
730 #endif
731
732 static CallInfo*
733 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
734 {
735         guint i, fr, gr;
736         int n = sig->hasthis + sig->param_count;
737         guint32 simpletype;
738         guint32 stack_size = 0;
739         CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
740
741         fr = PPC_FIRST_FPARG_REG;
742         gr = PPC_FIRST_ARG_REG;
743
744         /* FIXME: handle returning a struct */
745         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
746                 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
747                 cinfo->struct_ret = PPC_FIRST_ARG_REG;
748         }
749
750         n = 0;
751         if (sig->hasthis) {
752                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
753                 n++;
754         }
755         DEBUG(printf("params: %d\n", sig->param_count));
756         for (i = 0; i < sig->param_count; ++i) {
757                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
758                         /* Prevent implicit arguments and sig_cookie from
759                            being passed in registers */
760                         gr = PPC_LAST_ARG_REG + 1;
761                         /* FIXME: don't we have to set fr, too? */
762                         /* Emit the signature cookie just before the implicit arguments */
763                         add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
764                 }
765                 DEBUG(printf("param %d: ", i));
766                 if (sig->params [i]->byref) {
767                         DEBUG(printf("byref\n"));
768                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
769                         n++;
770                         continue;
771                 }
772                 simpletype = mini_type_get_underlying_type (NULL, sig->params [i])->type;
773                 switch (simpletype) {
774                 case MONO_TYPE_BOOLEAN:
775                 case MONO_TYPE_I1:
776                 case MONO_TYPE_U1:
777                         cinfo->args [n].size = 1;
778                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
779                         n++;
780                         break;
781                 case MONO_TYPE_CHAR:
782                 case MONO_TYPE_I2:
783                 case MONO_TYPE_U2:
784                         cinfo->args [n].size = 2;
785                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
786                         n++;
787                         break;
788                 case MONO_TYPE_I4:
789                 case MONO_TYPE_U4:
790                         cinfo->args [n].size = 4;
791                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
792                         n++;
793                         break;
794                 case MONO_TYPE_I:
795                 case MONO_TYPE_U:
796                 case MONO_TYPE_PTR:
797                 case MONO_TYPE_FNPTR:
798                 case MONO_TYPE_CLASS:
799                 case MONO_TYPE_OBJECT:
800                 case MONO_TYPE_STRING:
801                 case MONO_TYPE_SZARRAY:
802                 case MONO_TYPE_ARRAY:
803                         cinfo->args [n].size = sizeof (gpointer);
804                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
805                         n++;
806                         break;
807                 case MONO_TYPE_GENERICINST:
808                         if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
809                                 cinfo->args [n].size = sizeof (gpointer);
810                                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
811                                 n++;
812                                 break;
813                         }
814                         /* Fall through */
815                 case MONO_TYPE_VALUETYPE: {
816                         gint size;
817                         MonoClass *klass;
818                         klass = mono_class_from_mono_type (sig->params [i]);
819                         if (is_pinvoke)
820                             size = mono_class_native_size (klass, NULL);
821                         else
822                             size = mono_class_value_size (klass, NULL);
823 #if __APPLE__
824                         if ((size == 4 || size == 8) && has_only_a_r48_field (klass)) {
825                                 cinfo->args [n].size = size;
826
827                                 /* It was 7, now it is 8 in LinuxPPC */
828                                 if (fr <= PPC_LAST_FPARG_REG) {
829                                         cinfo->args [n].regtype = RegTypeFP;
830                                         cinfo->args [n].reg = fr;
831                                         fr ++;
832                                         FP_ALSO_IN_REG (gr ++);
833                                         if (size == 8)
834                                                 FP_ALSO_IN_REG (gr ++);
835                                         ALWAYS_ON_STACK (stack_size += size);
836                                 } else {
837                                         cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
838                                         cinfo->args [n].regtype = RegTypeBase;
839                                         cinfo->args [n].reg = ppc_sp; /* in the caller*/
840                                         stack_size += 8;
841                                 }
842                                 n++;
843                                 break;
844                         }
845 #endif
846                         DEBUG(printf ("load %d bytes struct\n",
847                                       mono_class_native_size (sig->params [i]->data.klass, NULL)));
848 #if PPC_PASS_STRUCTS_BY_VALUE
849                         {
850                                 int align_size = size;
851                                 int nwords = 0;
852                                 int rest = PPC_LAST_ARG_REG - gr + 1;
853                                 int n_in_regs;
854                                 align_size += (sizeof (gpointer) - 1);
855                                 align_size &= ~(sizeof (gpointer) - 1);
856                                 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
857                                 n_in_regs = rest >= nwords? nwords: rest;
858                                 cinfo->args [n].regtype = RegTypeStructByVal;
859                                 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
860                                         cinfo->args [n].size = 0;
861                                         cinfo->args [n].vtsize = nwords;
862                                 } else {
863                                         cinfo->args [n].size = n_in_regs;
864                                         cinfo->args [n].vtsize = nwords - n_in_regs;
865                                         cinfo->args [n].reg = gr;
866                                 }
867                                 gr += n_in_regs;
868                                 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
869                                 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
870                                 stack_size += nwords * sizeof (gpointer);
871                         }
872 #else
873                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
874                         cinfo->args [n].regtype = RegTypeStructByAddr;
875                         cinfo->args [n].vtsize = size;
876 #endif
877                         n++;
878                         break;
879                 }
880                 case MONO_TYPE_TYPEDBYREF: {
881                         int size = sizeof (MonoTypedRef);
882                         /* keep in sync or merge with the valuetype case */
883 #if PPC_PASS_STRUCTS_BY_VALUE
884                         {
885                                 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
886                                 cinfo->args [n].regtype = RegTypeStructByVal;
887                                 if (gr <= PPC_LAST_ARG_REG) {
888                                         int rest = PPC_LAST_ARG_REG - gr + 1;
889                                         int n_in_regs = rest >= nwords? nwords: rest;
890                                         cinfo->args [n].size = n_in_regs;
891                                         cinfo->args [n].vtsize = nwords - n_in_regs;
892                                         cinfo->args [n].reg = gr;
893                                         gr += n_in_regs;
894                                 } else {
895                                         cinfo->args [n].size = 0;
896                                         cinfo->args [n].vtsize = nwords;
897                                 }
898                                 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
899                                 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
900                                 stack_size += nwords * sizeof (gpointer);
901                         }
902 #else
903                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
904                         cinfo->args [n].regtype = RegTypeStructByAddr;
905                         cinfo->args [n].vtsize = size;
906 #endif
907                         n++;
908                         break;
909                 }
910                 case MONO_TYPE_U8:
911                 case MONO_TYPE_I8:
912                         cinfo->args [n].size = 8;
913                         add_general (&gr, &stack_size, cinfo->args + n, FALSE);
914                         n++;
915                         break;
916                 case MONO_TYPE_R4:
917                         cinfo->args [n].size = 4;
918
919                         /* It was 7, now it is 8 in LinuxPPC */
920                         if (fr <= PPC_LAST_FPARG_REG) {
921                                 cinfo->args [n].regtype = RegTypeFP;
922                                 cinfo->args [n].reg = fr;
923                                 fr ++;
924                                 FP_ALSO_IN_REG (gr ++);
925                                 ALWAYS_ON_STACK (stack_size += 4);
926                         } else {
927                                 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
928                                 cinfo->args [n].regtype = RegTypeBase;
929                                 cinfo->args [n].reg = ppc_sp; /* in the caller*/
930                                 stack_size += 4;
931                         }
932                         n++;
933                         break;
934                 case MONO_TYPE_R8:
935                         cinfo->args [n].size = 8;
936                         /* It was 7, now it is 8 in LinuxPPC */
937                         if (fr <= PPC_LAST_FPARG_REG) {
938                                 cinfo->args [n].regtype = RegTypeFP;
939                                 cinfo->args [n].reg = fr;
940                                 fr ++;
941                                 FP_ALSO_IN_REG (gr += 2);
942                                 ALWAYS_ON_STACK (stack_size += 8);
943                         } else {
944                                 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
945                                 cinfo->args [n].regtype = RegTypeBase;
946                                 cinfo->args [n].reg = ppc_sp; /* in the caller*/
947                                 stack_size += 8;
948                         }
949                         n++;
950                         break;
951                 default:
952                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
953                 }
954         }
955
956         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
957                 /* Prevent implicit arguments and sig_cookie from
958                    being passed in registers */
959                 gr = PPC_LAST_ARG_REG + 1;
960                 /* Emit the signature cookie just before the implicit arguments */
961                 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
962         }
963
964         {
965                 simpletype = mini_type_get_underlying_type (NULL, sig->ret)->type;
966                 switch (simpletype) {
967                 case MONO_TYPE_BOOLEAN:
968                 case MONO_TYPE_I1:
969                 case MONO_TYPE_U1:
970                 case MONO_TYPE_I2:
971                 case MONO_TYPE_U2:
972                 case MONO_TYPE_CHAR:
973                 case MONO_TYPE_I4:
974                 case MONO_TYPE_U4:
975                 case MONO_TYPE_I:
976                 case MONO_TYPE_U:
977                 case MONO_TYPE_PTR:
978                 case MONO_TYPE_FNPTR:
979                 case MONO_TYPE_CLASS:
980                 case MONO_TYPE_OBJECT:
981                 case MONO_TYPE_SZARRAY:
982                 case MONO_TYPE_ARRAY:
983                 case MONO_TYPE_STRING:
984                         cinfo->ret.reg = ppc_r3;
985                         break;
986                 case MONO_TYPE_U8:
987                 case MONO_TYPE_I8:
988                         cinfo->ret.reg = ppc_r3;
989                         break;
990                 case MONO_TYPE_R4:
991                 case MONO_TYPE_R8:
992                         cinfo->ret.reg = ppc_f1;
993                         cinfo->ret.regtype = RegTypeFP;
994                         break;
995                 case MONO_TYPE_GENERICINST:
996                         if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
997                                 cinfo->ret.reg = ppc_r3;
998                                 break;
999                         }
1000                         break;
1001                 case MONO_TYPE_VALUETYPE:
1002                         break;
1003                 case MONO_TYPE_TYPEDBYREF:
1004                 case MONO_TYPE_VOID:
1005                         break;
1006                 default:
1007                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
1008                 }
1009         }
1010
1011         /* align stack size to 16 */
1012         DEBUG (printf ("      stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1013         stack_size = (stack_size + 15) & ~15;
1014
1015         cinfo->stack_usage = stack_size;
1016         return cinfo;
1017 }
1018
1019 static void
1020 allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
1021 {
1022 #if !PPC_PASS_STRUCTS_BY_VALUE
1023         MonoMethodSignature *sig = mono_method_signature (cfg->method);
1024         int num_structs = 0;
1025         int i;
1026
1027         if (!(cfg->flags & MONO_CFG_HAS_TAIL))
1028                 return;
1029
1030         for (i = 0; i < sig->param_count; ++i) {
1031                 MonoType *type = mono_type_get_underlying_type (sig->params [i]);
1032                 if (type->type == MONO_TYPE_VALUETYPE)
1033                         num_structs++;
1034         }
1035
1036         if (num_structs) {
1037                 cfg->tailcall_valuetype_addrs =
1038                         mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
1039                 for (i = 0; i < num_structs; ++i) {
1040                         cfg->tailcall_valuetype_addrs [i] =
1041                                 mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1042                         cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
1043                 }
1044         }
1045 #endif
1046 }
1047
1048 /*
1049  * Set var information according to the calling convention. ppc version.
1050  * The locals var stuff should most likely be split in another method.
1051  */
1052 void
1053 mono_arch_allocate_vars (MonoCompile *m)
1054 {
1055         MonoMethodSignature *sig;
1056         MonoMethodHeader *header;
1057         MonoInst *inst;
1058         int i, offset, size, align, curinst;
1059         int frame_reg = ppc_sp;
1060         gint32 *offsets;
1061         guint32 locals_stack_size, locals_stack_align;
1062
1063         allocate_tailcall_valuetype_addrs (m);
1064
1065         m->flags |= MONO_CFG_HAS_SPILLUP;
1066
1067         /* allow room for the vararg method args: void* and long/double */
1068         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1069                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1070         /* this is bug #60332: remove when #59509 is fixed, so no weird vararg 
1071          * call convs needs to be handled this way.
1072          */
1073         if (m->flags & MONO_CFG_HAS_VARARGS)
1074                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1075         /* gtk-sharp and other broken code will dllimport vararg functions even with
1076          * non-varargs signatures. Since there is little hope people will get this right
1077          * we assume they won't.
1078          */
1079         if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1080                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1081
1082         header = mono_method_get_header (m->method);
1083
1084         /* 
1085          * We use the frame register also for any method that has
1086          * exception clauses. This way, when the handlers are called,
1087          * the code will reference local variables using the frame reg instead of
1088          * the stack pointer: if we had to restore the stack pointer, we'd
1089          * corrupt the method frames that are already on the stack (since
1090          * filters get called before stack unwinding happens) when the filter
1091          * code would call any method (this also applies to finally etc.).
1092          */ 
1093         if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1094                 frame_reg = ppc_r31;
1095         m->frame_reg = frame_reg;
1096         if (frame_reg != ppc_sp) {
1097                 m->used_int_regs |= 1 << frame_reg;
1098         }
1099
1100         sig = mono_method_signature (m->method);
1101         
1102         offset = 0;
1103         curinst = 0;
1104         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1105                 m->ret->opcode = OP_REGVAR;
1106                 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1107         } else {
1108                 /* FIXME: handle long values? */
1109                 switch (mini_type_get_underlying_type (m->generic_sharing_context, sig->ret)->type) {
1110                 case MONO_TYPE_VOID:
1111                         break;
1112                 case MONO_TYPE_R4:
1113                 case MONO_TYPE_R8:
1114                         m->ret->opcode = OP_REGVAR;
1115                         m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1116                         break;
1117                 default:
1118                         m->ret->opcode = OP_REGVAR;
1119                         m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1120                         break;
1121                 }
1122         }
1123         /* local vars are at a positive offset from the stack pointer */
1124         /* 
1125          * also note that if the function uses alloca, we use ppc_r31
1126          * to point at the local variables.
1127          */
1128         offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1129         /* align the offset to 16 bytes: not sure this is needed here  */
1130         //offset += 16 - 1;
1131         //offset &= ~(16 - 1);
1132
1133         /* add parameter area size for called functions */
1134         offset += m->param_area;
1135         offset += 16 - 1;
1136         offset &= ~(16 - 1);
1137
1138         /* allow room to save the return value */
1139         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1140                 offset += 8;
1141
1142         /* the MonoLMF structure is stored just below the stack pointer */
1143
1144 #if 0
1145         /* this stuff should not be needed on ppc and the new jit,
1146          * because a call on ppc to the handlers doesn't change the 
1147          * stack pointer and the jist doesn't manipulate the stack pointer
1148          * for operations involving valuetypes.
1149          */
1150         /* reserve space to store the esp */
1151         offset += sizeof (gpointer);
1152
1153         /* this is a global constant */
1154         mono_exc_esp_offset = offset;
1155 #endif
1156         if (sig->call_convention == MONO_CALL_VARARG) {
1157                 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1158         }
1159
1160         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1161                 offset += sizeof(gpointer) - 1;
1162                 offset &= ~(sizeof(gpointer) - 1);
1163
1164                 if (m->new_ir) {
1165                         m->vret_addr->opcode = OP_REGOFFSET;
1166                         m->vret_addr->inst_basereg = frame_reg;
1167                         m->vret_addr->inst_offset = offset;
1168
1169                         if (G_UNLIKELY (m->verbose_level > 1)) {
1170                                 printf ("vret_addr =");
1171                                 mono_print_ins (m->vret_addr);
1172                         }
1173                 } else {
1174                         inst = m->ret;
1175                         inst->inst_offset = offset;
1176                         inst->opcode = OP_REGOFFSET;
1177                         inst->inst_basereg = frame_reg;
1178                 }
1179
1180                 offset += sizeof(gpointer);
1181                 if (sig->call_convention == MONO_CALL_VARARG)
1182                         m->sig_cookie += sizeof (gpointer);
1183         }
1184
1185         offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1186         if (locals_stack_align) {
1187                 offset += (locals_stack_align - 1);
1188                 offset &= ~(locals_stack_align - 1);
1189         }
1190         for (i = m->locals_start; i < m->num_varinfo; i++) {
1191                 if (offsets [i] != -1) {
1192                         MonoInst *inst = m->varinfo [i];
1193                         inst->opcode = OP_REGOFFSET;
1194                         inst->inst_basereg = frame_reg;
1195                         inst->inst_offset = offset + offsets [i];
1196                         /*
1197                         g_print ("allocating local %d (%s) to %d\n",
1198                                 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1199                         */
1200                 }
1201         }
1202         offset += locals_stack_size;
1203
1204         curinst = 0;
1205         if (sig->hasthis) {
1206                 inst = m->args [curinst];
1207                 if (inst->opcode != OP_REGVAR) {
1208                         inst->opcode = OP_REGOFFSET;
1209                         inst->inst_basereg = frame_reg;
1210                         offset += sizeof (gpointer) - 1;
1211                         offset &= ~(sizeof (gpointer) - 1);
1212                         inst->inst_offset = offset;
1213                         offset += sizeof (gpointer);
1214                         if (sig->call_convention == MONO_CALL_VARARG)
1215                                 m->sig_cookie += sizeof (gpointer);
1216                 }
1217                 curinst++;
1218         }
1219
1220         for (i = 0; i < sig->param_count; ++i) {
1221                 inst = m->args [curinst];
1222                 if (inst->opcode != OP_REGVAR) {
1223                         inst->opcode = OP_REGOFFSET;
1224                         inst->inst_basereg = frame_reg;
1225                         if (sig->pinvoke) {
1226                                 size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
1227                                 inst->backend.is_pinvoke = 1;
1228                         } else {
1229                                 size = mono_type_size (sig->params [i], &align);
1230                         }
1231                         offset += align - 1;
1232                         offset &= ~(align - 1);
1233                         inst->inst_offset = offset;
1234                         offset += size;
1235                         if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) 
1236                                 m->sig_cookie += size;
1237                 }
1238                 curinst++;
1239         }
1240
1241         /* align the offset to 16 bytes */
1242         offset += 16 - 1;
1243         offset &= ~(16 - 1);
1244
1245         /* change sign? */
1246         m->stack_offset = offset;
1247
1248         if (m->new_ir && sig->call_convention == MONO_CALL_VARARG) {
1249                 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1250
1251                 m->sig_cookie = cinfo->sig_cookie.offset;
1252
1253                 g_free(cinfo);
1254         }
1255 }
1256
1257 void
1258 mono_arch_create_vars (MonoCompile *cfg)
1259 {
1260         MonoMethodSignature *sig = mono_method_signature (cfg->method);
1261
1262         if (cfg->new_ir && MONO_TYPE_ISSTRUCT (sig->ret)) {
1263                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1264         }
1265 }
1266
1267 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1268  * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
1269  */
1270
1271 /* 
1272  * take the arguments and generate the arch-specific
1273  * instructions to properly call the function in call.
1274  * This includes pushing, moving arguments to the right register
1275  * etc.
1276  * Issue: who does the spilling if needed, and when?
1277  */
1278 MonoCallInst*
1279 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1280         MonoInst *arg, *in;
1281         MonoMethodSignature *sig;
1282         int i, n;
1283         CallInfo *cinfo;
1284         ArgInfo *ainfo;
1285
1286         sig = call->signature;
1287         n = sig->param_count + sig->hasthis;
1288         
1289         cinfo = calculate_sizes (sig, sig->pinvoke);
1290         if (cinfo->struct_ret)
1291                 call->used_iregs |= 1 << cinfo->struct_ret;
1292
1293         for (i = 0; i < n; ++i) {
1294                 ainfo = cinfo->args + i;
1295                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1296                         MonoInst *sig_arg;
1297                         cfg->disable_aot = TRUE;
1298                                 
1299                         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1300                         sig_arg->inst_p0 = call->signature;
1301                         
1302                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1303                         arg->inst_imm = cinfo->sig_cookie.offset;
1304                         arg->inst_left = sig_arg;
1305                         arg->inst_call = call;
1306                         /* prepend, so they get reversed */
1307                         arg->next = call->out_args;
1308                         call->out_args = arg;
1309                 }
1310                 if (is_virtual && i == 0) {
1311                         /* the argument will be attached to the call instrucion */
1312                         in = call->args [i];
1313                         call->used_iregs |= 1 << ainfo->reg;
1314                 } else {
1315                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1316                         in = call->args [i];
1317                         arg->cil_code = in->cil_code;
1318                         arg->inst_left = in;
1319                         arg->inst_call = call;
1320                         arg->type = in->type;
1321                         /* prepend, so they get reversed */
1322                         arg->next = call->out_args;
1323                         call->out_args = arg;
1324                         if (ainfo->regtype == RegTypeGeneral) {
1325                                 arg->backend.reg3 = ainfo->reg;
1326                                 call->used_iregs |= 1 << ainfo->reg;
1327                                 if (arg->type == STACK_I8)
1328                                         call->used_iregs |= 1 << (ainfo->reg + 1);
1329                         } else if (ainfo->regtype == RegTypeStructByAddr) {
1330                                 if (ainfo->offset) {
1331                                         MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1332                                         arg->opcode = OP_OUTARG_MEMBASE;
1333                                         ai->reg = ainfo->reg;
1334                                         ai->size = sizeof (gpointer);
1335                                         ai->offset = ainfo->offset;
1336                                         arg->backend.data = ai;
1337                                 } else {
1338                                         arg->backend.reg3 = ainfo->reg;
1339                                         call->used_iregs |= 1 << ainfo->reg;
1340                                 }
1341                         } else if (ainfo->regtype == RegTypeStructByVal) {
1342                                 int cur_reg;
1343                                 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1344                                 /* mark the used regs */
1345                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1346                                         call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1347                                 }
1348                                 arg->opcode = OP_OUTARG_VT;
1349                                 ai->reg = ainfo->reg;
1350                                 ai->size = ainfo->size;
1351                                 ai->vtsize = ainfo->vtsize;
1352                                 ai->offset = ainfo->offset;
1353                                 arg->backend.data = ai;
1354                         } else if (ainfo->regtype == RegTypeBase) {
1355                                 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1356                                 arg->opcode = OP_OUTARG_MEMBASE;
1357                                 ai->reg = ainfo->reg;
1358                                 ai->size = ainfo->size;
1359                                 ai->offset = ainfo->offset;
1360                                 arg->backend.data = ai;
1361                         } else if (ainfo->regtype == RegTypeFP) {
1362                                 arg->opcode = OP_OUTARG_R8;
1363                                 arg->backend.reg3 = ainfo->reg;
1364                                 call->used_fregs |= 1 << ainfo->reg;
1365                                 if (ainfo->size == 4) {
1366                                         arg->opcode = OP_OUTARG_R8;
1367                                         /* we reduce the precision */
1368                                         /*MonoInst *conv;
1369                                         MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1370                                         conv->inst_left = arg->inst_left;
1371                                         arg->inst_left = conv;*/
1372                                 }
1373                         } else {
1374                                 g_assert_not_reached ();
1375                         }
1376                 }
1377         }
1378         /*
1379          * Reverse the call->out_args list.
1380          */
1381         {
1382                 MonoInst *prev = NULL, *list = call->out_args, *next;
1383                 while (list) {
1384                         next = list->next;
1385                         list->next = prev;
1386                         prev = list;
1387                         list = next;
1388                 }
1389                 call->out_args = prev;
1390         }
1391
1392         call->stack_usage = cinfo->stack_usage;
1393         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1394         cfg->flags |= MONO_CFG_HAS_CALLS;
1395         /* 
1396          * should set more info in call, such as the stack space
1397          * used by the args that needs to be added back to esp
1398          */
1399
1400         g_free (cinfo);
1401         return call;
1402 }
1403
1404 static void
1405 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1406 {
1407         int sig_reg = mono_alloc_ireg (cfg);
1408
1409         MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1410         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1411                         ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1412 }
1413
1414 void
1415 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1416 {
1417         MonoInst *in, *ins;
1418         MonoMethodSignature *sig;
1419         int i, n;
1420         CallInfo *cinfo;
1421
1422         sig = call->signature;
1423         n = sig->param_count + sig->hasthis;
1424         
1425         cinfo = calculate_sizes (sig, sig->pinvoke);
1426
1427         for (i = 0; i < n; ++i) {
1428                 ArgInfo *ainfo = cinfo->args + i;
1429                 MonoType *t;
1430
1431                 if (i >= sig->hasthis)
1432                         t = sig->params [i - sig->hasthis];
1433                 else
1434                         t = &mono_defaults.int_class->byval_arg;
1435                 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1436
1437                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1438                         emit_sig_cookie (cfg, call, cinfo);
1439
1440                 in = call->args [i];
1441
1442                 if (ainfo->regtype == RegTypeGeneral) {
1443                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1444                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1445                                 ins->dreg = mono_alloc_ireg (cfg);
1446                                 ins->sreg1 = in->dreg + 1;
1447                                 MONO_ADD_INS (cfg->cbb, ins);
1448                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1449
1450                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1451                                 ins->dreg = mono_alloc_ireg (cfg);
1452                                 ins->sreg1 = in->dreg + 2;
1453                                 MONO_ADD_INS (cfg->cbb, ins);
1454                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1455                         } else {
1456                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1457                                 ins->dreg = mono_alloc_ireg (cfg);
1458                                 ins->sreg1 = in->dreg;
1459                                 MONO_ADD_INS (cfg->cbb, ins);
1460
1461                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1462                         }
1463                 } else if (ainfo->regtype == RegTypeStructByAddr) {
1464                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1465                         ins->opcode = OP_OUTARG_VT;
1466                         ins->sreg1 = in->dreg;
1467                         ins->klass = in->klass;
1468                         ins->inst_p0 = call;
1469                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1470                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1471                         MONO_ADD_INS (cfg->cbb, ins);
1472                 } else if (ainfo->regtype == RegTypeStructByVal) {
1473                         /* this is further handled in mono_arch_emit_outarg_vt () */
1474                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1475                         ins->opcode = OP_OUTARG_VT;
1476                         ins->sreg1 = in->dreg;
1477                         ins->klass = in->klass;
1478                         ins->inst_p0 = call;
1479                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1480                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1481                         MONO_ADD_INS (cfg->cbb, ins);
1482                 } else if (ainfo->regtype == RegTypeBase) {
1483                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1484                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1485                         } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1486                                 if (t->type == MONO_TYPE_R8)
1487                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1488                                 else
1489                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1490                         } else {
1491                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1492                         }
1493                 } else if (ainfo->regtype == RegTypeFP) {
1494                         if (t->type == MONO_TYPE_VALUETYPE) {
1495                                 /* this is further handled in mono_arch_emit_outarg_vt () */
1496                                 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1497                                 ins->opcode = OP_OUTARG_VT;
1498                                 ins->sreg1 = in->dreg;
1499                                 ins->klass = in->klass;
1500                                 ins->inst_p0 = call;
1501                                 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1502                                 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1503                                 MONO_ADD_INS (cfg->cbb, ins);
1504
1505                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1506                         } else {
1507                                 int dreg = mono_alloc_freg (cfg);
1508
1509                                 if (ainfo->size == 4) {
1510                                         MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
1511                                 } else {
1512                                         MONO_INST_NEW (cfg, ins, OP_FMOVE);
1513                                         ins->dreg = dreg;
1514                                         ins->sreg1 = in->dreg;
1515                                         MONO_ADD_INS (cfg->cbb, ins);
1516                                 }
1517
1518                                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1519                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1520                         }
1521                 } else {
1522                         g_assert_not_reached ();
1523                 }
1524         }
1525
1526         /* Emit the signature cookie in the case that there is no
1527            additional argument */
1528         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1529                 emit_sig_cookie (cfg, call, cinfo);
1530
1531         if (cinfo->struct_ret) {
1532                 MonoInst *vtarg;
1533
1534                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1535                 vtarg->sreg1 = call->vret_var->dreg;
1536                 vtarg->dreg = mono_alloc_preg (cfg);
1537                 MONO_ADD_INS (cfg->cbb, vtarg);
1538
1539                 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1540         }
1541
1542         call->stack_usage = cinfo->stack_usage;
1543         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1544         cfg->flags |= MONO_CFG_HAS_CALLS;
1545
1546         g_free (cinfo);
1547 }
1548
1549 void
1550 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1551 {
1552         MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1553         ArgInfo *ainfo = ins->inst_p1;
1554         int ovf_size = ainfo->vtsize;
1555         int doffset = ainfo->offset;
1556         int i, soffset, dreg;
1557
1558         if (ainfo->regtype == RegTypeStructByVal) {
1559                 guint32 size = 0;
1560                 soffset = 0;
1561 #ifdef __APPLE__
1562                 /*
1563                  * Darwin pinvokes needs some special handling for 1
1564                  * and 2 byte arguments
1565                  */
1566                 g_assert (ins->klass);
1567                 if (call->signature->pinvoke)
1568                         size =  mono_class_native_size (ins->klass, NULL);
1569                 if (size == 2 || size == 1) {
1570                         int tmpr = mono_alloc_ireg (cfg);
1571                         if (size == 1)
1572                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1573                         else
1574                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1575                         dreg = mono_alloc_ireg (cfg);
1576                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1577                         mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1578                 } else
1579 #endif
1580                         for (i = 0; i < ainfo->size; ++i) {
1581                                 dreg = mono_alloc_ireg (cfg);
1582                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1583                                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1584                                 soffset += sizeof (gpointer);
1585                         }
1586                 if (ovf_size != 0)
1587                         mini_emit_memcpy2 (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1588         } else if (ainfo->regtype == RegTypeFP) {
1589                 int tmpr = mono_alloc_freg (cfg);
1590                 if (ainfo->size == 4)
1591                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1592                 else
1593                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1594                 dreg = mono_alloc_freg (cfg);
1595                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1596                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1597         } else {
1598                 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1599                 MonoInst *load;
1600                 guint32 size;
1601
1602                 /* FIXME: alignment? */
1603                 if (call->signature->pinvoke) {
1604                         size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1605                         vtcopy->backend.is_pinvoke = 1;
1606                 } else {
1607                         size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1608                 }
1609                 if (size > 0)
1610                         g_assert (ovf_size > 0);
1611
1612                 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1613                 mini_emit_memcpy2 (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1614
1615                 if (ainfo->offset)
1616                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1617                 else
1618                         mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1619         }
1620 }
1621
1622 void
1623 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1624 {
1625         MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1626                         mono_method_signature (method)->ret);
1627
1628         if (!ret->byref) {
1629                 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1630                         MonoInst *ins;
1631
1632                         MONO_INST_NEW (cfg, ins, OP_SETLRET);
1633                         ins->sreg1 = val->dreg + 1;
1634                         ins->sreg2 = val->dreg + 2;
1635                         MONO_ADD_INS (cfg->cbb, ins);
1636                         return;
1637                 }
1638                 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1639                         MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1640                         return;
1641                 }
1642         }
1643         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1644 }
1645
1646 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1647 gboolean
1648 mono_arch_is_inst_imm (gint64 imm)
1649 {
1650        return TRUE;
1651 }
1652
1653 /*
1654  * Allow tracing to work with this interface (with an optional argument)
1655  */
1656
1657 void*
1658 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1659 {
1660         guchar *code = p;
1661
1662         ppc_load (code, ppc_r3, cfg->method);
1663         ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1664         ppc_load (code, ppc_r0, func);
1665         ppc_mtlr (code, ppc_r0);
1666         ppc_blrl (code);
1667         return code;
1668 }
1669
1670 enum {
1671         SAVE_NONE,
1672         SAVE_STRUCT,
1673         SAVE_ONE,
1674         SAVE_TWO,
1675         SAVE_FP
1676 };
1677
1678 void*
1679 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1680 {
1681         guchar *code = p;
1682         int save_mode = SAVE_NONE;
1683         int offset;
1684         MonoMethod *method = cfg->method;
1685         int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1686                         mono_method_signature (method)->ret)->type;
1687         int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1688         save_offset += 15;
1689         save_offset &= ~15;
1690         
1691         offset = code - cfg->native_code;
1692         /* we need about 16 instructions */
1693         if (offset > (cfg->code_size - 16 * 4)) {
1694                 cfg->code_size *= 2;
1695                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1696                 code = cfg->native_code + offset;
1697         }
1698
1699         switch (rtype) {
1700         case MONO_TYPE_VOID:
1701                 /* special case string .ctor icall */
1702                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1703                         save_mode = SAVE_ONE;
1704                 else
1705                         save_mode = SAVE_NONE;
1706                 break;
1707         case MONO_TYPE_I8:
1708         case MONO_TYPE_U8:
1709                 save_mode = SAVE_TWO;
1710                 break;
1711         case MONO_TYPE_R4:
1712         case MONO_TYPE_R8:
1713                 save_mode = SAVE_FP;
1714                 break;
1715         case MONO_TYPE_VALUETYPE:
1716                 save_mode = SAVE_STRUCT;
1717                 break;
1718         default:
1719                 save_mode = SAVE_ONE;
1720                 break;
1721         }
1722
1723         switch (save_mode) {
1724         case SAVE_TWO:
1725                 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1726                 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1727                 if (enable_arguments) {
1728                         ppc_mr (code, ppc_r5, ppc_r4);
1729                         ppc_mr (code, ppc_r4, ppc_r3);
1730                 }
1731                 break;
1732         case SAVE_ONE:
1733                 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1734                 if (enable_arguments) {
1735                         ppc_mr (code, ppc_r4, ppc_r3);
1736                 }
1737                 break;
1738         case SAVE_FP:
1739                 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1740                 if (enable_arguments) {
1741                         /* FIXME: what reg?  */
1742                         ppc_fmr (code, ppc_f3, ppc_f1);
1743                         ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1744                         ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1745                 }
1746                 break;
1747         case SAVE_STRUCT:
1748                 if (enable_arguments) {
1749                         /* FIXME: get the actual address  */
1750                         ppc_mr (code, ppc_r4, ppc_r3);
1751                 }
1752                 break;
1753         case SAVE_NONE:
1754         default:
1755                 break;
1756         }
1757
1758         ppc_load (code, ppc_r3, cfg->method);
1759         ppc_load (code, ppc_r0, func);
1760         ppc_mtlr (code, ppc_r0);
1761         ppc_blrl (code);
1762
1763         switch (save_mode) {
1764         case SAVE_TWO:
1765                 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1766                 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1767                 break;
1768         case SAVE_ONE:
1769                 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1770                 break;
1771         case SAVE_FP:
1772                 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1773                 break;
1774         case SAVE_NONE:
1775         default:
1776                 break;
1777         }
1778
1779         return code;
1780 }
1781 /*
1782  * Conditional branches have a small offset, so if it is likely overflowed,
1783  * we do a branch to the end of the method (uncond branches have much larger
1784  * offsets) where we perform the conditional and jump back unconditionally.
1785  * It's slightly slower, since we add two uncond branches, but it's very simple
1786  * with the current patch implementation and such large methods are likely not
1787  * going to be perf critical anyway.
1788  */
1789 typedef struct {
1790         union {
1791                 MonoBasicBlock *bb;
1792                 const char *exception;
1793         } data;
1794         guint32 ip_offset;
1795         guint16 b0_cond;
1796         guint16 b1_cond;
1797 } MonoOvfJump;
1798
1799 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1800 if (ins->flags & MONO_INST_BRLABEL) { \
1801         if (0 && ins->inst_i0->inst_c0) { \
1802                 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff);  \
1803         } else { \
1804                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1805                 ppc_bc (code, (b0), (b1), 0);   \
1806         } \
1807 } else { \
1808         if (0 && ins->inst_true_bb->native_offset) { \
1809                 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1810         } else { \
1811                 int br_disp = ins->inst_true_bb->max_offset - offset;   \
1812                 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1813                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));    \
1814                         ovfj->data.bb = ins->inst_true_bb;      \
1815                         ovfj->ip_offset = 0;    \
1816                         ovfj->b0_cond = (b0);   \
1817                         ovfj->b1_cond = (b1);   \
1818                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1819                         ppc_b (code, 0);        \
1820                 } else {        \
1821                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1822                         ppc_bc (code, (b0), (b1), 0);   \
1823                 }       \
1824         } \
1825 }
1826
1827 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1828
1829 /* emit an exception if condition is fail
1830  *
1831  * We assign the extra code used to throw the implicit exceptions
1832  * to cfg->bb_exit as far as the big branch handling is concerned
1833  */
1834 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name)            \
1835         do {                                                        \
1836                 int br_disp = cfg->bb_exit->max_offset - offset;        \
1837                 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1838                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));    \
1839                         ovfj->data.exception = (exc_name);      \
1840                         ovfj->ip_offset = code - cfg->native_code;      \
1841                         ovfj->b0_cond = (b0);   \
1842                         ovfj->b1_cond = (b1);   \
1843                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1844                         ppc_bl (code, 0);       \
1845                         cfg->bb_exit->max_offset += 24; \
1846                 } else {        \
1847                         mono_add_patch_info (cfg, code - cfg->native_code,   \
1848                                     MONO_PATCH_INFO_EXC, exc_name);  \
1849                         ppc_bcl (code, (b0), (b1), 0);  \
1850                 }       \
1851         } while (0); 
1852
1853 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1854
1855 void
1856 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1857 {
1858 }
1859
1860 void
1861 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1862 {
1863         MonoInst *ins, *n, *last_ins = NULL;
1864
1865         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1866                 switch (ins->opcode) {
1867                 case OP_MUL_IMM: 
1868                         /* remove unnecessary multiplication with 1 */
1869                         if (ins->inst_imm == 1) {
1870                                 if (ins->dreg != ins->sreg1) {
1871                                         ins->opcode = OP_MOVE;
1872                                 } else {
1873                                         MONO_DELETE_INS (bb, ins);
1874                                         continue;
1875                                 }
1876                         } else {
1877                                 int power2 = mono_is_power_of_two (ins->inst_imm);
1878                                 if (power2 > 0) {
1879                                         ins->opcode = OP_SHL_IMM;
1880                                         ins->inst_imm = power2;
1881                                 }
1882                         }
1883                         break;
1884                 case OP_LOAD_MEMBASE:
1885                 case OP_LOADI4_MEMBASE:
1886                         /* 
1887                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1888                          * OP_LOAD_MEMBASE offset(basereg), reg
1889                          */
1890                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1891                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1892                             ins->inst_basereg == last_ins->inst_destbasereg &&
1893                             ins->inst_offset == last_ins->inst_offset) {
1894                                 if (ins->dreg == last_ins->sreg1) {
1895                                         MONO_DELETE_INS (bb, ins);
1896                                         continue;
1897                                 } else {
1898                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1899                                         ins->opcode = OP_MOVE;
1900                                         ins->sreg1 = last_ins->sreg1;
1901                                 }
1902
1903                         /* 
1904                          * Note: reg1 must be different from the basereg in the second load
1905                          * OP_LOAD_MEMBASE offset(basereg), reg1
1906                          * OP_LOAD_MEMBASE offset(basereg), reg2
1907                          * -->
1908                          * OP_LOAD_MEMBASE offset(basereg), reg1
1909                          * OP_MOVE reg1, reg2
1910                          */
1911                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1912                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1913                               ins->inst_basereg != last_ins->dreg &&
1914                               ins->inst_basereg == last_ins->inst_basereg &&
1915                               ins->inst_offset == last_ins->inst_offset) {
1916
1917                                 if (ins->dreg == last_ins->dreg) {
1918                                         MONO_DELETE_INS (bb, ins);
1919                                         continue;
1920                                 } else {
1921                                         ins->opcode = OP_MOVE;
1922                                         ins->sreg1 = last_ins->dreg;
1923                                 }
1924
1925                                 //g_assert_not_reached ();
1926
1927 #if 0
1928                         /* 
1929                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1930                          * OP_LOAD_MEMBASE offset(basereg), reg
1931                          * -->
1932                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1933                          * OP_ICONST reg, imm
1934                          */
1935                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1936                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1937                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1938                                    ins->inst_offset == last_ins->inst_offset) {
1939                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1940                                 ins->opcode = OP_ICONST;
1941                                 ins->inst_c0 = last_ins->inst_imm;
1942                                 g_assert_not_reached (); // check this rule
1943 #endif
1944                         }
1945                         break;
1946                 case OP_LOADU1_MEMBASE:
1947                 case OP_LOADI1_MEMBASE:
1948                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1949                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1950                                         ins->inst_offset == last_ins->inst_offset) {
1951                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1952                                 ins->sreg1 = last_ins->sreg1;                           
1953                         }
1954                         break;
1955                 case OP_LOADU2_MEMBASE:
1956                 case OP_LOADI2_MEMBASE:
1957                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1958                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1959                                         ins->inst_offset == last_ins->inst_offset) {
1960                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1961                                 ins->sreg1 = last_ins->sreg1;                           
1962                         }
1963                         break;
1964                 case OP_MOVE:
1965                         ins->opcode = OP_MOVE;
1966                         /* 
1967                          * OP_MOVE reg, reg 
1968                          */
1969                         if (ins->dreg == ins->sreg1) {
1970                                 MONO_DELETE_INS (bb, ins);
1971                                 continue;
1972                         }
1973                         /* 
1974                          * OP_MOVE sreg, dreg 
1975                          * OP_MOVE dreg, sreg
1976                          */
1977                         if (last_ins && last_ins->opcode == OP_MOVE &&
1978                             ins->sreg1 == last_ins->dreg &&
1979                             ins->dreg == last_ins->sreg1) {
1980                                 MONO_DELETE_INS (bb, ins);
1981                                 continue;
1982                         }
1983                         break;
1984                 }
1985                 last_ins = ins;
1986                 ins = ins->next;
1987         }
1988         bb->last_ins = last_ins;
1989 }
1990
1991 void
1992 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1993 {
1994         g_assert (cfg->new_ir);
1995
1996         switch (ins->opcode) {
1997         case OP_ICONV_TO_R_UN: {
1998                 static const guint64 adjust_val = 0x4330000000000000ULL;
1999                 int msw_reg = mono_alloc_ireg (cfg);
2000                 int adj_reg = mono_alloc_freg (cfg);
2001                 int tmp_reg = mono_alloc_freg (cfg);
2002                 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2003                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2004                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
2005                 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2006                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2007                 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2008                 ins->opcode = OP_NOP;
2009                 break;
2010         }
2011         case OP_ICONV_TO_R4:
2012         case OP_ICONV_TO_R8: {
2013                 /* FIXME: change precision for CEE_CONV_R4 */
2014                 static const guint64 adjust_val = 0x4330000080000000ULL;
2015                 int msw_reg = mono_alloc_ireg (cfg);
2016                 int xored = mono_alloc_ireg (cfg);
2017                 int adj_reg = mono_alloc_freg (cfg);
2018                 int tmp_reg = mono_alloc_freg (cfg);
2019                 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2020                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2021                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2022                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
2023                 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2024                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2025                 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2026                 if (ins->opcode == OP_ICONV_TO_R4)
2027                         MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2028                 ins->opcode = OP_NOP;
2029                 break;
2030         }
2031         case OP_CKFINITE: {
2032                 int msw_reg = mono_alloc_ireg (cfg);
2033                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
2034                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
2035                 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2036                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2037                 ins->opcode = OP_NOP;
2038                 break;
2039         }
2040         }
2041 }
2042
2043 /* 
2044  * the branch_b0_table should maintain the order of these
2045  * opcodes.
2046 case CEE_BEQ:
2047 case CEE_BGE:
2048 case CEE_BGT:
2049 case CEE_BLE:
2050 case CEE_BLT:
2051 case CEE_BNE_UN:
2052 case CEE_BGE_UN:
2053 case CEE_BGT_UN:
2054 case CEE_BLE_UN:
2055 case CEE_BLT_UN:
2056  */
2057 static const guchar 
2058 branch_b0_table [] = {
2059         PPC_BR_TRUE, 
2060         PPC_BR_FALSE, 
2061         PPC_BR_TRUE, 
2062         PPC_BR_FALSE, 
2063         PPC_BR_TRUE, 
2064         
2065         PPC_BR_FALSE, 
2066         PPC_BR_FALSE, 
2067         PPC_BR_TRUE, 
2068         PPC_BR_FALSE,
2069         PPC_BR_TRUE
2070 };
2071
2072 static const guchar 
2073 branch_b1_table [] = {
2074         PPC_BR_EQ, 
2075         PPC_BR_LT, 
2076         PPC_BR_GT, 
2077         PPC_BR_GT,
2078         PPC_BR_LT, 
2079         
2080         PPC_BR_EQ, 
2081         PPC_BR_LT, 
2082         PPC_BR_GT, 
2083         PPC_BR_GT,
2084         PPC_BR_LT 
2085 };
2086
2087 #define NEW_INS(cfg,dest,op) do {                                       \
2088                 MONO_INST_NEW((cfg), (dest), (op));                     \
2089                 mono_bblock_insert_after_ins (bb, last_ins, (dest));    \
2090         } while (0)
2091
2092 static int
2093 map_to_reg_reg_op (int op)
2094 {
2095         switch (op) {
2096         case OP_ADD_IMM:
2097                 return OP_IADD;
2098         case OP_SUB_IMM:
2099                 return OP_ISUB;
2100         case OP_AND_IMM:
2101                 return OP_IAND;
2102         case OP_COMPARE_IMM:
2103                 return OP_COMPARE;
2104         case OP_ICOMPARE_IMM:
2105                 return OP_ICOMPARE;
2106         case OP_ADDCC_IMM:
2107                 return OP_IADDCC;
2108         case OP_ADC_IMM:
2109                 return OP_IADC;
2110         case OP_SUBCC_IMM:
2111                 return OP_ISUBCC;
2112         case OP_SBB_IMM:
2113                 return OP_ISBB;
2114         case OP_OR_IMM:
2115                 return OP_IOR;
2116         case OP_XOR_IMM:
2117                 return OP_IXOR;
2118         case OP_MUL_IMM:
2119                 return OP_IMUL;
2120         case OP_LOAD_MEMBASE:
2121                 return OP_LOAD_MEMINDEX;
2122         case OP_LOADI4_MEMBASE:
2123                 return OP_LOADI4_MEMINDEX;
2124         case OP_LOADU4_MEMBASE:
2125                 return OP_LOADU4_MEMINDEX;
2126         case OP_LOADU1_MEMBASE:
2127                 return OP_LOADU1_MEMINDEX;
2128         case OP_LOADI2_MEMBASE:
2129                 return OP_LOADI2_MEMINDEX;
2130         case OP_LOADU2_MEMBASE:
2131                 return OP_LOADU2_MEMINDEX;
2132         case OP_LOADI1_MEMBASE:
2133                 return OP_LOADI1_MEMINDEX;
2134         case OP_LOADR4_MEMBASE:
2135                 return OP_LOADR4_MEMINDEX;
2136         case OP_LOADR8_MEMBASE:
2137                 return OP_LOADR8_MEMINDEX;
2138         case OP_STOREI1_MEMBASE_REG:
2139                 return OP_STOREI1_MEMINDEX;
2140         case OP_STOREI2_MEMBASE_REG:
2141                 return OP_STOREI2_MEMINDEX;
2142         case OP_STOREI4_MEMBASE_REG:
2143                 return OP_STOREI4_MEMINDEX;
2144         case OP_STORE_MEMBASE_REG:
2145                 return OP_STORE_MEMINDEX;
2146         case OP_STORER4_MEMBASE_REG:
2147                 return OP_STORER4_MEMINDEX;
2148         case OP_STORER8_MEMBASE_REG:
2149                 return OP_STORER8_MEMINDEX;
2150         case OP_STORE_MEMBASE_IMM:
2151                 return OP_STORE_MEMBASE_REG;
2152         case OP_STOREI1_MEMBASE_IMM:
2153                 return OP_STOREI1_MEMBASE_REG;
2154         case OP_STOREI2_MEMBASE_IMM:
2155                 return OP_STOREI2_MEMBASE_REG;
2156         case OP_STOREI4_MEMBASE_IMM:
2157                 return OP_STOREI4_MEMBASE_REG;
2158         }
2159         return mono_op_imm_to_op (op);
2160 }
2161
2162 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2163
2164 #define compare_opcode_is_unsigned(opcode) \
2165                 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) ||  \
2166                 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) ||  \
2167                 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) ||     \
2168                 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) ||   \
2169                 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2170 /*
2171  * Remove from the instruction list the instructions that can't be
2172  * represented with very simple instructions with no register
2173  * requirements.
2174  */
2175 void
2176 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2177 {
2178         MonoInst *ins, *next, *temp, *last_ins = NULL;
2179         int imm;
2180
2181         /* setup the virtual reg allocator */
2182         if (bb->max_vreg > cfg->rs->next_vreg)
2183                 cfg->rs->next_vreg = bb->max_vreg;
2184
2185         MONO_BB_FOR_EACH_INS (bb, ins) {
2186 loop_start:
2187                 switch (ins->opcode) {
2188                 case OP_IDIV_UN_IMM:
2189                 case OP_IDIV_IMM:
2190                 case OP_IREM_IMM:
2191                 case OP_IREM_UN_IMM:
2192                         NEW_INS (cfg, temp, OP_ICONST);
2193                         temp->inst_c0 = ins->inst_imm;
2194                         temp->dreg = mono_regstate_next_int (cfg->rs);
2195                         ins->sreg2 = temp->dreg;
2196                         if (ins->opcode == OP_IDIV_IMM)
2197                                 ins->opcode = OP_IDIV;
2198                         else if (ins->opcode == OP_IREM_IMM)
2199                                 ins->opcode = OP_IREM;
2200                         else if (ins->opcode == OP_IDIV_UN_IMM)
2201                                 ins->opcode = OP_IDIV_UN;
2202                         else if (ins->opcode == OP_IREM_UN_IMM)
2203                                 ins->opcode = OP_IREM_UN;
2204                         last_ins = temp;
2205                         /* handle rem separately */
2206                         goto loop_start;
2207                 case OP_IREM:
2208                 case OP_IREM_UN: {
2209                         MonoInst *mul;
2210                         /* we change a rem dest, src1, src2 to
2211                          * div temp1, src1, src2
2212                          * mul temp2, temp1, src2
2213                          * sub dest, src1, temp2
2214                          */
2215                         NEW_INS (cfg, mul, OP_IMUL);
2216                         NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2217                         temp->sreg1 = ins->sreg1;
2218                         temp->sreg2 = ins->sreg2;
2219                         temp->dreg = mono_regstate_next_int (cfg->rs);
2220                         mul->sreg1 = temp->dreg;
2221                         mul->sreg2 = ins->sreg2;
2222                         mul->dreg = mono_regstate_next_int (cfg->rs);
2223                         ins->opcode = OP_ISUB;
2224                         ins->sreg2 = mul->dreg;
2225                         break;
2226                 }
2227                 case OP_IADD_IMM:
2228                 case OP_ADD_IMM:
2229                 case OP_ADDCC_IMM:
2230                         if (!ppc_is_imm16 (ins->inst_imm)) {
2231                                 NEW_INS (cfg,  temp, OP_ICONST);
2232                                 temp->inst_c0 = ins->inst_imm;
2233                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2234                                 ins->sreg2 = temp->dreg;
2235                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2236                         }
2237                         break;
2238                 case OP_ISUB_IMM:
2239                 case OP_SUB_IMM:
2240                         if (!ppc_is_imm16 (-ins->inst_imm)) {
2241                                 NEW_INS (cfg, temp, OP_ICONST);
2242                                 temp->inst_c0 = ins->inst_imm;
2243                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2244                                 ins->sreg2 = temp->dreg;
2245                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2246                         }
2247                         break;
2248                 case OP_IAND_IMM:
2249                 case OP_IOR_IMM:
2250                 case OP_IXOR_IMM:
2251                 case OP_AND_IMM:
2252                 case OP_OR_IMM:
2253                 case OP_XOR_IMM:
2254                         if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2255                                 NEW_INS (cfg, temp, OP_ICONST);
2256                                 temp->inst_c0 = ins->inst_imm;
2257                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2258                                 ins->sreg2 = temp->dreg;
2259                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2260                         }
2261                         break;
2262                 case OP_ISBB_IMM:
2263                 case OP_IADC_IMM:
2264                 case OP_SBB_IMM:
2265                 case OP_SUBCC_IMM:
2266                 case OP_ADC_IMM:
2267                         NEW_INS (cfg, temp, OP_ICONST);
2268                         temp->inst_c0 = ins->inst_imm;
2269                         temp->dreg = mono_regstate_next_int (cfg->rs);
2270                         ins->sreg2 = temp->dreg;
2271                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2272                         break;
2273                 case OP_COMPARE_IMM:
2274                 case OP_ICOMPARE_IMM:
2275                         next = ins->next;
2276                         /* Branch opts can eliminate the branch */
2277                         if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2278                                 ins->opcode = OP_NOP;
2279                                 break;
2280                         }
2281                         g_assert(next);
2282                         if (compare_opcode_is_unsigned (next->opcode)) {
2283                                 if (!ppc_is_uimm16 (ins->inst_imm)) {
2284                                         NEW_INS (cfg, temp, OP_ICONST);
2285                                         temp->inst_c0 = ins->inst_imm;
2286                                         temp->dreg = mono_regstate_next_int (cfg->rs);
2287                                         ins->sreg2 = temp->dreg;
2288                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2289                                 }
2290                         } else {
2291                                 if (!ppc_is_imm16 (ins->inst_imm)) {
2292                                         NEW_INS (cfg, temp, OP_ICONST);
2293                                         temp->inst_c0 = ins->inst_imm;
2294                                         temp->dreg = mono_regstate_next_int (cfg->rs);
2295                                         ins->sreg2 = temp->dreg;
2296                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2297                                 }
2298                         }
2299                         break;
2300                 case OP_IMUL_IMM:
2301                 case OP_MUL_IMM:
2302                         if (ins->inst_imm == 1) {
2303                                 ins->opcode = OP_MOVE;
2304                                 break;
2305                         }
2306                         if (ins->inst_imm == 0) {
2307                                 ins->opcode = OP_ICONST;
2308                                 ins->inst_c0 = 0;
2309                                 break;
2310                         }
2311                         imm = mono_is_power_of_two (ins->inst_imm);
2312                         if (imm > 0) {
2313                                 ins->opcode = OP_SHL_IMM;
2314                                 ins->inst_imm = imm;
2315                                 break;
2316                         }
2317                         if (!ppc_is_imm16 (ins->inst_imm)) {
2318                                 NEW_INS (cfg, temp, OP_ICONST);
2319                                 temp->inst_c0 = ins->inst_imm;
2320                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2321                                 ins->sreg2 = temp->dreg;
2322                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2323                         }
2324                         break;
2325                 case OP_LOCALLOC_IMM:
2326                         NEW_INS (cfg, temp, OP_ICONST);
2327                         temp->inst_c0 = ins->inst_imm;
2328                         temp->dreg = mono_regstate_next_int (cfg->rs);
2329                         ins->sreg1 = temp->dreg;
2330                         ins->opcode = OP_LOCALLOC;
2331                         break;
2332                 case OP_LOAD_MEMBASE:
2333                 case OP_LOADI4_MEMBASE:
2334                 case OP_LOADU4_MEMBASE:
2335                 case OP_LOADI2_MEMBASE:
2336                 case OP_LOADU2_MEMBASE:
2337                 case OP_LOADI1_MEMBASE:
2338                 case OP_LOADU1_MEMBASE:
2339                 case OP_LOADR4_MEMBASE:
2340                 case OP_LOADR8_MEMBASE:
2341                 case OP_STORE_MEMBASE_REG:
2342                 case OP_STOREI4_MEMBASE_REG:
2343                 case OP_STOREI2_MEMBASE_REG:
2344                 case OP_STOREI1_MEMBASE_REG:
2345                 case OP_STORER4_MEMBASE_REG:
2346                 case OP_STORER8_MEMBASE_REG:
2347                         /* we can do two things: load the immed in a register
2348                          * and use an indexed load, or see if the immed can be
2349                          * represented as an ad_imm + a load with a smaller offset
2350                          * that fits. We just do the first for now, optimize later.
2351                          */
2352                         if (ppc_is_imm16 (ins->inst_offset))
2353                                 break;
2354                         NEW_INS (cfg, temp, OP_ICONST);
2355                         temp->inst_c0 = ins->inst_offset;
2356                         temp->dreg = mono_regstate_next_int (cfg->rs);
2357                         ins->sreg2 = temp->dreg;
2358                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2359                         break;
2360                 case OP_STORE_MEMBASE_IMM:
2361                 case OP_STOREI1_MEMBASE_IMM:
2362                 case OP_STOREI2_MEMBASE_IMM:
2363                 case OP_STOREI4_MEMBASE_IMM:
2364                         NEW_INS (cfg, temp, OP_ICONST);
2365                         temp->inst_c0 = ins->inst_imm;
2366                         temp->dreg = mono_regstate_next_int (cfg->rs);
2367                         ins->sreg1 = temp->dreg;
2368                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2369                         last_ins = temp;
2370                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
2371                 case OP_R8CONST:
2372                 case OP_R4CONST:
2373                         NEW_INS (cfg, temp, OP_ICONST);
2374                         temp->inst_c0 = (guint32)ins->inst_p0;
2375                         temp->dreg = mono_regstate_next_int (cfg->rs);
2376                         ins->inst_basereg = temp->dreg;
2377                         ins->inst_offset = 0;
2378                         ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2379                         last_ins = temp;
2380                         /* make it handle the possibly big ins->inst_offset
2381                          * later optimize to use lis + load_membase
2382                          */
2383                         goto loop_start;
2384                 }
2385                 last_ins = ins;
2386         }
2387         bb->last_ins = last_ins;
2388         bb->max_vreg = cfg->rs->next_vreg;
2389         
2390 }
2391
2392 static guchar*
2393 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2394 {
2395         /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2396         ppc_fctiwz (code, ppc_f0, sreg);
2397         ppc_stfd (code, ppc_f0, -8, ppc_sp);
2398         ppc_lwz (code, dreg, -4, ppc_sp);
2399         if (!is_signed) {
2400                 if (size == 1)
2401                         ppc_andid (code, dreg, dreg, 0xff);
2402                 else if (size == 2)
2403                         ppc_andid (code, dreg, dreg, 0xffff);
2404         } else {
2405                 if (size == 1)
2406                         ppc_extsb (code, dreg, dreg);
2407                 else if (size == 2)
2408                         ppc_extsh (code, dreg, dreg);
2409         }
2410         return code;
2411 }
2412
2413 typedef struct {
2414         guchar *code;
2415         const guchar *target;
2416         int absolute;
2417         int found;
2418 } PatchData;
2419
2420 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2421
2422 static int
2423 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2424         PatchData *pdata = (PatchData*)user_data;
2425         guchar *code = data;
2426         guint32 *thunks = data;
2427         guint32 *endthunks = (guint32*)(code + bsize);
2428         guint32 load [2];
2429         guchar *templ;
2430         int count = 0;
2431         int difflow, diffhigh;
2432
2433         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2434         difflow = (char*)pdata->code - (char*)thunks;
2435         diffhigh = (char*)pdata->code - (char*)endthunks;
2436         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2437                 return 0;
2438
2439         templ = (guchar*)load;
2440         ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2441         ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2442
2443         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2444         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2445                 while (thunks < endthunks) {
2446                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2447                         if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2448                                 ppc_patch (pdata->code, (guchar*)thunks);
2449                                 mono_arch_flush_icache (pdata->code, 4);
2450                                 pdata->found = 1;
2451                                 /*{
2452                                         static int num_thunks = 0;
2453                                         num_thunks++;
2454                                         if ((num_thunks % 20) == 0)
2455                                                 g_print ("num_thunks lookup: %d\n", num_thunks);
2456                                 }*/
2457                                 return 1;
2458                         } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2459                                 /* found a free slot instead: emit thunk */
2460                                 code = (guchar*)thunks;
2461                                 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2462                                 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2463                                 ppc_mtctr (code, ppc_r0);
2464                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2465                                 mono_arch_flush_icache ((guchar*)thunks, 16);
2466
2467                                 ppc_patch (pdata->code, (guchar*)thunks);
2468                                 mono_arch_flush_icache (pdata->code, 4);
2469                                 pdata->found = 1;
2470                                 /*{
2471                                         static int num_thunks = 0;
2472                                         num_thunks++;
2473                                         if ((num_thunks % 20) == 0)
2474                                                 g_print ("num_thunks: %d\n", num_thunks);
2475                                 }*/
2476                                 return 1;
2477                         }
2478                         /* skip 16 bytes, the size of the thunk */
2479                         thunks += 4;
2480                         count++;
2481                 }
2482                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2483         }
2484         return 0;
2485 }
2486
2487 static void
2488 handle_thunk (int absolute, guchar *code, const guchar *target) {
2489         MonoDomain *domain = mono_domain_get ();
2490         PatchData pdata;
2491
2492         pdata.code = code;
2493         pdata.target = target;
2494         pdata.absolute = absolute;
2495         pdata.found = 0;
2496
2497         mono_domain_lock (domain);
2498         mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2499
2500         if (!pdata.found) {
2501                 /* this uses the first available slot */
2502                 pdata.found = 2;
2503                 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2504         }
2505         mono_domain_unlock (domain);
2506
2507         if (pdata.found != 1)
2508                 g_print ("thunk failed for %p from %p\n", target, code);
2509         g_assert (pdata.found == 1);
2510 }
2511
2512 void
2513 ppc_patch (guchar *code, const guchar *target)
2514 {
2515         guint32 ins = *(guint32*)code;
2516         guint32 prim = ins >> 26;
2517         guint32 ovf;
2518
2519         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2520         if (prim == 18) {
2521                 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2522                 gint diff = target - code;
2523                 if (diff >= 0){
2524                         if (diff <= 33554431){
2525                                 ins = (18 << 26) | (diff) | (ins & 1);
2526                                 *(guint32*)code = ins;
2527                                 return;
2528                         }
2529                 } else {
2530                         /* diff between 0 and -33554432 */
2531                         if (diff >= -33554432){
2532                                 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2533                                 *(guint32*)code = ins;
2534                                 return;
2535                         }
2536                 }
2537                 
2538                 if ((glong)target >= 0){
2539                         if ((glong)target <= 33554431){
2540                                 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2541                                 *(guint32*)code = ins;
2542                                 return;
2543                         }
2544                 } else {
2545                         if ((glong)target >= -33554432){
2546                                 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2547                                 *(guint32*)code = ins;
2548                                 return;
2549                         }
2550                 }
2551
2552                 handle_thunk (TRUE, code, target);
2553                 return;
2554
2555                 g_assert_not_reached ();
2556         }
2557         
2558         
2559         if (prim == 16) {
2560                 // absolute address
2561                 if (ins & 2) {
2562                         guint32 li = (guint32)target;
2563                         ins = (ins & 0xffff0000) | (ins & 3);
2564                         ovf  = li & 0xffff0000;
2565                         if (ovf != 0 && ovf != 0xffff0000)
2566                                 g_assert_not_reached ();
2567                         li &= 0xffff;
2568                         ins |= li;
2569                         // FIXME: assert the top bits of li are 0
2570                 } else {
2571                         gint diff = target - code;
2572                         ins = (ins & 0xffff0000) | (ins & 3);
2573                         ovf  = diff & 0xffff0000;
2574                         if (ovf != 0 && ovf != 0xffff0000)
2575                                 g_assert_not_reached ();
2576                         diff &= 0xffff;
2577                         ins |= diff;
2578                 }
2579                 *(guint32*)code = ins;
2580                 return;
2581         }
2582
2583         if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2584                 guint32 *seq;
2585                 /* the trampoline code will try to patch the blrl, blr, bcctr */
2586                 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2587                         code -= 12;
2588                 }
2589                 /* this is the lis/ori/mtlr/blrl sequence */
2590                 seq = (guint32*)code;
2591                 g_assert ((seq [0] >> 26) == 15);
2592                 g_assert ((seq [1] >> 26) == 24);
2593                 g_assert ((seq [2] >> 26) == 31);
2594                 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2595                 /* FIXME: make this thread safe */
2596                 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2597                 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2598                 mono_arch_flush_icache (code - 8, 8);
2599         } else {
2600                 g_assert_not_reached ();
2601         }
2602 //      g_print ("patched with 0x%08x\n", ins);
2603 }
2604
2605 static guint8*
2606 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2607 {
2608         switch (ins->opcode) {
2609         case OP_FCALL:
2610         case OP_FCALL_REG:
2611         case OP_FCALL_MEMBASE:
2612                 if (ins->dreg != ppc_f1)
2613                         ppc_fmr (code, ins->dreg, ppc_f1);
2614                 break;
2615         }
2616
2617         return code;
2618 }
2619
2620 /*
2621  * emit_load_volatile_arguments:
2622  *
2623  *  Load volatile arguments from the stack to the original input registers.
2624  * Required before a tail call.
2625  */
2626 static guint8*
2627 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2628 {
2629         MonoMethod *method = cfg->method;
2630         MonoMethodSignature *sig;
2631         MonoInst *inst;
2632         CallInfo *cinfo;
2633         guint32 i, pos;
2634         int struct_index = 0;
2635
2636         /* FIXME: Generate intermediate code instead */
2637
2638         sig = mono_method_signature (method);
2639
2640         /* This is the opposite of the code in emit_prolog */
2641
2642         pos = 0;
2643
2644         cinfo = calculate_sizes (sig, sig->pinvoke);
2645
2646         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2647                 ArgInfo *ainfo = &cinfo->ret;
2648                 inst = cfg->vret_addr;
2649                 g_assert (ppc_is_imm16 (inst->inst_offset));
2650                 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2651         }
2652         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2653                 ArgInfo *ainfo = cinfo->args + i;
2654                 inst = cfg->args [pos];
2655
2656                 g_assert (inst->opcode != OP_REGVAR);
2657                 g_assert (ppc_is_imm16 (inst->inst_offset));
2658
2659                 switch (ainfo->regtype) {
2660                 case RegTypeGeneral:
2661                         switch (ainfo->size) {
2662                                 case 1:
2663                                         ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2664                                         break;
2665                                 case 2:
2666                                         ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2667                                         break;
2668                                 default:
2669                                         ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2670                                         break;
2671                         }
2672                         break;
2673
2674                 case RegTypeFP:
2675                         switch (ainfo->size) {
2676                                 case 4:
2677                                         ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2678                                         break;
2679                                 case 8:
2680                                         ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2681                                         break;
2682                                 default:
2683                                         g_assert_not_reached ();
2684                         }
2685                         break;
2686
2687                 case RegTypeBase: {
2688                         MonoType *type = mini_type_get_underlying_type (cfg->generic_sharing_context,
2689                                 &inst->klass->byval_arg);
2690
2691                         if (!MONO_TYPE_IS_REFERENCE (type) && type->type != MONO_TYPE_I4)
2692                                 NOT_IMPLEMENTED;
2693
2694                         ppc_lwz (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
2695                         ppc_stw (code, ppc_r0, ainfo->offset, ainfo->reg);
2696                         break;
2697                 }
2698
2699                 case RegTypeStructByVal: {
2700                         guint32 size = 0;
2701                         int j;
2702
2703                         /* FIXME: */
2704                         if (ainfo->vtsize)
2705                                 NOT_IMPLEMENTED;
2706 #ifdef __APPLE__
2707                         /*
2708                          * Darwin pinvokes needs some special handling
2709                          * for 1 and 2 byte arguments
2710                          */
2711                         if (method->signature->pinvoke)
2712                                 size = mono_class_native_size (inst->klass, NULL);
2713                         if (size == 1 || size == 2) {
2714                                 /* FIXME: */
2715                                 NOT_IMPLEMENTED;
2716                         } else
2717 #endif
2718                                 for (j = 0; j < ainfo->size; ++j) {
2719                                         ppc_lwz (code, ainfo->reg  + j,
2720                                                 inst->inst_offset + j * sizeof (gpointer), inst->inst_basereg);
2721                                 }
2722                         break;
2723                 }
2724
2725                 case RegTypeStructByAddr: {
2726                         MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2727
2728                         g_assert (ppc_is_imm16 (addr->inst_offset));
2729                         g_assert (!ainfo->offset);
2730                         ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2731
2732                         struct_index++;
2733                         break;
2734                 }
2735
2736                 default:
2737                         g_assert_not_reached ();
2738                 }
2739
2740                 pos ++;
2741         }
2742
2743         g_free (cinfo);
2744
2745         return code;
2746 }
2747
2748 /* This must be kept in sync with emit_load_volatile_arguments(). */
2749 static int
2750 ins_native_length (MonoCompile *cfg, MonoInst *ins)
2751 {
2752         int len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2753         MonoMethodSignature *sig;
2754         MonoCallInst *call;
2755         CallInfo *cinfo;
2756         int i;
2757
2758         if (ins->opcode != OP_JMP)
2759                 return len;
2760
2761         call = (MonoCallInst*)ins;
2762         sig = mono_method_signature (cfg->method);
2763         cinfo = calculate_sizes (sig, sig->pinvoke);
2764
2765         if (MONO_TYPE_ISSTRUCT (sig->ret))
2766                 len += 4;
2767         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2768                 ArgInfo *ainfo = cinfo->args + i;
2769
2770                 switch (ainfo->regtype) {
2771                 case RegTypeGeneral:
2772                 case RegTypeFP:
2773                         len += 4;
2774                         break;
2775
2776                 case RegTypeBase:
2777                         len += 8;
2778                         break;
2779
2780                 case RegTypeStructByVal:
2781                         len += 4 * ainfo->size;
2782                         break;
2783
2784                 case RegTypeStructByAddr:
2785                         len += 4;
2786                         break;
2787
2788                 default:
2789                         g_assert_not_reached ();
2790                 }
2791         }
2792
2793         g_free (cinfo);
2794
2795         return len;
2796 }
2797
2798 void
2799 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2800 {
2801         MonoInst *ins, *next;
2802         MonoCallInst *call;
2803         guint offset;
2804         guint8 *code = cfg->native_code + cfg->code_len;
2805         MonoInst *last_ins = NULL;
2806         guint last_offset = 0;
2807         int max_len, cpos;
2808
2809         /* we don't align basic blocks of loops on ppc */
2810
2811         if (cfg->verbose_level > 2)
2812                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2813
2814         cpos = bb->max_offset;
2815
2816         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2817                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2818                 //g_assert (!mono_compile_aot);
2819                 //cpos += 6;
2820                 //if (bb->cil_code)
2821                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2822                 /* this is not thread save, but good enough */
2823                 /* fixme: howto handle overflows? */
2824                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
2825         }
2826
2827         MONO_BB_FOR_EACH_INS (bb, ins) {
2828                 offset = code - cfg->native_code;
2829
2830                 max_len = ins_native_length (cfg, ins);
2831
2832                 if (offset > (cfg->code_size - max_len - 16)) {
2833                         cfg->code_size *= 2;
2834                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2835                         code = cfg->native_code + offset;
2836                 }
2837         //      if (ins->cil_code)
2838         //              g_print ("cil code\n");
2839                 mono_debug_record_line_number (cfg, ins, offset);
2840
2841                 switch (ins->opcode) {
2842                 case OP_RELAXED_NOP:
2843                 case OP_NOP:
2844                 case OP_DUMMY_USE:
2845                 case OP_DUMMY_STORE:
2846                 case OP_NOT_REACHED:
2847                 case OP_NOT_NULL:
2848                         break;
2849                 case OP_TLS_GET:
2850                         emit_tls_access (code, ins->dreg, ins->inst_offset);
2851                         break;
2852                 case OP_BIGMUL:
2853                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2854                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2855                         ppc_mr (code, ppc_r4, ppc_r0);
2856                         break;
2857                 case OP_BIGMUL_UN:
2858                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2859                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2860                         ppc_mr (code, ppc_r4, ppc_r0);
2861                         break;
2862                 case OP_MEMORY_BARRIER:
2863                         ppc_sync (code);
2864                         break;
2865                 case OP_STOREI1_MEMBASE_REG:
2866                         if (ppc_is_imm16 (ins->inst_offset)) {
2867                                 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2868                         } else {
2869                                 ppc_load (code, ppc_r0, ins->inst_offset);
2870                                 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2871                         }
2872                         break;
2873                 case OP_STOREI2_MEMBASE_REG:
2874                         if (ppc_is_imm16 (ins->inst_offset)) {
2875                                 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2876                         } else {
2877                                 ppc_load (code, ppc_r0, ins->inst_offset);
2878                                 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2879                         }
2880                         break;
2881                 case OP_STORE_MEMBASE_REG:
2882                 case OP_STOREI4_MEMBASE_REG:
2883                         if (ppc_is_imm16 (ins->inst_offset)) {
2884                                 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2885                         } else {
2886                                 ppc_load (code, ppc_r0, ins->inst_offset);
2887                                 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2888                         }
2889                         break;
2890                 case OP_STOREI1_MEMINDEX:
2891                         ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2892                         break;
2893                 case OP_STOREI2_MEMINDEX:
2894                         ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2895                         break;
2896                 case OP_STORE_MEMINDEX:
2897                 case OP_STOREI4_MEMINDEX:
2898                         ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2899                         break;
2900                 case OP_LOADU4_MEM:
2901                         g_assert_not_reached ();
2902                         break;
2903                 case OP_LOAD_MEMBASE:
2904                 case OP_LOADI4_MEMBASE:
2905                 case OP_LOADU4_MEMBASE:
2906                         if (ppc_is_imm16 (ins->inst_offset)) {
2907                                 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2908                         } else {
2909                                 ppc_load (code, ppc_r0, ins->inst_offset);
2910                                 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2911                         }
2912                         break;
2913                 case OP_LOADI1_MEMBASE:
2914                 case OP_LOADU1_MEMBASE:
2915                         if (ppc_is_imm16 (ins->inst_offset)) {
2916                                 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2917                         } else {
2918                                 ppc_load (code, ppc_r0, ins->inst_offset);
2919                                 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2920                         }
2921                         if (ins->opcode == OP_LOADI1_MEMBASE)
2922                                 ppc_extsb (code, ins->dreg, ins->dreg);
2923                         break;
2924                 case OP_LOADU2_MEMBASE:
2925                         if (ppc_is_imm16 (ins->inst_offset)) {
2926                                 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2927                         } else {
2928                                 ppc_load (code, ppc_r0, ins->inst_offset);
2929                                 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2930                         }
2931                         break;
2932                 case OP_LOADI2_MEMBASE:
2933                         if (ppc_is_imm16 (ins->inst_offset)) {
2934                                 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2935                         } else {
2936                                 ppc_load (code, ppc_r0, ins->inst_offset);
2937                                 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2938                         }
2939                         break;
2940                 case OP_LOAD_MEMINDEX:
2941                 case OP_LOADI4_MEMINDEX:
2942                 case OP_LOADU4_MEMINDEX:
2943                         ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2944                         break;
2945                 case OP_LOADU2_MEMINDEX:
2946                         ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2947                         break;
2948                 case OP_LOADI2_MEMINDEX:
2949                         ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2950                         break;
2951                 case OP_LOADU1_MEMINDEX:
2952                         ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2953                         break;
2954                 case OP_LOADI1_MEMINDEX:
2955                         ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2956                         ppc_extsb (code, ins->dreg, ins->dreg);
2957                         break;
2958                 case OP_ICONV_TO_I1:
2959                         ppc_extsb (code, ins->dreg, ins->sreg1);
2960                         break;
2961                 case OP_ICONV_TO_I2:
2962                         ppc_extsh (code, ins->dreg, ins->sreg1);
2963                         break;
2964                 case OP_ICONV_TO_U1:
2965                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2966                         break;
2967                 case OP_ICONV_TO_U2:
2968                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2969                         break;
2970                 case OP_COMPARE:
2971                 case OP_ICOMPARE:
2972                         next = ins->next;
2973                         if (next && compare_opcode_is_unsigned (next->opcode))
2974                                 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2975                         else
2976                                 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2977                         break;
2978                 case OP_COMPARE_IMM:
2979                 case OP_ICOMPARE_IMM:
2980                         next = ins->next;
2981                         if (next && compare_opcode_is_unsigned (next->opcode)) {
2982                                 if (ppc_is_uimm16 (ins->inst_imm)) {
2983                                         ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2984                                 } else {
2985                                         g_assert_not_reached ();
2986                                 }
2987                         } else {
2988                                 if (ppc_is_imm16 (ins->inst_imm)) {
2989                                         ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2990                                 } else {
2991                                         g_assert_not_reached ();
2992                                 }
2993                         }
2994                         break;
2995                 case OP_BREAK:
2996                         ppc_break (code);
2997                         break;
2998                 case OP_ADDCC:
2999                 case OP_IADDCC:
3000                         ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
3001                         break;
3002                 case OP_IADD:
3003                         ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3004                         break;
3005                 case OP_ADC:
3006                 case OP_IADC:
3007                         ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3008                         break;
3009                 case OP_ADDCC_IMM:
3010                         if (ppc_is_imm16 (ins->inst_imm)) {
3011                                 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3012                         } else {
3013                                 g_assert_not_reached ();
3014                         }
3015                         break;
3016                 case OP_ADD_IMM:
3017                 case OP_IADD_IMM:
3018                         if (ppc_is_imm16 (ins->inst_imm)) {
3019                                 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3020                         } else {
3021                                 g_assert_not_reached ();
3022                         }
3023                         break;
3024                 case OP_IADD_OVF:
3025                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3026                          */
3027                         ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3028                         ppc_mfspr (code, ppc_r0, ppc_xer);
3029                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3030                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3031                         break;
3032                 case OP_IADD_OVF_UN:
3033                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3034                          */
3035                         ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3036                         ppc_mfspr (code, ppc_r0, ppc_xer);
3037                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3038                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3039                         break;
3040                 case OP_ISUB_OVF:
3041                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3042                          */
3043                         ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3044                         ppc_mfspr (code, ppc_r0, ppc_xer);
3045                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3046                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3047                         break;
3048                 case OP_ISUB_OVF_UN:
3049                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3050                          */
3051                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3052                         ppc_mfspr (code, ppc_r0, ppc_xer);
3053                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3054                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3055                         break;
3056                 case OP_ADD_OVF_CARRY:
3057                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3058                          */
3059                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3060                         ppc_mfspr (code, ppc_r0, ppc_xer);
3061                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3062                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3063                         break;
3064                 case OP_ADD_OVF_UN_CARRY:
3065                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3066                          */
3067                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3068                         ppc_mfspr (code, ppc_r0, ppc_xer);
3069                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3070                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3071                         break;
3072                 case OP_SUB_OVF_CARRY:
3073                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3074                          */
3075                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3076                         ppc_mfspr (code, ppc_r0, ppc_xer);
3077                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3078                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3079                         break;
3080                 case OP_SUB_OVF_UN_CARRY:
3081                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3082                          */
3083                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3084                         ppc_mfspr (code, ppc_r0, ppc_xer);
3085                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3086                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3087                         break;
3088                 case OP_SUBCC:
3089                 case OP_ISUBCC:
3090                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3091                         break;
3092                 case OP_ISUB:
3093                         ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3094                         break;
3095                 case OP_SBB:
3096                 case OP_ISBB:
3097                         ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3098                         break;
3099                 case OP_SUB_IMM:
3100                 case OP_ISUB_IMM:
3101                         // we add the negated value
3102                         if (ppc_is_imm16 (-ins->inst_imm))
3103                                 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3104                         else {
3105                                 g_assert_not_reached ();
3106                         }
3107                         break;
3108                 case OP_PPC_SUBFIC:
3109                         g_assert (ppc_is_imm16 (ins->inst_imm));
3110                         ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3111                         break;
3112                 case OP_PPC_SUBFZE:
3113                         ppc_subfze (code, ins->dreg, ins->sreg1);
3114                         break;
3115                 case OP_IAND:
3116                         /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3117                         ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3118                         break;
3119                 case OP_AND_IMM:
3120                 case OP_IAND_IMM:
3121                         if (!(ins->inst_imm & 0xffff0000)) {
3122                                 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3123                         } else if (!(ins->inst_imm & 0xffff)) {
3124                                 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3125                         } else {
3126                                 g_assert_not_reached ();
3127                         }
3128                         break;
3129                 case OP_IDIV: {
3130                         guint8 *divisor_is_m1;
3131                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3132                          */
3133                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3134                         divisor_is_m1 = code;
3135                         ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3136                         ppc_lis (code, ppc_r0, 0x8000);
3137                         ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
3138                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3139                         ppc_patch (divisor_is_m1, code);
3140                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3141                          */
3142                         ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3143                         ppc_mfspr (code, ppc_r0, ppc_xer);
3144                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3145                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3146                         break;
3147                 }
3148                 case OP_IDIV_UN:
3149                         ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3150                         ppc_mfspr (code, ppc_r0, ppc_xer);
3151                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3152                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3153                         break;
3154                 case OP_DIV_IMM:
3155                 case OP_IREM:
3156                 case OP_IREM_UN:
3157                 case OP_REM_IMM:
3158                         g_assert_not_reached ();
3159                 case OP_IOR:
3160                         ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3161                         break;
3162                 case OP_OR_IMM:
3163                 case OP_IOR_IMM:
3164                         if (!(ins->inst_imm & 0xffff0000)) {
3165                                 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3166                         } else if (!(ins->inst_imm & 0xffff)) {
3167                                 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3168                         } else {
3169                                 g_assert_not_reached ();
3170                         }
3171                         break;
3172                 case OP_IXOR:
3173                         ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3174                         break;
3175                 case OP_IXOR_IMM:
3176                 case OP_XOR_IMM:
3177                         if (!(ins->inst_imm & 0xffff0000)) {
3178                                 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3179                         } else if (!(ins->inst_imm & 0xffff)) {
3180                                 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3181                         } else {
3182                                 g_assert_not_reached ();
3183                         }
3184                         break;
3185                 case OP_ISHL:
3186                         ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3187                         break;
3188                 case OP_SHL_IMM:
3189                 case OP_ISHL_IMM:
3190                         ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3191                         break;
3192                 case OP_ISHR:
3193                         ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3194                         break;
3195                 case OP_SHR_IMM:
3196                 case OP_ISHR_IMM:
3197                         ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3198                         break;
3199                 case OP_SHR_UN_IMM:
3200                 case OP_ISHR_UN_IMM:
3201                         if (ins->inst_imm)
3202                                 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3203                         else
3204                                 ppc_mr (code, ins->dreg, ins->sreg1);
3205                         break;
3206                 case OP_ISHR_UN:
3207                         ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3208                         break;
3209                 case OP_INOT:
3210                         ppc_not (code, ins->dreg, ins->sreg1);
3211                         break;
3212                 case OP_INEG:
3213                         ppc_neg (code, ins->dreg, ins->sreg1);
3214                         break;
3215                 case OP_IMUL:
3216                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3217                         break;
3218                 case OP_IMUL_IMM:
3219                 case OP_MUL_IMM:
3220                         if (ppc_is_imm16 (ins->inst_imm)) {
3221                             ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3222                         } else {
3223                             g_assert_not_reached ();
3224                         }
3225                         break;
3226                 case OP_IMUL_OVF:
3227                         /* we annot use mcrxr, since it's not implemented on some processors 
3228                          * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3229                          */
3230                         ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3231                         ppc_mfspr (code, ppc_r0, ppc_xer);
3232                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3233                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3234                         break;
3235                 case OP_IMUL_OVF_UN:
3236                         /* we first multiply to get the high word and compare to 0
3237                          * to set the flags, then the result is discarded and then 
3238                          * we multiply to get the lower * bits result
3239                          */
3240                         ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3241                         ppc_cmpi (code, 0, 0, ppc_r0, 0);
3242                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3243                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3244                         break;
3245                 case OP_ICONST:
3246                         ppc_load (code, ins->dreg, ins->inst_c0);
3247                         break;
3248                 case OP_AOTCONST:
3249                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3250                         ppc_lis (code, ins->dreg, 0);
3251                         ppc_ori (code, ins->dreg, ins->dreg, 0);
3252                         break;
3253                 case OP_ICONV_TO_I4:
3254                 case OP_ICONV_TO_U4:
3255                 case OP_MOVE:
3256                         ppc_mr (code, ins->dreg, ins->sreg1);
3257                         break;
3258                 case OP_SETLRET: {
3259                         int saved = ins->sreg1;
3260                         if (ins->sreg1 == ppc_r3) {
3261                                 ppc_mr (code, ppc_r0, ins->sreg1);
3262                                 saved = ppc_r0;
3263                         }
3264                         if (ins->sreg2 != ppc_r3)
3265                                 ppc_mr (code, ppc_r3, ins->sreg2);
3266                         if (saved != ppc_r4)
3267                                 ppc_mr (code, ppc_r4, saved);
3268                         break;
3269                 }
3270                 case OP_FMOVE:
3271                         ppc_fmr (code, ins->dreg, ins->sreg1);
3272                         break;
3273                 case OP_FCONV_TO_R4:
3274                         ppc_frsp (code, ins->dreg, ins->sreg1);
3275                         break;
3276                 case OP_JMP: {
3277                         int i, pos = 0;
3278                         
3279                         /*
3280                          * Keep in sync with mono_arch_emit_epilog
3281                          */
3282                         g_assert (!cfg->method->save_lmf);
3283                         /*
3284                          * Note: we can use ppc_r11 here because it is dead anyway:
3285                          * we're leaving the method.
3286                          */
3287                         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3288                                 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3289                                         ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3290                                 } else {
3291                                         ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3292                                         ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3293                                 }
3294                                 ppc_mtlr (code, ppc_r0);
3295                         }
3296
3297                         code = emit_load_volatile_arguments (cfg, code);
3298
3299                         if (ppc_is_imm16 (cfg->stack_usage)) {
3300                                 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3301                         } else {
3302                                 ppc_load (code, ppc_r11, cfg->stack_usage);
3303                                 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3304                         }
3305                         if (!cfg->method->save_lmf) {
3306                                 /*for (i = 31; i >= 14; --i) {
3307                                         if (cfg->used_float_regs & (1 << i)) {
3308                                                 pos += sizeof (double);
3309                                                 ppc_lfd (code, i, -pos, cfg->frame_reg);
3310                                         }
3311                                 }*/
3312                                 for (i = 31; i >= 13; --i) {
3313                                         if (cfg->used_int_regs & (1 << i)) {
3314                                                 pos += sizeof (gulong);
3315                                                 ppc_lwz (code, i, -pos, ppc_sp);
3316                                         }
3317                                 }
3318                         } else {
3319                                 /* FIXME restore from MonoLMF: though this can't happen yet */
3320                         }
3321                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3322                         ppc_b (code, 0);
3323                         break;
3324                 }
3325                 case OP_CHECK_THIS:
3326                         /* ensure ins->sreg1 is not NULL */
3327                         ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3328                         break;
3329                 case OP_ARGLIST: {
3330                         if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3331                                 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3332                         } else {
3333                                 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3334                                 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3335                         }
3336                         ppc_stw (code, ppc_r0, 0, ins->sreg1);
3337                         break;
3338                 }
3339                 case OP_FCALL:
3340                 case OP_LCALL:
3341                 case OP_VCALL:
3342                 case OP_VCALL2:
3343                 case OP_VOIDCALL:
3344                 case OP_CALL:
3345                         call = (MonoCallInst*)ins;
3346                         if (ins->flags & MONO_INST_HAS_METHOD)
3347                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3348                         else
3349                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3350                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3351                                 ppc_lis (code, ppc_r0, 0);
3352                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3353                                 ppc_mtlr (code, ppc_r0);
3354                                 ppc_blrl (code);
3355                         } else {
3356                                 ppc_bl (code, 0);
3357                         }
3358                         /* FIXME: this should be handled somewhere else in the new jit */
3359                         code = emit_move_return_value (cfg, ins, code);
3360                         break;
3361                 case OP_FCALL_REG:
3362                 case OP_LCALL_REG:
3363                 case OP_VCALL_REG:
3364                 case OP_VCALL2_REG:
3365                 case OP_VOIDCALL_REG:
3366                 case OP_CALL_REG:
3367                         ppc_mtlr (code, ins->sreg1);
3368                         ppc_blrl (code);
3369                         /* FIXME: this should be handled somewhere else in the new jit */
3370                         code = emit_move_return_value (cfg, ins, code);
3371                         break;
3372                 case OP_FCALL_MEMBASE:
3373                 case OP_LCALL_MEMBASE:
3374                 case OP_VCALL_MEMBASE:
3375                 case OP_VCALL2_MEMBASE:
3376                 case OP_VOIDCALL_MEMBASE:
3377                 case OP_CALL_MEMBASE:
3378                         ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3379                         ppc_mtlr (code, ppc_r0);
3380                         ppc_blrl (code);
3381                         /* FIXME: this should be handled somewhere else in the new jit */
3382                         code = emit_move_return_value (cfg, ins, code);
3383                         break;
3384                 case OP_OUTARG:
3385                         g_assert_not_reached ();
3386                         break;
3387                 case OP_LOCALLOC: {
3388                         guint8 * zero_loop_jump, * zero_loop_start;
3389                         /* keep alignment */
3390                         int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3391                         int area_offset = alloca_waste;
3392                         area_offset &= ~31;
3393                         ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3394                         ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3395                         /* use ctr to store the number of words to 0 if needed */
3396                         if (ins->flags & MONO_INST_INIT) {
3397                                 /* we zero 4 bytes at a time:
3398                                  * we add 7 instead of 3 so that we set the counter to
3399                                  * at least 1, otherwise the bdnz instruction will make
3400                                  * it negative and iterate billions of times.
3401                                  */
3402                                 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3403                                 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3404                                 ppc_mtctr (code, ppc_r0);
3405                         }
3406                         ppc_lwz (code, ppc_r0, 0, ppc_sp);
3407                         ppc_neg (code, ppc_r11, ppc_r11);
3408                         ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3409                         
3410                         if (ins->flags & MONO_INST_INIT) {
3411                                 /* adjust the dest reg by -4 so we can use stwu */
3412                                 /* we actually adjust -8 because we let the loop
3413                                  * run at least once
3414                                  */
3415                                 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3416                                 ppc_li (code, ppc_r11, 0);
3417                                 zero_loop_start = code;
3418                                 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3419                                 zero_loop_jump = code;
3420                                 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3421                                 ppc_patch (zero_loop_jump, zero_loop_start);
3422                         }
3423                         ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3424                         break;
3425                 }
3426                 case OP_THROW: {
3427                         //ppc_break (code);
3428                         ppc_mr (code, ppc_r3, ins->sreg1);
3429                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3430                                              (gpointer)"mono_arch_throw_exception");
3431                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3432                                 ppc_lis (code, ppc_r0, 0);
3433                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3434                                 ppc_mtlr (code, ppc_r0);
3435                                 ppc_blrl (code);
3436                         } else {
3437                                 ppc_bl (code, 0);
3438                         }
3439                         break;
3440                 }
3441                 case OP_RETHROW: {
3442                         //ppc_break (code);
3443                         ppc_mr (code, ppc_r3, ins->sreg1);
3444                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3445                                              (gpointer)"mono_arch_rethrow_exception");
3446                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3447                                 ppc_lis (code, ppc_r0, 0);
3448                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3449                                 ppc_mtlr (code, ppc_r0);
3450                                 ppc_blrl (code);
3451                         } else {
3452                                 ppc_bl (code, 0);
3453                         }
3454                         break;
3455                 }
3456                 case OP_START_HANDLER: {
3457                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3458                         ppc_mflr (code, ppc_r0);
3459                         if (ppc_is_imm16 (spvar->inst_offset)) {
3460                                 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3461                         } else {
3462                                 ppc_load (code, ppc_r11, spvar->inst_offset);
3463                                 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3464                         }
3465                         break;
3466                 }
3467                 case OP_ENDFILTER: {
3468                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3469                         if (ins->sreg1 != ppc_r3)
3470                                 ppc_mr (code, ppc_r3, ins->sreg1);
3471                         if (ppc_is_imm16 (spvar->inst_offset)) {
3472                                 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3473                         } else {
3474                                 ppc_load (code, ppc_r11, spvar->inst_offset);
3475                                 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3476                         }
3477                         ppc_mtlr (code, ppc_r0);
3478                         ppc_blr (code);
3479                         break;
3480                 }
3481                 case OP_ENDFINALLY: {
3482                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3483                         ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3484                         ppc_mtlr (code, ppc_r0);
3485                         ppc_blr (code);
3486                         break;
3487                 }
3488                 case OP_CALL_HANDLER: 
3489                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3490                         ppc_bl (code, 0);
3491                         break;
3492                 case OP_LABEL:
3493                         ins->inst_c0 = code - cfg->native_code;
3494                         break;
3495                 case OP_BR:
3496                         if (ins->flags & MONO_INST_BRLABEL) {
3497                                 /*if (ins->inst_i0->inst_c0) {
3498                                         ppc_b (code, 0);
3499                                         //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3500                                 } else*/ {
3501                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3502                                         ppc_b (code, 0);
3503                                 }
3504                         } else {
3505                                 /*if (ins->inst_target_bb->native_offset) {
3506                                         ppc_b (code, 0);
3507                                         //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
3508                                 } else*/ {
3509                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3510                                         ppc_b (code, 0);
3511                                 } 
3512                         }
3513                         break;
3514                 case OP_BR_REG:
3515                         ppc_mtctr (code, ins->sreg1);
3516                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3517                         break;
3518                 case OP_CEQ:
3519                 case OP_ICEQ:
3520                         ppc_li (code, ins->dreg, 0);
3521                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3522                         ppc_li (code, ins->dreg, 1);
3523                         break;
3524                 case OP_CLT:
3525                 case OP_CLT_UN:
3526                 case OP_ICLT:
3527                 case OP_ICLT_UN:
3528                         ppc_li (code, ins->dreg, 1);
3529                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3530                         ppc_li (code, ins->dreg, 0);
3531                         break;
3532                 case OP_CGT:
3533                 case OP_CGT_UN:
3534                 case OP_ICGT:
3535                 case OP_ICGT_UN:
3536                         ppc_li (code, ins->dreg, 1);
3537                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3538                         ppc_li (code, ins->dreg, 0);
3539                         break;
3540                 case OP_COND_EXC_EQ:
3541                 case OP_COND_EXC_NE_UN:
3542                 case OP_COND_EXC_LT:
3543                 case OP_COND_EXC_LT_UN:
3544                 case OP_COND_EXC_GT:
3545                 case OP_COND_EXC_GT_UN:
3546                 case OP_COND_EXC_GE:
3547                 case OP_COND_EXC_GE_UN:
3548                 case OP_COND_EXC_LE:
3549                 case OP_COND_EXC_LE_UN:
3550                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3551                         break;
3552                 case OP_COND_EXC_IEQ:
3553                 case OP_COND_EXC_INE_UN:
3554                 case OP_COND_EXC_ILT:
3555                 case OP_COND_EXC_ILT_UN:
3556                 case OP_COND_EXC_IGT:
3557                 case OP_COND_EXC_IGT_UN:
3558                 case OP_COND_EXC_IGE:
3559                 case OP_COND_EXC_IGE_UN:
3560                 case OP_COND_EXC_ILE:
3561                 case OP_COND_EXC_ILE_UN:
3562                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3563                         break;
3564                 case OP_COND_EXC_C:
3565                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3566                          */
3567                         /*ppc_mfspr (code, ppc_r0, ppc_xer);
3568                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3569                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3570                         break;*/
3571                 case OP_COND_EXC_OV:
3572                         /*ppc_mcrxr (code, 0);
3573                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3574                         break;*/
3575                 case OP_COND_EXC_NC:
3576                 case OP_COND_EXC_NO:
3577                         g_assert_not_reached ();
3578                         break;
3579                 case OP_IBEQ:
3580                 case OP_IBNE_UN:
3581                 case OP_IBLT:
3582                 case OP_IBLT_UN:
3583                 case OP_IBGT:
3584                 case OP_IBGT_UN:
3585                 case OP_IBGE:
3586                 case OP_IBGE_UN:
3587                 case OP_IBLE:
3588                 case OP_IBLE_UN:
3589                         EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3590                         break;
3591
3592                 /* floating point opcodes */
3593                 case OP_R8CONST:
3594                 case OP_R4CONST:
3595                         g_assert_not_reached ();
3596                 case OP_STORER8_MEMBASE_REG:
3597                         if (ppc_is_imm16 (ins->inst_offset)) {
3598                                 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3599                         } else {
3600                                 ppc_load (code, ppc_r0, ins->inst_offset);
3601                                 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3602                         }
3603                         break;
3604                 case OP_LOADR8_MEMBASE:
3605                         if (ppc_is_imm16 (ins->inst_offset)) {
3606                                 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3607                         } else {
3608                                 ppc_load (code, ppc_r0, ins->inst_offset);
3609                                 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3610                         }
3611                         break;
3612                 case OP_STORER4_MEMBASE_REG:
3613                         ppc_frsp (code, ins->sreg1, ins->sreg1);
3614                         if (ppc_is_imm16 (ins->inst_offset)) {
3615                                 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3616                         } else {
3617                                 ppc_load (code, ppc_r0, ins->inst_offset);
3618                                 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3619                         }
3620                         break;
3621                 case OP_LOADR4_MEMBASE:
3622                         if (ppc_is_imm16 (ins->inst_offset)) {
3623                                 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3624                         } else {
3625                                 ppc_load (code, ppc_r0, ins->inst_offset);
3626                                 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3627                         }
3628                         break;
3629                 case OP_LOADR4_MEMINDEX:
3630                         ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3631                         break;
3632                 case OP_LOADR8_MEMINDEX:
3633                         ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3634                         break;
3635                 case OP_STORER4_MEMINDEX:
3636                         ppc_frsp (code, ins->sreg1, ins->sreg1);
3637                         ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3638                         break;
3639                 case OP_STORER8_MEMINDEX:
3640                         ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3641                         break;
3642                 case CEE_CONV_R_UN:
3643                 case CEE_CONV_R4: /* FIXME: change precision */
3644                 case CEE_CONV_R8:
3645                         g_assert_not_reached ();
3646                 case OP_FCONV_TO_I1:
3647                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3648                         break;
3649                 case OP_FCONV_TO_U1:
3650                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3651                         break;
3652                 case OP_FCONV_TO_I2:
3653                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3654                         break;
3655                 case OP_FCONV_TO_U2:
3656                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3657                         break;
3658                 case OP_FCONV_TO_I4:
3659                 case OP_FCONV_TO_I:
3660                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3661                         break;
3662                 case OP_FCONV_TO_U4:
3663                 case OP_FCONV_TO_U:
3664                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3665                         break;
3666                 case OP_FCONV_TO_I8:
3667                 case OP_FCONV_TO_U8:
3668                         g_assert_not_reached ();
3669                         /* Implemented as helper calls */
3670                         break;
3671                 case OP_LCONV_TO_R_UN:
3672                         g_assert_not_reached ();
3673                         /* Implemented as helper calls */
3674                         break;
3675                 case OP_LCONV_TO_OVF_I4_2:
3676                 case OP_LCONV_TO_OVF_I: {
3677                         guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3678                         // Check if its negative
3679                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3680                         negative_branch = code;
3681                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3682                         // Its positive msword == 0
3683                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3684                         msword_positive_branch = code;
3685                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3686
3687                         ovf_ex_target = code;
3688                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3689                         // Negative
3690                         ppc_patch (negative_branch, code);
3691                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3692                         msword_negative_branch = code;
3693                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3694                         ppc_patch (msword_negative_branch, ovf_ex_target);
3695                         
3696                         ppc_patch (msword_positive_branch, code);
3697                         if (ins->dreg != ins->sreg1)
3698                                 ppc_mr (code, ins->dreg, ins->sreg1);
3699                         break;
3700                 }
3701                 case OP_SQRT:
3702                         ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3703                         break;
3704                 case OP_FADD:
3705                         ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3706                         break;
3707                 case OP_FSUB:
3708                         ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3709                         break;          
3710                 case OP_FMUL:
3711                         ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3712                         break;          
3713                 case OP_FDIV:
3714                         ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3715                         break;          
3716                 case OP_FNEG:
3717                         ppc_fneg (code, ins->dreg, ins->sreg1);
3718                         break;          
3719                 case OP_FREM:
3720                         /* emulated */
3721                         g_assert_not_reached ();
3722                         break;
3723                 case OP_FCOMPARE:
3724                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3725                         break;
3726                 case OP_FCEQ:
3727                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3728                         ppc_li (code, ins->dreg, 0);
3729                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3730                         ppc_li (code, ins->dreg, 1);
3731                         break;
3732                 case OP_FCLT:
3733                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3734                         ppc_li (code, ins->dreg, 1);
3735                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3736                         ppc_li (code, ins->dreg, 0);
3737                         break;
3738                 case OP_FCLT_UN:
3739                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3740                         ppc_li (code, ins->dreg, 1);
3741                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3742                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3743                         ppc_li (code, ins->dreg, 0);
3744                         break;
3745                 case OP_FCGT:
3746                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3747                         ppc_li (code, ins->dreg, 1);
3748                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3749                         ppc_li (code, ins->dreg, 0);
3750                         break;
3751                 case OP_FCGT_UN:
3752                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3753                         ppc_li (code, ins->dreg, 1);
3754                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3755                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3756                         ppc_li (code, ins->dreg, 0);
3757                         break;
3758                 case OP_FBEQ:
3759                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3760                         break;
3761                 case OP_FBNE_UN:
3762                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3763                         break;
3764                 case OP_FBLT:
3765                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3766                         EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3767                         break;
3768                 case OP_FBLT_UN:
3769                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3770                         EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3771                         break;
3772                 case OP_FBGT:
3773                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3774                         EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3775                         break;
3776                 case OP_FBGT_UN:
3777                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3778                         EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3779                         break;
3780                 case OP_FBGE:
3781                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3782                         EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3783                         break;
3784                 case OP_FBGE_UN:
3785                         EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3786                         break;
3787                 case OP_FBLE:
3788                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3789                         EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3790                         break;
3791                 case OP_FBLE_UN:
3792                         EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3793                         break;
3794                 case OP_CKFINITE:
3795                         g_assert_not_reached ();
3796                 case OP_CHECK_FINITE: {
3797                         ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3798                         ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3799                         ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3800                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3801                         break;
3802                 case OP_JUMP_TABLE:
3803                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3804                         ppc_load (code, ins->dreg, 0x0f0f0f0f);
3805                         break;
3806                 }
3807                 default:
3808                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3809                         g_assert_not_reached ();
3810                 }
3811
3812                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3813                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3814                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3815                         g_assert_not_reached ();
3816                 }
3817                
3818                 cpos += max_len;
3819
3820                 last_ins = ins;
3821                 last_offset = offset;
3822         }
3823
3824         cfg->code_len = code - cfg->native_code;
3825 }
3826
3827 void
3828 mono_arch_register_lowlevel_calls (void)
3829 {
3830 }
3831
3832 #define patch_lis_ori(ip,val) do {\
3833                 guint16 *__lis_ori = (guint16*)(ip);    \
3834                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
3835                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
3836         } while (0)
3837
3838 void
3839 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3840 {
3841         MonoJumpInfo *patch_info;
3842
3843         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3844                 unsigned char *ip = patch_info->ip.i + code;
3845                 unsigned char *target;
3846
3847                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3848
3849                 switch (patch_info->type) {
3850                 case MONO_PATCH_INFO_IP:
3851                         patch_lis_ori (ip, ip);
3852                         continue;
3853                 case MONO_PATCH_INFO_METHOD_REL:
3854                         g_assert_not_reached ();
3855                         *((gpointer *)(ip)) = code + patch_info->data.offset;
3856                         continue;
3857                 case MONO_PATCH_INFO_SWITCH: {
3858                         gpointer *table = (gpointer *)patch_info->data.table->table;
3859                         int i;
3860
3861                         patch_lis_ori (ip, table);
3862
3863                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
3864                                 table [i] = (int)patch_info->data.table->table [i] + code;
3865                         }
3866                         /* we put into the table the absolute address, no need for ppc_patch in this case */
3867                         continue;
3868                 }
3869                 case MONO_PATCH_INFO_METHODCONST:
3870                 case MONO_PATCH_INFO_CLASS:
3871                 case MONO_PATCH_INFO_IMAGE:
3872                 case MONO_PATCH_INFO_FIELD:
3873                 case MONO_PATCH_INFO_VTABLE:
3874                 case MONO_PATCH_INFO_IID:
3875                 case MONO_PATCH_INFO_SFLDA:
3876                 case MONO_PATCH_INFO_LDSTR:
3877                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3878                 case MONO_PATCH_INFO_LDTOKEN:
3879                         /* from OP_AOTCONST : lis + ori */
3880                         patch_lis_ori (ip, target);
3881                         continue;
3882                 case MONO_PATCH_INFO_R4:
3883                 case MONO_PATCH_INFO_R8:
3884                         g_assert_not_reached ();
3885                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3886                         continue;
3887                 case MONO_PATCH_INFO_EXC_NAME:
3888                         g_assert_not_reached ();
3889                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3890                         continue;
3891                 case MONO_PATCH_INFO_NONE:
3892                 case MONO_PATCH_INFO_BB_OVF:
3893                 case MONO_PATCH_INFO_EXC_OVF:
3894                         /* everything is dealt with at epilog output time */
3895                         continue;
3896                 default:
3897                         break;
3898                 }
3899                 ppc_patch (ip, target);
3900         }
3901 }
3902
3903 /*
3904  * Stack frame layout:
3905  * 
3906  *   ------------------- sp
3907  *      MonoLMF structure or saved registers
3908  *   -------------------
3909  *      spilled regs
3910  *   -------------------
3911  *      locals
3912  *   -------------------
3913  *      optional 8 bytes for tracing
3914  *   -------------------
3915  *      param area             size is cfg->param_area
3916  *   -------------------
3917  *      linkage area           size is PPC_STACK_PARAM_OFFSET
3918  *   ------------------- sp
3919  *      red zone
3920  */
3921 guint8 *
3922 mono_arch_emit_prolog (MonoCompile *cfg)
3923 {
3924         MonoMethod *method = cfg->method;
3925         MonoBasicBlock *bb;
3926         MonoMethodSignature *sig;
3927         MonoInst *inst;
3928         int alloc_size, pos, max_offset, i;
3929         guint8 *code;
3930         CallInfo *cinfo;
3931         int tracing = 0;
3932         int lmf_offset = 0;
3933         int tailcall_struct_index;
3934
3935         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3936                 tracing = 1;
3937
3938         sig = mono_method_signature (method);
3939         cfg->code_size = 256 + sig->param_count * 20;
3940         code = cfg->native_code = g_malloc (cfg->code_size);
3941
3942         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3943                 ppc_mflr (code, ppc_r0);
3944                 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3945         }
3946
3947         alloc_size = cfg->stack_offset;
3948         pos = 0;
3949
3950         if (!method->save_lmf) {
3951                 /*for (i = 31; i >= 14; --i) {
3952                         if (cfg->used_float_regs & (1 << i)) {
3953                                 pos += sizeof (gdouble);
3954                                 ppc_stfd (code, i, -pos, ppc_sp);
3955                         }
3956                 }*/
3957                 for (i = 31; i >= 13; --i) {
3958                         if (cfg->used_int_regs & (1 << i)) {
3959                                 pos += sizeof (gulong);
3960                                 ppc_stw (code, i, -pos, ppc_sp);
3961                         }
3962                 }
3963         } else {
3964                 int ofs;
3965                 pos += sizeof (MonoLMF);
3966                 lmf_offset = pos;
3967                 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3968                 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3969                 for (i = 14; i < 32; i++) {
3970                         ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3971                 }
3972         }
3973         alloc_size += pos;
3974         // align to PPC_STACK_ALIGNMENT bytes
3975         if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3976                 alloc_size += PPC_STACK_ALIGNMENT - 1;
3977                 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3978         }
3979
3980         cfg->stack_usage = alloc_size;
3981         g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3982         if (alloc_size) {
3983                 if (ppc_is_imm16 (-alloc_size)) {
3984                         ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3985                 } else {
3986                         ppc_load (code, ppc_r11, -alloc_size);
3987                         ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3988                 }
3989         }
3990         if (cfg->frame_reg != ppc_sp)
3991                 ppc_mr (code, cfg->frame_reg, ppc_sp);
3992
3993         /* store runtime generic context */
3994         if (cfg->rgctx_var) {
3995                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
3996                                 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
3997
3998                 ppc_stw (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
3999         }
4000
4001         /* compute max_offset in order to use short forward jumps
4002          * we always do it on ppc because the immediate displacement
4003          * for jumps is too small 
4004          */
4005         max_offset = 0;
4006         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4007                 MonoInst *ins;
4008                 bb->max_offset = max_offset;
4009
4010                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4011                         max_offset += 6; 
4012
4013                 MONO_BB_FOR_EACH_INS (bb, ins)
4014                         max_offset += ins_native_length (cfg, ins);
4015         }
4016
4017         /* load arguments allocated to register from the stack */
4018         pos = 0;
4019
4020         cinfo = calculate_sizes (sig, sig->pinvoke);
4021
4022         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4023                 ArgInfo *ainfo = &cinfo->ret;
4024
4025                 if (cfg->new_ir)
4026                         inst = cfg->vret_addr;
4027                 else
4028                         inst = cfg->ret;
4029                 g_assert (inst);
4030
4031                 if (ppc_is_imm16 (inst->inst_offset)) {
4032                         ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4033                 } else {
4034                         ppc_load (code, ppc_r11, inst->inst_offset);
4035                         ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4036                 }
4037         }
4038
4039         tailcall_struct_index = 0;
4040         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4041                 ArgInfo *ainfo = cinfo->args + i;
4042                 inst = cfg->args [pos];
4043                 
4044                 if (cfg->verbose_level > 2)
4045                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4046                 if (inst->opcode == OP_REGVAR) {
4047                         if (ainfo->regtype == RegTypeGeneral)
4048                                 ppc_mr (code, inst->dreg, ainfo->reg);
4049                         else if (ainfo->regtype == RegTypeFP)
4050                                 ppc_fmr (code, inst->dreg, ainfo->reg);
4051                         else if (ainfo->regtype == RegTypeBase) {
4052                                 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4053                                 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
4054                         } else
4055                                 g_assert_not_reached ();
4056
4057                         if (cfg->verbose_level > 2)
4058                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4059                 } else {
4060                         /* the argument should be put on the stack: FIXME handle size != word  */
4061                         if (ainfo->regtype == RegTypeGeneral) {
4062                                 switch (ainfo->size) {
4063                                 case 1:
4064                                         if (ppc_is_imm16 (inst->inst_offset)) {
4065                                                 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4066                                         } else {
4067                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4068                                                 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4069                                         }
4070                                         break;
4071                                 case 2:
4072                                         if (ppc_is_imm16 (inst->inst_offset)) {
4073                                                 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4074                                         } else {
4075                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4076                                                 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4077                                         }
4078                                         break;
4079                                 case 8:
4080                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
4081                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4082                                                 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4083                                         } else {
4084                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4085                                                 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4086                                                 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4087                                                 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4088                                         }
4089                                         break;
4090                                 default:
4091                                         if (ppc_is_imm16 (inst->inst_offset)) {
4092                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4093                                         } else {
4094                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4095                                                 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4096                                         }
4097                                         break;
4098                                 }
4099                         } else if (ainfo->regtype == RegTypeBase) {
4100                                 /* load the previous stack pointer in r11 */
4101                                 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4102                                 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
4103                                 switch (ainfo->size) {
4104                                 case 1:
4105                                         if (ppc_is_imm16 (inst->inst_offset)) {
4106                                                 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4107                                         } else {
4108                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4109                                                 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4110                                         }
4111                                         break;
4112                                 case 2:
4113                                         if (ppc_is_imm16 (inst->inst_offset)) {
4114                                                 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4115                                         } else {
4116                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4117                                                 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4118                                         }
4119                                         break;
4120                                 case 8:
4121                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
4122                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4123                                                 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4124                                                 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4125                                         } else {
4126                                                 /* FIXME */
4127                                                 g_assert_not_reached ();
4128                                         }
4129                                         break;
4130                                 default:
4131                                         if (ppc_is_imm16 (inst->inst_offset)) {
4132                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4133                                         } else {
4134                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4135                                                 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4136                                         }
4137                                         break;
4138                                 }
4139                         } else if (ainfo->regtype == RegTypeFP) {
4140                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4141                                 if (ainfo->size == 8)
4142                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4143                                 else if (ainfo->size == 4)
4144                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4145                                 else
4146                                         g_assert_not_reached ();
4147                         } else if (ainfo->regtype == RegTypeStructByVal) {
4148                                 int doffset = inst->inst_offset;
4149                                 int soffset = 0;
4150                                 int cur_reg;
4151                                 int size = 0;
4152                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4153                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4154                                 /* FIXME: what if there is no class? */
4155                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4156                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4157                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4158 #if __APPLE__
4159                                         /*
4160                                          * Darwin handles 1 and 2 byte
4161                                          * structs specially by
4162                                          * loading h/b into the arg
4163                                          * register.  Only done for
4164                                          * pinvokes.
4165                                          */
4166                                         if (size == 2)
4167                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4168                                         else if (size == 1)
4169                                                 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4170                                         else
4171 #endif
4172                                                 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4173                                         soffset += sizeof (gpointer);
4174                                         doffset += sizeof (gpointer);
4175                                 }
4176                                 if (ainfo->vtsize) {
4177                                         /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4178                                         ppc_lwz (code, ppc_r11, 0, ppc_sp);
4179                                         if ((size & 3) != 0) {
4180                                                 code = emit_memcpy (code, size - soffset,
4181                                                         inst->inst_basereg, doffset,
4182                                                         ppc_r11, ainfo->offset + soffset);
4183                                         } else {
4184                                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4185                                                         inst->inst_basereg, doffset,
4186                                                         ppc_r11, ainfo->offset + soffset);
4187                                         }
4188                                 }
4189                         } else if (ainfo->regtype == RegTypeStructByAddr) {
4190                                 /* if it was originally a RegTypeBase */
4191                                 if (ainfo->offset) {
4192                                         /* load the previous stack pointer in r11 */
4193                                         ppc_lwz (code, ppc_r11, 0, ppc_sp);
4194                                         ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4195                                 } else {
4196                                         ppc_mr (code, ppc_r11, ainfo->reg);
4197                                 }
4198
4199                                 if (cfg->tailcall_valuetype_addrs) {
4200                                         MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4201
4202                                         g_assert (ppc_is_imm16 (addr->inst_offset));
4203                                         ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4204
4205                                         tailcall_struct_index++;
4206                                 }
4207
4208                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4209                                 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4210                                 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4211                         } else
4212                                 g_assert_not_reached ();
4213                 }
4214                 pos++;
4215         }
4216
4217         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4218                 ppc_load (code, ppc_r3, cfg->domain);
4219                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4220                 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4221                         ppc_lis (code, ppc_r0, 0);
4222                         ppc_ori (code, ppc_r0, ppc_r0, 0);
4223                         ppc_mtlr (code, ppc_r0);
4224                         ppc_blrl (code);
4225                 } else {
4226                         ppc_bl (code, 0);
4227                 }
4228         }
4229
4230         if (method->save_lmf) {
4231                 if (lmf_pthread_key != -1) {
4232                         emit_tls_access (code, ppc_r3, lmf_pthread_key);
4233                         if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4234                                 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4235                 } else {
4236                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4237                                      (gpointer)"mono_get_lmf_addr");
4238                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4239                                 ppc_lis (code, ppc_r0, 0);
4240                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
4241                                 ppc_mtlr (code, ppc_r0);
4242                                 ppc_blrl (code);
4243                         } else {
4244                                 ppc_bl (code, 0);
4245                         }
4246                 }
4247                 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4248                 /* lmf_offset is the offset from the previous stack pointer,
4249                  * alloc_size is the total stack space allocated, so the offset
4250                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4251                  * The pointer to the struct is put in ppc_r11 (new_lmf).
4252                  * The callee-saved registers are already in the MonoLMF structure
4253                  */
4254                 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4255                 /* ppc_r3 is the result from mono_get_lmf_addr () */
4256                 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4257                 /* new_lmf->previous_lmf = *lmf_addr */
4258                 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4259                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4260                 /* *(lmf_addr) = r11 */
4261                 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4262                 /* save method info */
4263                 ppc_load (code, ppc_r0, method);
4264                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4265                 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4266                 /* save the current IP */
4267                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4268                 ppc_load (code, ppc_r0, 0x01010101);
4269                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4270         }
4271
4272         if (tracing)
4273                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4274
4275         cfg->code_len = code - cfg->native_code;
4276         g_assert (cfg->code_len < cfg->code_size);
4277         g_free (cinfo);
4278
4279         return code;
4280 }
4281
4282 void
4283 mono_arch_emit_epilog (MonoCompile *cfg)
4284 {
4285         MonoMethod *method = cfg->method;
4286         int pos, i;
4287         int max_epilog_size = 16 + 20*4;
4288         guint8 *code;
4289
4290         if (cfg->method->save_lmf)
4291                 max_epilog_size += 128;
4292         
4293         if (mono_jit_trace_calls != NULL)
4294                 max_epilog_size += 50;
4295
4296         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4297                 max_epilog_size += 50;
4298
4299         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4300                 cfg->code_size *= 2;
4301                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4302                 mono_jit_stats.code_reallocs++;
4303         }
4304
4305         /*
4306          * Keep in sync with OP_JMP
4307          */
4308         code = cfg->native_code + cfg->code_len;
4309
4310         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4311                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4312         }
4313         pos = 0;
4314
4315         if (method->save_lmf) {
4316                 int lmf_offset;
4317                 pos +=  sizeof (MonoLMF);
4318                 lmf_offset = pos;
4319                 /* save the frame reg in r8 */
4320                 ppc_mr (code, ppc_r8, cfg->frame_reg);
4321                 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4322                 /* r5 = previous_lmf */
4323                 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4324                 /* r6 = lmf_addr */
4325                 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4326                 /* *(lmf_addr) = previous_lmf */
4327                 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4328                 /* FIXME: speedup: there is no actual need to restore the registers if
4329                  * we didn't actually change them (idea from Zoltan).
4330                  */
4331                 /* restore iregs */
4332                 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4333                 /* restore fregs */
4334                 /*for (i = 14; i < 32; i++) {
4335                         ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4336                 }*/
4337                 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4338                 /* use the saved copy of the frame reg in r8 */
4339                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4340                         ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4341                         ppc_mtlr (code, ppc_r0);
4342                 }
4343                 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4344         } else {
4345                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4346                         if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4347                                 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4348                         } else {
4349                                 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4350                                 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4351                         }
4352                         ppc_mtlr (code, ppc_r0);
4353                 }
4354                 if (ppc_is_imm16 (cfg->stack_usage)) {
4355                         ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
4356                 } else {
4357                         ppc_load (code, ppc_r11, cfg->stack_usage);
4358                         ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4359                 }
4360
4361                 /*for (i = 31; i >= 14; --i) {
4362                         if (cfg->used_float_regs & (1 << i)) {
4363                                 pos += sizeof (double);
4364                                 ppc_lfd (code, i, -pos, ppc_sp);
4365                         }
4366                 }*/
4367                 for (i = 31; i >= 13; --i) {
4368                         if (cfg->used_int_regs & (1 << i)) {
4369                                 pos += sizeof (gulong);
4370                                 ppc_lwz (code, i, -pos, ppc_sp);
4371                         }
4372                 }
4373         }
4374         ppc_blr (code);
4375
4376         cfg->code_len = code - cfg->native_code;
4377
4378         g_assert (cfg->code_len < cfg->code_size);
4379
4380 }
4381
4382 /* remove once throw_exception_by_name is eliminated */
4383 static int
4384 exception_id_by_name (const char *name)
4385 {
4386         if (strcmp (name, "IndexOutOfRangeException") == 0)
4387                 return MONO_EXC_INDEX_OUT_OF_RANGE;
4388         if (strcmp (name, "OverflowException") == 0)
4389                 return MONO_EXC_OVERFLOW;
4390         if (strcmp (name, "ArithmeticException") == 0)
4391                 return MONO_EXC_ARITHMETIC;
4392         if (strcmp (name, "DivideByZeroException") == 0)
4393                 return MONO_EXC_DIVIDE_BY_ZERO;
4394         if (strcmp (name, "InvalidCastException") == 0)
4395                 return MONO_EXC_INVALID_CAST;
4396         if (strcmp (name, "NullReferenceException") == 0)
4397                 return MONO_EXC_NULL_REF;
4398         if (strcmp (name, "ArrayTypeMismatchException") == 0)
4399                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4400         g_error ("Unknown intrinsic exception %s\n", name);
4401         return 0;
4402 }
4403
4404 void
4405 mono_arch_emit_exceptions (MonoCompile *cfg)
4406 {
4407         MonoJumpInfo *patch_info;
4408         int i;
4409         guint8 *code;
4410         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4411         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4412         int max_epilog_size = 50;
4413
4414         /* count the number of exception infos */
4415      
4416         /* 
4417          * make sure we have enough space for exceptions
4418          * 24 is the simulated call to throw_exception_by_name
4419          */
4420         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4421                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4422                         i = exception_id_by_name (patch_info->data.target);
4423                         if (!exc_throw_found [i]) {
4424                                 max_epilog_size += 24;
4425                                 exc_throw_found [i] = TRUE;
4426                         }
4427                 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4428                         max_epilog_size += 12;
4429                 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4430                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4431                         i = exception_id_by_name (ovfj->data.exception);
4432                         if (!exc_throw_found [i]) {
4433                                 max_epilog_size += 24;
4434                                 exc_throw_found [i] = TRUE;
4435                         }
4436                         max_epilog_size += 8;
4437                 }
4438         }
4439
4440         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4441                 cfg->code_size *= 2;
4442                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4443                 mono_jit_stats.code_reallocs++;
4444         }
4445
4446         code = cfg->native_code + cfg->code_len;
4447
4448         /* add code to raise exceptions */
4449         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4450                 switch (patch_info->type) {
4451                 case MONO_PATCH_INFO_BB_OVF: {
4452                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4453                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4454                         /* patch the initial jump */
4455                         ppc_patch (ip, code);
4456                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4457                         ppc_b (code, 0);
4458                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4459                         /* jump back to the true target */
4460                         ppc_b (code, 0);
4461                         ip = ovfj->data.bb->native_offset + cfg->native_code;
4462                         ppc_patch (code - 4, ip);
4463                         break;
4464                 }
4465                 case MONO_PATCH_INFO_EXC_OVF: {
4466                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4467                         MonoJumpInfo *newji;
4468                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4469                         unsigned char *bcl = code;
4470                         /* patch the initial jump: we arrived here with a call */
4471                         ppc_patch (ip, code);
4472                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4473                         ppc_b (code, 0);
4474                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4475                         /* patch the conditional jump to the right handler */
4476                         /* make it processed next */
4477                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4478                         newji->type = MONO_PATCH_INFO_EXC;
4479                         newji->ip.i = bcl - cfg->native_code;
4480                         newji->data.target = ovfj->data.exception;
4481                         newji->next = patch_info->next;
4482                         patch_info->next = newji;
4483                         break;
4484                 }
4485                 case MONO_PATCH_INFO_EXC: {
4486                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4487                         i = exception_id_by_name (patch_info->data.target);
4488                         if (exc_throw_pos [i]) {
4489                                 ppc_patch (ip, exc_throw_pos [i]);
4490                                 patch_info->type = MONO_PATCH_INFO_NONE;
4491                                 break;
4492                         } else {
4493                                 exc_throw_pos [i] = code;
4494                         }
4495                         ppc_patch (ip, code);
4496                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4497                         ppc_load (code, ppc_r3, patch_info->data.target);
4498                         /* we got here from a conditional call, so the calling ip is set in lr already */
4499                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4500                         patch_info->data.name = "mono_arch_throw_exception_by_name";
4501                         patch_info->ip.i = code - cfg->native_code;
4502                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4503                                 ppc_lis (code, ppc_r0, 0);
4504                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
4505                                 ppc_mtctr (code, ppc_r0);
4506                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4507                         } else {
4508                                 ppc_b (code, 0);
4509                         }
4510                         break;
4511                 }
4512                 default:
4513                         /* do nothing */
4514                         break;
4515                 }
4516         }
4517
4518         cfg->code_len = code - cfg->native_code;
4519
4520         g_assert (cfg->code_len < cfg->code_size);
4521
4522 }
4523
4524 static int
4525 try_offset_access (void *value, guint32 idx)
4526 {
4527         register void* me __asm__ ("r2");
4528         void ***p = (void***)((char*)me + 284);
4529         int idx1 = idx / 32;
4530         int idx2 = idx % 32;
4531         if (!p [idx1])
4532                 return 0;
4533         if (value != p[idx1][idx2])
4534                 return 0;
4535         return 1;
4536 }
4537
4538 static void
4539 setup_tls_access (void)
4540 {
4541         guint32 ptk;
4542         guint32 *ins, *code;
4543         guint32 cmplwi_1023, li_0x48, blr_ins;
4544         if (tls_mode == TLS_MODE_FAILED)
4545                 return;
4546
4547         if (g_getenv ("MONO_NO_TLS")) {
4548                 tls_mode = TLS_MODE_FAILED;
4549                 return;
4550         }
4551
4552         if (tls_mode == TLS_MODE_DETECT) {
4553                 ins = (guint32*)pthread_getspecific;
4554                 /* uncond branch to the real method */
4555                 if ((*ins >> 26) == 18) {
4556                         gint32 val;
4557                         val = (*ins & ~3) << 6;
4558                         val >>= 6;
4559                         if (*ins & 2) {
4560                                 /* absolute */
4561                                 ins = (guint32*)val;
4562                         } else {
4563                                 ins = (guint32*) ((char*)ins + val);
4564                         }
4565                 }
4566                 code = &cmplwi_1023;
4567                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4568                 code = &li_0x48;
4569                 ppc_li (code, ppc_r4, 0x48);
4570                 code = &blr_ins;
4571                 ppc_blr (code);
4572                 if (*ins == cmplwi_1023) {
4573                         int found_lwz_284 = 0;
4574                         for (ptk = 0; ptk < 20; ++ptk) {
4575                                 ++ins;
4576                                 if (!*ins || *ins == blr_ins)
4577                                         break;
4578                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4579                                         found_lwz_284 = 1;
4580                                         break;
4581                                 }
4582                         }
4583                         if (!found_lwz_284) {
4584                                 tls_mode = TLS_MODE_FAILED;
4585                                 return;
4586                         }
4587                         tls_mode = TLS_MODE_LTHREADS;
4588                 } else if (*ins == li_0x48) {
4589                         ++ins;
4590                         /* uncond branch to the real method */
4591                         if ((*ins >> 26) == 18) {
4592                                 gint32 val;
4593                                 val = (*ins & ~3) << 6;
4594                                 val >>= 6;
4595                                 if (*ins & 2) {
4596                                         /* absolute */
4597                                         ins = (guint32*)val;
4598                                 } else {
4599                                         ins = (guint32*) ((char*)ins + val);
4600                                 }
4601                                 code = (guint32*)&val;
4602                                 ppc_li (code, ppc_r0, 0x7FF2);
4603                                 if (ins [1] == val) {
4604                                         /* Darwin on G4, implement */
4605                                         tls_mode = TLS_MODE_FAILED;
4606                                         return;
4607                                 } else {
4608                                         code = (guint32*)&val;
4609                                         ppc_mfspr (code, ppc_r3, 104);
4610                                         if (ins [1] != val) {
4611                                                 tls_mode = TLS_MODE_FAILED;
4612                                                 return;
4613                                         }
4614                                         tls_mode = TLS_MODE_DARWIN_G5;
4615                                 }
4616                         } else {
4617                                 tls_mode = TLS_MODE_FAILED;
4618                                 return;
4619                         }
4620                 } else {
4621                         tls_mode = TLS_MODE_FAILED;
4622                         return;
4623                 }
4624         }
4625         if (monodomain_key == -1) {
4626                 ptk = mono_domain_get_tls_key ();
4627                 if (ptk < 1024) {
4628                         ptk = mono_pthread_key_for_tls (ptk);
4629                         if (ptk < 1024) {
4630                                 monodomain_key = ptk;
4631                         }
4632                 }
4633         }
4634         if (lmf_pthread_key == -1) {
4635                 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4636                 if (ptk < 1024) {
4637                         /*g_print ("MonoLMF at: %d\n", ptk);*/
4638                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4639                                 init_tls_failed = 1;
4640                                 return;
4641                         }*/
4642                         lmf_pthread_key = ptk;
4643                 }
4644         }
4645         if (monothread_key == -1) {
4646                 ptk = mono_thread_get_tls_key ();
4647                 if (ptk < 1024) {
4648                         ptk = mono_pthread_key_for_tls (ptk);
4649                         if (ptk < 1024) {
4650                                 monothread_key = ptk;
4651                                 /*g_print ("thread inited: %d\n", ptk);*/
4652                         }
4653                 } else {
4654                         /*g_print ("thread not inited yet %d\n", ptk);*/
4655                 }
4656         }
4657 }
4658
4659 void
4660 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4661 {
4662         setup_tls_access ();
4663 }
4664
4665 void
4666 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4667 {
4668 }
4669
4670 void
4671 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4672 {
4673         int this_dreg = ppc_r3;
4674         
4675         if (vt_reg != -1)
4676                 this_dreg = ppc_r4;
4677
4678         /* add the this argument */
4679         if (this_reg != -1) {
4680                 MonoInst *this;
4681                 MONO_INST_NEW (cfg, this, OP_MOVE);
4682                 this->type = this_type;
4683                 this->sreg1 = this_reg;
4684                 this->dreg = mono_regstate_next_int (cfg->rs);
4685                 mono_bblock_add_inst (cfg->cbb, this);
4686                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4687         }
4688
4689         if (vt_reg != -1) {
4690                 MonoInst *vtarg;
4691                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4692                 vtarg->type = STACK_MP;
4693                 vtarg->sreg1 = vt_reg;
4694                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4695                 mono_bblock_add_inst (cfg->cbb, vtarg);
4696                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
4697         }
4698 }
4699
4700 #ifdef MONO_ARCH_HAVE_IMT
4701
4702 #define CMP_SIZE 12
4703 #define BR_SIZE 4
4704 #define JUMP_IMM_SIZE 12
4705 #define JUMP_IMM32_SIZE 16
4706 #define ENABLE_WRONG_METHOD_CHECK 0
4707
4708 /*
4709  * LOCKING: called with the domain lock held
4710  */
4711 gpointer
4712 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4713         gpointer fail_tramp)
4714 {
4715         int i;
4716         int size = 0;
4717         guint8 *code, *start;
4718
4719         for (i = 0; i < count; ++i) {
4720                 MonoIMTCheckItem *item = imt_entries [i];
4721                 if (item->is_equals) {
4722                         if (item->check_target_idx) {
4723                                 if (!item->compare_done)
4724                                         item->chunk_size += CMP_SIZE;
4725                                 if (fail_tramp)
4726                                         item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
4727                                 else
4728                                         item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4729                         } else {
4730                                 if (fail_tramp) {
4731                                         item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
4732                                 } else {
4733                                         item->chunk_size += JUMP_IMM_SIZE;
4734 #if ENABLE_WRONG_METHOD_CHECK
4735                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4736 #endif
4737                                 }
4738                         }
4739                 } else {
4740                         item->chunk_size += CMP_SIZE + BR_SIZE;
4741                         imt_entries [item->check_target_idx]->compare_done = TRUE;
4742                 }
4743                 size += item->chunk_size;
4744         }
4745         if (fail_tramp) {
4746                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
4747         } else {
4748                 /* the initial load of the vtable address */
4749                 size += 8;
4750                 code = mono_code_manager_reserve (domain->code_mp, size);
4751         }
4752         start = code;
4753         if (!fail_tramp)
4754                 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4755         for (i = 0; i < count; ++i) {
4756                 MonoIMTCheckItem *item = imt_entries [i];
4757                 item->code_target = code;
4758                 if (item->is_equals) {
4759                         if (item->check_target_idx) {
4760                                 if (!item->compare_done) {
4761                                         ppc_load (code, ppc_r0, (guint32)item->key);
4762                                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4763                                 }
4764                                 item->jmp_code = code;
4765                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4766                                 if (fail_tramp)
4767                                         ppc_load (code, ppc_r0, item->value.target_code);
4768                                 else
4769                                         ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4770                                 ppc_mtctr (code, ppc_r0);
4771                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4772                         } else {
4773                                 if (fail_tramp) {
4774                                         ppc_load (code, ppc_r0, (guint32)item->key);
4775                                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4776                                         item->jmp_code = code;
4777                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4778                                         ppc_load (code, ppc_r0, item->value.target_code);
4779                                         ppc_mtctr (code, ppc_r0);
4780                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4781                                         ppc_patch (item->jmp_code, code);
4782                                         ppc_load (code, ppc_r0, fail_tramp);
4783                                         ppc_mtctr (code, ppc_r0);
4784                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4785                                         item->jmp_code = NULL;
4786                                 } else {
4787                                         /* enable the commented code to assert on wrong method */
4788 #if ENABLE_WRONG_METHOD_CHECK
4789                                         ppc_load (code, ppc_r0, (guint32)item->key);
4790                                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4791                                         item->jmp_code = code;
4792                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4793 #endif
4794                                         ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
4795                                         ppc_mtctr (code, ppc_r0);
4796                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4797 #if ENABLE_WRONG_METHOD_CHECK
4798                                         ppc_patch (item->jmp_code, code);
4799                                         ppc_break (code);
4800                                         item->jmp_code = NULL;
4801 #endif
4802                                 }
4803                         }
4804                 } else {
4805                         ppc_load (code, ppc_r0, (guint32)item->key);
4806                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4807                         item->jmp_code = code;
4808                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4809                 }
4810         }
4811         /* patch the branches to get to the target items */
4812         for (i = 0; i < count; ++i) {
4813                 MonoIMTCheckItem *item = imt_entries [i];
4814                 if (item->jmp_code) {
4815                         if (item->check_target_idx) {
4816                                 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4817                         }
4818                 }
4819         }
4820
4821         if (!fail_tramp)
4822                 mono_stats.imt_thunks_size += code - start;
4823         g_assert (code - start <= size);
4824         mono_arch_flush_icache (start, size);
4825         return start;
4826 }
4827
4828 MonoMethod*
4829 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4830 {
4831         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4832 }
4833
4834 MonoObject*
4835 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4836 {
4837         return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4838 }
4839 #endif
4840
4841 MonoVTable*
4842 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4843 {
4844         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
4845 }
4846
4847 MonoInst*
4848 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4849 {
4850         MonoInst *ins = NULL;
4851
4852         /*if (cmethod->klass == mono_defaults.math_class) {
4853                 if (strcmp (cmethod->name, "Sqrt") == 0) {
4854                         MONO_INST_NEW (cfg, ins, OP_SQRT);
4855                         ins->inst_i0 = args [0];
4856                 }
4857         }*/
4858         return ins;
4859 }
4860
4861 MonoInst*
4862 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4863 {
4864         /* FIXME: */
4865         return NULL;
4866 }
4867
4868 gboolean
4869 mono_arch_print_tree (MonoInst *tree, int arity)
4870 {
4871         return 0;
4872 }
4873
4874 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4875 {
4876         MonoInst* ins;
4877
4878         setup_tls_access ();
4879         if (monodomain_key == -1)
4880                 return NULL;
4881         
4882         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4883         ins->inst_offset = monodomain_key;
4884         return ins;
4885 }
4886
4887 MonoInst* 
4888 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4889 {
4890         MonoInst* ins;
4891
4892         setup_tls_access ();
4893         if (monothread_key == -1)
4894                 return NULL;
4895         
4896         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4897         ins->inst_offset = monothread_key;
4898         return ins;
4899 }
4900
4901 gpointer
4902 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4903 {
4904         g_assert (reg >= ppc_r13);
4905
4906         return (gpointer)ctx->regs [reg - ppc_r13];
4907 }