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