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