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