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