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