9c5ae320c986086509ac45a61a148a20a6f0eeb8
[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*)((guint32)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->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1629                 MonoInst *ins;
1630
1631                 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1632                 ins->sreg1 = val->dreg + 1;
1633                 ins->sreg2 = val->dreg + 2;
1634                 MONO_ADD_INS (cfg->cbb, ins);
1635                 return;
1636         }
1637         if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1638                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1639                 return;
1640         }
1641         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1642 }
1643
1644 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1645 gboolean
1646 mono_arch_is_inst_imm (gint64 imm)
1647 {
1648        return TRUE;
1649 }
1650
1651 /*
1652  * Allow tracing to work with this interface (with an optional argument)
1653  */
1654
1655 void*
1656 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1657 {
1658         guchar *code = p;
1659
1660         ppc_load (code, ppc_r3, cfg->method);
1661         ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1662         ppc_load (code, ppc_r0, func);
1663         ppc_mtlr (code, ppc_r0);
1664         ppc_blrl (code);
1665         return code;
1666 }
1667
1668 enum {
1669         SAVE_NONE,
1670         SAVE_STRUCT,
1671         SAVE_ONE,
1672         SAVE_TWO,
1673         SAVE_FP
1674 };
1675
1676 void*
1677 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1678 {
1679         guchar *code = p;
1680         int save_mode = SAVE_NONE;
1681         int offset;
1682         MonoMethod *method = cfg->method;
1683         int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context,
1684                         mono_method_signature (method)->ret)->type;
1685         int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1686         save_offset += 15;
1687         save_offset &= ~15;
1688         
1689         offset = code - cfg->native_code;
1690         /* we need about 16 instructions */
1691         if (offset > (cfg->code_size - 16 * 4)) {
1692                 cfg->code_size *= 2;
1693                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1694                 code = cfg->native_code + offset;
1695         }
1696
1697         switch (rtype) {
1698         case MONO_TYPE_VOID:
1699                 /* special case string .ctor icall */
1700                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1701                         save_mode = SAVE_ONE;
1702                 else
1703                         save_mode = SAVE_NONE;
1704                 break;
1705         case MONO_TYPE_I8:
1706         case MONO_TYPE_U8:
1707                 save_mode = SAVE_TWO;
1708                 break;
1709         case MONO_TYPE_R4:
1710         case MONO_TYPE_R8:
1711                 save_mode = SAVE_FP;
1712                 break;
1713         case MONO_TYPE_VALUETYPE:
1714                 save_mode = SAVE_STRUCT;
1715                 break;
1716         default:
1717                 save_mode = SAVE_ONE;
1718                 break;
1719         }
1720
1721         switch (save_mode) {
1722         case SAVE_TWO:
1723                 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1724                 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1725                 if (enable_arguments) {
1726                         ppc_mr (code, ppc_r5, ppc_r4);
1727                         ppc_mr (code, ppc_r4, ppc_r3);
1728                 }
1729                 break;
1730         case SAVE_ONE:
1731                 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1732                 if (enable_arguments) {
1733                         ppc_mr (code, ppc_r4, ppc_r3);
1734                 }
1735                 break;
1736         case SAVE_FP:
1737                 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1738                 if (enable_arguments) {
1739                         /* FIXME: what reg?  */
1740                         ppc_fmr (code, ppc_f3, ppc_f1);
1741                         ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1742                         ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1743                 }
1744                 break;
1745         case SAVE_STRUCT:
1746                 if (enable_arguments) {
1747                         /* FIXME: get the actual address  */
1748                         ppc_mr (code, ppc_r4, ppc_r3);
1749                 }
1750                 break;
1751         case SAVE_NONE:
1752         default:
1753                 break;
1754         }
1755
1756         ppc_load (code, ppc_r3, cfg->method);
1757         ppc_load (code, ppc_r0, func);
1758         ppc_mtlr (code, ppc_r0);
1759         ppc_blrl (code);
1760
1761         switch (save_mode) {
1762         case SAVE_TWO:
1763                 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1764                 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1765                 break;
1766         case SAVE_ONE:
1767                 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1768                 break;
1769         case SAVE_FP:
1770                 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1771                 break;
1772         case SAVE_NONE:
1773         default:
1774                 break;
1775         }
1776
1777         return code;
1778 }
1779 /*
1780  * Conditional branches have a small offset, so if it is likely overflowed,
1781  * we do a branch to the end of the method (uncond branches have much larger
1782  * offsets) where we perform the conditional and jump back unconditionally.
1783  * It's slightly slower, since we add two uncond branches, but it's very simple
1784  * with the current patch implementation and such large methods are likely not
1785  * going to be perf critical anyway.
1786  */
1787 typedef struct {
1788         union {
1789                 MonoBasicBlock *bb;
1790                 const char *exception;
1791         } data;
1792         guint32 ip_offset;
1793         guint16 b0_cond;
1794         guint16 b1_cond;
1795 } MonoOvfJump;
1796
1797 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1798 if (ins->flags & MONO_INST_BRLABEL) { \
1799         if (0 && ins->inst_i0->inst_c0) { \
1800                 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff);  \
1801         } else { \
1802                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1803                 ppc_bc (code, (b0), (b1), 0);   \
1804         } \
1805 } else { \
1806         if (0 && ins->inst_true_bb->native_offset) { \
1807                 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1808         } else { \
1809                 int br_disp = ins->inst_true_bb->max_offset - offset;   \
1810                 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1811                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));    \
1812                         ovfj->data.bb = ins->inst_true_bb;      \
1813                         ovfj->ip_offset = 0;    \
1814                         ovfj->b0_cond = (b0);   \
1815                         ovfj->b1_cond = (b1);   \
1816                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1817                         ppc_b (code, 0);        \
1818                 } else {        \
1819                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1820                         ppc_bc (code, (b0), (b1), 0);   \
1821                 }       \
1822         } \
1823 }
1824
1825 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1826
1827 /* emit an exception if condition is fail
1828  *
1829  * We assign the extra code used to throw the implicit exceptions
1830  * to cfg->bb_exit as far as the big branch handling is concerned
1831  */
1832 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name)            \
1833         do {                                                        \
1834                 int br_disp = cfg->bb_exit->max_offset - offset;        \
1835                 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1836                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));    \
1837                         ovfj->data.exception = (exc_name);      \
1838                         ovfj->ip_offset = code - cfg->native_code;      \
1839                         ovfj->b0_cond = (b0);   \
1840                         ovfj->b1_cond = (b1);   \
1841                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1842                         ppc_bl (code, 0);       \
1843                         cfg->bb_exit->max_offset += 24; \
1844                 } else {        \
1845                         mono_add_patch_info (cfg, code - cfg->native_code,   \
1846                                     MONO_PATCH_INFO_EXC, exc_name);  \
1847                         ppc_bcl (code, (b0), (b1), 0);  \
1848                 }       \
1849         } while (0); 
1850
1851 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1852
1853 void
1854 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1855 {
1856 }
1857
1858 void
1859 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1860 {
1861         MonoInst *ins, *n, *last_ins = NULL;
1862
1863         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1864                 switch (ins->opcode) {
1865                 case OP_MUL_IMM: 
1866                         /* remove unnecessary multiplication with 1 */
1867                         if (ins->inst_imm == 1) {
1868                                 if (ins->dreg != ins->sreg1) {
1869                                         ins->opcode = OP_MOVE;
1870                                 } else {
1871                                         MONO_DELETE_INS (bb, ins);
1872                                         continue;
1873                                 }
1874                         } else {
1875                                 int power2 = mono_is_power_of_two (ins->inst_imm);
1876                                 if (power2 > 0) {
1877                                         ins->opcode = OP_SHL_IMM;
1878                                         ins->inst_imm = power2;
1879                                 }
1880                         }
1881                         break;
1882                 case OP_LOAD_MEMBASE:
1883                 case OP_LOADI4_MEMBASE:
1884                         /* 
1885                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1886                          * OP_LOAD_MEMBASE offset(basereg), reg
1887                          */
1888                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1889                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1890                             ins->inst_basereg == last_ins->inst_destbasereg &&
1891                             ins->inst_offset == last_ins->inst_offset) {
1892                                 if (ins->dreg == last_ins->sreg1) {
1893                                         MONO_DELETE_INS (bb, ins);
1894                                         continue;
1895                                 } else {
1896                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1897                                         ins->opcode = OP_MOVE;
1898                                         ins->sreg1 = last_ins->sreg1;
1899                                 }
1900
1901                         /* 
1902                          * Note: reg1 must be different from the basereg in the second load
1903                          * OP_LOAD_MEMBASE offset(basereg), reg1
1904                          * OP_LOAD_MEMBASE offset(basereg), reg2
1905                          * -->
1906                          * OP_LOAD_MEMBASE offset(basereg), reg1
1907                          * OP_MOVE reg1, reg2
1908                          */
1909                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1910                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1911                               ins->inst_basereg != last_ins->dreg &&
1912                               ins->inst_basereg == last_ins->inst_basereg &&
1913                               ins->inst_offset == last_ins->inst_offset) {
1914
1915                                 if (ins->dreg == last_ins->dreg) {
1916                                         MONO_DELETE_INS (bb, ins);
1917                                         continue;
1918                                 } else {
1919                                         ins->opcode = OP_MOVE;
1920                                         ins->sreg1 = last_ins->dreg;
1921                                 }
1922
1923                                 //g_assert_not_reached ();
1924
1925 #if 0
1926                         /* 
1927                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1928                          * OP_LOAD_MEMBASE offset(basereg), reg
1929                          * -->
1930                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1931                          * OP_ICONST reg, imm
1932                          */
1933                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1934                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1935                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1936                                    ins->inst_offset == last_ins->inst_offset) {
1937                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1938                                 ins->opcode = OP_ICONST;
1939                                 ins->inst_c0 = last_ins->inst_imm;
1940                                 g_assert_not_reached (); // check this rule
1941 #endif
1942                         }
1943                         break;
1944                 case OP_LOADU1_MEMBASE:
1945                 case OP_LOADI1_MEMBASE:
1946                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1947                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1948                                         ins->inst_offset == last_ins->inst_offset) {
1949                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1950                                 ins->sreg1 = last_ins->sreg1;                           
1951                         }
1952                         break;
1953                 case OP_LOADU2_MEMBASE:
1954                 case OP_LOADI2_MEMBASE:
1955                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1956                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1957                                         ins->inst_offset == last_ins->inst_offset) {
1958                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1959                                 ins->sreg1 = last_ins->sreg1;                           
1960                         }
1961                         break;
1962                 case OP_MOVE:
1963                         ins->opcode = OP_MOVE;
1964                         /* 
1965                          * OP_MOVE reg, reg 
1966                          */
1967                         if (ins->dreg == ins->sreg1) {
1968                                 MONO_DELETE_INS (bb, ins);
1969                                 continue;
1970                         }
1971                         /* 
1972                          * OP_MOVE sreg, dreg 
1973                          * OP_MOVE dreg, sreg
1974                          */
1975                         if (last_ins && last_ins->opcode == OP_MOVE &&
1976                             ins->sreg1 == last_ins->dreg &&
1977                             ins->dreg == last_ins->sreg1) {
1978                                 MONO_DELETE_INS (bb, ins);
1979                                 continue;
1980                         }
1981                         break;
1982                 }
1983                 last_ins = ins;
1984                 ins = ins->next;
1985         }
1986         bb->last_ins = last_ins;
1987 }
1988
1989 void
1990 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1991 {
1992         g_assert (cfg->new_ir);
1993
1994         switch (ins->opcode) {
1995         case OP_ICONV_TO_R_UN: {
1996                 static const guint64 adjust_val = 0x4330000000000000ULL;
1997                 int msw_reg = mono_alloc_ireg (cfg);
1998                 int adj_reg = mono_alloc_freg (cfg);
1999                 int tmp_reg = mono_alloc_freg (cfg);
2000                 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2001                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2002                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
2003                 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
2004                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2005                 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2006                 ins->opcode = OP_NOP;
2007                 break;
2008         }
2009         case OP_ICONV_TO_R4:
2010         case OP_ICONV_TO_R8: {
2011                 /* FIXME: change precision for CEE_CONV_R4 */
2012                 static const guint64 adjust_val = 0x4330000080000000ULL;
2013                 int msw_reg = mono_alloc_ireg (cfg);
2014                 int xored = mono_alloc_ireg (cfg);
2015                 int adj_reg = mono_alloc_freg (cfg);
2016                 int tmp_reg = mono_alloc_freg (cfg);
2017                 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2018                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2019                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2020                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
2021                 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2022                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2023                 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2024                 if (ins->opcode == OP_ICONV_TO_R4)
2025                         MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2026                 ins->opcode = OP_NOP;
2027                 break;
2028         }
2029         case OP_CKFINITE: {
2030                 int msw_reg = mono_alloc_ireg (cfg);
2031                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
2032                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
2033                 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2034                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2035                 ins->opcode = OP_NOP;
2036                 break;
2037         }
2038         }
2039 }
2040
2041 /* 
2042  * the branch_b0_table should maintain the order of these
2043  * opcodes.
2044 case CEE_BEQ:
2045 case CEE_BGE:
2046 case CEE_BGT:
2047 case CEE_BLE:
2048 case CEE_BLT:
2049 case CEE_BNE_UN:
2050 case CEE_BGE_UN:
2051 case CEE_BGT_UN:
2052 case CEE_BLE_UN:
2053 case CEE_BLT_UN:
2054  */
2055 static const guchar 
2056 branch_b0_table [] = {
2057         PPC_BR_TRUE, 
2058         PPC_BR_FALSE, 
2059         PPC_BR_TRUE, 
2060         PPC_BR_FALSE, 
2061         PPC_BR_TRUE, 
2062         
2063         PPC_BR_FALSE, 
2064         PPC_BR_FALSE, 
2065         PPC_BR_TRUE, 
2066         PPC_BR_FALSE,
2067         PPC_BR_TRUE
2068 };
2069
2070 static const guchar 
2071 branch_b1_table [] = {
2072         PPC_BR_EQ, 
2073         PPC_BR_LT, 
2074         PPC_BR_GT, 
2075         PPC_BR_GT,
2076         PPC_BR_LT, 
2077         
2078         PPC_BR_EQ, 
2079         PPC_BR_LT, 
2080         PPC_BR_GT, 
2081         PPC_BR_GT,
2082         PPC_BR_LT 
2083 };
2084
2085 #define NEW_INS(cfg,dest,op) do {                                       \
2086                 MONO_INST_NEW((cfg), (dest), (op));                     \
2087                 mono_bblock_insert_after_ins (bb, last_ins, (dest));    \
2088         } while (0)
2089
2090 static int
2091 map_to_reg_reg_op (int op)
2092 {
2093         switch (op) {
2094         case OP_ADD_IMM:
2095                 return OP_IADD;
2096         case OP_SUB_IMM:
2097                 return OP_ISUB;
2098         case OP_AND_IMM:
2099                 return OP_IAND;
2100         case OP_COMPARE_IMM:
2101                 return OP_COMPARE;
2102         case OP_ICOMPARE_IMM:
2103                 return OP_ICOMPARE;
2104         case OP_ADDCC_IMM:
2105                 return OP_IADDCC;
2106         case OP_ADC_IMM:
2107                 return OP_IADC;
2108         case OP_SUBCC_IMM:
2109                 return OP_ISUBCC;
2110         case OP_SBB_IMM:
2111                 return OP_ISBB;
2112         case OP_OR_IMM:
2113                 return OP_IOR;
2114         case OP_XOR_IMM:
2115                 return OP_IXOR;
2116         case OP_MUL_IMM:
2117                 return OP_IMUL;
2118         case OP_LOAD_MEMBASE:
2119                 return OP_LOAD_MEMINDEX;
2120         case OP_LOADI4_MEMBASE:
2121                 return OP_LOADI4_MEMINDEX;
2122         case OP_LOADU4_MEMBASE:
2123                 return OP_LOADU4_MEMINDEX;
2124         case OP_LOADU1_MEMBASE:
2125                 return OP_LOADU1_MEMINDEX;
2126         case OP_LOADI2_MEMBASE:
2127                 return OP_LOADI2_MEMINDEX;
2128         case OP_LOADU2_MEMBASE:
2129                 return OP_LOADU2_MEMINDEX;
2130         case OP_LOADI1_MEMBASE:
2131                 return OP_LOADI1_MEMINDEX;
2132         case OP_LOADR4_MEMBASE:
2133                 return OP_LOADR4_MEMINDEX;
2134         case OP_LOADR8_MEMBASE:
2135                 return OP_LOADR8_MEMINDEX;
2136         case OP_STOREI1_MEMBASE_REG:
2137                 return OP_STOREI1_MEMINDEX;
2138         case OP_STOREI2_MEMBASE_REG:
2139                 return OP_STOREI2_MEMINDEX;
2140         case OP_STOREI4_MEMBASE_REG:
2141                 return OP_STOREI4_MEMINDEX;
2142         case OP_STORE_MEMBASE_REG:
2143                 return OP_STORE_MEMINDEX;
2144         case OP_STORER4_MEMBASE_REG:
2145                 return OP_STORER4_MEMINDEX;
2146         case OP_STORER8_MEMBASE_REG:
2147                 return OP_STORER8_MEMINDEX;
2148         case OP_STORE_MEMBASE_IMM:
2149                 return OP_STORE_MEMBASE_REG;
2150         case OP_STOREI1_MEMBASE_IMM:
2151                 return OP_STOREI1_MEMBASE_REG;
2152         case OP_STOREI2_MEMBASE_IMM:
2153                 return OP_STOREI2_MEMBASE_REG;
2154         case OP_STOREI4_MEMBASE_IMM:
2155                 return OP_STOREI4_MEMBASE_REG;
2156         }
2157         return mono_op_imm_to_op (op);
2158 }
2159
2160 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2161
2162 #define compare_opcode_is_unsigned(opcode) \
2163                 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) ||  \
2164                 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) ||  \
2165                 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) ||     \
2166                 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) ||   \
2167                 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2168 /*
2169  * Remove from the instruction list the instructions that can't be
2170  * represented with very simple instructions with no register
2171  * requirements.
2172  */
2173 void
2174 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2175 {
2176         MonoInst *ins, *next, *temp, *last_ins = NULL;
2177         int imm;
2178
2179         /* setup the virtual reg allocator */
2180         if (bb->max_vreg > cfg->rs->next_vreg)
2181                 cfg->rs->next_vreg = bb->max_vreg;
2182
2183         MONO_BB_FOR_EACH_INS (bb, ins) {
2184 loop_start:
2185                 switch (ins->opcode) {
2186                 case OP_IDIV_UN_IMM:
2187                 case OP_IDIV_IMM:
2188                 case OP_IREM_IMM:
2189                 case OP_IREM_UN_IMM:
2190                         NEW_INS (cfg, temp, OP_ICONST);
2191                         temp->inst_c0 = ins->inst_imm;
2192                         temp->dreg = mono_regstate_next_int (cfg->rs);
2193                         ins->sreg2 = temp->dreg;
2194                         if (ins->opcode == OP_IDIV_IMM)
2195                                 ins->opcode = OP_IDIV;
2196                         else if (ins->opcode == OP_IREM_IMM)
2197                                 ins->opcode = OP_IREM;
2198                         else if (ins->opcode == OP_IDIV_UN_IMM)
2199                                 ins->opcode = OP_IDIV_UN;
2200                         else if (ins->opcode == OP_IREM_UN_IMM)
2201                                 ins->opcode = OP_IREM_UN;
2202                         last_ins = temp;
2203                         /* handle rem separately */
2204                         goto loop_start;
2205                 case OP_IREM:
2206                 case OP_IREM_UN: {
2207                         MonoInst *mul;
2208                         /* we change a rem dest, src1, src2 to
2209                          * div temp1, src1, src2
2210                          * mul temp2, temp1, src2
2211                          * sub dest, src1, temp2
2212                          */
2213                         NEW_INS (cfg, mul, OP_IMUL);
2214                         NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2215                         temp->sreg1 = ins->sreg1;
2216                         temp->sreg2 = ins->sreg2;
2217                         temp->dreg = mono_regstate_next_int (cfg->rs);
2218                         mul->sreg1 = temp->dreg;
2219                         mul->sreg2 = ins->sreg2;
2220                         mul->dreg = mono_regstate_next_int (cfg->rs);
2221                         ins->opcode = OP_ISUB;
2222                         ins->sreg2 = mul->dreg;
2223                         break;
2224                 }
2225                 case OP_IADD_IMM:
2226                 case OP_ADD_IMM:
2227                 case OP_ADDCC_IMM:
2228                         if (!ppc_is_imm16 (ins->inst_imm)) {
2229                                 NEW_INS (cfg,  temp, OP_ICONST);
2230                                 temp->inst_c0 = ins->inst_imm;
2231                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2232                                 ins->sreg2 = temp->dreg;
2233                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2234                         }
2235                         break;
2236                 case OP_ISUB_IMM:
2237                 case OP_SUB_IMM:
2238                         if (!ppc_is_imm16 (-ins->inst_imm)) {
2239                                 NEW_INS (cfg, temp, OP_ICONST);
2240                                 temp->inst_c0 = ins->inst_imm;
2241                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2242                                 ins->sreg2 = temp->dreg;
2243                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2244                         }
2245                         break;
2246                 case OP_IAND_IMM:
2247                 case OP_IOR_IMM:
2248                 case OP_IXOR_IMM:
2249                 case OP_AND_IMM:
2250                 case OP_OR_IMM:
2251                 case OP_XOR_IMM:
2252                         if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2253                                 NEW_INS (cfg, temp, OP_ICONST);
2254                                 temp->inst_c0 = ins->inst_imm;
2255                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2256                                 ins->sreg2 = temp->dreg;
2257                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2258                         }
2259                         break;
2260                 case OP_ISBB_IMM:
2261                 case OP_IADC_IMM:
2262                 case OP_SBB_IMM:
2263                 case OP_SUBCC_IMM:
2264                 case OP_ADC_IMM:
2265                         NEW_INS (cfg, temp, OP_ICONST);
2266                         temp->inst_c0 = ins->inst_imm;
2267                         temp->dreg = mono_regstate_next_int (cfg->rs);
2268                         ins->sreg2 = temp->dreg;
2269                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2270                         break;
2271                 case OP_COMPARE_IMM:
2272                 case OP_ICOMPARE_IMM:
2273                         next = ins->next;
2274                         /* Branch opts can eliminate the branch */
2275                         if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2276                                 ins->opcode = OP_NOP;
2277                                 break;
2278                         }
2279                         g_assert(next);
2280                         if (compare_opcode_is_unsigned (next->opcode)) {
2281                                 if (!ppc_is_uimm16 (ins->inst_imm)) {
2282                                         NEW_INS (cfg, temp, OP_ICONST);
2283                                         temp->inst_c0 = ins->inst_imm;
2284                                         temp->dreg = mono_regstate_next_int (cfg->rs);
2285                                         ins->sreg2 = temp->dreg;
2286                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2287                                 }
2288                         } else {
2289                                 if (!ppc_is_imm16 (ins->inst_imm)) {
2290                                         NEW_INS (cfg, temp, OP_ICONST);
2291                                         temp->inst_c0 = ins->inst_imm;
2292                                         temp->dreg = mono_regstate_next_int (cfg->rs);
2293                                         ins->sreg2 = temp->dreg;
2294                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2295                                 }
2296                         }
2297                         break;
2298                 case OP_IMUL_IMM:
2299                 case OP_MUL_IMM:
2300                         if (ins->inst_imm == 1) {
2301                                 ins->opcode = OP_MOVE;
2302                                 break;
2303                         }
2304                         if (ins->inst_imm == 0) {
2305                                 ins->opcode = OP_ICONST;
2306                                 ins->inst_c0 = 0;
2307                                 break;
2308                         }
2309                         imm = mono_is_power_of_two (ins->inst_imm);
2310                         if (imm > 0) {
2311                                 ins->opcode = OP_SHL_IMM;
2312                                 ins->inst_imm = imm;
2313                                 break;
2314                         }
2315                         if (!ppc_is_imm16 (ins->inst_imm)) {
2316                                 NEW_INS (cfg, temp, OP_ICONST);
2317                                 temp->inst_c0 = ins->inst_imm;
2318                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2319                                 ins->sreg2 = temp->dreg;
2320                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2321                         }
2322                         break;
2323                 case OP_LOCALLOC_IMM:
2324                         NEW_INS (cfg, temp, OP_ICONST);
2325                         temp->inst_c0 = ins->inst_imm;
2326                         temp->dreg = mono_regstate_next_int (cfg->rs);
2327                         ins->sreg1 = temp->dreg;
2328                         ins->opcode = OP_LOCALLOC;
2329                         break;
2330                 case OP_LOAD_MEMBASE:
2331                 case OP_LOADI4_MEMBASE:
2332                 case OP_LOADU4_MEMBASE:
2333                 case OP_LOADI2_MEMBASE:
2334                 case OP_LOADU2_MEMBASE:
2335                 case OP_LOADI1_MEMBASE:
2336                 case OP_LOADU1_MEMBASE:
2337                 case OP_LOADR4_MEMBASE:
2338                 case OP_LOADR8_MEMBASE:
2339                 case OP_STORE_MEMBASE_REG:
2340                 case OP_STOREI4_MEMBASE_REG:
2341                 case OP_STOREI2_MEMBASE_REG:
2342                 case OP_STOREI1_MEMBASE_REG:
2343                 case OP_STORER4_MEMBASE_REG:
2344                 case OP_STORER8_MEMBASE_REG:
2345                         /* we can do two things: load the immed in a register
2346                          * and use an indexed load, or see if the immed can be
2347                          * represented as an ad_imm + a load with a smaller offset
2348                          * that fits. We just do the first for now, optimize later.
2349                          */
2350                         if (ppc_is_imm16 (ins->inst_offset))
2351                                 break;
2352                         NEW_INS (cfg, temp, OP_ICONST);
2353                         temp->inst_c0 = ins->inst_offset;
2354                         temp->dreg = mono_regstate_next_int (cfg->rs);
2355                         ins->sreg2 = temp->dreg;
2356                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2357                         break;
2358                 case OP_STORE_MEMBASE_IMM:
2359                 case OP_STOREI1_MEMBASE_IMM:
2360                 case OP_STOREI2_MEMBASE_IMM:
2361                 case OP_STOREI4_MEMBASE_IMM:
2362                         NEW_INS (cfg, temp, OP_ICONST);
2363                         temp->inst_c0 = ins->inst_imm;
2364                         temp->dreg = mono_regstate_next_int (cfg->rs);
2365                         ins->sreg1 = temp->dreg;
2366                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2367                         last_ins = temp;
2368                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
2369                 case OP_R8CONST:
2370                 case OP_R4CONST:
2371                         NEW_INS (cfg, temp, OP_ICONST);
2372                         temp->inst_c0 = (guint32)ins->inst_p0;
2373                         temp->dreg = mono_regstate_next_int (cfg->rs);
2374                         ins->inst_basereg = temp->dreg;
2375                         ins->inst_offset = 0;
2376                         ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2377                         last_ins = temp;
2378                         /* make it handle the possibly big ins->inst_offset
2379                          * later optimize to use lis + load_membase
2380                          */
2381                         goto loop_start;
2382                 }
2383                 last_ins = ins;
2384         }
2385         bb->last_ins = last_ins;
2386         bb->max_vreg = cfg->rs->next_vreg;
2387         
2388 }
2389
2390 static guchar*
2391 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2392 {
2393         /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2394         ppc_fctiwz (code, ppc_f0, sreg);
2395         ppc_stfd (code, ppc_f0, -8, ppc_sp);
2396         ppc_lwz (code, dreg, -4, ppc_sp);
2397         if (!is_signed) {
2398                 if (size == 1)
2399                         ppc_andid (code, dreg, dreg, 0xff);
2400                 else if (size == 2)
2401                         ppc_andid (code, dreg, dreg, 0xffff);
2402         } else {
2403                 if (size == 1)
2404                         ppc_extsb (code, dreg, dreg);
2405                 else if (size == 2)
2406                         ppc_extsh (code, dreg, dreg);
2407         }
2408         return code;
2409 }
2410
2411 typedef struct {
2412         guchar *code;
2413         const guchar *target;
2414         int absolute;
2415         int found;
2416 } PatchData;
2417
2418 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2419
2420 static int
2421 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2422         PatchData *pdata = (PatchData*)user_data;
2423         guchar *code = data;
2424         guint32 *thunks = data;
2425         guint32 *endthunks = (guint32*)(code + bsize);
2426         guint32 load [2];
2427         guchar *templ;
2428         int count = 0;
2429         int difflow, diffhigh;
2430
2431         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2432         difflow = (char*)pdata->code - (char*)thunks;
2433         diffhigh = (char*)pdata->code - (char*)endthunks;
2434         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2435                 return 0;
2436
2437         templ = (guchar*)load;
2438         ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2439         ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2440
2441         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2442         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2443                 while (thunks < endthunks) {
2444                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2445                         if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2446                                 ppc_patch (pdata->code, (guchar*)thunks);
2447                                 mono_arch_flush_icache (pdata->code, 4);
2448                                 pdata->found = 1;
2449                                 /*{
2450                                         static int num_thunks = 0;
2451                                         num_thunks++;
2452                                         if ((num_thunks % 20) == 0)
2453                                                 g_print ("num_thunks lookup: %d\n", num_thunks);
2454                                 }*/
2455                                 return 1;
2456                         } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2457                                 /* found a free slot instead: emit thunk */
2458                                 code = (guchar*)thunks;
2459                                 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2460                                 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2461                                 ppc_mtctr (code, ppc_r0);
2462                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2463                                 mono_arch_flush_icache ((guchar*)thunks, 16);
2464
2465                                 ppc_patch (pdata->code, (guchar*)thunks);
2466                                 mono_arch_flush_icache (pdata->code, 4);
2467                                 pdata->found = 1;
2468                                 /*{
2469                                         static int num_thunks = 0;
2470                                         num_thunks++;
2471                                         if ((num_thunks % 20) == 0)
2472                                                 g_print ("num_thunks: %d\n", num_thunks);
2473                                 }*/
2474                                 return 1;
2475                         }
2476                         /* skip 16 bytes, the size of the thunk */
2477                         thunks += 4;
2478                         count++;
2479                 }
2480                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2481         }
2482         return 0;
2483 }
2484
2485 static void
2486 handle_thunk (int absolute, guchar *code, const guchar *target) {
2487         MonoDomain *domain = mono_domain_get ();
2488         PatchData pdata;
2489
2490         pdata.code = code;
2491         pdata.target = target;
2492         pdata.absolute = absolute;
2493         pdata.found = 0;
2494
2495         mono_domain_lock (domain);
2496         mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2497
2498         if (!pdata.found) {
2499                 /* this uses the first available slot */
2500                 pdata.found = 2;
2501                 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2502         }
2503         mono_domain_unlock (domain);
2504
2505         if (pdata.found != 1)
2506                 g_print ("thunk failed for %p from %p\n", target, code);
2507         g_assert (pdata.found == 1);
2508 }
2509
2510 void
2511 ppc_patch (guchar *code, const guchar *target)
2512 {
2513         guint32 ins = *(guint32*)code;
2514         guint32 prim = ins >> 26;
2515         guint32 ovf;
2516
2517         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2518         if (prim == 18) {
2519                 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2520                 gint diff = target - code;
2521                 if (diff >= 0){
2522                         if (diff <= 33554431){
2523                                 ins = (18 << 26) | (diff) | (ins & 1);
2524                                 *(guint32*)code = ins;
2525                                 return;
2526                         }
2527                 } else {
2528                         /* diff between 0 and -33554432 */
2529                         if (diff >= -33554432){
2530                                 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2531                                 *(guint32*)code = ins;
2532                                 return;
2533                         }
2534                 }
2535                 
2536                 if ((glong)target >= 0){
2537                         if ((glong)target <= 33554431){
2538                                 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2539                                 *(guint32*)code = ins;
2540                                 return;
2541                         }
2542                 } else {
2543                         if ((glong)target >= -33554432){
2544                                 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2545                                 *(guint32*)code = ins;
2546                                 return;
2547                         }
2548                 }
2549
2550                 handle_thunk (TRUE, code, target);
2551                 return;
2552
2553                 g_assert_not_reached ();
2554         }
2555         
2556         
2557         if (prim == 16) {
2558                 // absolute address
2559                 if (ins & 2) {
2560                         guint32 li = (guint32)target;
2561                         ins = (ins & 0xffff0000) | (ins & 3);
2562                         ovf  = li & 0xffff0000;
2563                         if (ovf != 0 && ovf != 0xffff0000)
2564                                 g_assert_not_reached ();
2565                         li &= 0xffff;
2566                         ins |= li;
2567                         // FIXME: assert the top bits of li are 0
2568                 } else {
2569                         gint diff = target - code;
2570                         ins = (ins & 0xffff0000) | (ins & 3);
2571                         ovf  = diff & 0xffff0000;
2572                         if (ovf != 0 && ovf != 0xffff0000)
2573                                 g_assert_not_reached ();
2574                         diff &= 0xffff;
2575                         ins |= diff;
2576                 }
2577                 *(guint32*)code = ins;
2578                 return;
2579         }
2580
2581         if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2582                 guint32 *seq;
2583                 /* the trampoline code will try to patch the blrl, blr, bcctr */
2584                 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2585                         code -= 12;
2586                 }
2587                 /* this is the lis/ori/mtlr/blrl sequence */
2588                 seq = (guint32*)code;
2589                 g_assert ((seq [0] >> 26) == 15);
2590                 g_assert ((seq [1] >> 26) == 24);
2591                 g_assert ((seq [2] >> 26) == 31);
2592                 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2593                 /* FIXME: make this thread safe */
2594                 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2595                 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2596                 mono_arch_flush_icache (code - 8, 8);
2597         } else {
2598                 g_assert_not_reached ();
2599         }
2600 //      g_print ("patched with 0x%08x\n", ins);
2601 }
2602
2603 static guint8*
2604 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2605 {
2606         switch (ins->opcode) {
2607         case OP_FCALL:
2608         case OP_FCALL_REG:
2609         case OP_FCALL_MEMBASE:
2610                 if (ins->dreg != ppc_f1)
2611                         ppc_fmr (code, ins->dreg, ppc_f1);
2612                 break;
2613         }
2614
2615         return code;
2616 }
2617
2618 /*
2619  * emit_load_volatile_arguments:
2620  *
2621  *  Load volatile arguments from the stack to the original input registers.
2622  * Required before a tail call.
2623  */
2624 static guint8*
2625 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2626 {
2627         MonoMethod *method = cfg->method;
2628         MonoMethodSignature *sig;
2629         MonoInst *inst;
2630         CallInfo *cinfo;
2631         guint32 i, pos;
2632         int struct_index = 0;
2633
2634         /* FIXME: Generate intermediate code instead */
2635
2636         sig = mono_method_signature (method);
2637
2638         /* This is the opposite of the code in emit_prolog */
2639
2640         pos = 0;
2641
2642         cinfo = calculate_sizes (sig, sig->pinvoke);
2643
2644         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2645                 ArgInfo *ainfo = &cinfo->ret;
2646                 inst = cfg->vret_addr;
2647                 g_assert (ppc_is_imm16 (inst->inst_offset));
2648                 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2649         }
2650         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2651                 ArgInfo *ainfo = cinfo->args + i;
2652                 inst = cfg->args [pos];
2653
2654                 g_assert (inst->opcode != OP_REGVAR);
2655                 g_assert (ppc_is_imm16 (inst->inst_offset));
2656
2657                 switch (ainfo->regtype) {
2658                 case RegTypeGeneral:
2659                         switch (ainfo->size) {
2660                                 case 1:
2661                                         ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2662                                         break;
2663                                 case 2:
2664                                         ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2665                                         break;
2666                                 default:
2667                                         ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2668                                         break;
2669                         }
2670                         break;
2671
2672                 case RegTypeFP:
2673                         switch (ainfo->size) {
2674                                 case 4:
2675                                         ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2676                                         break;
2677                                 case 8:
2678                                         ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2679                                         break;
2680                                 default:
2681                                         g_assert_not_reached ();
2682                         }
2683                         break;
2684
2685                 case RegTypeBase:
2686                         /* FIXME: */
2687                         NOT_IMPLEMENTED;
2688
2689                 case RegTypeStructByVal: {
2690                         guint32 size = 0;
2691
2692                         /* FIXME: */
2693                         if (ainfo->vtsize)
2694                                 NOT_IMPLEMENTED;
2695 #ifdef __APPLE__
2696                         /*
2697                          * Darwin pinvokes needs some special handling
2698                          * for 1 and 2 byte arguments
2699                          */
2700                         if (method->signature->pinvoke)
2701                                 size = mono_class_native_size (inst->klass, NULL);
2702                         if (size == 1 || size == 2) {
2703                                 /* FIXME: */
2704                                 NOT_IMPLEMENTED;
2705                         } else
2706 #endif
2707                                 for (i = 0; i < ainfo->size; ++i) {
2708                                         ppc_lwz (code, ainfo->reg  + i,
2709                                                 inst->inst_offset + i * sizeof (gpointer), inst->inst_basereg);
2710                                 }
2711                         break;
2712                 }
2713
2714                 case RegTypeStructByAddr: {
2715                         MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2716
2717                         g_assert (ppc_is_imm16 (addr->inst_offset));
2718                         g_assert (!ainfo->offset);
2719                         ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2720
2721                         struct_index++;
2722                         break;
2723                 }
2724
2725                 default:
2726                         g_assert_not_reached ();
2727                 }
2728
2729                 pos ++;
2730         }
2731
2732         g_free (cinfo);
2733
2734         return code;
2735 }
2736
2737 void
2738 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2739 {
2740         MonoInst *ins, *next;
2741         MonoCallInst *call;
2742         guint offset;
2743         guint8 *code = cfg->native_code + cfg->code_len;
2744         MonoInst *last_ins = NULL;
2745         guint last_offset = 0;
2746         int max_len, cpos;
2747
2748         /* we don't align basic blocks of loops on ppc */
2749
2750         if (cfg->verbose_level > 2)
2751                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2752
2753         cpos = bb->max_offset;
2754
2755         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2756                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2757                 //g_assert (!mono_compile_aot);
2758                 //cpos += 6;
2759                 //if (bb->cil_code)
2760                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2761                 /* this is not thread save, but good enough */
2762                 /* fixme: howto handle overflows? */
2763                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
2764         }
2765
2766         MONO_BB_FOR_EACH_INS (bb, ins) {
2767                 offset = code - cfg->native_code;
2768
2769                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2770
2771                 if (offset > (cfg->code_size - max_len - 16)) {
2772                         cfg->code_size *= 2;
2773                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2774                         code = cfg->native_code + offset;
2775                 }
2776         //      if (ins->cil_code)
2777         //              g_print ("cil code\n");
2778                 mono_debug_record_line_number (cfg, ins, offset);
2779
2780                 switch (ins->opcode) {
2781                 case OP_RELAXED_NOP:
2782                 case OP_NOP:
2783                 case OP_DUMMY_USE:
2784                 case OP_DUMMY_STORE:
2785                 case OP_NOT_REACHED:
2786                 case OP_NOT_NULL:
2787                         break;
2788                 case OP_TLS_GET:
2789                         emit_tls_access (code, ins->dreg, ins->inst_offset);
2790                         break;
2791                 case OP_BIGMUL:
2792                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2793                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2794                         ppc_mr (code, ppc_r4, ppc_r0);
2795                         break;
2796                 case OP_BIGMUL_UN:
2797                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2798                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2799                         ppc_mr (code, ppc_r4, ppc_r0);
2800                         break;
2801                 case OP_MEMORY_BARRIER:
2802                         ppc_sync (code);
2803                         break;
2804                 case OP_STOREI1_MEMBASE_REG:
2805                         if (ppc_is_imm16 (ins->inst_offset)) {
2806                                 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2807                         } else {
2808                                 ppc_load (code, ppc_r0, ins->inst_offset);
2809                                 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2810                         }
2811                         break;
2812                 case OP_STOREI2_MEMBASE_REG:
2813                         if (ppc_is_imm16 (ins->inst_offset)) {
2814                                 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2815                         } else {
2816                                 ppc_load (code, ppc_r0, ins->inst_offset);
2817                                 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2818                         }
2819                         break;
2820                 case OP_STORE_MEMBASE_REG:
2821                 case OP_STOREI4_MEMBASE_REG:
2822                         if (ppc_is_imm16 (ins->inst_offset)) {
2823                                 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2824                         } else {
2825                                 ppc_load (code, ppc_r0, ins->inst_offset);
2826                                 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2827                         }
2828                         break;
2829                 case OP_STOREI1_MEMINDEX:
2830                         ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2831                         break;
2832                 case OP_STOREI2_MEMINDEX:
2833                         ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2834                         break;
2835                 case OP_STORE_MEMINDEX:
2836                 case OP_STOREI4_MEMINDEX:
2837                         ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2838                         break;
2839                 case OP_LOADU4_MEM:
2840                         g_assert_not_reached ();
2841                         break;
2842                 case OP_LOAD_MEMBASE:
2843                 case OP_LOADI4_MEMBASE:
2844                 case OP_LOADU4_MEMBASE:
2845                         if (ppc_is_imm16 (ins->inst_offset)) {
2846                                 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2847                         } else {
2848                                 ppc_load (code, ppc_r0, ins->inst_offset);
2849                                 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2850                         }
2851                         break;
2852                 case OP_LOADI1_MEMBASE:
2853                 case OP_LOADU1_MEMBASE:
2854                         if (ppc_is_imm16 (ins->inst_offset)) {
2855                                 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2856                         } else {
2857                                 ppc_load (code, ppc_r0, ins->inst_offset);
2858                                 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2859                         }
2860                         if (ins->opcode == OP_LOADI1_MEMBASE)
2861                                 ppc_extsb (code, ins->dreg, ins->dreg);
2862                         break;
2863                 case OP_LOADU2_MEMBASE:
2864                         if (ppc_is_imm16 (ins->inst_offset)) {
2865                                 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2866                         } else {
2867                                 ppc_load (code, ppc_r0, ins->inst_offset);
2868                                 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2869                         }
2870                         break;
2871                 case OP_LOADI2_MEMBASE:
2872                         if (ppc_is_imm16 (ins->inst_offset)) {
2873                                 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2874                         } else {
2875                                 ppc_load (code, ppc_r0, ins->inst_offset);
2876                                 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2877                         }
2878                         break;
2879                 case OP_LOAD_MEMINDEX:
2880                 case OP_LOADI4_MEMINDEX:
2881                 case OP_LOADU4_MEMINDEX:
2882                         ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2883                         break;
2884                 case OP_LOADU2_MEMINDEX:
2885                         ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2886                         break;
2887                 case OP_LOADI2_MEMINDEX:
2888                         ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2889                         break;
2890                 case OP_LOADU1_MEMINDEX:
2891                         ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2892                         break;
2893                 case OP_LOADI1_MEMINDEX:
2894                         ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2895                         ppc_extsb (code, ins->dreg, ins->dreg);
2896                         break;
2897                 case OP_ICONV_TO_I1:
2898                         ppc_extsb (code, ins->dreg, ins->sreg1);
2899                         break;
2900                 case OP_ICONV_TO_I2:
2901                         ppc_extsh (code, ins->dreg, ins->sreg1);
2902                         break;
2903                 case OP_ICONV_TO_U1:
2904                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2905                         break;
2906                 case OP_ICONV_TO_U2:
2907                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2908                         break;
2909                 case OP_COMPARE:
2910                 case OP_ICOMPARE:
2911                         next = ins->next;
2912                         if (next && compare_opcode_is_unsigned (next->opcode))
2913                                 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2914                         else
2915                                 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2916                         break;
2917                 case OP_COMPARE_IMM:
2918                 case OP_ICOMPARE_IMM:
2919                         next = ins->next;
2920                         if (next && compare_opcode_is_unsigned (next->opcode)) {
2921                                 if (ppc_is_uimm16 (ins->inst_imm)) {
2922                                         ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2923                                 } else {
2924                                         g_assert_not_reached ();
2925                                 }
2926                         } else {
2927                                 if (ppc_is_imm16 (ins->inst_imm)) {
2928                                         ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2929                                 } else {
2930                                         g_assert_not_reached ();
2931                                 }
2932                         }
2933                         break;
2934                 case OP_BREAK:
2935                         ppc_break (code);
2936                         break;
2937                 case OP_ADDCC:
2938                 case OP_IADDCC:
2939                         ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2940                         break;
2941                 case OP_IADD:
2942                         ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2943                         break;
2944                 case OP_ADC:
2945                 case OP_IADC:
2946                         ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2947                         break;
2948                 case OP_ADDCC_IMM:
2949                         if (ppc_is_imm16 (ins->inst_imm)) {
2950                                 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2951                         } else {
2952                                 g_assert_not_reached ();
2953                         }
2954                         break;
2955                 case OP_ADD_IMM:
2956                 case OP_IADD_IMM:
2957                         if (ppc_is_imm16 (ins->inst_imm)) {
2958                                 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2959                         } else {
2960                                 g_assert_not_reached ();
2961                         }
2962                         break;
2963                 case OP_IADD_OVF:
2964                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2965                          */
2966                         ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2967                         ppc_mfspr (code, ppc_r0, ppc_xer);
2968                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2969                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2970                         break;
2971                 case OP_IADD_OVF_UN:
2972                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2973                          */
2974                         ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2975                         ppc_mfspr (code, ppc_r0, ppc_xer);
2976                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2977                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2978                         break;
2979                 case OP_ISUB_OVF:
2980                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2981                          */
2982                         ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2983                         ppc_mfspr (code, ppc_r0, ppc_xer);
2984                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2985                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2986                         break;
2987                 case OP_ISUB_OVF_UN:
2988                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2989                          */
2990                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2991                         ppc_mfspr (code, ppc_r0, ppc_xer);
2992                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2993                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2994                         break;
2995                 case OP_ADD_OVF_CARRY:
2996                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2997                          */
2998                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2999                         ppc_mfspr (code, ppc_r0, ppc_xer);
3000                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3001                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3002                         break;
3003                 case OP_ADD_OVF_UN_CARRY:
3004                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3005                          */
3006                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3007                         ppc_mfspr (code, ppc_r0, ppc_xer);
3008                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3009                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3010                         break;
3011                 case OP_SUB_OVF_CARRY:
3012                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3013                          */
3014                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3015                         ppc_mfspr (code, ppc_r0, ppc_xer);
3016                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3017                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3018                         break;
3019                 case OP_SUB_OVF_UN_CARRY:
3020                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3021                          */
3022                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3023                         ppc_mfspr (code, ppc_r0, ppc_xer);
3024                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3025                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3026                         break;
3027                 case OP_SUBCC:
3028                 case OP_ISUBCC:
3029                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3030                         break;
3031                 case OP_ISUB:
3032                         ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3033                         break;
3034                 case OP_SBB:
3035                 case OP_ISBB:
3036                         ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3037                         break;
3038                 case OP_SUB_IMM:
3039                 case OP_ISUB_IMM:
3040                         // we add the negated value
3041                         if (ppc_is_imm16 (-ins->inst_imm))
3042                                 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3043                         else {
3044                                 g_assert_not_reached ();
3045                         }
3046                         break;
3047                 case OP_PPC_SUBFIC:
3048                         g_assert (ppc_is_imm16 (ins->inst_imm));
3049                         ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3050                         break;
3051                 case OP_PPC_SUBFZE:
3052                         ppc_subfze (code, ins->dreg, ins->sreg1);
3053                         break;
3054                 case OP_IAND:
3055                         /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3056                         ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3057                         break;
3058                 case OP_AND_IMM:
3059                 case OP_IAND_IMM:
3060                         if (!(ins->inst_imm & 0xffff0000)) {
3061                                 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3062                         } else if (!(ins->inst_imm & 0xffff)) {
3063                                 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3064                         } else {
3065                                 g_assert_not_reached ();
3066                         }
3067                         break;
3068                 case OP_IDIV: {
3069                         guint8 *divisor_is_m1;
3070                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3071                          */
3072                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3073                         divisor_is_m1 = code;
3074                         ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3075                         ppc_lis (code, ppc_r0, 0x8000);
3076                         ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
3077                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3078                         ppc_patch (divisor_is_m1, code);
3079                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3080                          */
3081                         ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3082                         ppc_mfspr (code, ppc_r0, ppc_xer);
3083                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3084                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3085                         break;
3086                 }
3087                 case OP_IDIV_UN:
3088                         ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3089                         ppc_mfspr (code, ppc_r0, ppc_xer);
3090                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3091                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3092                         break;
3093                 case OP_DIV_IMM:
3094                 case OP_IREM:
3095                 case OP_IREM_UN:
3096                 case OP_REM_IMM:
3097                         g_assert_not_reached ();
3098                 case OP_IOR:
3099                         ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3100                         break;
3101                 case OP_OR_IMM:
3102                 case OP_IOR_IMM:
3103                         if (!(ins->inst_imm & 0xffff0000)) {
3104                                 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3105                         } else if (!(ins->inst_imm & 0xffff)) {
3106                                 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3107                         } else {
3108                                 g_assert_not_reached ();
3109                         }
3110                         break;
3111                 case OP_IXOR:
3112                         ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3113                         break;
3114                 case OP_IXOR_IMM:
3115                 case OP_XOR_IMM:
3116                         if (!(ins->inst_imm & 0xffff0000)) {
3117                                 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3118                         } else if (!(ins->inst_imm & 0xffff)) {
3119                                 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3120                         } else {
3121                                 g_assert_not_reached ();
3122                         }
3123                         break;
3124                 case OP_ISHL:
3125                         ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3126                         break;
3127                 case OP_SHL_IMM:
3128                 case OP_ISHL_IMM:
3129                         ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3130                         break;
3131                 case OP_ISHR:
3132                         ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3133                         break;
3134                 case OP_SHR_IMM:
3135                 case OP_ISHR_IMM:
3136                         ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3137                         break;
3138                 case OP_SHR_UN_IMM:
3139                 case OP_ISHR_UN_IMM:
3140                         if (ins->inst_imm)
3141                                 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3142                         else
3143                                 ppc_mr (code, ins->dreg, ins->sreg1);
3144                         break;
3145                 case OP_ISHR_UN:
3146                         ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3147                         break;
3148                 case OP_INOT:
3149                         ppc_not (code, ins->dreg, ins->sreg1);
3150                         break;
3151                 case OP_INEG:
3152                         ppc_neg (code, ins->dreg, ins->sreg1);
3153                         break;
3154                 case OP_IMUL:
3155                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3156                         break;
3157                 case OP_IMUL_IMM:
3158                 case OP_MUL_IMM:
3159                         if (ppc_is_imm16 (ins->inst_imm)) {
3160                             ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3161                         } else {
3162                             g_assert_not_reached ();
3163                         }
3164                         break;
3165                 case OP_IMUL_OVF:
3166                         /* we annot use mcrxr, since it's not implemented on some processors 
3167                          * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3168                          */
3169                         ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3170                         ppc_mfspr (code, ppc_r0, ppc_xer);
3171                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3172                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3173                         break;
3174                 case OP_IMUL_OVF_UN:
3175                         /* we first multiply to get the high word and compare to 0
3176                          * to set the flags, then the result is discarded and then 
3177                          * we multiply to get the lower * bits result
3178                          */
3179                         ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3180                         ppc_cmpi (code, 0, 0, ppc_r0, 0);
3181                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3182                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3183                         break;
3184                 case OP_ICONST:
3185                         ppc_load (code, ins->dreg, ins->inst_c0);
3186                         break;
3187                 case OP_AOTCONST:
3188                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3189                         ppc_lis (code, ins->dreg, 0);
3190                         ppc_ori (code, ins->dreg, ins->dreg, 0);
3191                         break;
3192                 case OP_ICONV_TO_I4:
3193                 case OP_ICONV_TO_U4:
3194                 case OP_MOVE:
3195                         ppc_mr (code, ins->dreg, ins->sreg1);
3196                         break;
3197                 case OP_SETLRET: {
3198                         int saved = ins->sreg1;
3199                         if (ins->sreg1 == ppc_r3) {
3200                                 ppc_mr (code, ppc_r0, ins->sreg1);
3201                                 saved = ppc_r0;
3202                         }
3203                         if (ins->sreg2 != ppc_r3)
3204                                 ppc_mr (code, ppc_r3, ins->sreg2);
3205                         if (saved != ppc_r4)
3206                                 ppc_mr (code, ppc_r4, saved);
3207                         break;
3208                 }
3209                 case OP_FMOVE:
3210                         ppc_fmr (code, ins->dreg, ins->sreg1);
3211                         break;
3212                 case OP_FCONV_TO_R4:
3213                         ppc_frsp (code, ins->dreg, ins->sreg1);
3214                         break;
3215                 case OP_JMP: {
3216                         int i, pos = 0;
3217                         
3218                         /*
3219                          * Keep in sync with mono_arch_emit_epilog
3220                          */
3221                         g_assert (!cfg->method->save_lmf);
3222                         /*
3223                          * Note: we can use ppc_r11 here because it is dead anyway:
3224                          * we're leaving the method.
3225                          */
3226                         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3227                                 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3228                                         ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3229                                 } else {
3230                                         ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3231                                         ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3232                                 }
3233                                 ppc_mtlr (code, ppc_r0);
3234                         }
3235
3236                         code = emit_load_volatile_arguments (cfg, code);
3237
3238                         if (ppc_is_imm16 (cfg->stack_usage)) {
3239                                 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3240                         } else {
3241                                 ppc_load (code, ppc_r11, cfg->stack_usage);
3242                                 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3243                         }
3244                         if (!cfg->method->save_lmf) {
3245                                 /*for (i = 31; i >= 14; --i) {
3246                                         if (cfg->used_float_regs & (1 << i)) {
3247                                                 pos += sizeof (double);
3248                                                 ppc_lfd (code, i, -pos, cfg->frame_reg);
3249                                         }
3250                                 }*/
3251                                 for (i = 31; i >= 13; --i) {
3252                                         if (cfg->used_int_regs & (1 << i)) {
3253                                                 pos += sizeof (gulong);
3254                                                 ppc_lwz (code, i, -pos, cfg->frame_reg);
3255                                         }
3256                                 }
3257                         } else {
3258                                 /* FIXME restore from MonoLMF: though this can't happen yet */
3259                         }
3260                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3261                         ppc_b (code, 0);
3262                         break;
3263                 }
3264                 case OP_CHECK_THIS:
3265                         /* ensure ins->sreg1 is not NULL */
3266                         ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3267                         break;
3268                 case OP_ARGLIST: {
3269                         if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3270                                 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3271                         } else {
3272                                 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3273                                 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3274                         }
3275                         ppc_stw (code, ppc_r0, 0, ins->sreg1);
3276                         break;
3277                 }
3278                 case OP_FCALL:
3279                 case OP_LCALL:
3280                 case OP_VCALL:
3281                 case OP_VCALL2:
3282                 case OP_VOIDCALL:
3283                 case OP_CALL:
3284                         call = (MonoCallInst*)ins;
3285                         if (ins->flags & MONO_INST_HAS_METHOD)
3286                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3287                         else
3288                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3289                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3290                                 ppc_lis (code, ppc_r0, 0);
3291                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3292                                 ppc_mtlr (code, ppc_r0);
3293                                 ppc_blrl (code);
3294                         } else {
3295                                 ppc_bl (code, 0);
3296                         }
3297                         /* FIXME: this should be handled somewhere else in the new jit */
3298                         code = emit_move_return_value (cfg, ins, code);
3299                         break;
3300                 case OP_FCALL_REG:
3301                 case OP_LCALL_REG:
3302                 case OP_VCALL_REG:
3303                 case OP_VCALL2_REG:
3304                 case OP_VOIDCALL_REG:
3305                 case OP_CALL_REG:
3306                         ppc_mtlr (code, ins->sreg1);
3307                         ppc_blrl (code);
3308                         /* FIXME: this should be handled somewhere else in the new jit */
3309                         code = emit_move_return_value (cfg, ins, code);
3310                         break;
3311                 case OP_FCALL_MEMBASE:
3312                 case OP_LCALL_MEMBASE:
3313                 case OP_VCALL_MEMBASE:
3314                 case OP_VCALL2_MEMBASE:
3315                 case OP_VOIDCALL_MEMBASE:
3316                 case OP_CALL_MEMBASE:
3317                         ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3318                         ppc_mtlr (code, ppc_r0);
3319                         ppc_blrl (code);
3320                         /* FIXME: this should be handled somewhere else in the new jit */
3321                         code = emit_move_return_value (cfg, ins, code);
3322                         break;
3323                 case OP_OUTARG:
3324                         g_assert_not_reached ();
3325                         break;
3326                 case OP_LOCALLOC: {
3327                         guint8 * zero_loop_jump, * zero_loop_start;
3328                         /* keep alignment */
3329                         int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3330                         int area_offset = alloca_waste;
3331                         area_offset &= ~31;
3332                         ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3333                         ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3334                         /* use ctr to store the number of words to 0 if needed */
3335                         if (ins->flags & MONO_INST_INIT) {
3336                                 /* we zero 4 bytes at a time:
3337                                  * we add 7 instead of 3 so that we set the counter to
3338                                  * at least 1, otherwise the bdnz instruction will make
3339                                  * it negative and iterate billions of times.
3340                                  */
3341                                 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3342                                 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3343                                 ppc_mtctr (code, ppc_r0);
3344                         }
3345                         ppc_lwz (code, ppc_r0, 0, ppc_sp);
3346                         ppc_neg (code, ppc_r11, ppc_r11);
3347                         ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3348                         
3349                         if (ins->flags & MONO_INST_INIT) {
3350                                 /* adjust the dest reg by -4 so we can use stwu */
3351                                 /* we actually adjust -8 because we let the loop
3352                                  * run at least once
3353                                  */
3354                                 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3355                                 ppc_li (code, ppc_r11, 0);
3356                                 zero_loop_start = code;
3357                                 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3358                                 zero_loop_jump = code;
3359                                 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3360                                 ppc_patch (zero_loop_jump, zero_loop_start);
3361                         }
3362                         ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3363                         break;
3364                 }
3365                 case OP_THROW: {
3366                         //ppc_break (code);
3367                         ppc_mr (code, ppc_r3, ins->sreg1);
3368                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3369                                              (gpointer)"mono_arch_throw_exception");
3370                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3371                                 ppc_lis (code, ppc_r0, 0);
3372                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3373                                 ppc_mtlr (code, ppc_r0);
3374                                 ppc_blrl (code);
3375                         } else {
3376                                 ppc_bl (code, 0);
3377                         }
3378                         break;
3379                 }
3380                 case OP_RETHROW: {
3381                         //ppc_break (code);
3382                         ppc_mr (code, ppc_r3, ins->sreg1);
3383                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3384                                              (gpointer)"mono_arch_rethrow_exception");
3385                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3386                                 ppc_lis (code, ppc_r0, 0);
3387                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3388                                 ppc_mtlr (code, ppc_r0);
3389                                 ppc_blrl (code);
3390                         } else {
3391                                 ppc_bl (code, 0);
3392                         }
3393                         break;
3394                 }
3395                 case OP_START_HANDLER: {
3396                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3397                         ppc_mflr (code, ppc_r0);
3398                         if (ppc_is_imm16 (spvar->inst_offset)) {
3399                                 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3400                         } else {
3401                                 ppc_load (code, ppc_r11, spvar->inst_offset);
3402                                 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3403                         }
3404                         break;
3405                 }
3406                 case OP_ENDFILTER: {
3407                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3408                         if (ins->sreg1 != ppc_r3)
3409                                 ppc_mr (code, ppc_r3, ins->sreg1);
3410                         if (ppc_is_imm16 (spvar->inst_offset)) {
3411                                 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3412                         } else {
3413                                 ppc_load (code, ppc_r11, spvar->inst_offset);
3414                                 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3415                         }
3416                         ppc_mtlr (code, ppc_r0);
3417                         ppc_blr (code);
3418                         break;
3419                 }
3420                 case OP_ENDFINALLY: {
3421                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3422                         ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3423                         ppc_mtlr (code, ppc_r0);
3424                         ppc_blr (code);
3425                         break;
3426                 }
3427                 case OP_CALL_HANDLER: 
3428                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3429                         ppc_bl (code, 0);
3430                         break;
3431                 case OP_LABEL:
3432                         ins->inst_c0 = code - cfg->native_code;
3433                         break;
3434                 case OP_BR:
3435                         if (ins->flags & MONO_INST_BRLABEL) {
3436                                 /*if (ins->inst_i0->inst_c0) {
3437                                         ppc_b (code, 0);
3438                                         //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3439                                 } else*/ {
3440                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3441                                         ppc_b (code, 0);
3442                                 }
3443                         } else {
3444                                 /*if (ins->inst_target_bb->native_offset) {
3445                                         ppc_b (code, 0);
3446                                         //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
3447                                 } else*/ {
3448                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3449                                         ppc_b (code, 0);
3450                                 } 
3451                         }
3452                         break;
3453                 case OP_BR_REG:
3454                         ppc_mtctr (code, ins->sreg1);
3455                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3456                         break;
3457                 case OP_CEQ:
3458                 case OP_ICEQ:
3459                         ppc_li (code, ins->dreg, 0);
3460                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3461                         ppc_li (code, ins->dreg, 1);
3462                         break;
3463                 case OP_CLT:
3464                 case OP_CLT_UN:
3465                 case OP_ICLT:
3466                 case OP_ICLT_UN:
3467                         ppc_li (code, ins->dreg, 1);
3468                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3469                         ppc_li (code, ins->dreg, 0);
3470                         break;
3471                 case OP_CGT:
3472                 case OP_CGT_UN:
3473                 case OP_ICGT:
3474                 case OP_ICGT_UN:
3475                         ppc_li (code, ins->dreg, 1);
3476                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3477                         ppc_li (code, ins->dreg, 0);
3478                         break;
3479                 case OP_COND_EXC_EQ:
3480                 case OP_COND_EXC_NE_UN:
3481                 case OP_COND_EXC_LT:
3482                 case OP_COND_EXC_LT_UN:
3483                 case OP_COND_EXC_GT:
3484                 case OP_COND_EXC_GT_UN:
3485                 case OP_COND_EXC_GE:
3486                 case OP_COND_EXC_GE_UN:
3487                 case OP_COND_EXC_LE:
3488                 case OP_COND_EXC_LE_UN:
3489                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3490                         break;
3491                 case OP_COND_EXC_IEQ:
3492                 case OP_COND_EXC_INE_UN:
3493                 case OP_COND_EXC_ILT:
3494                 case OP_COND_EXC_ILT_UN:
3495                 case OP_COND_EXC_IGT:
3496                 case OP_COND_EXC_IGT_UN:
3497                 case OP_COND_EXC_IGE:
3498                 case OP_COND_EXC_IGE_UN:
3499                 case OP_COND_EXC_ILE:
3500                 case OP_COND_EXC_ILE_UN:
3501                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3502                         break;
3503                 case OP_COND_EXC_C:
3504                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3505                          */
3506                         /*ppc_mfspr (code, ppc_r0, ppc_xer);
3507                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3508                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3509                         break;*/
3510                 case OP_COND_EXC_OV:
3511                         /*ppc_mcrxr (code, 0);
3512                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3513                         break;*/
3514                 case OP_COND_EXC_NC:
3515                 case OP_COND_EXC_NO:
3516                         g_assert_not_reached ();
3517                         break;
3518                 case OP_IBEQ:
3519                 case OP_IBNE_UN:
3520                 case OP_IBLT:
3521                 case OP_IBLT_UN:
3522                 case OP_IBGT:
3523                 case OP_IBGT_UN:
3524                 case OP_IBGE:
3525                 case OP_IBGE_UN:
3526                 case OP_IBLE:
3527                 case OP_IBLE_UN:
3528                         EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3529                         break;
3530
3531                 /* floating point opcodes */
3532                 case OP_R8CONST:
3533                 case OP_R4CONST:
3534                         g_assert_not_reached ();
3535                 case OP_STORER8_MEMBASE_REG:
3536                         if (ppc_is_imm16 (ins->inst_offset)) {
3537                                 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3538                         } else {
3539                                 ppc_load (code, ppc_r0, ins->inst_offset);
3540                                 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3541                         }
3542                         break;
3543                 case OP_LOADR8_MEMBASE:
3544                         if (ppc_is_imm16 (ins->inst_offset)) {
3545                                 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3546                         } else {
3547                                 ppc_load (code, ppc_r0, ins->inst_offset);
3548                                 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3549                         }
3550                         break;
3551                 case OP_STORER4_MEMBASE_REG:
3552                         ppc_frsp (code, ins->sreg1, ins->sreg1);
3553                         if (ppc_is_imm16 (ins->inst_offset)) {
3554                                 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3555                         } else {
3556                                 ppc_load (code, ppc_r0, ins->inst_offset);
3557                                 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3558                         }
3559                         break;
3560                 case OP_LOADR4_MEMBASE:
3561                         if (ppc_is_imm16 (ins->inst_offset)) {
3562                                 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3563                         } else {
3564                                 ppc_load (code, ppc_r0, ins->inst_offset);
3565                                 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3566                         }
3567                         break;
3568                 case OP_LOADR4_MEMINDEX:
3569                         ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3570                         break;
3571                 case OP_LOADR8_MEMINDEX:
3572                         ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3573                         break;
3574                 case OP_STORER4_MEMINDEX:
3575                         ppc_frsp (code, ins->sreg1, ins->sreg1);
3576                         ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3577                         break;
3578                 case OP_STORER8_MEMINDEX:
3579                         ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3580                         break;
3581                 case CEE_CONV_R_UN:
3582                 case CEE_CONV_R4: /* FIXME: change precision */
3583                 case CEE_CONV_R8:
3584                         g_assert_not_reached ();
3585                 case OP_FCONV_TO_I1:
3586                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3587                         break;
3588                 case OP_FCONV_TO_U1:
3589                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3590                         break;
3591                 case OP_FCONV_TO_I2:
3592                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3593                         break;
3594                 case OP_FCONV_TO_U2:
3595                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3596                         break;
3597                 case OP_FCONV_TO_I4:
3598                 case OP_FCONV_TO_I:
3599                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3600                         break;
3601                 case OP_FCONV_TO_U4:
3602                 case OP_FCONV_TO_U:
3603                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3604                         break;
3605                 case OP_FCONV_TO_I8:
3606                 case OP_FCONV_TO_U8:
3607                         g_assert_not_reached ();
3608                         /* Implemented as helper calls */
3609                         break;
3610                 case OP_LCONV_TO_R_UN:
3611                         g_assert_not_reached ();
3612                         /* Implemented as helper calls */
3613                         break;
3614                 case OP_LCONV_TO_OVF_I4_2:
3615                 case OP_LCONV_TO_OVF_I: {
3616                         guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3617                         // Check if its negative
3618                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3619                         negative_branch = code;
3620                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3621                         // Its positive msword == 0
3622                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3623                         msword_positive_branch = code;
3624                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3625
3626                         ovf_ex_target = code;
3627                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3628                         // Negative
3629                         ppc_patch (negative_branch, code);
3630                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3631                         msword_negative_branch = code;
3632                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3633                         ppc_patch (msword_negative_branch, ovf_ex_target);
3634                         
3635                         ppc_patch (msword_positive_branch, code);
3636                         if (ins->dreg != ins->sreg1)
3637                                 ppc_mr (code, ins->dreg, ins->sreg1);
3638                         break;
3639                 }
3640                 case OP_SQRT:
3641                         ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3642                         break;
3643                 case OP_FADD:
3644                         ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3645                         break;
3646                 case OP_FSUB:
3647                         ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3648                         break;          
3649                 case OP_FMUL:
3650                         ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3651                         break;          
3652                 case OP_FDIV:
3653                         ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3654                         break;          
3655                 case OP_FNEG:
3656                         ppc_fneg (code, ins->dreg, ins->sreg1);
3657                         break;          
3658                 case OP_FREM:
3659                         /* emulated */
3660                         g_assert_not_reached ();
3661                         break;
3662                 case OP_FCOMPARE:
3663                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3664                         break;
3665                 case OP_FCEQ:
3666                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3667                         ppc_li (code, ins->dreg, 0);
3668                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3669                         ppc_li (code, ins->dreg, 1);
3670                         break;
3671                 case OP_FCLT:
3672                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3673                         ppc_li (code, ins->dreg, 1);
3674                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3675                         ppc_li (code, ins->dreg, 0);
3676                         break;
3677                 case OP_FCLT_UN:
3678                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3679                         ppc_li (code, ins->dreg, 1);
3680                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3681                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3682                         ppc_li (code, ins->dreg, 0);
3683                         break;
3684                 case OP_FCGT:
3685                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3686                         ppc_li (code, ins->dreg, 1);
3687                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3688                         ppc_li (code, ins->dreg, 0);
3689                         break;
3690                 case OP_FCGT_UN:
3691                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3692                         ppc_li (code, ins->dreg, 1);
3693                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3694                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3695                         ppc_li (code, ins->dreg, 0);
3696                         break;
3697                 case OP_FBEQ:
3698                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3699                         break;
3700                 case OP_FBNE_UN:
3701                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3702                         break;
3703                 case OP_FBLT:
3704                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3705                         EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3706                         break;
3707                 case OP_FBLT_UN:
3708                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3709                         EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3710                         break;
3711                 case OP_FBGT:
3712                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3713                         EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3714                         break;
3715                 case OP_FBGT_UN:
3716                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3717                         EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3718                         break;
3719                 case OP_FBGE:
3720                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3721                         EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3722                         break;
3723                 case OP_FBGE_UN:
3724                         EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3725                         break;
3726                 case OP_FBLE:
3727                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3728                         EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3729                         break;
3730                 case OP_FBLE_UN:
3731                         EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3732                         break;
3733                 case OP_CKFINITE:
3734                         g_assert_not_reached ();
3735                 case OP_CHECK_FINITE: {
3736                         ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3737                         ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3738                         ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3739                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3740                         break;
3741                 case OP_JUMP_TABLE:
3742                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3743                         ppc_load (code, ins->dreg, 0x0f0f0f0f);
3744                         break;
3745                 }
3746                 default:
3747                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3748                         g_assert_not_reached ();
3749                 }
3750
3751                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3752                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3753                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3754                         g_assert_not_reached ();
3755                 }
3756                
3757                 cpos += max_len;
3758
3759                 last_ins = ins;
3760                 last_offset = offset;
3761         }
3762
3763         cfg->code_len = code - cfg->native_code;
3764 }
3765
3766 void
3767 mono_arch_register_lowlevel_calls (void)
3768 {
3769 }
3770
3771 #define patch_lis_ori(ip,val) do {\
3772                 guint16 *__lis_ori = (guint16*)(ip);    \
3773                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
3774                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
3775         } while (0)
3776
3777 void
3778 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3779 {
3780         MonoJumpInfo *patch_info;
3781
3782         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3783                 unsigned char *ip = patch_info->ip.i + code;
3784                 unsigned char *target;
3785
3786                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3787
3788                 switch (patch_info->type) {
3789                 case MONO_PATCH_INFO_IP:
3790                         patch_lis_ori (ip, ip);
3791                         continue;
3792                 case MONO_PATCH_INFO_METHOD_REL:
3793                         g_assert_not_reached ();
3794                         *((gpointer *)(ip)) = code + patch_info->data.offset;
3795                         continue;
3796                 case MONO_PATCH_INFO_SWITCH: {
3797                         gpointer *table = (gpointer *)patch_info->data.table->table;
3798                         int i;
3799
3800                         patch_lis_ori (ip, table);
3801
3802                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
3803                                 table [i] = (int)patch_info->data.table->table [i] + code;
3804                         }
3805                         /* we put into the table the absolute address, no need for ppc_patch in this case */
3806                         continue;
3807                 }
3808                 case MONO_PATCH_INFO_METHODCONST:
3809                 case MONO_PATCH_INFO_CLASS:
3810                 case MONO_PATCH_INFO_IMAGE:
3811                 case MONO_PATCH_INFO_FIELD:
3812                 case MONO_PATCH_INFO_VTABLE:
3813                 case MONO_PATCH_INFO_IID:
3814                 case MONO_PATCH_INFO_SFLDA:
3815                 case MONO_PATCH_INFO_LDSTR:
3816                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3817                 case MONO_PATCH_INFO_LDTOKEN:
3818                         /* from OP_AOTCONST : lis + ori */
3819                         patch_lis_ori (ip, target);
3820                         continue;
3821                 case MONO_PATCH_INFO_R4:
3822                 case MONO_PATCH_INFO_R8:
3823                         g_assert_not_reached ();
3824                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3825                         continue;
3826                 case MONO_PATCH_INFO_EXC_NAME:
3827                         g_assert_not_reached ();
3828                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3829                         continue;
3830                 case MONO_PATCH_INFO_NONE:
3831                 case MONO_PATCH_INFO_BB_OVF:
3832                 case MONO_PATCH_INFO_EXC_OVF:
3833                         /* everything is dealt with at epilog output time */
3834                         continue;
3835                 default:
3836                         break;
3837                 }
3838                 ppc_patch (ip, target);
3839         }
3840 }
3841
3842 /*
3843  * Stack frame layout:
3844  * 
3845  *   ------------------- sp
3846  *      MonoLMF structure or saved registers
3847  *   -------------------
3848  *      spilled regs
3849  *   -------------------
3850  *      locals
3851  *   -------------------
3852  *      optional 8 bytes for tracing
3853  *   -------------------
3854  *      param area             size is cfg->param_area
3855  *   -------------------
3856  *      linkage area           size is PPC_STACK_PARAM_OFFSET
3857  *   ------------------- sp
3858  *      red zone
3859  */
3860 guint8 *
3861 mono_arch_emit_prolog (MonoCompile *cfg)
3862 {
3863         MonoMethod *method = cfg->method;
3864         MonoBasicBlock *bb;
3865         MonoMethodSignature *sig;
3866         MonoInst *inst;
3867         int alloc_size, pos, max_offset, i;
3868         guint8 *code;
3869         CallInfo *cinfo;
3870         int tracing = 0;
3871         int lmf_offset = 0;
3872         int tailcall_struct_index;
3873
3874         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3875                 tracing = 1;
3876
3877         sig = mono_method_signature (method);
3878         cfg->code_size = 256 + sig->param_count * 20;
3879         code = cfg->native_code = g_malloc (cfg->code_size);
3880
3881         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3882                 ppc_mflr (code, ppc_r0);
3883                 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3884         }
3885
3886         alloc_size = cfg->stack_offset;
3887         pos = 0;
3888
3889         if (!method->save_lmf) {
3890                 /*for (i = 31; i >= 14; --i) {
3891                         if (cfg->used_float_regs & (1 << i)) {
3892                                 pos += sizeof (gdouble);
3893                                 ppc_stfd (code, i, -pos, ppc_sp);
3894                         }
3895                 }*/
3896                 for (i = 31; i >= 13; --i) {
3897                         if (cfg->used_int_regs & (1 << i)) {
3898                                 pos += sizeof (gulong);
3899                                 ppc_stw (code, i, -pos, ppc_sp);
3900                         }
3901                 }
3902         } else {
3903                 int ofs;
3904                 pos += sizeof (MonoLMF);
3905                 lmf_offset = pos;
3906                 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3907                 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3908                 for (i = 14; i < 32; i++) {
3909                         ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3910                 }
3911         }
3912         alloc_size += pos;
3913         // align to PPC_STACK_ALIGNMENT bytes
3914         if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3915                 alloc_size += PPC_STACK_ALIGNMENT - 1;
3916                 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3917         }
3918
3919         cfg->stack_usage = alloc_size;
3920         g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3921         if (alloc_size) {
3922                 if (ppc_is_imm16 (-alloc_size)) {
3923                         ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3924                 } else {
3925                         ppc_load (code, ppc_r11, -alloc_size);
3926                         ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3927                 }
3928         }
3929         if (cfg->frame_reg != ppc_sp)
3930                 ppc_mr (code, cfg->frame_reg, ppc_sp);
3931
3932         /* store runtime generic context */
3933         if (cfg->rgctx_var) {
3934                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
3935                                 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
3936
3937                 ppc_stw (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
3938         }
3939
3940         /* compute max_offset in order to use short forward jumps
3941          * we always do it on ppc because the immediate displacement
3942          * for jumps is too small 
3943          */
3944         max_offset = 0;
3945         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3946                 MonoInst *ins;
3947                 bb->max_offset = max_offset;
3948
3949                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3950                         max_offset += 6; 
3951
3952                 MONO_BB_FOR_EACH_INS (bb, ins)
3953                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3954         }
3955
3956         /* load arguments allocated to register from the stack */
3957         pos = 0;
3958
3959         cinfo = calculate_sizes (sig, sig->pinvoke);
3960
3961         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3962                 ArgInfo *ainfo = &cinfo->ret;
3963
3964                 if (cfg->new_ir)
3965                         inst = cfg->vret_addr;
3966                 else
3967                         inst = cfg->ret;
3968                 g_assert (inst);
3969
3970                 if (ppc_is_imm16 (inst->inst_offset)) {
3971                         ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3972                 } else {
3973                         ppc_load (code, ppc_r11, inst->inst_offset);
3974                         ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3975                 }
3976         }
3977
3978         tailcall_struct_index = 0;
3979         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3980                 ArgInfo *ainfo = cinfo->args + i;
3981                 inst = cfg->args [pos];
3982                 
3983                 if (cfg->verbose_level > 2)
3984                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3985                 if (inst->opcode == OP_REGVAR) {
3986                         if (ainfo->regtype == RegTypeGeneral)
3987                                 ppc_mr (code, inst->dreg, ainfo->reg);
3988                         else if (ainfo->regtype == RegTypeFP)
3989                                 ppc_fmr (code, inst->dreg, ainfo->reg);
3990                         else if (ainfo->regtype == RegTypeBase) {
3991                                 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3992                                 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3993                         } else
3994                                 g_assert_not_reached ();
3995
3996                         if (cfg->verbose_level > 2)
3997                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3998                 } else {
3999                         /* the argument should be put on the stack: FIXME handle size != word  */
4000                         if (ainfo->regtype == RegTypeGeneral) {
4001                                 switch (ainfo->size) {
4002                                 case 1:
4003                                         if (ppc_is_imm16 (inst->inst_offset)) {
4004                                                 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4005                                         } else {
4006                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4007                                                 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4008                                         }
4009                                         break;
4010                                 case 2:
4011                                         if (ppc_is_imm16 (inst->inst_offset)) {
4012                                                 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4013                                         } else {
4014                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4015                                                 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4016                                         }
4017                                         break;
4018                                 case 8:
4019                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
4020                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4021                                                 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4022                                         } else {
4023                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4024                                                 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4025                                                 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4026                                                 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4027                                         }
4028                                         break;
4029                                 default:
4030                                         if (ppc_is_imm16 (inst->inst_offset)) {
4031                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4032                                         } else {
4033                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4034                                                 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4035                                         }
4036                                         break;
4037                                 }
4038                         } else if (ainfo->regtype == RegTypeBase) {
4039                                 /* load the previous stack pointer in r11 */
4040                                 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4041                                 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
4042                                 switch (ainfo->size) {
4043                                 case 1:
4044                                         if (ppc_is_imm16 (inst->inst_offset)) {
4045                                                 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4046                                         } else {
4047                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4048                                                 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4049                                         }
4050                                         break;
4051                                 case 2:
4052                                         if (ppc_is_imm16 (inst->inst_offset)) {
4053                                                 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4054                                         } else {
4055                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4056                                                 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4057                                         }
4058                                         break;
4059                                 case 8:
4060                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
4061                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4062                                                 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4063                                                 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4064                                         } else {
4065                                                 /* FIXME */
4066                                                 g_assert_not_reached ();
4067                                         }
4068                                         break;
4069                                 default:
4070                                         if (ppc_is_imm16 (inst->inst_offset)) {
4071                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4072                                         } else {
4073                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4074                                                 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4075                                         }
4076                                         break;
4077                                 }
4078                         } else if (ainfo->regtype == RegTypeFP) {
4079                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4080                                 if (ainfo->size == 8)
4081                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4082                                 else if (ainfo->size == 4)
4083                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4084                                 else
4085                                         g_assert_not_reached ();
4086                         } else if (ainfo->regtype == RegTypeStructByVal) {
4087                                 int doffset = inst->inst_offset;
4088                                 int soffset = 0;
4089                                 int cur_reg;
4090                                 int size = 0;
4091                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4092                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4093                                 /* FIXME: what if there is no class? */
4094                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4095                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4096                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4097 #if __APPLE__
4098                                         /*
4099                                          * Darwin handles 1 and 2 byte
4100                                          * structs specially by
4101                                          * loading h/b into the arg
4102                                          * register.  Only done for
4103                                          * pinvokes.
4104                                          */
4105                                         if (size == 2)
4106                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4107                                         else if (size == 1)
4108                                                 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4109                                         else
4110 #endif
4111                                                 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4112                                         soffset += sizeof (gpointer);
4113                                         doffset += sizeof (gpointer);
4114                                 }
4115                                 if (ainfo->vtsize) {
4116                                         /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4117                                         ppc_lwz (code, ppc_r11, 0, ppc_sp);
4118                                         if ((size & 3) != 0) {
4119                                                 code = emit_memcpy (code, size - soffset,
4120                                                         inst->inst_basereg, doffset,
4121                                                         ppc_r11, ainfo->offset + soffset);
4122                                         } else {
4123                                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4124                                                         inst->inst_basereg, doffset,
4125                                                         ppc_r11, ainfo->offset + soffset);
4126                                         }
4127                                 }
4128                         } else if (ainfo->regtype == RegTypeStructByAddr) {
4129                                 /* if it was originally a RegTypeBase */
4130                                 if (ainfo->offset) {
4131                                         /* load the previous stack pointer in r11 */
4132                                         ppc_lwz (code, ppc_r11, 0, ppc_sp);
4133                                         ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4134                                 } else {
4135                                         ppc_mr (code, ppc_r11, ainfo->reg);
4136                                 }
4137
4138                                 if (cfg->tailcall_valuetype_addrs) {
4139                                         MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4140
4141                                         g_assert (ppc_is_imm16 (addr->inst_offset));
4142                                         ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4143
4144                                         tailcall_struct_index++;
4145                                 }
4146
4147                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4148                                 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4149                                 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4150                         } else
4151                                 g_assert_not_reached ();
4152                 }
4153                 pos++;
4154         }
4155
4156         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4157                 ppc_load (code, ppc_r3, cfg->domain);
4158                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4159                 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4160                         ppc_lis (code, ppc_r0, 0);
4161                         ppc_ori (code, ppc_r0, ppc_r0, 0);
4162                         ppc_mtlr (code, ppc_r0);
4163                         ppc_blrl (code);
4164                 } else {
4165                         ppc_bl (code, 0);
4166                 }
4167         }
4168
4169         if (method->save_lmf) {
4170                 if (lmf_pthread_key != -1) {
4171                         emit_tls_access (code, ppc_r3, lmf_pthread_key);
4172                         if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4173                                 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4174                 } else {
4175                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4176                                      (gpointer)"mono_get_lmf_addr");
4177                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4178                                 ppc_lis (code, ppc_r0, 0);
4179                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
4180                                 ppc_mtlr (code, ppc_r0);
4181                                 ppc_blrl (code);
4182                         } else {
4183                                 ppc_bl (code, 0);
4184                         }
4185                 }
4186                 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4187                 /* lmf_offset is the offset from the previous stack pointer,
4188                  * alloc_size is the total stack space allocated, so the offset
4189                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4190                  * The pointer to the struct is put in ppc_r11 (new_lmf).
4191                  * The callee-saved registers are already in the MonoLMF structure
4192                  */
4193                 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4194                 /* ppc_r3 is the result from mono_get_lmf_addr () */
4195                 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4196                 /* new_lmf->previous_lmf = *lmf_addr */
4197                 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4198                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4199                 /* *(lmf_addr) = r11 */
4200                 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4201                 /* save method info */
4202                 ppc_load (code, ppc_r0, method);
4203                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4204                 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4205                 /* save the current IP */
4206                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4207                 ppc_load (code, ppc_r0, 0x01010101);
4208                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4209         }
4210
4211         if (tracing)
4212                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4213
4214         cfg->code_len = code - cfg->native_code;
4215         g_assert (cfg->code_len < cfg->code_size);
4216         g_free (cinfo);
4217
4218         return code;
4219 }
4220
4221 void
4222 mono_arch_emit_epilog (MonoCompile *cfg)
4223 {
4224         MonoMethod *method = cfg->method;
4225         int pos, i;
4226         int max_epilog_size = 16 + 20*4;
4227         guint8 *code;
4228
4229         if (cfg->method->save_lmf)
4230                 max_epilog_size += 128;
4231         
4232         if (mono_jit_trace_calls != NULL)
4233                 max_epilog_size += 50;
4234
4235         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4236                 max_epilog_size += 50;
4237
4238         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4239                 cfg->code_size *= 2;
4240                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4241                 mono_jit_stats.code_reallocs++;
4242         }
4243
4244         /*
4245          * Keep in sync with OP_JMP
4246          */
4247         code = cfg->native_code + cfg->code_len;
4248
4249         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4250                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4251         }
4252         pos = 0;
4253
4254         if (method->save_lmf) {
4255                 int lmf_offset;
4256                 pos +=  sizeof (MonoLMF);
4257                 lmf_offset = pos;
4258                 /* save the frame reg in r8 */
4259                 ppc_mr (code, ppc_r8, cfg->frame_reg);
4260                 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4261                 /* r5 = previous_lmf */
4262                 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4263                 /* r6 = lmf_addr */
4264                 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4265                 /* *(lmf_addr) = previous_lmf */
4266                 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4267                 /* FIXME: speedup: there is no actual need to restore the registers if
4268                  * we didn't actually change them (idea from Zoltan).
4269                  */
4270                 /* restore iregs */
4271                 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4272                 /* restore fregs */
4273                 /*for (i = 14; i < 32; i++) {
4274                         ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4275                 }*/
4276                 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4277                 /* use the saved copy of the frame reg in r8 */
4278                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4279                         ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4280                         ppc_mtlr (code, ppc_r0);
4281                 }
4282                 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4283         } else {
4284                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4285                         if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4286                                 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4287                         } else {
4288                                 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4289                                 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4290                         }
4291                         ppc_mtlr (code, ppc_r0);
4292                 }
4293                 if (ppc_is_imm16 (cfg->stack_usage)) {
4294                         ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
4295                 } else {
4296                         ppc_load (code, ppc_r11, cfg->stack_usage);
4297                         ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4298                 }
4299
4300                 /*for (i = 31; i >= 14; --i) {
4301                         if (cfg->used_float_regs & (1 << i)) {
4302                                 pos += sizeof (double);
4303                                 ppc_lfd (code, i, -pos, ppc_sp);
4304                         }
4305                 }*/
4306                 for (i = 31; i >= 13; --i) {
4307                         if (cfg->used_int_regs & (1 << i)) {
4308                                 pos += sizeof (gulong);
4309                                 ppc_lwz (code, i, -pos, ppc_sp);
4310                         }
4311                 }
4312         }
4313         ppc_blr (code);
4314
4315         cfg->code_len = code - cfg->native_code;
4316
4317         g_assert (cfg->code_len < cfg->code_size);
4318
4319 }
4320
4321 /* remove once throw_exception_by_name is eliminated */
4322 static int
4323 exception_id_by_name (const char *name)
4324 {
4325         if (strcmp (name, "IndexOutOfRangeException") == 0)
4326                 return MONO_EXC_INDEX_OUT_OF_RANGE;
4327         if (strcmp (name, "OverflowException") == 0)
4328                 return MONO_EXC_OVERFLOW;
4329         if (strcmp (name, "ArithmeticException") == 0)
4330                 return MONO_EXC_ARITHMETIC;
4331         if (strcmp (name, "DivideByZeroException") == 0)
4332                 return MONO_EXC_DIVIDE_BY_ZERO;
4333         if (strcmp (name, "InvalidCastException") == 0)
4334                 return MONO_EXC_INVALID_CAST;
4335         if (strcmp (name, "NullReferenceException") == 0)
4336                 return MONO_EXC_NULL_REF;
4337         if (strcmp (name, "ArrayTypeMismatchException") == 0)
4338                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4339         g_error ("Unknown intrinsic exception %s\n", name);
4340         return 0;
4341 }
4342
4343 void
4344 mono_arch_emit_exceptions (MonoCompile *cfg)
4345 {
4346         MonoJumpInfo *patch_info;
4347         int i;
4348         guint8 *code;
4349         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4350         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4351         int max_epilog_size = 50;
4352
4353         /* count the number of exception infos */
4354      
4355         /* 
4356          * make sure we have enough space for exceptions
4357          * 24 is the simulated call to throw_exception_by_name
4358          */
4359         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4360                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4361                         i = exception_id_by_name (patch_info->data.target);
4362                         if (!exc_throw_found [i]) {
4363                                 max_epilog_size += 24;
4364                                 exc_throw_found [i] = TRUE;
4365                         }
4366                 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4367                         max_epilog_size += 12;
4368                 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4369                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4370                         i = exception_id_by_name (ovfj->data.exception);
4371                         if (!exc_throw_found [i]) {
4372                                 max_epilog_size += 24;
4373                                 exc_throw_found [i] = TRUE;
4374                         }
4375                         max_epilog_size += 8;
4376                 }
4377         }
4378
4379         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4380                 cfg->code_size *= 2;
4381                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4382                 mono_jit_stats.code_reallocs++;
4383         }
4384
4385         code = cfg->native_code + cfg->code_len;
4386
4387         /* add code to raise exceptions */
4388         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4389                 switch (patch_info->type) {
4390                 case MONO_PATCH_INFO_BB_OVF: {
4391                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4392                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4393                         /* patch the initial jump */
4394                         ppc_patch (ip, code);
4395                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4396                         ppc_b (code, 0);
4397                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4398                         /* jump back to the true target */
4399                         ppc_b (code, 0);
4400                         ip = ovfj->data.bb->native_offset + cfg->native_code;
4401                         ppc_patch (code - 4, ip);
4402                         break;
4403                 }
4404                 case MONO_PATCH_INFO_EXC_OVF: {
4405                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4406                         MonoJumpInfo *newji;
4407                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4408                         unsigned char *bcl = code;
4409                         /* patch the initial jump: we arrived here with a call */
4410                         ppc_patch (ip, code);
4411                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4412                         ppc_b (code, 0);
4413                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4414                         /* patch the conditional jump to the right handler */
4415                         /* make it processed next */
4416                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4417                         newji->type = MONO_PATCH_INFO_EXC;
4418                         newji->ip.i = bcl - cfg->native_code;
4419                         newji->data.target = ovfj->data.exception;
4420                         newji->next = patch_info->next;
4421                         patch_info->next = newji;
4422                         break;
4423                 }
4424                 case MONO_PATCH_INFO_EXC: {
4425                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4426                         i = exception_id_by_name (patch_info->data.target);
4427                         if (exc_throw_pos [i]) {
4428                                 ppc_patch (ip, exc_throw_pos [i]);
4429                                 patch_info->type = MONO_PATCH_INFO_NONE;
4430                                 break;
4431                         } else {
4432                                 exc_throw_pos [i] = code;
4433                         }
4434                         ppc_patch (ip, code);
4435                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4436                         ppc_load (code, ppc_r3, patch_info->data.target);
4437                         /* we got here from a conditional call, so the calling ip is set in lr already */
4438                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4439                         patch_info->data.name = "mono_arch_throw_exception_by_name";
4440                         patch_info->ip.i = code - cfg->native_code;
4441                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4442                                 ppc_lis (code, ppc_r0, 0);
4443                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
4444                                 ppc_mtctr (code, ppc_r0);
4445                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4446                         } else {
4447                                 ppc_b (code, 0);
4448                         }
4449                         break;
4450                 }
4451                 default:
4452                         /* do nothing */
4453                         break;
4454                 }
4455         }
4456
4457         cfg->code_len = code - cfg->native_code;
4458
4459         g_assert (cfg->code_len < cfg->code_size);
4460
4461 }
4462
4463 static int
4464 try_offset_access (void *value, guint32 idx)
4465 {
4466         register void* me __asm__ ("r2");
4467         void ***p = (void***)((char*)me + 284);
4468         int idx1 = idx / 32;
4469         int idx2 = idx % 32;
4470         if (!p [idx1])
4471                 return 0;
4472         if (value != p[idx1][idx2])
4473                 return 0;
4474         return 1;
4475 }
4476
4477 static void
4478 setup_tls_access (void)
4479 {
4480         guint32 ptk;
4481         guint32 *ins, *code;
4482         guint32 cmplwi_1023, li_0x48, blr_ins;
4483         if (tls_mode == TLS_MODE_FAILED)
4484                 return;
4485
4486         if (g_getenv ("MONO_NO_TLS")) {
4487                 tls_mode = TLS_MODE_FAILED;
4488                 return;
4489         }
4490
4491         if (tls_mode == TLS_MODE_DETECT) {
4492                 ins = (guint32*)pthread_getspecific;
4493                 /* uncond branch to the real method */
4494                 if ((*ins >> 26) == 18) {
4495                         gint32 val;
4496                         val = (*ins & ~3) << 6;
4497                         val >>= 6;
4498                         if (*ins & 2) {
4499                                 /* absolute */
4500                                 ins = (guint32*)val;
4501                         } else {
4502                                 ins = (guint32*) ((char*)ins + val);
4503                         }
4504                 }
4505                 code = &cmplwi_1023;
4506                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4507                 code = &li_0x48;
4508                 ppc_li (code, ppc_r4, 0x48);
4509                 code = &blr_ins;
4510                 ppc_blr (code);
4511                 if (*ins == cmplwi_1023) {
4512                         int found_lwz_284 = 0;
4513                         for (ptk = 0; ptk < 20; ++ptk) {
4514                                 ++ins;
4515                                 if (!*ins || *ins == blr_ins)
4516                                         break;
4517                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4518                                         found_lwz_284 = 1;
4519                                         break;
4520                                 }
4521                         }
4522                         if (!found_lwz_284) {
4523                                 tls_mode = TLS_MODE_FAILED;
4524                                 return;
4525                         }
4526                         tls_mode = TLS_MODE_LTHREADS;
4527                 } else if (*ins == li_0x48) {
4528                         ++ins;
4529                         /* uncond branch to the real method */
4530                         if ((*ins >> 26) == 18) {
4531                                 gint32 val;
4532                                 val = (*ins & ~3) << 6;
4533                                 val >>= 6;
4534                                 if (*ins & 2) {
4535                                         /* absolute */
4536                                         ins = (guint32*)val;
4537                                 } else {
4538                                         ins = (guint32*) ((char*)ins + val);
4539                                 }
4540                                 code = (guint32*)&val;
4541                                 ppc_li (code, ppc_r0, 0x7FF2);
4542                                 if (ins [1] == val) {
4543                                         /* Darwin on G4, implement */
4544                                         tls_mode = TLS_MODE_FAILED;
4545                                         return;
4546                                 } else {
4547                                         code = (guint32*)&val;
4548                                         ppc_mfspr (code, ppc_r3, 104);
4549                                         if (ins [1] != val) {
4550                                                 tls_mode = TLS_MODE_FAILED;
4551                                                 return;
4552                                         }
4553                                         tls_mode = TLS_MODE_DARWIN_G5;
4554                                 }
4555                         } else {
4556                                 tls_mode = TLS_MODE_FAILED;
4557                                 return;
4558                         }
4559                 } else {
4560                         tls_mode = TLS_MODE_FAILED;
4561                         return;
4562                 }
4563         }
4564         if (monodomain_key == -1) {
4565                 ptk = mono_domain_get_tls_key ();
4566                 if (ptk < 1024) {
4567                         ptk = mono_pthread_key_for_tls (ptk);
4568                         if (ptk < 1024) {
4569                                 monodomain_key = ptk;
4570                         }
4571                 }
4572         }
4573         if (lmf_pthread_key == -1) {
4574                 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4575                 if (ptk < 1024) {
4576                         /*g_print ("MonoLMF at: %d\n", ptk);*/
4577                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4578                                 init_tls_failed = 1;
4579                                 return;
4580                         }*/
4581                         lmf_pthread_key = ptk;
4582                 }
4583         }
4584         if (monothread_key == -1) {
4585                 ptk = mono_thread_get_tls_key ();
4586                 if (ptk < 1024) {
4587                         ptk = mono_pthread_key_for_tls (ptk);
4588                         if (ptk < 1024) {
4589                                 monothread_key = ptk;
4590                                 /*g_print ("thread inited: %d\n", ptk);*/
4591                         }
4592                 } else {
4593                         /*g_print ("thread not inited yet %d\n", ptk);*/
4594                 }
4595         }
4596 }
4597
4598 void
4599 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4600 {
4601         setup_tls_access ();
4602 }
4603
4604 void
4605 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4606 {
4607 }
4608
4609 void
4610 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4611 {
4612         int this_dreg = ppc_r3;
4613         
4614         if (vt_reg != -1)
4615                 this_dreg = ppc_r4;
4616
4617         /* add the this argument */
4618         if (this_reg != -1) {
4619                 MonoInst *this;
4620                 MONO_INST_NEW (cfg, this, OP_MOVE);
4621                 this->type = this_type;
4622                 this->sreg1 = this_reg;
4623                 this->dreg = mono_regstate_next_int (cfg->rs);
4624                 mono_bblock_add_inst (cfg->cbb, this);
4625                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4626         }
4627
4628         if (vt_reg != -1) {
4629                 MonoInst *vtarg;
4630                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4631                 vtarg->type = STACK_MP;
4632                 vtarg->sreg1 = vt_reg;
4633                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4634                 mono_bblock_add_inst (cfg->cbb, vtarg);
4635                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
4636         }
4637 }
4638
4639 #ifdef MONO_ARCH_HAVE_IMT
4640
4641 #define CMP_SIZE 12
4642 #define BR_SIZE 4
4643 #define JUMP_IMM_SIZE 12
4644 #define ENABLE_WRONG_METHOD_CHECK 0
4645
4646 /*
4647  * LOCKING: called with the domain lock held
4648  */
4649 gpointer
4650 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4651 {
4652         int i;
4653         int size = 0;
4654         guint8 *code, *start;
4655
4656         for (i = 0; i < count; ++i) {
4657                 MonoIMTCheckItem *item = imt_entries [i];
4658                 if (item->is_equals) {
4659                         if (item->check_target_idx) {
4660                                 if (!item->compare_done)
4661                                         item->chunk_size += CMP_SIZE;
4662                                 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4663                         } else {
4664                                 item->chunk_size += JUMP_IMM_SIZE;
4665 #if ENABLE_WRONG_METHOD_CHECK
4666                                 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4667 #endif
4668                         }
4669                 } else {
4670                         item->chunk_size += CMP_SIZE + BR_SIZE;
4671                         imt_entries [item->check_target_idx]->compare_done = TRUE;
4672                 }
4673                 size += item->chunk_size;
4674         }
4675         /* the initial load of the vtable address */
4676         size += 8;
4677         code = mono_code_manager_reserve (domain->code_mp, size);
4678         start = code;
4679         ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4680         for (i = 0; i < count; ++i) {
4681                 MonoIMTCheckItem *item = imt_entries [i];
4682                 item->code_target = code;
4683                 if (item->is_equals) {
4684                         if (item->check_target_idx) {
4685                                 if (!item->compare_done) {
4686                                         ppc_load (code, ppc_r0, (guint32)item->method);
4687                                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4688                                 }
4689                                 item->jmp_code = code;
4690                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4691                                 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4692                                 ppc_mtctr (code, ppc_r0);
4693                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4694                         } else {
4695                                 /* enable the commented code to assert on wrong method */
4696 #if ENABLE_WRONG_METHOD_CHECK
4697                                 ppc_load (code, ppc_r0, (guint32)item->method);
4698                                 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4699                                 item->jmp_code = code;
4700                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4701 #endif
4702                                 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4703                                 ppc_mtctr (code, ppc_r0);
4704                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4705 #if ENABLE_WRONG_METHOD_CHECK
4706                                 ppc_patch (item->jmp_code, code);
4707                                 ppc_break (code);
4708                                 item->jmp_code = NULL;
4709 #endif
4710                         }
4711                 } else {
4712                         ppc_load (code, ppc_r0, (guint32)item->method);
4713                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4714                         item->jmp_code = code;
4715                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4716                 }
4717         }
4718         /* patch the branches to get to the target items */
4719         for (i = 0; i < count; ++i) {
4720                 MonoIMTCheckItem *item = imt_entries [i];
4721                 if (item->jmp_code) {
4722                         if (item->check_target_idx) {
4723                                 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4724                         }
4725                 }
4726         }
4727                 
4728         mono_stats.imt_thunks_size += code - start;
4729         g_assert (code - start <= size);
4730         mono_arch_flush_icache (start, size);
4731         return start;
4732 }
4733
4734 MonoMethod*
4735 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4736 {
4737         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4738 }
4739
4740 MonoObject*
4741 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4742 {
4743         return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4744 }
4745 #endif
4746
4747 MonoVTable*
4748 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4749 {
4750         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
4751 }
4752
4753 MonoInst*
4754 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4755 {
4756         MonoInst *ins = NULL;
4757
4758         /*if (cmethod->klass == mono_defaults.math_class) {
4759                 if (strcmp (cmethod->name, "Sqrt") == 0) {
4760                         MONO_INST_NEW (cfg, ins, OP_SQRT);
4761                         ins->inst_i0 = args [0];
4762                 }
4763         }*/
4764         return ins;
4765 }
4766
4767 MonoInst*
4768 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4769 {
4770         /* FIXME: */
4771         return NULL;
4772 }
4773
4774 gboolean
4775 mono_arch_print_tree (MonoInst *tree, int arity)
4776 {
4777         return 0;
4778 }
4779
4780 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4781 {
4782         MonoInst* ins;
4783
4784         setup_tls_access ();
4785         if (monodomain_key == -1)
4786                 return NULL;
4787         
4788         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4789         ins->inst_offset = monodomain_key;
4790         return ins;
4791 }
4792
4793 MonoInst* 
4794 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4795 {
4796         MonoInst* ins;
4797
4798         setup_tls_access ();
4799         if (monothread_key == -1)
4800                 return NULL;
4801         
4802         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4803         ins->inst_offset = monothread_key;
4804         return ins;
4805 }
4806
4807 gpointer
4808 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4809 {
4810         g_assert (reg >= ppc_r13);
4811
4812         return (gpointer)ctx->regs [reg - ppc_r13];
4813 }