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