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