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