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