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