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