2008-03-14 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 void
1106 mono_arch_create_vars (MonoCompile *cfg)
1107 {
1108 }
1109
1110 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1111  * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
1112  */
1113
1114 /* 
1115  * take the arguments and generate the arch-specific
1116  * instructions to properly call the function in call.
1117  * This includes pushing, moving arguments to the right register
1118  * etc.
1119  * Issue: who does the spilling if needed, and when?
1120  */
1121 MonoCallInst*
1122 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1123         MonoInst *arg, *in;
1124         MonoMethodSignature *sig;
1125         int i, n;
1126         CallInfo *cinfo;
1127         ArgInfo *ainfo;
1128
1129         sig = call->signature;
1130         n = sig->param_count + sig->hasthis;
1131         
1132         cinfo = calculate_sizes (sig, sig->pinvoke);
1133         if (cinfo->struct_ret)
1134                 call->used_iregs |= 1 << cinfo->struct_ret;
1135
1136         for (i = 0; i < n; ++i) {
1137                 ainfo = cinfo->args + i;
1138                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1139                         MonoInst *sig_arg;
1140                         cfg->disable_aot = TRUE;
1141                                 
1142                         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1143                         sig_arg->inst_p0 = call->signature;
1144                         
1145                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1146                         arg->inst_imm = cinfo->sig_cookie.offset;
1147                         arg->inst_left = sig_arg;
1148                         MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1149                 }
1150                 if (is_virtual && i == 0) {
1151                         /* the argument will be attached to the call instrucion */
1152                         in = call->args [i];
1153                         call->used_iregs |= 1 << ainfo->reg;
1154                 } else {
1155                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1156                         in = call->args [i];
1157                         arg->cil_code = in->cil_code;
1158                         arg->inst_left = in;
1159                         arg->inst_call = call;
1160                         arg->type = in->type;
1161                         MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1162                         if (ainfo->regtype == RegTypeGeneral) {
1163                                 arg->backend.reg3 = ainfo->reg;
1164                                 call->used_iregs |= 1 << ainfo->reg;
1165                                 if (arg->type == STACK_I8)
1166                                         call->used_iregs |= 1 << (ainfo->reg + 1);
1167                         } else if (ainfo->regtype == RegTypeStructByAddr) {
1168                                 if (ainfo->offset) {
1169                                         MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1170                                         arg->opcode = OP_OUTARG_MEMBASE;
1171                                         ai->reg = ainfo->reg;
1172                                         ai->size = sizeof (gpointer);
1173                                         ai->offset = ainfo->offset;
1174                                         arg->backend.data = ai;
1175                                 } else {
1176                                         arg->backend.reg3 = ainfo->reg;
1177                                         call->used_iregs |= 1 << ainfo->reg;
1178                                 }
1179                         } else if (ainfo->regtype == RegTypeStructByVal) {
1180                                 int cur_reg;
1181                                 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1182                                 /* mark the used regs */
1183                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1184                                         call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1185                                 }
1186                                 arg->opcode = OP_OUTARG_VT;
1187                                 ai->reg = ainfo->reg;
1188                                 ai->size = ainfo->size;
1189                                 ai->vtsize = ainfo->vtsize;
1190                                 ai->offset = ainfo->offset;
1191                                 arg->backend.data = ai;
1192                         } else if (ainfo->regtype == RegTypeBase) {
1193                                 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1194                                 arg->opcode = OP_OUTARG_MEMBASE;
1195                                 ai->reg = ainfo->reg;
1196                                 ai->size = ainfo->size;
1197                                 ai->offset = ainfo->offset;
1198                                 arg->backend.data = ai;
1199                         } else if (ainfo->regtype == RegTypeFP) {
1200                                 arg->opcode = OP_OUTARG_R8;
1201                                 arg->backend.reg3 = ainfo->reg;
1202                                 call->used_fregs |= 1 << ainfo->reg;
1203                                 if (ainfo->size == 4) {
1204                                         arg->opcode = OP_OUTARG_R8;
1205                                         /* we reduce the precision */
1206                                         /*MonoInst *conv;
1207                                         MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1208                                         conv->inst_left = arg->inst_left;
1209                                         arg->inst_left = conv;*/
1210                                 }
1211                         } else {
1212                                 g_assert_not_reached ();
1213                         }
1214                 }
1215         }
1216         call->stack_usage = cinfo->stack_usage;
1217         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1218         cfg->flags |= MONO_CFG_HAS_CALLS;
1219         /* 
1220          * should set more info in call, such as the stack space
1221          * used by the args that needs to be added back to esp
1222          */
1223
1224         g_free (cinfo);
1225         return call;
1226 }
1227
1228 /*
1229  * Allow tracing to work with this interface (with an optional argument)
1230  */
1231
1232 void*
1233 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1234 {
1235         guchar *code = p;
1236
1237         ppc_load (code, ppc_r3, cfg->method);
1238         ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1239         ppc_load (code, ppc_r0, func);
1240         ppc_mtlr (code, ppc_r0);
1241         ppc_blrl (code);
1242         return code;
1243 }
1244
1245 enum {
1246         SAVE_NONE,
1247         SAVE_STRUCT,
1248         SAVE_ONE,
1249         SAVE_TWO,
1250         SAVE_FP
1251 };
1252
1253 void*
1254 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1255 {
1256         guchar *code = p;
1257         int save_mode = SAVE_NONE;
1258         int offset;
1259         MonoMethod *method = cfg->method;
1260         int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1261         int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1262         save_offset += 15;
1263         save_offset &= ~15;
1264         
1265         offset = code - cfg->native_code;
1266         /* we need about 16 instructions */
1267         if (offset > (cfg->code_size - 16 * 4)) {
1268                 cfg->code_size *= 2;
1269                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1270                 code = cfg->native_code + offset;
1271         }
1272 handle_enum:
1273         switch (rtype) {
1274         case MONO_TYPE_VOID:
1275                 /* special case string .ctor icall */
1276                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1277                         save_mode = SAVE_ONE;
1278                 else
1279                         save_mode = SAVE_NONE;
1280                 break;
1281         case MONO_TYPE_I8:
1282         case MONO_TYPE_U8:
1283                 save_mode = SAVE_TWO;
1284                 break;
1285         case MONO_TYPE_R4:
1286         case MONO_TYPE_R8:
1287                 save_mode = SAVE_FP;
1288                 break;
1289         case MONO_TYPE_VALUETYPE:
1290                 save_mode = SAVE_STRUCT;
1291                 break;
1292         default:
1293                 save_mode = SAVE_ONE;
1294                 break;
1295         }
1296
1297         switch (save_mode) {
1298         case SAVE_TWO:
1299                 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1300                 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1301                 if (enable_arguments) {
1302                         ppc_mr (code, ppc_r5, ppc_r4);
1303                         ppc_mr (code, ppc_r4, ppc_r3);
1304                 }
1305                 break;
1306         case SAVE_ONE:
1307                 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1308                 if (enable_arguments) {
1309                         ppc_mr (code, ppc_r4, ppc_r3);
1310                 }
1311                 break;
1312         case SAVE_FP:
1313                 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1314                 if (enable_arguments) {
1315                         /* FIXME: what reg?  */
1316                         ppc_fmr (code, ppc_f3, ppc_f1);
1317                         ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1318                         ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1319                 }
1320                 break;
1321         case SAVE_STRUCT:
1322                 if (enable_arguments) {
1323                         /* FIXME: get the actual address  */
1324                         ppc_mr (code, ppc_r4, ppc_r3);
1325                 }
1326                 break;
1327         case SAVE_NONE:
1328         default:
1329                 break;
1330         }
1331
1332         ppc_load (code, ppc_r3, cfg->method);
1333         ppc_load (code, ppc_r0, func);
1334         ppc_mtlr (code, ppc_r0);
1335         ppc_blrl (code);
1336
1337         switch (save_mode) {
1338         case SAVE_TWO:
1339                 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1340                 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1341                 break;
1342         case SAVE_ONE:
1343                 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1344                 break;
1345         case SAVE_FP:
1346                 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1347                 break;
1348         case SAVE_NONE:
1349         default:
1350                 break;
1351         }
1352
1353         return code;
1354 }
1355 /*
1356  * Conditional branches have a small offset, so if it is likely overflowed,
1357  * we do a branch to the end of the method (uncond branches have much larger
1358  * offsets) where we perform the conditional and jump back unconditionally.
1359  * It's slightly slower, since we add two uncond branches, but it's very simple
1360  * with the current patch implementation and such large methods are likely not
1361  * going to be perf critical anyway.
1362  */
1363 typedef struct {
1364         union {
1365                 MonoBasicBlock *bb;
1366                 const char *exception;
1367         } data;
1368         guint32 ip_offset;
1369         guint16 b0_cond;
1370         guint16 b1_cond;
1371 } MonoOvfJump;
1372
1373 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1374 if (ins->flags & MONO_INST_BRLABEL) { \
1375         if (0 && ins->inst_i0->inst_c0) { \
1376                 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff);  \
1377         } else { \
1378                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1379                 ppc_bc (code, (b0), (b1), 0);   \
1380         } \
1381 } else { \
1382         if (0 && ins->inst_true_bb->native_offset) { \
1383                 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1384         } else { \
1385                 int br_disp = ins->inst_true_bb->max_offset - offset;   \
1386                 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1387                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));    \
1388                         ovfj->data.bb = ins->inst_true_bb;      \
1389                         ovfj->ip_offset = 0;    \
1390                         ovfj->b0_cond = (b0);   \
1391                         ovfj->b1_cond = (b1);   \
1392                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1393                         ppc_b (code, 0);        \
1394                 } else {        \
1395                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1396                         ppc_bc (code, (b0), (b1), 0);   \
1397                 }       \
1398         } \
1399 }
1400
1401 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1402
1403 /* emit an exception if condition is fail
1404  *
1405  * We assign the extra code used to throw the implicit exceptions
1406  * to cfg->bb_exit as far as the big branch handling is concerned
1407  */
1408 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name)            \
1409         do {                                                        \
1410                 int br_disp = cfg->bb_exit->max_offset - offset;        \
1411                 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1412                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));    \
1413                         ovfj->data.exception = (exc_name);      \
1414                         ovfj->ip_offset = code - cfg->native_code;      \
1415                         ovfj->b0_cond = (b0);   \
1416                         ovfj->b1_cond = (b1);   \
1417                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1418                         ppc_bl (code, 0);       \
1419                         cfg->bb_exit->max_offset += 24; \
1420                 } else {        \
1421                         mono_add_patch_info (cfg, code - cfg->native_code,   \
1422                                     MONO_PATCH_INFO_EXC, exc_name);  \
1423                         ppc_bcl (code, (b0), (b1), 0);  \
1424                 }       \
1425         } while (0); 
1426
1427 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1428
1429 void
1430 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1431 {
1432 }
1433
1434 void
1435 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1436 {
1437         MonoInst *ins, *n;
1438
1439         MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
1440                 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1441                 switch (ins->opcode) {
1442                 case OP_MUL_IMM: 
1443                         /* remove unnecessary multiplication with 1 */
1444                         if (ins->inst_imm == 1) {
1445                                 if (ins->dreg != ins->sreg1) {
1446                                         ins->opcode = OP_MOVE;
1447                                 } else {
1448                                         MONO_DEL_INS (ins);
1449                                         continue;
1450                                 }
1451                         } else {
1452                                 int power2 = mono_is_power_of_two (ins->inst_imm);
1453                                 if (power2 > 0) {
1454                                         ins->opcode = OP_SHL_IMM;
1455                                         ins->inst_imm = power2;
1456                                 }
1457                         }
1458                         break;
1459                 case OP_LOAD_MEMBASE:
1460                 case OP_LOADI4_MEMBASE:
1461                         /* 
1462                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1463                          * OP_LOAD_MEMBASE offset(basereg), reg
1464                          */
1465                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1466                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1467                             ins->inst_basereg == last_ins->inst_destbasereg &&
1468                             ins->inst_offset == last_ins->inst_offset) {
1469                                 if (ins->dreg == last_ins->sreg1) {
1470                                         MONO_DEL_INS (ins);
1471                                         continue;
1472                                 } else {
1473                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1474                                         ins->opcode = OP_MOVE;
1475                                         ins->sreg1 = last_ins->sreg1;
1476                                 }
1477
1478                         /* 
1479                          * Note: reg1 must be different from the basereg in the second load
1480                          * OP_LOAD_MEMBASE offset(basereg), reg1
1481                          * OP_LOAD_MEMBASE offset(basereg), reg2
1482                          * -->
1483                          * OP_LOAD_MEMBASE offset(basereg), reg1
1484                          * OP_MOVE reg1, reg2
1485                          */
1486                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1487                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1488                               ins->inst_basereg != last_ins->dreg &&
1489                               ins->inst_basereg == last_ins->inst_basereg &&
1490                               ins->inst_offset == last_ins->inst_offset) {
1491
1492                                 if (ins->dreg == last_ins->dreg) {
1493                                         MONO_DEL_INS (ins);
1494                                         continue;
1495                                 } else {
1496                                         ins->opcode = OP_MOVE;
1497                                         ins->sreg1 = last_ins->dreg;
1498                                 }
1499
1500                                 //g_assert_not_reached ();
1501
1502 #if 0
1503                         /* 
1504                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1505                          * OP_LOAD_MEMBASE offset(basereg), reg
1506                          * -->
1507                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1508                          * OP_ICONST reg, imm
1509                          */
1510                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1511                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1512                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1513                                    ins->inst_offset == last_ins->inst_offset) {
1514                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1515                                 ins->opcode = OP_ICONST;
1516                                 ins->inst_c0 = last_ins->inst_imm;
1517                                 g_assert_not_reached (); // check this rule
1518 #endif
1519                         }
1520                         break;
1521                 case OP_LOADU1_MEMBASE:
1522                 case OP_LOADI1_MEMBASE:
1523                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1524                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1525                                         ins->inst_offset == last_ins->inst_offset) {
1526                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
1527                                 ins->sreg1 = last_ins->sreg1;                           
1528                         }
1529                         break;
1530                 case OP_LOADU2_MEMBASE:
1531                 case OP_LOADI2_MEMBASE:
1532                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1533                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1534                                         ins->inst_offset == last_ins->inst_offset) {
1535                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
1536                                 ins->sreg1 = last_ins->sreg1;                           
1537                         }
1538                         break;
1539                 case CEE_CONV_I4:
1540                 case CEE_CONV_U4:
1541                 case OP_MOVE:
1542                         ins->opcode = OP_MOVE;
1543                         /* 
1544                          * OP_MOVE reg, reg 
1545                          */
1546                         if (ins->dreg == ins->sreg1) {
1547                                 MONO_DEL_INS (ins);
1548                                 continue;
1549                         }
1550                         /* 
1551                          * OP_MOVE sreg, dreg 
1552                          * OP_MOVE dreg, sreg
1553                          */
1554                         if (last_ins && last_ins->opcode == OP_MOVE &&
1555                             ins->sreg1 == last_ins->dreg &&
1556                             ins->dreg == last_ins->sreg1) {
1557                                 MONO_DEL_INS (ins);
1558                                 continue;
1559                         }
1560                         break;
1561                 }
1562         }
1563 }
1564
1565 /* 
1566  * the branch_b0_table should maintain the order of these
1567  * opcodes.
1568 case CEE_BEQ:
1569 case CEE_BGE:
1570 case CEE_BGT:
1571 case CEE_BLE:
1572 case CEE_BLT:
1573 case CEE_BNE_UN:
1574 case CEE_BGE_UN:
1575 case CEE_BGT_UN:
1576 case CEE_BLE_UN:
1577 case CEE_BLT_UN:
1578  */
1579 static const guchar 
1580 branch_b0_table [] = {
1581         PPC_BR_TRUE, 
1582         PPC_BR_FALSE, 
1583         PPC_BR_TRUE, 
1584         PPC_BR_FALSE, 
1585         PPC_BR_TRUE, 
1586         
1587         PPC_BR_FALSE, 
1588         PPC_BR_FALSE, 
1589         PPC_BR_TRUE, 
1590         PPC_BR_FALSE,
1591         PPC_BR_TRUE
1592 };
1593
1594 static const guchar 
1595 branch_b1_table [] = {
1596         PPC_BR_EQ, 
1597         PPC_BR_LT, 
1598         PPC_BR_GT, 
1599         PPC_BR_GT,
1600         PPC_BR_LT, 
1601         
1602         PPC_BR_EQ, 
1603         PPC_BR_LT, 
1604         PPC_BR_GT, 
1605         PPC_BR_GT,
1606         PPC_BR_LT 
1607 };
1608
1609 #define NEW_INS(cfg,ins,dest,op) do {                                   \
1610                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
1611                 (dest)->opcode = (op);  \
1612                 MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node);  \
1613         } while (0)
1614
1615 static int
1616 map_to_reg_reg_op (int op)
1617 {
1618         switch (op) {
1619         case OP_ADD_IMM:
1620                 return CEE_ADD;
1621         case OP_SUB_IMM:
1622                 return CEE_SUB;
1623         case OP_AND_IMM:
1624                 return CEE_AND;
1625         case OP_COMPARE_IMM:
1626                 return OP_COMPARE;
1627         case OP_ADDCC_IMM:
1628                 return OP_ADDCC;
1629         case OP_ADC_IMM:
1630                 return OP_ADC;
1631         case OP_SUBCC_IMM:
1632                 return OP_SUBCC;
1633         case OP_SBB_IMM:
1634                 return OP_SBB;
1635         case OP_OR_IMM:
1636                 return CEE_OR;
1637         case OP_XOR_IMM:
1638                 return CEE_XOR;
1639         case OP_MUL_IMM:
1640                 return CEE_MUL;
1641         case OP_LOAD_MEMBASE:
1642                 return OP_LOAD_MEMINDEX;
1643         case OP_LOADI4_MEMBASE:
1644                 return OP_LOADI4_MEMINDEX;
1645         case OP_LOADU4_MEMBASE:
1646                 return OP_LOADU4_MEMINDEX;
1647         case OP_LOADU1_MEMBASE:
1648                 return OP_LOADU1_MEMINDEX;
1649         case OP_LOADI2_MEMBASE:
1650                 return OP_LOADI2_MEMINDEX;
1651         case OP_LOADU2_MEMBASE:
1652                 return OP_LOADU2_MEMINDEX;
1653         case OP_LOADI1_MEMBASE:
1654                 return OP_LOADI1_MEMINDEX;
1655         case OP_LOADR4_MEMBASE:
1656                 return OP_LOADR4_MEMINDEX;
1657         case OP_LOADR8_MEMBASE:
1658                 return OP_LOADR8_MEMINDEX;
1659         case OP_STOREI1_MEMBASE_REG:
1660                 return OP_STOREI1_MEMINDEX;
1661         case OP_STOREI2_MEMBASE_REG:
1662                 return OP_STOREI2_MEMINDEX;
1663         case OP_STOREI4_MEMBASE_REG:
1664                 return OP_STOREI4_MEMINDEX;
1665         case OP_STORE_MEMBASE_REG:
1666                 return OP_STORE_MEMINDEX;
1667         case OP_STORER4_MEMBASE_REG:
1668                 return OP_STORER4_MEMINDEX;
1669         case OP_STORER8_MEMBASE_REG:
1670                 return OP_STORER8_MEMINDEX;
1671         case OP_STORE_MEMBASE_IMM:
1672                 return OP_STORE_MEMBASE_REG;
1673         case OP_STOREI1_MEMBASE_IMM:
1674                 return OP_STOREI1_MEMBASE_REG;
1675         case OP_STOREI2_MEMBASE_IMM:
1676                 return OP_STOREI2_MEMBASE_REG;
1677         case OP_STOREI4_MEMBASE_IMM:
1678                 return OP_STOREI4_MEMBASE_REG;
1679         }
1680         g_assert_not_reached ();
1681 }
1682
1683 #define compare_opcode_is_unsigned(opcode) \
1684                 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) ||  \
1685                 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) ||     \
1686                 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1687 /*
1688  * Remove from the instruction list the instructions that can't be
1689  * represented with very simple instructions with no register
1690  * requirements.
1691  */
1692 void
1693 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1694 {
1695         MonoInst *ins, *next, *temp;
1696         int imm;
1697
1698         /* setup the virtual reg allocator */
1699         if (bb->max_vreg > cfg->rs->next_vreg)
1700                 cfg->rs->next_vreg = bb->max_vreg;
1701
1702         MONO_BB_FOR_EACH_INS (bb, ins) {
1703 loop_start:
1704                 switch (ins->opcode) {
1705                 case OP_ADD_IMM:
1706                 case OP_ADDCC_IMM:
1707                         if (!ppc_is_imm16 (ins->inst_imm)) {
1708                                 NEW_INS (cfg, ins, temp, OP_ICONST);
1709                                 temp->inst_c0 = ins->inst_imm;
1710                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1711                                 ins->sreg2 = temp->dreg;
1712                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1713                         }
1714                         break;
1715                 case OP_SUB_IMM:
1716                         if (!ppc_is_imm16 (-ins->inst_imm)) {
1717                                 NEW_INS (cfg, ins, temp, OP_ICONST);
1718                                 temp->inst_c0 = ins->inst_imm;
1719                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1720                                 ins->sreg2 = temp->dreg;
1721                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1722                         }
1723                         break;
1724                 case OP_AND_IMM:
1725                 case OP_OR_IMM:
1726                 case OP_XOR_IMM:
1727                         if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
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                         }
1734                         break;
1735                 case OP_SBB_IMM:
1736                 case OP_SUBCC_IMM:
1737                 case OP_ADC_IMM:
1738                         NEW_INS (cfg, ins, temp, OP_ICONST);
1739                         temp->inst_c0 = ins->inst_imm;
1740                         temp->dreg = mono_regstate_next_int (cfg->rs);
1741                         ins->sreg2 = temp->dreg;
1742                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1743                         break;
1744                 case OP_COMPARE_IMM:
1745                         next = mono_inst_list_next (&ins->node, &bb->ins_list);
1746                         g_assert(next);
1747                         if (compare_opcode_is_unsigned (next->opcode)) {
1748                                 if (!ppc_is_uimm16 (ins->inst_imm)) {
1749                                         NEW_INS (cfg, ins, temp, OP_ICONST);
1750                                         temp->inst_c0 = ins->inst_imm;
1751                                         temp->dreg = mono_regstate_next_int (cfg->rs);
1752                                         ins->sreg2 = temp->dreg;
1753                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1754                                 }
1755                         } else {
1756                                 if (!ppc_is_imm16 (ins->inst_imm)) {
1757                                         NEW_INS (cfg, ins, temp, OP_ICONST);
1758                                         temp->inst_c0 = ins->inst_imm;
1759                                         temp->dreg = mono_regstate_next_int (cfg->rs);
1760                                         ins->sreg2 = temp->dreg;
1761                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1762                                 }
1763                         }
1764                         break;
1765                 case OP_MUL_IMM:
1766                         if (ins->inst_imm == 1) {
1767                                 ins->opcode = OP_MOVE;
1768                                 break;
1769                         }
1770                         if (ins->inst_imm == 0) {
1771                                 ins->opcode = OP_ICONST;
1772                                 ins->inst_c0 = 0;
1773                                 break;
1774                         }
1775                         imm = mono_is_power_of_two (ins->inst_imm);
1776                         if (imm > 0) {
1777                                 ins->opcode = OP_SHL_IMM;
1778                                 ins->inst_imm = imm;
1779                                 break;
1780                         }
1781                         if (!ppc_is_imm16 (ins->inst_imm)) {
1782                                 NEW_INS (cfg, ins, temp, OP_ICONST);
1783                                 temp->inst_c0 = ins->inst_imm;
1784                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1785                                 ins->sreg2 = temp->dreg;
1786                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1787                         }
1788                         break;
1789                 case OP_LOAD_MEMBASE:
1790                 case OP_LOADI4_MEMBASE:
1791                 case OP_LOADU4_MEMBASE:
1792                 case OP_LOADI2_MEMBASE:
1793                 case OP_LOADU2_MEMBASE:
1794                 case OP_LOADI1_MEMBASE:
1795                 case OP_LOADU1_MEMBASE:
1796                 case OP_LOADR4_MEMBASE:
1797                 case OP_LOADR8_MEMBASE:
1798                 case OP_STORE_MEMBASE_REG:
1799                 case OP_STOREI4_MEMBASE_REG:
1800                 case OP_STOREI2_MEMBASE_REG:
1801                 case OP_STOREI1_MEMBASE_REG:
1802                 case OP_STORER4_MEMBASE_REG:
1803                 case OP_STORER8_MEMBASE_REG:
1804                         /* we can do two things: load the immed in a register
1805                          * and use an indexed load, or see if the immed can be
1806                          * represented as an ad_imm + a load with a smaller offset
1807                          * that fits. We just do the first for now, optimize later.
1808                          */
1809                         if (ppc_is_imm16 (ins->inst_offset))
1810                                 break;
1811                         NEW_INS (cfg, ins, temp, OP_ICONST);
1812                         temp->inst_c0 = ins->inst_offset;
1813                         temp->dreg = mono_regstate_next_int (cfg->rs);
1814                         ins->sreg2 = temp->dreg;
1815                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1816                         break;
1817                 case OP_STORE_MEMBASE_IMM:
1818                 case OP_STOREI1_MEMBASE_IMM:
1819                 case OP_STOREI2_MEMBASE_IMM:
1820                 case OP_STOREI4_MEMBASE_IMM:
1821                         NEW_INS (cfg, ins, temp, OP_ICONST);
1822                         temp->inst_c0 = ins->inst_imm;
1823                         temp->dreg = mono_regstate_next_int (cfg->rs);
1824                         ins->sreg1 = temp->dreg;
1825                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1826                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
1827                 case OP_R8CONST:
1828                 case OP_R4CONST:
1829                         NEW_INS (cfg, ins, temp, OP_ICONST);
1830                         temp->inst_c0 = ins->inst_p0;
1831                         temp->dreg = mono_regstate_next_int (cfg->rs);
1832                         ins->inst_basereg = temp->dreg;
1833                         ins->inst_offset = 0;
1834                         ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
1835                         /* make it handle the possibly big ins->inst_offset
1836                          * later optimize to use lis + load_membase
1837                          */
1838                         goto loop_start;
1839                 }
1840         }
1841         bb->max_vreg = cfg->rs->next_vreg;
1842         
1843 }
1844
1845 static guchar*
1846 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1847 {
1848         /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1849         ppc_fctiwz (code, ppc_f0, sreg);
1850         ppc_stfd (code, ppc_f0, -8, ppc_sp);
1851         ppc_lwz (code, dreg, -4, ppc_sp);
1852         if (!is_signed) {
1853                 if (size == 1)
1854                         ppc_andid (code, dreg, dreg, 0xff);
1855                 else if (size == 2)
1856                         ppc_andid (code, dreg, dreg, 0xffff);
1857         } else {
1858                 if (size == 1)
1859                         ppc_extsb (code, dreg, dreg);
1860                 else if (size == 2)
1861                         ppc_extsh (code, dreg, dreg);
1862         }
1863         return code;
1864 }
1865
1866 static unsigned char*
1867 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1868 {
1869 #if 0
1870         int sreg = tree->sreg1;
1871         x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1872         if (tree->flags & MONO_INST_INIT) {
1873                 int offset = 0;
1874                 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1875                         x86_push_reg (code, X86_EAX);
1876                         offset += 4;
1877                 }
1878                 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1879                         x86_push_reg (code, X86_ECX);
1880                         offset += 4;
1881                 }
1882                 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1883                         x86_push_reg (code, X86_EDI);
1884                         offset += 4;
1885                 }
1886                 
1887                 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1888                 if (sreg != X86_ECX)
1889                         x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1890                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1891                                 
1892                 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1893                 x86_cld (code);
1894                 x86_prefix (code, X86_REP_PREFIX);
1895                 x86_stosl (code);
1896                 
1897                 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1898                         x86_pop_reg (code, X86_EDI);
1899                 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1900                         x86_pop_reg (code, X86_ECX);
1901                 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1902                         x86_pop_reg (code, X86_EAX);
1903         }
1904 #endif
1905         return code;
1906 }
1907
1908 typedef struct {
1909         guchar *code;
1910         guchar *target;
1911         int absolute;
1912         int found;
1913 } PatchData;
1914
1915 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1916
1917 static int
1918 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1919         PatchData *pdata = (PatchData*)user_data;
1920         guchar *code = data;
1921         guint32 *thunks = data;
1922         guint32 *endthunks = (guint32*)(code + bsize);
1923         guint32 load [2];
1924         guchar *templ;
1925         int i, count = 0;
1926         int difflow, diffhigh;
1927
1928         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1929         difflow = (char*)pdata->code - (char*)thunks;
1930         diffhigh = (char*)pdata->code - (char*)endthunks;
1931         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1932                 return 0;
1933
1934         templ = (guchar*)load;
1935         ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1936         ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1937
1938         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1939         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1940                 while (thunks < endthunks) {
1941                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1942                         if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1943                                 ppc_patch (pdata->code, (guchar*)thunks);
1944                                 mono_arch_flush_icache (pdata->code, 4);
1945                                 pdata->found = 1;
1946                                 /*{
1947                                         static int num_thunks = 0;
1948                                         num_thunks++;
1949                                         if ((num_thunks % 20) == 0)
1950                                                 g_print ("num_thunks lookup: %d\n", num_thunks);
1951                                 }*/
1952                                 return 1;
1953                         } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1954                                 /* found a free slot instead: emit thunk */
1955                                 code = (guchar*)thunks;
1956                                 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1957                                 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1958                                 ppc_mtctr (code, ppc_r0);
1959                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1960                                 mono_arch_flush_icache ((guchar*)thunks, 16);
1961
1962                                 ppc_patch (pdata->code, (guchar*)thunks);
1963                                 mono_arch_flush_icache (pdata->code, 4);
1964                                 pdata->found = 1;
1965                                 /*{
1966                                         static int num_thunks = 0;
1967                                         num_thunks++;
1968                                         if ((num_thunks % 20) == 0)
1969                                                 g_print ("num_thunks: %d\n", num_thunks);
1970                                 }*/
1971                                 return 1;
1972                         }
1973                         /* skip 16 bytes, the size of the thunk */
1974                         thunks += 4;
1975                         count++;
1976                 }
1977                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1978         }
1979         return 0;
1980 }
1981
1982 static void
1983 handle_thunk (int absolute, guchar *code, guchar *target) {
1984         MonoDomain *domain = mono_domain_get ();
1985         PatchData pdata;
1986
1987         pdata.code = code;
1988         pdata.target = target;
1989         pdata.absolute = absolute;
1990         pdata.found = 0;
1991
1992         mono_domain_lock (domain);
1993         mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1994
1995         if (!pdata.found) {
1996                 /* this uses the first available slot */
1997                 pdata.found = 2;
1998                 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1999         }
2000         mono_domain_unlock (domain);
2001
2002         if (pdata.found != 1)
2003                 g_print ("thunk failed for %p from %p\n", target, code);
2004         g_assert (pdata.found == 1);
2005 }
2006
2007 void
2008 ppc_patch (guchar *code, guchar *target)
2009 {
2010         guint32 ins = *(guint32*)code;
2011         guint32 prim = ins >> 26;
2012         guint32 ovf;
2013
2014         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2015         if (prim == 18) {
2016                 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2017                 gint diff = target - code;
2018                 if (diff >= 0){
2019                         if (diff <= 33554431){
2020                                 ins = (18 << 26) | (diff) | (ins & 1);
2021                                 *(guint32*)code = ins;
2022                                 return;
2023                         }
2024                 } else {
2025                         /* diff between 0 and -33554432 */
2026                         if (diff >= -33554432){
2027                                 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2028                                 *(guint32*)code = ins;
2029                                 return;
2030                         }
2031                 }
2032                 
2033                 if ((glong)target >= 0){
2034                         if ((glong)target <= 33554431){
2035                                 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2036                                 *(guint32*)code = ins;
2037                                 return;
2038                         }
2039                 } else {
2040                         if ((glong)target >= -33554432){
2041                                 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2042                                 *(guint32*)code = ins;
2043                                 return;
2044                         }
2045                 }
2046
2047                 handle_thunk (TRUE, code, target);
2048                 return;
2049
2050                 g_assert_not_reached ();
2051         }
2052         
2053         
2054         if (prim == 16) {
2055                 // absolute address
2056                 if (ins & 2) {
2057                         guint32 li = (guint32)target;
2058                         ins = (ins & 0xffff0000) | (ins & 3);
2059                         ovf  = li & 0xffff0000;
2060                         if (ovf != 0 && ovf != 0xffff0000)
2061                                 g_assert_not_reached ();
2062                         li &= 0xffff;
2063                         ins |= li;
2064                         // FIXME: assert the top bits of li are 0
2065                 } else {
2066                         gint diff = target - code;
2067                         ins = (ins & 0xffff0000) | (ins & 3);
2068                         ovf  = diff & 0xffff0000;
2069                         if (ovf != 0 && ovf != 0xffff0000)
2070                                 g_assert_not_reached ();
2071                         diff &= 0xffff;
2072                         ins |= diff;
2073                 }
2074                 *(guint32*)code = ins;
2075                 return;
2076         }
2077
2078         if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2079                 guint32 *seq;
2080                 /* the trampoline code will try to patch the blrl, blr, bcctr */
2081                 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2082                         code -= 12;
2083                 }
2084                 /* this is the lis/ori/mtlr/blrl sequence */
2085                 seq = (guint32*)code;
2086                 g_assert ((seq [0] >> 26) == 15);
2087                 g_assert ((seq [1] >> 26) == 24);
2088                 g_assert ((seq [2] >> 26) == 31);
2089                 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2090                 /* FIXME: make this thread safe */
2091                 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2092                 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2093                 mono_arch_flush_icache (code - 8, 8);
2094         } else {
2095                 g_assert_not_reached ();
2096         }
2097 //      g_print ("patched with 0x%08x\n", ins);
2098 }
2099
2100 void
2101 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2102 {
2103         MonoInst *ins, *next;
2104         MonoCallInst *call;
2105         guint offset;
2106         guint8 *code = cfg->native_code + cfg->code_len;
2107         guint last_offset = 0;
2108         int max_len, cpos;
2109
2110         /* we don't align basic blocks of loops on ppc */
2111
2112         if (cfg->verbose_level > 2)
2113                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2114
2115         cpos = bb->max_offset;
2116
2117         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2118                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2119                 //g_assert (!mono_compile_aot);
2120                 //cpos += 6;
2121                 //if (bb->cil_code)
2122                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2123                 /* this is not thread save, but good enough */
2124                 /* fixme: howto handle overflows? */
2125                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
2126         }
2127
2128         MONO_BB_FOR_EACH_INS (bb, ins) {
2129                 offset = code - cfg->native_code;
2130
2131                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2132
2133                 if (offset > (cfg->code_size - max_len - 16)) {
2134                         cfg->code_size *= 2;
2135                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2136                         code = cfg->native_code + offset;
2137                 }
2138         //      if (ins->cil_code)
2139         //              g_print ("cil code\n");
2140                 mono_debug_record_line_number (cfg, ins, offset);
2141
2142                 switch (ins->opcode) {
2143                 case OP_TLS_GET:
2144                         emit_tls_access (code, ins->dreg, ins->inst_offset);
2145                         break;
2146                 case OP_BIGMUL:
2147                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2148                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2149                         ppc_mr (code, ppc_r4, ppc_r0);
2150                         break;
2151                 case OP_BIGMUL_UN:
2152                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2153                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2154                         ppc_mr (code, ppc_r4, ppc_r0);
2155                         break;
2156                 case OP_MEMORY_BARRIER:
2157                         ppc_sync (code);
2158                         break;
2159                 case OP_STOREI1_MEMBASE_REG:
2160                         if (ppc_is_imm16 (ins->inst_offset)) {
2161                                 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2162                         } else {
2163                                 g_assert_not_reached ();
2164                         }
2165                         break;
2166                 case OP_STOREI2_MEMBASE_REG:
2167                         if (ppc_is_imm16 (ins->inst_offset)) {
2168                                 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2169                         } else {
2170                                 g_assert_not_reached ();
2171                         }
2172                         break;
2173                 case OP_STORE_MEMBASE_REG:
2174                 case OP_STOREI4_MEMBASE_REG:
2175                         if (ppc_is_imm16 (ins->inst_offset)) {
2176                                 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2177                         } else {
2178                                 g_assert_not_reached ();
2179                         }
2180                         break;
2181                 case OP_STOREI1_MEMINDEX:
2182                         ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2183                         break;
2184                 case OP_STOREI2_MEMINDEX:
2185                         ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2186                         break;
2187                 case OP_STORE_MEMINDEX:
2188                 case OP_STOREI4_MEMINDEX:
2189                         ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2190                         break;
2191                 case OP_LOADU4_MEM:
2192                         g_assert_not_reached ();
2193                         break;
2194                 case OP_LOAD_MEMBASE:
2195                 case OP_LOADI4_MEMBASE:
2196                 case OP_LOADU4_MEMBASE:
2197                         if (ppc_is_imm16 (ins->inst_offset)) {
2198                                 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2199                         } else {
2200                                 g_assert_not_reached ();
2201                         }
2202                         break;
2203                 case OP_LOADI1_MEMBASE:
2204                 case OP_LOADU1_MEMBASE:
2205                         if (ppc_is_imm16 (ins->inst_offset)) {
2206                                 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2207                         } else {
2208                                 g_assert_not_reached ();
2209                         }
2210                         if (ins->opcode == OP_LOADI1_MEMBASE)
2211                                 ppc_extsb (code, ins->dreg, ins->dreg);
2212                         break;
2213                 case OP_LOADU2_MEMBASE:
2214                         if (ppc_is_imm16 (ins->inst_offset)) {
2215                                 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2216                         } else {
2217                                 g_assert_not_reached ();
2218                         }
2219                         break;
2220                 case OP_LOADI2_MEMBASE:
2221                         if (ppc_is_imm16 (ins->inst_offset)) {
2222                                 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2223                         } else {
2224                                 g_assert_not_reached ();
2225                         }
2226                         break;
2227                 case OP_LOAD_MEMINDEX:
2228                 case OP_LOADI4_MEMINDEX:
2229                 case OP_LOADU4_MEMINDEX:
2230                         ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2231                         break;
2232                 case OP_LOADU2_MEMINDEX:
2233                         ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2234                         break;
2235                 case OP_LOADI2_MEMINDEX:
2236                         ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2237                         break;
2238                 case OP_LOADU1_MEMINDEX:
2239                         ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2240                         break;
2241                 case OP_LOADI1_MEMINDEX:
2242                         ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2243                         ppc_extsb (code, ins->dreg, ins->dreg);
2244                         break;
2245                 case CEE_CONV_I1:
2246                         ppc_extsb (code, ins->dreg, ins->sreg1);
2247                         break;
2248                 case CEE_CONV_I2:
2249                         ppc_extsh (code, ins->dreg, ins->sreg1);
2250                         break;
2251                 case CEE_CONV_U1:
2252                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2253                         break;
2254                 case CEE_CONV_U2:
2255                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2256                         break;
2257                 case OP_COMPARE:
2258                         next = mono_inst_list_next (&ins->node, &bb->ins_list);
2259                         if (next && compare_opcode_is_unsigned (next->opcode))
2260                                 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2261                         else
2262                                 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2263                         break;
2264                 case OP_COMPARE_IMM:
2265                         next = mono_inst_list_next (&ins->node, &bb->ins_list);
2266                         if (next && compare_opcode_is_unsigned (next->opcode)) {
2267                                 if (ppc_is_uimm16 (ins->inst_imm)) {
2268                                         ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2269                                 } else {
2270                                         g_assert_not_reached ();
2271                                 }
2272                         } else {
2273                                 if (ppc_is_imm16 (ins->inst_imm)) {
2274                                         ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2275                                 } else {
2276                                         g_assert_not_reached ();
2277                                 }
2278                         }
2279                         break;
2280                 case OP_BREAK:
2281                         ppc_break (code);
2282                         break;
2283                 case OP_ADDCC:
2284                         ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2285                         break;
2286                 case CEE_ADD:
2287                         ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2288                         break;
2289                 case OP_ADC:
2290                         ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2291                         break;
2292                 case OP_ADDCC_IMM:
2293                         if (ppc_is_imm16 (ins->inst_imm)) {
2294                                 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2295                         } else {
2296                                 g_assert_not_reached ();
2297                         }
2298                         break;
2299                 case OP_ADD_IMM:
2300                         if (ppc_is_imm16 (ins->inst_imm)) {
2301                                 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2302                         } else {
2303                                 g_assert_not_reached ();
2304                         }
2305                         break;
2306                 case CEE_ADD_OVF:
2307                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2308                          */
2309                         ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2310                         ppc_mfspr (code, ppc_r0, ppc_xer);
2311                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2312                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2313                         break;
2314                 case CEE_ADD_OVF_UN:
2315                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2316                          */
2317                         ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2318                         ppc_mfspr (code, ppc_r0, ppc_xer);
2319                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2320                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2321                         break;
2322                 case CEE_SUB_OVF:
2323                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2324                          */
2325                         ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2326                         ppc_mfspr (code, ppc_r0, ppc_xer);
2327                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2328                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2329                         break;
2330                 case CEE_SUB_OVF_UN:
2331                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2332                          */
2333                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2334                         ppc_mfspr (code, ppc_r0, ppc_xer);
2335                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2336                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2337                         break;
2338                 case OP_ADD_OVF_CARRY:
2339                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2340                          */
2341                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2342                         ppc_mfspr (code, ppc_r0, ppc_xer);
2343                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2344                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2345                         break;
2346                 case OP_ADD_OVF_UN_CARRY:
2347                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2348                          */
2349                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2350                         ppc_mfspr (code, ppc_r0, ppc_xer);
2351                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2352                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2353                         break;
2354                 case OP_SUB_OVF_CARRY:
2355                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2356                          */
2357                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2358                         ppc_mfspr (code, ppc_r0, ppc_xer);
2359                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2360                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2361                         break;
2362                 case OP_SUB_OVF_UN_CARRY:
2363                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2364                          */
2365                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2366                         ppc_mfspr (code, ppc_r0, ppc_xer);
2367                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2368                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2369                         break;
2370                 case OP_SUBCC:
2371                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2372                         break;
2373                 case CEE_SUB:
2374                         ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2375                         break;
2376                 case OP_SBB:
2377                         ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2378                         break;
2379                 case OP_SUB_IMM:
2380                         // we add the negated value
2381                         if (ppc_is_imm16 (-ins->inst_imm))
2382                                 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2383                         else {
2384                                 g_assert_not_reached ();
2385                         }
2386                         break;
2387                 case OP_PPC_SUBFIC:
2388                         g_assert (ppc_is_imm16 (ins->inst_imm));
2389                         ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2390                         break;
2391                 case OP_PPC_SUBFZE:
2392                         ppc_subfze (code, ins->dreg, ins->sreg1);
2393                         break;
2394                 case CEE_AND:
2395                         /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2396                         ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2397                         break;
2398                 case OP_AND_IMM:
2399                         if (!(ins->inst_imm & 0xffff0000)) {
2400                                 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2401                         } else if (!(ins->inst_imm & 0xffff)) {
2402                                 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2403                         } else {
2404                                 g_assert_not_reached ();
2405                         }
2406                         break;
2407                 case CEE_DIV: {
2408                         guint32 *divisor_is_m1;
2409                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2410                          */
2411                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2412                         divisor_is_m1 = code;
2413                         ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2414                         ppc_lis (code, ppc_r0, 0x8000);
2415                         ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
2416                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2417                         ppc_patch (divisor_is_m1, code);
2418                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2419                          */
2420                         ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2421                         ppc_mfspr (code, ppc_r0, ppc_xer);
2422                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2423                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2424                         break;
2425                 }
2426                 case CEE_DIV_UN:
2427                         ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2428                         ppc_mfspr (code, ppc_r0, ppc_xer);
2429                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2430                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2431                         break;
2432                 case OP_DIV_IMM:
2433                 case CEE_REM:
2434                 case CEE_REM_UN:
2435                 case OP_REM_IMM:
2436                         g_assert_not_reached ();
2437                 case CEE_OR:
2438                         ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2439                         break;
2440                 case OP_OR_IMM:
2441                         if (!(ins->inst_imm & 0xffff0000)) {
2442                                 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2443                         } else if (!(ins->inst_imm & 0xffff)) {
2444                                 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
2445                         } else {
2446                                 g_assert_not_reached ();
2447                         }
2448                         break;
2449                 case CEE_XOR:
2450                         ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2451                         break;
2452                 case OP_XOR_IMM:
2453                         if (!(ins->inst_imm & 0xffff0000)) {
2454                                 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2455                         } else if (!(ins->inst_imm & 0xffff)) {
2456                                 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2457                         } else {
2458                                 g_assert_not_reached ();
2459                         }
2460                         break;
2461                 case CEE_SHL:
2462                         ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2463                         break;
2464                 case OP_SHL_IMM:
2465                         ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2466                         break;
2467                 case CEE_SHR:
2468                         ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2469                         break;
2470                 case OP_SHR_IMM:
2471                         ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2472                         break;
2473                 case OP_SHR_UN_IMM:
2474                         if (ins->inst_imm)
2475                                 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2476                         else
2477                                 ppc_mr (code, ins->dreg, ins->sreg1);
2478                         break;
2479                 case CEE_SHR_UN:
2480                         ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2481                         break;
2482                 case CEE_NOT:
2483                         ppc_not (code, ins->dreg, ins->sreg1);
2484                         break;
2485                 case CEE_NEG:
2486                         ppc_neg (code, ins->dreg, ins->sreg1);
2487                         break;
2488                 case CEE_MUL:
2489                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2490                         break;
2491                 case OP_MUL_IMM:
2492                         if (ppc_is_imm16 (ins->inst_imm)) {
2493                             ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2494                         } else {
2495                             g_assert_not_reached ();
2496                         }
2497                         break;
2498                 case CEE_MUL_OVF:
2499                         /* we annot use mcrxr, since it's not implemented on some processors 
2500                          * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2501                          */
2502                         ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2503                         ppc_mfspr (code, ppc_r0, ppc_xer);
2504                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2505                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2506                         break;
2507                 case CEE_MUL_OVF_UN:
2508                         /* we first multiply to get the high word and compare to 0
2509                          * to set the flags, then the result is discarded and then 
2510                          * we multiply to get the lower * bits result
2511                          */
2512                         ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2513                         ppc_cmpi (code, 0, 0, ppc_r0, 0);
2514                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2515                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2516                         break;
2517                 case OP_ICONST:
2518                         ppc_load (code, ins->dreg, ins->inst_c0);
2519                         break;
2520                 case OP_AOTCONST:
2521                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2522                         ppc_lis (code, ins->dreg, 0);
2523                         ppc_ori (code, ins->dreg, ins->dreg, 0);
2524                         break;
2525                 case CEE_CONV_I4:
2526                 case CEE_CONV_U4:
2527                 case OP_MOVE:
2528                         ppc_mr (code, ins->dreg, ins->sreg1);
2529                         break;
2530                 case OP_SETLRET: {
2531                         int saved = ins->sreg1;
2532                         if (ins->sreg1 == ppc_r3) {
2533                                 ppc_mr (code, ppc_r0, ins->sreg1);
2534                                 saved = ppc_r0;
2535                         }
2536                         if (ins->sreg2 != ppc_r3)
2537                                 ppc_mr (code, ppc_r3, ins->sreg2);
2538                         if (saved != ppc_r4)
2539                                 ppc_mr (code, ppc_r4, saved);
2540                         break;
2541                 }
2542                 case OP_FMOVE:
2543                         ppc_fmr (code, ins->dreg, ins->sreg1);
2544                         break;
2545                 case OP_FCONV_TO_R4:
2546                         ppc_frsp (code, ins->dreg, ins->sreg1);
2547                         break;
2548                 case OP_JMP: {
2549                         int i, pos = 0;
2550                         
2551                         /*
2552                          * Keep in sync with mono_arch_emit_epilog
2553                          */
2554                         g_assert (!cfg->method->save_lmf);
2555                         /*
2556                          * Note: we can use ppc_r11 here because it is dead anyway:
2557                          * we're leaving the method.
2558                          */
2559                         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2560                                 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2561                                         ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2562                                 } else {
2563                                         ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2564                                         ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2565                                 }
2566                                 ppc_mtlr (code, ppc_r0);
2567                         }
2568                         if (ppc_is_imm16 (cfg->stack_usage)) {
2569                                 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2570                         } else {
2571                                 ppc_load (code, ppc_r11, cfg->stack_usage);
2572                                 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2573                         }
2574                         if (!cfg->method->save_lmf) {
2575                                 /*for (i = 31; i >= 14; --i) {
2576                                         if (cfg->used_float_regs & (1 << i)) {
2577                                                 pos += sizeof (double);
2578                                                 ppc_lfd (code, i, -pos, cfg->frame_reg);
2579                                         }
2580                                 }*/
2581                                 for (i = 31; i >= 13; --i) {
2582                                         if (cfg->used_int_regs & (1 << i)) {
2583                                                 pos += sizeof (gulong);
2584                                                 ppc_lwz (code, i, -pos, cfg->frame_reg);
2585                                         }
2586                                 }
2587                         } else {
2588                                 /* FIXME restore from MonoLMF: though this can't happen yet */
2589                         }
2590                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2591                         ppc_b (code, 0);
2592                         break;
2593                 }
2594                 case OP_CHECK_THIS:
2595                         /* ensure ins->sreg1 is not NULL */
2596                         ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2597                         break;
2598                 case OP_ARGLIST: {
2599                         if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2600                                 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2601                         } else {
2602                                 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
2603                                 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
2604                         }
2605                         ppc_stw (code, ppc_r0, 0, ins->sreg1);
2606                         break;
2607                 }
2608                 case OP_FCALL:
2609                 case OP_LCALL:
2610                 case OP_VCALL:
2611                 case OP_VOIDCALL:
2612                 case OP_CALL:
2613                         call = (MonoCallInst*)ins;
2614                         if (ins->flags & MONO_INST_HAS_METHOD)
2615                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2616                         else
2617                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2618                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2619                                 ppc_lis (code, ppc_r0, 0);
2620                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
2621                                 ppc_mtlr (code, ppc_r0);
2622                                 ppc_blrl (code);
2623                         } else {
2624                                 ppc_bl (code, 0);
2625                         }
2626                         break;
2627                 case OP_FCALL_REG:
2628                 case OP_LCALL_REG:
2629                 case OP_VCALL_REG:
2630                 case OP_VOIDCALL_REG:
2631                 case OP_CALL_REG:
2632                         ppc_mtlr (code, ins->sreg1);
2633                         ppc_blrl (code);
2634                         break;
2635                 case OP_FCALL_MEMBASE:
2636                 case OP_LCALL_MEMBASE:
2637                 case OP_VCALL_MEMBASE:
2638                 case OP_VOIDCALL_MEMBASE:
2639                 case OP_CALL_MEMBASE:
2640                         ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2641                         ppc_mtlr (code, ppc_r0);
2642                         ppc_blrl (code);
2643                         break;
2644                 case OP_OUTARG:
2645                         g_assert_not_reached ();
2646                         break;
2647                 case OP_LOCALLOC: {
2648                         guint32 * zero_loop_jump, * zero_loop_start;
2649                         /* keep alignment */
2650                         int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2651                         int area_offset = alloca_waste;
2652                         area_offset &= ~31;
2653                         ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2654                         ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2655                         /* use ctr to store the number of words to 0 if needed */
2656                         if (ins->flags & MONO_INST_INIT) {
2657                                 /* we zero 4 bytes at a time:
2658                                  * we add 7 instead of 3 so that we set the counter to
2659                                  * at least 1, otherwise the bdnz instruction will make
2660                                  * it negative and iterate billions of times.
2661                                  */
2662                                 ppc_addi (code, ppc_r0, ins->sreg1, 7);
2663                                 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2664                                 ppc_mtctr (code, ppc_r0);
2665                         }
2666                         ppc_lwz (code, ppc_r0, 0, ppc_sp);
2667                         ppc_neg (code, ppc_r11, ppc_r11);
2668                         ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2669                         
2670                         if (ins->flags & MONO_INST_INIT) {
2671                                 /* adjust the dest reg by -4 so we can use stwu */
2672                                 /* we actually adjust -8 because we let the loop
2673                                  * run at least once
2674                                  */
2675                                 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
2676                                 ppc_li (code, ppc_r11, 0);
2677                                 zero_loop_start = code;
2678                                 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2679                                 zero_loop_jump = code;
2680                                 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2681                                 ppc_patch (zero_loop_jump, zero_loop_start);
2682                         }
2683                         ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2684                         break;
2685                 }
2686                 case OP_THROW: {
2687                         //ppc_break (code);
2688                         ppc_mr (code, ppc_r3, ins->sreg1);
2689                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2690                                              (gpointer)"mono_arch_throw_exception");
2691                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2692                                 ppc_lis (code, ppc_r0, 0);
2693                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
2694                                 ppc_mtlr (code, ppc_r0);
2695                                 ppc_blrl (code);
2696                         } else {
2697                                 ppc_bl (code, 0);
2698                         }
2699                         break;
2700                 }
2701                 case OP_RETHROW: {
2702                         //ppc_break (code);
2703                         ppc_mr (code, ppc_r3, ins->sreg1);
2704                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2705                                              (gpointer)"mono_arch_rethrow_exception");
2706                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2707                                 ppc_lis (code, ppc_r0, 0);
2708                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
2709                                 ppc_mtlr (code, ppc_r0);
2710                                 ppc_blrl (code);
2711                         } else {
2712                                 ppc_bl (code, 0);
2713                         }
2714                         break;
2715                 }
2716                 case OP_START_HANDLER:
2717                         ppc_mflr (code, ppc_r0);
2718                         if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2719                                 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2720                         } else {
2721                                 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2722                                 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2723                         }
2724                         break;
2725                 case OP_ENDFILTER:
2726                         if (ins->sreg1 != ppc_r3)
2727                                 ppc_mr (code, ppc_r3, ins->sreg1);
2728                         if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2729                                 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2730                         } else {
2731                                 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2732                                 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2733                         }
2734                         ppc_mtlr (code, ppc_r0);
2735                         ppc_blr (code);
2736                         break;
2737                 case OP_ENDFINALLY:
2738                         ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2739                         ppc_mtlr (code, ppc_r0);
2740                         ppc_blr (code);
2741                         break;
2742                 case OP_CALL_HANDLER: 
2743                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2744                         ppc_bl (code, 0);
2745                         break;
2746                 case OP_LABEL:
2747                         ins->inst_c0 = code - cfg->native_code;
2748                         break;
2749                 case OP_BR:
2750                         if (ins->flags & MONO_INST_BRLABEL) {
2751                                 /*if (ins->inst_i0->inst_c0) {
2752                                         ppc_b (code, 0);
2753                                         //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2754                                 } else*/ {
2755                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2756                                         ppc_b (code, 0);
2757                                 }
2758                         } else {
2759                                 /*if (ins->inst_target_bb->native_offset) {
2760                                         ppc_b (code, 0);
2761                                         //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2762                                 } else*/ {
2763                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2764                                         ppc_b (code, 0);
2765                                 } 
2766                         }
2767                         break;
2768                 case OP_BR_REG:
2769                         ppc_mtctr (code, ins->sreg1);
2770                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2771                         break;
2772                 case OP_CEQ:
2773                         ppc_li (code, ins->dreg, 0);
2774                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2775                         ppc_li (code, ins->dreg, 1);
2776                         break;
2777                 case OP_CLT:
2778                 case OP_CLT_UN:
2779                         ppc_li (code, ins->dreg, 1);
2780                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2781                         ppc_li (code, ins->dreg, 0);
2782                         break;
2783                 case OP_CGT:
2784                 case OP_CGT_UN:
2785                         ppc_li (code, ins->dreg, 1);
2786                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2787                         ppc_li (code, ins->dreg, 0);
2788                         break;
2789                 case OP_COND_EXC_EQ:
2790                 case OP_COND_EXC_NE_UN:
2791                 case OP_COND_EXC_LT:
2792                 case OP_COND_EXC_LT_UN:
2793                 case OP_COND_EXC_GT:
2794                 case OP_COND_EXC_GT_UN:
2795                 case OP_COND_EXC_GE:
2796                 case OP_COND_EXC_GE_UN:
2797                 case OP_COND_EXC_LE:
2798                 case OP_COND_EXC_LE_UN:
2799                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2800                         break;
2801                 case OP_COND_EXC_C:
2802                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2803                          */
2804                         /*ppc_mfspr (code, ppc_r0, ppc_xer);
2805                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2806                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2807                         break;*/
2808                 case OP_COND_EXC_OV:
2809                         /*ppc_mcrxr (code, 0);
2810                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2811                         break;*/
2812                 case OP_COND_EXC_NC:
2813                 case OP_COND_EXC_NO:
2814                         g_assert_not_reached ();
2815                         break;
2816                 case CEE_BEQ:
2817                 case CEE_BNE_UN:
2818                 case CEE_BLT:
2819                 case CEE_BLT_UN:
2820                 case CEE_BGT:
2821                 case CEE_BGT_UN:
2822                 case CEE_BGE:
2823                 case CEE_BGE_UN:
2824                 case CEE_BLE:
2825                 case CEE_BLE_UN:
2826                         EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2827                         break;
2828
2829                 /* floating point opcodes */
2830                 case OP_R8CONST:
2831                 case OP_R4CONST:
2832                         g_assert_not_reached ();
2833                 case OP_STORER8_MEMBASE_REG:
2834                         if (ppc_is_imm16 (ins->inst_offset)) {
2835                                 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2836                         } else {
2837                                 g_assert_not_reached ();
2838                         }
2839                         break;
2840                 case OP_LOADR8_MEMBASE:
2841                         if (ppc_is_imm16 (ins->inst_offset)) {
2842                                 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2843                         } else {
2844                                 g_assert_not_reached ();
2845                         }
2846                         break;
2847                 case OP_STORER4_MEMBASE_REG:
2848                         ppc_frsp (code, ins->sreg1, ins->sreg1);
2849                         if (ppc_is_imm16 (ins->inst_offset)) {
2850                                 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2851                         } else {
2852                                 g_assert_not_reached ();
2853                         }
2854                         break;
2855                 case OP_LOADR4_MEMBASE:
2856                         if (ppc_is_imm16 (ins->inst_offset)) {
2857                                 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2858                         } else {
2859                                 g_assert_not_reached ();
2860                         }
2861                         break;
2862                 case OP_LOADR4_MEMINDEX:
2863                         ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2864                         break;
2865                 case OP_LOADR8_MEMINDEX:
2866                         ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2867                         break;
2868                 case OP_STORER4_MEMINDEX:
2869                         ppc_frsp (code, ins->sreg1, ins->sreg1);
2870                         ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2871                         break;
2872                 case OP_STORER8_MEMINDEX:
2873                         ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2874                         break;
2875                 case CEE_CONV_R_UN:
2876                 case CEE_CONV_R4: /* FIXME: change precision */
2877                 case CEE_CONV_R8:
2878                         g_assert_not_reached ();
2879                 case OP_FCONV_TO_I1:
2880                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2881                         break;
2882                 case OP_FCONV_TO_U1:
2883                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2884                         break;
2885                 case OP_FCONV_TO_I2:
2886                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2887                         break;
2888                 case OP_FCONV_TO_U2:
2889                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2890                         break;
2891                 case OP_FCONV_TO_I4:
2892                 case OP_FCONV_TO_I:
2893                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2894                         break;
2895                 case OP_FCONV_TO_U4:
2896                 case OP_FCONV_TO_U:
2897                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2898                         break;
2899                 case OP_FCONV_TO_I8:
2900                 case OP_FCONV_TO_U8:
2901                         g_assert_not_reached ();
2902                         /* Implemented as helper calls */
2903                         break;
2904                 case OP_LCONV_TO_R_UN:
2905                         g_assert_not_reached ();
2906                         /* Implemented as helper calls */
2907                         break;
2908                 case OP_LCONV_TO_OVF_I: {
2909                         guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2910                         // Check if its negative
2911                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2912                         negative_branch = code;
2913                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2914                         // Its positive msword == 0
2915                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2916                         msword_positive_branch = code;
2917                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2918
2919                         ovf_ex_target = code;
2920                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2921                         // Negative
2922                         ppc_patch (negative_branch, code);
2923                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2924                         msword_negative_branch = code;
2925                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2926                         ppc_patch (msword_negative_branch, ovf_ex_target);
2927                         
2928                         ppc_patch (msword_positive_branch, code);
2929                         if (ins->dreg != ins->sreg1)
2930                                 ppc_mr (code, ins->dreg, ins->sreg1);
2931                         break;
2932                 }
2933                 case OP_SQRT:
2934                         ppc_fsqrtd (code, ins->dreg, ins->sreg1);
2935                         break;
2936                 case OP_FADD:
2937                         ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2938                         break;
2939                 case OP_FSUB:
2940                         ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2941                         break;          
2942                 case OP_FMUL:
2943                         ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2944                         break;          
2945                 case OP_FDIV:
2946                         ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2947                         break;          
2948                 case OP_FNEG:
2949                         ppc_fneg (code, ins->dreg, ins->sreg1);
2950                         break;          
2951                 case OP_FREM:
2952                         /* emulated */
2953                         g_assert_not_reached ();
2954                         break;
2955                 case OP_FCOMPARE:
2956                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2957                         break;
2958                 case OP_FCEQ:
2959                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2960                         ppc_li (code, ins->dreg, 0);
2961                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2962                         ppc_li (code, ins->dreg, 1);
2963                         break;
2964                 case OP_FCLT:
2965                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2966                         ppc_li (code, ins->dreg, 1);
2967                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2968                         ppc_li (code, ins->dreg, 0);
2969                         break;
2970                 case OP_FCLT_UN:
2971                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2972                         ppc_li (code, ins->dreg, 1);
2973                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2974                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2975                         ppc_li (code, ins->dreg, 0);
2976                         break;
2977                 case OP_FCGT:
2978                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2979                         ppc_li (code, ins->dreg, 1);
2980                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2981                         ppc_li (code, ins->dreg, 0);
2982                         break;
2983                 case OP_FCGT_UN:
2984                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2985                         ppc_li (code, ins->dreg, 1);
2986                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2987                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2988                         ppc_li (code, ins->dreg, 0);
2989                         break;
2990                 case OP_FBEQ:
2991                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2992                         break;
2993                 case OP_FBNE_UN:
2994                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2995                         break;
2996                 case OP_FBLT:
2997                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
2998                         EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
2999                         break;
3000                 case OP_FBLT_UN:
3001                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3002                         EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3003                         break;
3004                 case OP_FBGT:
3005                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3006                         EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3007                         break;
3008                 case OP_FBGT_UN:
3009                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3010                         EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3011                         break;
3012                 case OP_FBGE:
3013                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3014                         EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3015                         break;
3016                 case OP_FBGE_UN:
3017                         EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3018                         break;
3019                 case OP_FBLE:
3020                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3021                         EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3022                         break;
3023                 case OP_FBLE_UN:
3024                         EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3025                         break;
3026                 case OP_CKFINITE:
3027                         g_assert_not_reached ();
3028                 case OP_CHECK_FINITE: {
3029                         ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3030                         ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3031                         ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3032                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3033                         break;
3034                 }
3035                 default:
3036                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3037                         g_assert_not_reached ();
3038                 }
3039
3040                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3041                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3042                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3043                         g_assert_not_reached ();
3044                 }
3045                
3046                 cpos += max_len;
3047
3048                 last_offset = offset;
3049         }
3050
3051         cfg->code_len = code - cfg->native_code;
3052 }
3053
3054 void
3055 mono_arch_register_lowlevel_calls (void)
3056 {
3057 }
3058
3059 #define patch_lis_ori(ip,val) do {\
3060                 guint16 *__lis_ori = (guint16*)(ip);    \
3061                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
3062                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
3063         } while (0)
3064
3065 void
3066 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3067 {
3068         MonoJumpInfo *patch_info;
3069
3070         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3071                 unsigned char *ip = patch_info->ip.i + code;
3072                 const unsigned char *target;
3073
3074                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3075
3076                 switch (patch_info->type) {
3077                 case MONO_PATCH_INFO_IP:
3078                         patch_lis_ori (ip, ip);
3079                         continue;
3080                 case MONO_PATCH_INFO_METHOD_REL:
3081                         g_assert_not_reached ();
3082                         *((gpointer *)(ip)) = code + patch_info->data.offset;
3083                         continue;
3084                 case MONO_PATCH_INFO_SWITCH: {
3085                         gpointer *table = (gpointer *)patch_info->data.table->table;
3086                         int i;
3087
3088                         patch_lis_ori (ip, table);
3089
3090                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
3091                                 table [i] = (int)patch_info->data.table->table [i] + code;
3092                         }
3093                         /* we put into the table the absolute address, no need for ppc_patch in this case */
3094                         continue;
3095                 }
3096                 case MONO_PATCH_INFO_METHODCONST:
3097                 case MONO_PATCH_INFO_CLASS:
3098                 case MONO_PATCH_INFO_IMAGE:
3099                 case MONO_PATCH_INFO_FIELD:
3100                 case MONO_PATCH_INFO_VTABLE:
3101                 case MONO_PATCH_INFO_IID:
3102                 case MONO_PATCH_INFO_SFLDA:
3103                 case MONO_PATCH_INFO_LDSTR:
3104                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3105                 case MONO_PATCH_INFO_LDTOKEN:
3106                         /* from OP_AOTCONST : lis + ori */
3107                         patch_lis_ori (ip, target);
3108                         continue;
3109                 case MONO_PATCH_INFO_R4:
3110                 case MONO_PATCH_INFO_R8:
3111                         g_assert_not_reached ();
3112                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3113                         continue;
3114                 case MONO_PATCH_INFO_EXC_NAME:
3115                         g_assert_not_reached ();
3116                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3117                         continue;
3118                 case MONO_PATCH_INFO_NONE:
3119                 case MONO_PATCH_INFO_BB_OVF:
3120                 case MONO_PATCH_INFO_EXC_OVF:
3121                         /* everything is dealt with at epilog output time */
3122                         continue;
3123                 default:
3124                         break;
3125                 }
3126                 ppc_patch (ip, target);
3127         }
3128 }
3129
3130 /*
3131  * Stack frame layout:
3132  * 
3133  *   ------------------- sp
3134  *      MonoLMF structure or saved registers
3135  *   -------------------
3136  *      spilled regs
3137  *   -------------------
3138  *      locals
3139  *   -------------------
3140  *      optional 8 bytes for tracing
3141  *   -------------------
3142  *      param area             size is cfg->param_area
3143  *   -------------------
3144  *      linkage area           size is PPC_STACK_PARAM_OFFSET
3145  *   ------------------- sp
3146  *      red zone
3147  */
3148 guint8 *
3149 mono_arch_emit_prolog (MonoCompile *cfg)
3150 {
3151         MonoMethod *method = cfg->method;
3152         MonoBasicBlock *bb;
3153         MonoMethodSignature *sig;
3154         MonoInst *inst;
3155         int alloc_size, pos, max_offset, i;
3156         guint8 *code;
3157         CallInfo *cinfo;
3158         int tracing = 0;
3159         int lmf_offset = 0;
3160
3161         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3162                 tracing = 1;
3163
3164         sig = mono_method_signature (method);
3165         cfg->code_size = 256 + sig->param_count * 20;
3166         code = cfg->native_code = g_malloc (cfg->code_size);
3167
3168         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3169                 ppc_mflr (code, ppc_r0);
3170                 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3171         }
3172
3173         alloc_size = cfg->stack_offset;
3174         pos = 0;
3175
3176         if (!method->save_lmf) {
3177                 /*for (i = 31; i >= 14; --i) {
3178                         if (cfg->used_float_regs & (1 << i)) {
3179                                 pos += sizeof (gdouble);
3180                                 ppc_stfd (code, i, -pos, ppc_sp);
3181                         }
3182                 }*/
3183                 for (i = 31; i >= 13; --i) {
3184                         if (cfg->used_int_regs & (1 << i)) {
3185                                 pos += sizeof (gulong);
3186                                 ppc_stw (code, i, -pos, ppc_sp);
3187                         }
3188                 }
3189         } else {
3190                 int ofs;
3191                 pos += sizeof (MonoLMF);
3192                 lmf_offset = pos;
3193                 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3194                 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3195                 for (i = 14; i < 32; i++) {
3196                         ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3197                 }
3198         }
3199         alloc_size += pos;
3200         // align to PPC_STACK_ALIGNMENT bytes
3201         if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3202                 alloc_size += PPC_STACK_ALIGNMENT - 1;
3203                 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3204         }
3205
3206         cfg->stack_usage = alloc_size;
3207         g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3208         if (alloc_size) {
3209                 if (ppc_is_imm16 (-alloc_size)) {
3210                         ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3211                 } else {
3212                         ppc_load (code, ppc_r11, -alloc_size);
3213                         ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3214                 }
3215         }
3216         if (cfg->frame_reg != ppc_sp)
3217                 ppc_mr (code, cfg->frame_reg, ppc_sp);
3218
3219         /* compute max_offset in order to use short forward jumps
3220          * we always do it on ppc because the immediate displacement
3221          * for jumps is too small 
3222          */
3223         max_offset = 0;
3224         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3225                 MonoInst *ins;
3226                 bb->max_offset = max_offset;
3227
3228                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3229                         max_offset += 6; 
3230
3231                 MONO_BB_FOR_EACH_INS (bb, ins)
3232                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3233         }
3234
3235         /* load arguments allocated to register from the stack */
3236         pos = 0;
3237
3238         cinfo = calculate_sizes (sig, sig->pinvoke);
3239
3240         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3241                 ArgInfo *ainfo = &cinfo->ret;
3242                 inst = cfg->ret;
3243                 if (ppc_is_imm16 (inst->inst_offset)) {
3244                         ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3245                 } else {
3246                         ppc_load (code, ppc_r11, inst->inst_offset);
3247                         ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3248                 }
3249         }
3250         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3251                 ArgInfo *ainfo = cinfo->args + i;
3252                 inst = cfg->args [pos];
3253                 
3254                 if (cfg->verbose_level > 2)
3255                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3256                 if (inst->opcode == OP_REGVAR) {
3257                         if (ainfo->regtype == RegTypeGeneral)
3258                                 ppc_mr (code, inst->dreg, ainfo->reg);
3259                         else if (ainfo->regtype == RegTypeFP)
3260                                 ppc_fmr (code, inst->dreg, ainfo->reg);
3261                         else if (ainfo->regtype == RegTypeBase) {
3262                                 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3263                                 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3264                         } else
3265                                 g_assert_not_reached ();
3266
3267                         if (cfg->verbose_level > 2)
3268                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3269                 } else {
3270                         /* the argument should be put on the stack: FIXME handle size != word  */
3271                         if (ainfo->regtype == RegTypeGeneral) {
3272                                 switch (ainfo->size) {
3273                                 case 1:
3274                                         if (ppc_is_imm16 (inst->inst_offset)) {
3275                                                 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3276                                         } else {
3277                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3278                                                 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3279                                         }
3280                                         break;
3281                                 case 2:
3282                                         if (ppc_is_imm16 (inst->inst_offset)) {
3283                                                 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3284                                         } else {
3285                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3286                                                 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3287                                         }
3288                                         break;
3289                                 case 8:
3290                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
3291                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3292                                                 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3293                                         } else {
3294                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3295                                                 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3296                                                 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3297                                                 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3298                                         }
3299                                         break;
3300                                 default:
3301                                         if (ppc_is_imm16 (inst->inst_offset)) {
3302                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3303                                         } else {
3304                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3305                                                 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3306                                         }
3307                                         break;
3308                                 }
3309                         } else if (ainfo->regtype == RegTypeBase) {
3310                                 /* load the previous stack pointer in r11 */
3311                                 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3312                                 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3313                                 switch (ainfo->size) {
3314                                 case 1:
3315                                         if (ppc_is_imm16 (inst->inst_offset)) {
3316                                                 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3317                                         } else {
3318                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3319                                                 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3320                                         }
3321                                         break;
3322                                 case 2:
3323                                         if (ppc_is_imm16 (inst->inst_offset)) {
3324                                                 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3325                                         } else {
3326                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3327                                                 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3328                                         }
3329                                         break;
3330                                 case 8:
3331                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
3332                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3333                                                 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3334                                                 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3335                                         } else {
3336                                                 /* FIXME */
3337                                                 g_assert_not_reached ();
3338                                         }
3339                                         break;
3340                                 default:
3341                                         if (ppc_is_imm16 (inst->inst_offset)) {
3342                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3343                                         } else {
3344                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3345                                                 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3346                                         }
3347                                         break;
3348                                 }
3349                         } else if (ainfo->regtype == RegTypeFP) {
3350                                 g_assert (ppc_is_imm16 (inst->inst_offset));
3351                                 if (ainfo->size == 8)
3352                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3353                                 else if (ainfo->size == 4)
3354                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3355                                 else
3356                                         g_assert_not_reached ();
3357                         } else if (ainfo->regtype == RegTypeStructByVal) {
3358                                 int doffset = inst->inst_offset;
3359                                 int soffset = 0;
3360                                 int cur_reg;
3361                                 int size = 0;
3362                                 g_assert (ppc_is_imm16 (inst->inst_offset));
3363                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3364                                 if (mono_class_from_mono_type (inst->inst_vtype))
3365                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3366                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3367 /*
3368 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3369 register.  Should this case include linux/ppc?
3370 */
3371 #if __APPLE__
3372                                         if (size == 2)
3373                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3374                                         else if (size == 1)
3375                                                 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3376                                         else 
3377 #endif
3378                                                 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3379                                         soffset += sizeof (gpointer);
3380                                         doffset += sizeof (gpointer);
3381                                 }
3382                                 if (ainfo->vtsize) {
3383                                         /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3384                                         ppc_lwz (code, ppc_r11, 0, ppc_sp);
3385                                         /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3386                                         code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3387                                 }
3388                         } else if (ainfo->regtype == RegTypeStructByAddr) {
3389                                 /* if it was originally a RegTypeBase */
3390                                 if (ainfo->offset) {
3391                                         /* load the previous stack pointer in r11 */
3392                                         ppc_lwz (code, ppc_r11, 0, ppc_sp);
3393                                         ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
3394                                 } else {
3395                                         ppc_mr (code, ppc_r11, ainfo->reg);
3396                                 }
3397                                 g_assert (ppc_is_imm16 (inst->inst_offset));
3398                                 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
3399                                 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
3400                         } else
3401                                 g_assert_not_reached ();
3402                 }
3403                 pos++;
3404         }
3405
3406         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3407                 ppc_load (code, ppc_r3, cfg->domain);
3408                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3409                 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3410                         ppc_lis (code, ppc_r0, 0);
3411                         ppc_ori (code, ppc_r0, ppc_r0, 0);
3412                         ppc_mtlr (code, ppc_r0);
3413                         ppc_blrl (code);
3414                 } else {
3415                         ppc_bl (code, 0);
3416                 }
3417         }
3418
3419         if (method->save_lmf) {
3420                 if (lmf_pthread_key != -1) {
3421                         emit_tls_access (code, ppc_r3, lmf_pthread_key);
3422                         if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3423                                 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3424                 } else {
3425                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3426                                      (gpointer)"mono_get_lmf_addr");
3427                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3428                                 ppc_lis (code, ppc_r0, 0);
3429                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3430                                 ppc_mtlr (code, ppc_r0);
3431                                 ppc_blrl (code);
3432                         } else {
3433                                 ppc_bl (code, 0);
3434                         }
3435                 }
3436                 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3437                 /* lmf_offset is the offset from the previous stack pointer,
3438                  * alloc_size is the total stack space allocated, so the offset
3439                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3440                  * The pointer to the struct is put in ppc_r11 (new_lmf).
3441                  * The callee-saved registers are already in the MonoLMF structure
3442                  */
3443                 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3444                 /* ppc_r3 is the result from mono_get_lmf_addr () */
3445                 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3446                 /* new_lmf->previous_lmf = *lmf_addr */
3447                 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3448                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3449                 /* *(lmf_addr) = r11 */
3450                 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3451                 /* save method info */
3452                 ppc_load (code, ppc_r0, method);
3453                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3454                 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3455                 /* save the current IP */
3456                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3457                 ppc_load (code, ppc_r0, 0x01010101);
3458                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3459         }
3460
3461         if (tracing)
3462                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3463
3464         cfg->code_len = code - cfg->native_code;
3465         g_assert (cfg->code_len < cfg->code_size);
3466         g_free (cinfo);
3467
3468         return code;
3469 }
3470
3471 void
3472 mono_arch_emit_epilog (MonoCompile *cfg)
3473 {
3474         MonoJumpInfo *patch_info;
3475         MonoMethod *method = cfg->method;
3476         int pos, i;
3477         int max_epilog_size = 16 + 20*4;
3478         guint8 *code;
3479
3480         if (cfg->method->save_lmf)
3481                 max_epilog_size += 128;
3482         
3483         if (mono_jit_trace_calls != NULL)
3484                 max_epilog_size += 50;
3485
3486         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3487                 max_epilog_size += 50;
3488
3489         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3490                 cfg->code_size *= 2;
3491                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3492                 mono_jit_stats.code_reallocs++;
3493         }
3494
3495         /*
3496          * Keep in sync with OP_JMP
3497          */
3498         code = cfg->native_code + cfg->code_len;
3499
3500         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3501                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3502         }
3503         pos = 0;
3504
3505         if (method->save_lmf) {
3506                 int lmf_offset;
3507                 pos +=  sizeof (MonoLMF);
3508                 lmf_offset = pos;
3509                 /* save the frame reg in r8 */
3510                 ppc_mr (code, ppc_r8, cfg->frame_reg);
3511                 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3512                 /* r5 = previous_lmf */
3513                 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3514                 /* r6 = lmf_addr */
3515                 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3516                 /* *(lmf_addr) = previous_lmf */
3517                 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3518                 /* FIXME: speedup: there is no actual need to restore the registers if
3519                  * we didn't actually change them (idea from Zoltan).
3520                  */
3521                 /* restore iregs */
3522                 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3523                 /* restore fregs */
3524                 /*for (i = 14; i < 32; i++) {
3525                         ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3526                 }*/
3527                 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3528                 /* use the saved copy of the frame reg in r8 */
3529                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3530                         ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3531                         ppc_mtlr (code, ppc_r0);
3532                 }
3533                 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3534         } else {
3535                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3536                         if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3537                                 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3538                         } else {
3539                                 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3540                                 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3541                         }
3542                         ppc_mtlr (code, ppc_r0);
3543                 }
3544                 if (ppc_is_imm16 (cfg->stack_usage)) {
3545                         ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3546                 } else {
3547                         ppc_load (code, ppc_r11, cfg->stack_usage);
3548                         ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3549                 }
3550
3551                 /*for (i = 31; i >= 14; --i) {
3552                         if (cfg->used_float_regs & (1 << i)) {
3553                                 pos += sizeof (double);
3554                                 ppc_lfd (code, i, -pos, ppc_sp);
3555                         }
3556                 }*/
3557                 for (i = 31; i >= 13; --i) {
3558                         if (cfg->used_int_regs & (1 << i)) {
3559                                 pos += sizeof (gulong);
3560                                 ppc_lwz (code, i, -pos, ppc_sp);
3561                         }
3562                 }
3563         }
3564         ppc_blr (code);
3565
3566         cfg->code_len = code - cfg->native_code;
3567
3568         g_assert (cfg->code_len < cfg->code_size);
3569
3570 }
3571
3572 /* remove once throw_exception_by_name is eliminated */
3573 static int
3574 exception_id_by_name (const char *name)
3575 {
3576         if (strcmp (name, "IndexOutOfRangeException") == 0)
3577                 return MONO_EXC_INDEX_OUT_OF_RANGE;
3578         if (strcmp (name, "OverflowException") == 0)
3579                 return MONO_EXC_OVERFLOW;
3580         if (strcmp (name, "ArithmeticException") == 0)
3581                 return MONO_EXC_ARITHMETIC;
3582         if (strcmp (name, "DivideByZeroException") == 0)
3583                 return MONO_EXC_DIVIDE_BY_ZERO;
3584         if (strcmp (name, "InvalidCastException") == 0)
3585                 return MONO_EXC_INVALID_CAST;
3586         if (strcmp (name, "NullReferenceException") == 0)
3587                 return MONO_EXC_NULL_REF;
3588         if (strcmp (name, "ArrayTypeMismatchException") == 0)
3589                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3590         g_error ("Unknown intrinsic exception %s\n", name);
3591         return 0;
3592 }
3593
3594 void
3595 mono_arch_emit_exceptions (MonoCompile *cfg)
3596 {
3597         MonoJumpInfo *patch_info;
3598         int nthrows, i;
3599         guint8 *code;
3600         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3601         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3602         guint32 code_size;
3603         int exc_count = 0;
3604         int max_epilog_size = 50;
3605
3606         /* count the number of exception infos */
3607      
3608         /* 
3609          * make sure we have enough space for exceptions
3610          * 24 is the simulated call to throw_exception_by_name
3611          */
3612         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3613                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3614                         i = exception_id_by_name (patch_info->data.target);
3615                         if (!exc_throw_found [i]) {
3616                                 max_epilog_size += 24;
3617                                 exc_throw_found [i] = TRUE;
3618                         }
3619                 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3620                         max_epilog_size += 12;
3621                 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3622                         MonoOvfJump *ovfj = patch_info->data.target;
3623                         i = exception_id_by_name (ovfj->data.exception);
3624                         if (!exc_throw_found [i]) {
3625                                 max_epilog_size += 24;
3626                                 exc_throw_found [i] = TRUE;
3627                         }
3628                         max_epilog_size += 8;
3629                 }
3630         }
3631
3632         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3633                 cfg->code_size *= 2;
3634                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3635                 mono_jit_stats.code_reallocs++;
3636         }
3637
3638         code = cfg->native_code + cfg->code_len;
3639
3640         /* add code to raise exceptions */
3641         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3642                 switch (patch_info->type) {
3643                 case MONO_PATCH_INFO_BB_OVF: {
3644                         MonoOvfJump *ovfj = patch_info->data.target;
3645                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
3646                         /* patch the initial jump */
3647                         ppc_patch (ip, code);
3648                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3649                         ppc_b (code, 0);
3650                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3651                         /* jump back to the true target */
3652                         ppc_b (code, 0);
3653                         ip = ovfj->data.bb->native_offset + cfg->native_code;
3654                         ppc_patch (code - 4, ip);
3655                         break;
3656                 }
3657                 case MONO_PATCH_INFO_EXC_OVF: {
3658                         MonoOvfJump *ovfj = patch_info->data.target;
3659                         MonoJumpInfo *newji;
3660                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
3661                         unsigned char *bcl = code;
3662                         /* patch the initial jump: we arrived here with a call */
3663                         ppc_patch (ip, code);
3664                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3665                         ppc_b (code, 0);
3666                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3667                         /* patch the conditional jump to the right handler */
3668                         /* make it processed next */
3669                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3670                         newji->type = MONO_PATCH_INFO_EXC;
3671                         newji->ip.i = bcl - cfg->native_code;
3672                         newji->data.target = ovfj->data.exception;
3673                         newji->next = patch_info->next;
3674                         patch_info->next = newji;
3675                         break;
3676                 }
3677                 case MONO_PATCH_INFO_EXC: {
3678                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
3679                         i = exception_id_by_name (patch_info->data.target);
3680                         if (exc_throw_pos [i]) {
3681                                 ppc_patch (ip, exc_throw_pos [i]);
3682                                 patch_info->type = MONO_PATCH_INFO_NONE;
3683                                 break;
3684                         } else {
3685                                 exc_throw_pos [i] = code;
3686                         }
3687                         ppc_patch (ip, code);
3688                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3689                         ppc_load (code, ppc_r3, patch_info->data.target);
3690                         /* we got here from a conditional call, so the calling ip is set in lr already */
3691                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3692                         patch_info->data.name = "mono_arch_throw_exception_by_name";
3693                         patch_info->ip.i = code - cfg->native_code;
3694                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3695                                 ppc_lis (code, ppc_r0, 0);
3696                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3697                                 ppc_mtctr (code, ppc_r0);
3698                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3699                         } else {
3700                                 ppc_b (code, 0);
3701                         }
3702                         break;
3703                 }
3704                 default:
3705                         /* do nothing */
3706                         break;
3707                 }
3708         }
3709
3710         cfg->code_len = code - cfg->native_code;
3711
3712         g_assert (cfg->code_len < cfg->code_size);
3713
3714 }
3715
3716 static int
3717 try_offset_access (void *value, guint32 idx)
3718 {
3719         register void* me __asm__ ("r2");
3720         void ***p = (void***)((char*)me + 284);
3721         int idx1 = idx / 32;
3722         int idx2 = idx % 32;
3723         if (!p [idx1])
3724                 return 0;
3725         if (value != p[idx1][idx2])
3726                 return 0;
3727         return 1;
3728 }
3729
3730 static void
3731 setup_tls_access (void)
3732 {
3733         guint32 ptk;
3734         guint32 *ins, *code;
3735         guint32 cmplwi_1023, li_0x48, blr_ins;
3736         if (tls_mode == TLS_MODE_FAILED)
3737                 return;
3738
3739         if (g_getenv ("MONO_NO_TLS")) {
3740                 tls_mode = TLS_MODE_FAILED;
3741                 return;
3742         }
3743
3744         if (tls_mode == TLS_MODE_DETECT) {
3745                 ins = (guint32*)pthread_getspecific;
3746                 /* uncond branch to the real method */
3747                 if ((*ins >> 26) == 18) {
3748                         gint32 val;
3749                         val = (*ins & ~3) << 6;
3750                         val >>= 6;
3751                         if (*ins & 2) {
3752                                 /* absolute */
3753                                 ins = (guint32*)val;
3754                         } else {
3755                                 ins = (guint32*) ((char*)ins + val);
3756                         }
3757                 }
3758                 code = &cmplwi_1023;
3759                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3760                 code = &li_0x48;
3761                 ppc_li (code, ppc_r4, 0x48);
3762                 code = &blr_ins;
3763                 ppc_blr (code);
3764                 if (*ins == cmplwi_1023) {
3765                         int found_lwz_284 = 0;
3766                         for (ptk = 0; ptk < 20; ++ptk) {
3767                                 ++ins;
3768                                 if (!*ins || *ins == blr_ins)
3769                                         break;
3770                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3771                                         found_lwz_284 = 1;
3772                                         break;
3773                                 }
3774                         }
3775                         if (!found_lwz_284) {
3776                                 tls_mode = TLS_MODE_FAILED;
3777                                 return;
3778                         }
3779                         tls_mode = TLS_MODE_LTHREADS;
3780                 } else if (*ins == li_0x48) {
3781                         ++ins;
3782                         /* uncond branch to the real method */
3783                         if ((*ins >> 26) == 18) {
3784                                 gint32 val;
3785                                 val = (*ins & ~3) << 6;
3786                                 val >>= 6;
3787                                 if (*ins & 2) {
3788                                         /* absolute */
3789                                         ins = (guint32*)val;
3790                                 } else {
3791                                         ins = (guint32*) ((char*)ins + val);
3792                                 }
3793                                 code = &val;
3794                                 ppc_li (code, ppc_r0, 0x7FF2);
3795                                 if (ins [1] == val) {
3796                                         /* Darwin on G4, implement */
3797                                         tls_mode = TLS_MODE_FAILED;
3798                                         return;
3799                                 } else {
3800                                         code = &val;
3801                                         ppc_mfspr (code, ppc_r3, 104);
3802                                         if (ins [1] != val) {
3803                                                 tls_mode = TLS_MODE_FAILED;
3804                                                 return;
3805                                         }
3806                                         tls_mode = TLS_MODE_DARWIN_G5;
3807                                 }
3808                         } else {
3809                                 tls_mode = TLS_MODE_FAILED;
3810                                 return;
3811                         }
3812                 } else {
3813                         tls_mode = TLS_MODE_FAILED;
3814                         return;
3815                 }
3816         }
3817         if (monodomain_key == -1) {
3818                 ptk = mono_domain_get_tls_key ();
3819                 if (ptk < 1024) {
3820                         ptk = mono_pthread_key_for_tls (ptk);
3821                         if (ptk < 1024) {
3822                                 monodomain_key = ptk;
3823                         }
3824                 }
3825         }
3826         if (lmf_pthread_key == -1) {
3827                 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3828                 if (ptk < 1024) {
3829                         /*g_print ("MonoLMF at: %d\n", ptk);*/
3830                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3831                                 init_tls_failed = 1;
3832                                 return;
3833                         }*/
3834                         lmf_pthread_key = ptk;
3835                 }
3836         }
3837         if (monothread_key == -1) {
3838                 ptk = mono_thread_get_tls_key ();
3839                 if (ptk < 1024) {
3840                         ptk = mono_pthread_key_for_tls (ptk);
3841                         if (ptk < 1024) {
3842                                 monothread_key = ptk;
3843                                 /*g_print ("thread inited: %d\n", ptk);*/
3844                         }
3845                 } else {
3846                         /*g_print ("thread not inited yet %d\n", ptk);*/
3847                 }
3848         }
3849 }
3850
3851 void
3852 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3853 {
3854         setup_tls_access ();
3855 }
3856
3857 void
3858 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3859 {
3860 }
3861
3862 void
3863 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3864 {
3865         int this_dreg = ppc_r3;
3866         
3867         if (vt_reg != -1)
3868                 this_dreg = ppc_r4;
3869
3870         /* add the this argument */
3871         if (this_reg != -1) {
3872                 MonoInst *this;
3873                 MONO_INST_NEW (cfg, this, OP_MOVE);
3874                 this->type = this_type;
3875                 this->sreg1 = this_reg;
3876                 this->dreg = mono_regstate_next_int (cfg->rs);
3877                 mono_bblock_add_inst (cfg->cbb, this);
3878                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3879         }
3880
3881         if (vt_reg != -1) {
3882                 MonoInst *vtarg;
3883                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
3884                 vtarg->type = STACK_MP;
3885                 vtarg->sreg1 = vt_reg;
3886                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3887                 mono_bblock_add_inst (cfg->cbb, vtarg);
3888                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3889         }
3890 }
3891
3892 #ifdef MONO_ARCH_HAVE_IMT
3893
3894 #define CMP_SIZE 12
3895 #define BR_SIZE 4
3896 #define JUMP_IMM_SIZE 12
3897 #define ENABLE_WRONG_METHOD_CHECK 0
3898
3899 /*
3900  * LOCKING: called with the domain lock held
3901  */
3902 gpointer
3903 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
3904 {
3905         int i;
3906         int size = 0;
3907         guint8 *code, *start;
3908
3909         for (i = 0; i < count; ++i) {
3910                 MonoIMTCheckItem *item = imt_entries [i];
3911                 if (item->is_equals) {
3912                         if (item->check_target_idx) {
3913                                 if (!item->compare_done)
3914                                         item->chunk_size += CMP_SIZE;
3915                                 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
3916                         } else {
3917                                 item->chunk_size += JUMP_IMM_SIZE;
3918 #if ENABLE_WRONG_METHOD_CHECK
3919                                 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
3920 #endif
3921                         }
3922                 } else {
3923                         item->chunk_size += CMP_SIZE + BR_SIZE;
3924                         imt_entries [item->check_target_idx]->compare_done = TRUE;
3925                 }
3926                 size += item->chunk_size;
3927         }
3928         /* the initial load of the vtable address */
3929         size += 8;
3930         code = mono_code_manager_reserve (domain->code_mp, size);
3931         start = code;
3932         ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
3933         for (i = 0; i < count; ++i) {
3934                 MonoIMTCheckItem *item = imt_entries [i];
3935                 item->code_target = code;
3936                 if (item->is_equals) {
3937                         if (item->check_target_idx) {
3938                                 if (!item->compare_done) {
3939                                         ppc_load (code, ppc_r0, (guint32)item->method);
3940                                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3941                                 }
3942                                 item->jmp_code = code;
3943                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3944                                 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
3945                                 ppc_mtctr (code, ppc_r0);
3946                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3947                         } else {
3948                                 /* enable the commented code to assert on wrong method */
3949 #if ENABLE_WRONG_METHOD_CHECK
3950                                 ppc_load (code, ppc_r0, (guint32)item->method);
3951                                 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3952                                 item->jmp_code = code;
3953                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3954 #endif
3955                                 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
3956                                 ppc_mtctr (code, ppc_r0);
3957                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3958 #if ENABLE_WRONG_METHOD_CHECK
3959                                 ppc_patch (item->jmp_code, code);
3960                                 ppc_break (code);
3961                                 item->jmp_code = NULL;
3962 #endif
3963                         }
3964                 } else {
3965                         ppc_load (code, ppc_r0, (guint32)item->method);
3966                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
3967                         item->jmp_code = code;
3968                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
3969                 }
3970         }
3971         /* patch the branches to get to the target items */
3972         for (i = 0; i < count; ++i) {
3973                 MonoIMTCheckItem *item = imt_entries [i];
3974                 if (item->jmp_code) {
3975                         if (item->check_target_idx) {
3976                                 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
3977                         }
3978                 }
3979         }
3980                 
3981         mono_stats.imt_thunks_size += code - start;
3982         g_assert (code - start <= size);
3983         mono_arch_flush_icache (start, size);
3984         return start;
3985 }
3986
3987 MonoMethod*
3988 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
3989 {
3990         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
3991 }
3992
3993 MonoObject*
3994 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
3995 {
3996         return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
3997 }
3998 #endif
3999
4000 MonoInst*
4001 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4002 {
4003         MonoInst *ins = NULL;
4004
4005         /*if (cmethod->klass == mono_defaults.math_class) {
4006                 if (strcmp (cmethod->name, "Sqrt") == 0) {
4007                         MONO_INST_NEW (cfg, ins, OP_SQRT);
4008                         ins->inst_i0 = args [0];
4009                 }
4010         }*/
4011         return ins;
4012 }
4013
4014 gboolean
4015 mono_arch_print_tree (MonoInst *tree, int arity)
4016 {
4017         return 0;
4018 }
4019
4020 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4021 {
4022         MonoInst* ins;
4023
4024         setup_tls_access ();
4025         if (monodomain_key == -1)
4026                 return NULL;
4027         
4028         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4029         ins->inst_offset = monodomain_key;
4030         return ins;
4031 }
4032
4033 MonoInst* 
4034 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4035 {
4036         MonoInst* ins;
4037
4038         setup_tls_access ();
4039         if (monothread_key == -1)
4040                 return NULL;
4041         
4042         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4043         ins->inst_offset = monothread_key;
4044         return ins;
4045 }
4046
4047 gpointer
4048 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4049 {
4050         /* FIXME: implement */
4051         g_assert_not_reached ();
4052 }