d78ef80dfbb9e7d5fb18722c5e1306ddb6a6920e
[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         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3187                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3188                 //g_assert (!mono_compile_aot);
3189                 //cpos += 6;
3190                 //if (bb->cil_code)
3191                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3192                 /* this is not thread save, but good enough */
3193                 /* fixme: howto handle overflows? */
3194                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
3195         }
3196
3197         MONO_BB_FOR_EACH_INS (bb, ins) {
3198                 offset = code - cfg->native_code;
3199
3200                 max_len = ins_native_length (cfg, ins);
3201
3202                 if (offset > (cfg->code_size - max_len - 16)) {
3203                         cfg->code_size *= 2;
3204                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3205                         code = cfg->native_code + offset;
3206                 }
3207         //      if (ins->cil_code)
3208         //              g_print ("cil code\n");
3209                 mono_debug_record_line_number (cfg, ins, offset);
3210
3211                 switch (normalize_opcode (ins->opcode)) {
3212                 case OP_RELAXED_NOP:
3213                 case OP_NOP:
3214                 case OP_DUMMY_USE:
3215                 case OP_DUMMY_STORE:
3216                 case OP_NOT_REACHED:
3217                 case OP_NOT_NULL:
3218                         break;
3219                 case OP_IL_SEQ_POINT:
3220                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3221                         break;
3222                 case OP_SEQ_POINT: {
3223                         int i;
3224
3225                         if (cfg->compile_aot)
3226                                 NOT_IMPLEMENTED;
3227
3228                         /* 
3229                          * Read from the single stepping trigger page. This will cause a
3230                          * SIGSEGV when single stepping is enabled.
3231                          * We do this _before_ the breakpoint, so single stepping after
3232                          * a breakpoint is hit will step to the next IL offset.
3233                          */
3234                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3235                                 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3236                                 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3237                         }
3238
3239                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3240
3241                         /* 
3242                          * A placeholder for a possible breakpoint inserted by
3243                          * mono_arch_set_breakpoint ().
3244                          */
3245                         for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3246                                 ppc_nop (code);
3247                         break;
3248                 }
3249                 case OP_BIGMUL:
3250                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3251                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3252                         ppc_mr (code, ppc_r4, ppc_r0);
3253                         break;
3254                 case OP_BIGMUL_UN:
3255                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3256                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3257                         ppc_mr (code, ppc_r4, ppc_r0);
3258                         break;
3259                 case OP_MEMORY_BARRIER:
3260                         ppc_sync (code);
3261                         break;
3262                 case OP_STOREI1_MEMBASE_REG:
3263                         if (ppc_is_imm16 (ins->inst_offset)) {
3264                                 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3265                         } else {
3266                                 if (ppc_is_imm32 (ins->inst_offset)) {
3267                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3268                                         ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3269                                 } else {
3270                                         ppc_load (code, ppc_r0, ins->inst_offset);
3271                                         ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3272                                 }
3273                         }
3274                         break;
3275                 case OP_STOREI2_MEMBASE_REG:
3276                         if (ppc_is_imm16 (ins->inst_offset)) {
3277                                 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3278                         } else {
3279                                 if (ppc_is_imm32 (ins->inst_offset)) {
3280                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3281                                         ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3282                                 } else {
3283                                         ppc_load (code, ppc_r0, ins->inst_offset);
3284                                         ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3285                                 }
3286                         }
3287                         break;
3288                 case OP_STORE_MEMBASE_REG:
3289                         if (ppc_is_imm16 (ins->inst_offset)) {
3290                                 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3291                         } else {
3292                                 if (ppc_is_imm32 (ins->inst_offset)) {
3293                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3294                                         ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3295                                 } else {
3296                                         ppc_load (code, ppc_r0, ins->inst_offset);
3297                                         ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3298                                 }
3299                         }
3300                         break;
3301 #ifdef __mono_ilp32__
3302                 case OP_STOREI8_MEMBASE_REG:
3303                         if (ppc_is_imm16 (ins->inst_offset)) {
3304                                 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3305                         } else {
3306                                 ppc_load (code, ppc_r0, ins->inst_offset);
3307                                 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3308                         }
3309                         break;
3310 #endif
3311                 case OP_STOREI1_MEMINDEX:
3312                         ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3313                         break;
3314                 case OP_STOREI2_MEMINDEX:
3315                         ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3316                         break;
3317                 case OP_STORE_MEMINDEX:
3318                         ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3319                         break;
3320                 case OP_LOADU4_MEM:
3321                         g_assert_not_reached ();
3322                         break;
3323                 case OP_LOAD_MEMBASE:
3324                         if (ppc_is_imm16 (ins->inst_offset)) {
3325                                 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3326                         } else {
3327                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3328                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3329                                         ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3330                                 } else {
3331                                         ppc_load (code, ppc_r0, ins->inst_offset);
3332                                         ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3333                                 }
3334                         }
3335                         break;
3336                 case OP_LOADI4_MEMBASE:
3337 #ifdef __mono_ppc64__
3338                         if (ppc_is_imm16 (ins->inst_offset)) {
3339                                 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3340                         } else {
3341                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3342                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3343                                         ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3344                                 } else {
3345                                         ppc_load (code, ppc_r0, ins->inst_offset);
3346                                         ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3347                                 }
3348                         }
3349                         break;
3350 #endif
3351                 case OP_LOADU4_MEMBASE:
3352                         if (ppc_is_imm16 (ins->inst_offset)) {
3353                                 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3354                         } else {
3355                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3356                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3357                                         ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3358                                 } else {
3359                                         ppc_load (code, ppc_r0, ins->inst_offset);
3360                                         ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3361                                 }
3362                         }
3363                         break;
3364                 case OP_LOADI1_MEMBASE:
3365                 case OP_LOADU1_MEMBASE:
3366                         if (ppc_is_imm16 (ins->inst_offset)) {
3367                                 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3368                         } else {
3369                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3370                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3371                                         ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3372                                 } else {
3373                                         ppc_load (code, ppc_r0, ins->inst_offset);
3374                                         ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3375                                 }
3376                         }
3377                         if (ins->opcode == OP_LOADI1_MEMBASE)
3378                                 ppc_extsb (code, ins->dreg, ins->dreg);
3379                         break;
3380                 case OP_LOADU2_MEMBASE:
3381                         if (ppc_is_imm16 (ins->inst_offset)) {
3382                                 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3383                         } else {
3384                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3385                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3386                                         ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3387                                 } else {
3388                                         ppc_load (code, ppc_r0, ins->inst_offset);
3389                                         ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3390                                 }
3391                         }
3392                         break;
3393                 case OP_LOADI2_MEMBASE:
3394                         if (ppc_is_imm16 (ins->inst_offset)) {
3395                                 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3396                         } else {
3397                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3398                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3399                                         ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3400                                 } else {
3401                                         ppc_load (code, ppc_r0, ins->inst_offset);
3402                                         ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3403                                 }
3404                         }
3405                         break;
3406 #ifdef __mono_ilp32__
3407                 case OP_LOADI8_MEMBASE:
3408                         if (ppc_is_imm16 (ins->inst_offset)) {
3409                                 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3410                         } else {
3411                                 ppc_load (code, ppc_r0, ins->inst_offset);
3412                                 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3413                         }
3414                         break;
3415 #endif
3416                 case OP_LOAD_MEMINDEX:
3417                         ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3418                         break;
3419                 case OP_LOADI4_MEMINDEX:
3420 #ifdef __mono_ppc64__
3421                         ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3422                         break;
3423 #endif
3424                 case OP_LOADU4_MEMINDEX:
3425                         ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3426                         break;
3427                 case OP_LOADU2_MEMINDEX:
3428                         ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3429                         break;
3430                 case OP_LOADI2_MEMINDEX:
3431                         ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3432                         break;
3433                 case OP_LOADU1_MEMINDEX:
3434                         ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3435                         break;
3436                 case OP_LOADI1_MEMINDEX:
3437                         ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3438                         ppc_extsb (code, ins->dreg, ins->dreg);
3439                         break;
3440                 case OP_ICONV_TO_I1:
3441                 CASE_PPC64 (OP_LCONV_TO_I1)
3442                         ppc_extsb (code, ins->dreg, ins->sreg1);
3443                         break;
3444                 case OP_ICONV_TO_I2:
3445                 CASE_PPC64 (OP_LCONV_TO_I2)
3446                         ppc_extsh (code, ins->dreg, ins->sreg1);
3447                         break;
3448                 case OP_ICONV_TO_U1:
3449                 CASE_PPC64 (OP_LCONV_TO_U1)
3450                         ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3451                         break;
3452                 case OP_ICONV_TO_U2:
3453                 CASE_PPC64 (OP_LCONV_TO_U2)
3454                         ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3455                         break;
3456                 case OP_COMPARE:
3457                 case OP_ICOMPARE:
3458                 CASE_PPC64 (OP_LCOMPARE)
3459                         L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3460                         next = ins->next;
3461                         if (next && compare_opcode_is_unsigned (next->opcode))
3462                                 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3463                         else
3464                                 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3465                         break;
3466                 case OP_COMPARE_IMM:
3467                 case OP_ICOMPARE_IMM:
3468                 CASE_PPC64 (OP_LCOMPARE_IMM)
3469                         L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3470                         next = ins->next;
3471                         if (next && compare_opcode_is_unsigned (next->opcode)) {
3472                                 if (ppc_is_uimm16 (ins->inst_imm)) {
3473                                         ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3474                                 } else {
3475                                         g_assert_not_reached ();
3476                                 }
3477                         } else {
3478                                 if (ppc_is_imm16 (ins->inst_imm)) {
3479                                         ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3480                                 } else {
3481                                         g_assert_not_reached ();
3482                                 }
3483                         }
3484                         break;
3485                 case OP_BREAK:
3486                         /*
3487                          * gdb does not like encountering a trap in the debugged code. So 
3488                          * instead of emitting a trap, we emit a call a C function and place a 
3489                          * breakpoint there.
3490                          */
3491                         //ppc_break (code);
3492                         ppc_mr (code, ppc_r3, ins->sreg1);
3493                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3494                                              (gpointer)"mono_break");
3495                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3496                                 ppc_load_func (code, PPC_CALL_REG, 0);
3497                                 ppc_mtlr (code, PPC_CALL_REG);
3498                                 ppc_blrl (code);
3499                         } else {
3500                                 ppc_bl (code, 0);
3501                         }
3502                         break;
3503                 case OP_ADDCC:
3504                 case OP_IADDCC:
3505                         ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3506                         break;
3507                 case OP_IADD:
3508                 CASE_PPC64 (OP_LADD)
3509                         ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3510                         break;
3511                 case OP_ADC:
3512                 case OP_IADC:
3513                         ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3514                         break;
3515                 case OP_ADDCC_IMM:
3516                         if (ppc_is_imm16 (ins->inst_imm)) {
3517                                 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3518                         } else {
3519                                 g_assert_not_reached ();
3520                         }
3521                         break;
3522                 case OP_ADD_IMM:
3523                 case OP_IADD_IMM:
3524                 CASE_PPC64 (OP_LADD_IMM)
3525                         if (ppc_is_imm16 (ins->inst_imm)) {
3526                                 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3527                         } else {
3528                                 g_assert_not_reached ();
3529                         }
3530                         break;
3531                 case OP_IADD_OVF:
3532                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3533                          */
3534                         ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3535                         ppc_mfspr (code, ppc_r0, ppc_xer);
3536                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3537                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3538                         break;
3539                 case OP_IADD_OVF_UN:
3540                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3541                          */
3542                         ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3543                         ppc_mfspr (code, ppc_r0, ppc_xer);
3544                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3545                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3546                         break;
3547                 case OP_ISUB_OVF:
3548                 CASE_PPC64 (OP_LSUB_OVF)
3549                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3550                          */
3551                         ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3552                         ppc_mfspr (code, ppc_r0, ppc_xer);
3553                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3554                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3555                         break;
3556                 case OP_ISUB_OVF_UN:
3557                 CASE_PPC64 (OP_LSUB_OVF_UN)
3558                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3559                          */
3560                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3561                         ppc_mfspr (code, ppc_r0, ppc_xer);
3562                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3563                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3564                         break;
3565                 case OP_ADD_OVF_CARRY:
3566                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3567                          */
3568                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3569                         ppc_mfspr (code, ppc_r0, ppc_xer);
3570                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3571                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3572                         break;
3573                 case OP_ADD_OVF_UN_CARRY:
3574                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3575                          */
3576                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3577                         ppc_mfspr (code, ppc_r0, ppc_xer);
3578                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3579                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3580                         break;
3581                 case OP_SUB_OVF_CARRY:
3582                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3583                          */
3584                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3585                         ppc_mfspr (code, ppc_r0, ppc_xer);
3586                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3587                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3588                         break;
3589                 case OP_SUB_OVF_UN_CARRY:
3590                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3591                          */
3592                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3593                         ppc_mfspr (code, ppc_r0, ppc_xer);
3594                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3595                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3596                         break;
3597                 case OP_SUBCC:
3598                 case OP_ISUBCC:
3599                         ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3600                         break;
3601                 case OP_ISUB:
3602                 CASE_PPC64 (OP_LSUB)
3603                         ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3604                         break;
3605                 case OP_SBB:
3606                 case OP_ISBB:
3607                         ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3608                         break;
3609                 case OP_SUB_IMM:
3610                 case OP_ISUB_IMM:
3611                 CASE_PPC64 (OP_LSUB_IMM)
3612                         // we add the negated value
3613                         if (ppc_is_imm16 (-ins->inst_imm))
3614                                 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3615                         else {
3616                                 g_assert_not_reached ();
3617                         }
3618                         break;
3619                 case OP_PPC_SUBFIC:
3620                         g_assert (ppc_is_imm16 (ins->inst_imm));
3621                         ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3622                         break;
3623                 case OP_PPC_SUBFZE:
3624                         ppc_subfze (code, ins->dreg, ins->sreg1);
3625                         break;
3626                 case OP_IAND:
3627                 CASE_PPC64 (OP_LAND)
3628                         /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3629                         ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3630                         break;
3631                 case OP_AND_IMM:
3632                 case OP_IAND_IMM:
3633                 CASE_PPC64 (OP_LAND_IMM)
3634                         if (!(ins->inst_imm & 0xffff0000)) {
3635                                 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3636                         } else if (!(ins->inst_imm & 0xffff)) {
3637                                 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3638                         } else {
3639                                 g_assert_not_reached ();
3640                         }
3641                         break;
3642                 case OP_IDIV:
3643                 CASE_PPC64 (OP_LDIV) {
3644                         guint8 *divisor_is_m1;
3645                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3646                          */
3647                         ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3648                         divisor_is_m1 = code;
3649                         ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3650                         ppc_lis (code, ppc_r0, 0x8000);
3651 #ifdef __mono_ppc64__
3652                         if (ins->opcode == OP_LDIV)
3653                                 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3654 #endif
3655                         ppc_compare (code, 0, ins->sreg1, ppc_r0);
3656                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3657                         ppc_patch (divisor_is_m1, code);
3658                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3659                          */
3660                         if (ins->opcode == OP_IDIV)
3661                                 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3662 #ifdef __mono_ppc64__
3663                         else
3664                                 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3665 #endif
3666                         ppc_mfspr (code, ppc_r0, ppc_xer);
3667                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3668                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3669                         break;
3670                 }
3671                 case OP_IDIV_UN:
3672                 CASE_PPC64 (OP_LDIV_UN)
3673                         if (ins->opcode == OP_IDIV_UN)
3674                                 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3675 #ifdef __mono_ppc64__
3676                         else
3677                                 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3678 #endif
3679                         ppc_mfspr (code, ppc_r0, ppc_xer);
3680                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3681                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3682                         break;
3683                 case OP_DIV_IMM:
3684                 case OP_IREM:
3685                 case OP_IREM_UN:
3686                 case OP_REM_IMM:
3687                         g_assert_not_reached ();
3688                 case OP_IOR:
3689                 CASE_PPC64 (OP_LOR)
3690                         ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3691                         break;
3692                 case OP_OR_IMM:
3693                 case OP_IOR_IMM:
3694                 CASE_PPC64 (OP_LOR_IMM)
3695                         if (!(ins->inst_imm & 0xffff0000)) {
3696                                 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3697                         } else if (!(ins->inst_imm & 0xffff)) {
3698                                 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3699                         } else {
3700                                 g_assert_not_reached ();
3701                         }
3702                         break;
3703                 case OP_IXOR:
3704                 CASE_PPC64 (OP_LXOR)
3705                         ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3706                         break;
3707                 case OP_IXOR_IMM:
3708                 case OP_XOR_IMM:
3709                 CASE_PPC64 (OP_LXOR_IMM)
3710                         if (!(ins->inst_imm & 0xffff0000)) {
3711                                 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3712                         } else if (!(ins->inst_imm & 0xffff)) {
3713                                 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3714                         } else {
3715                                 g_assert_not_reached ();
3716                         }
3717                         break;
3718                 case OP_ISHL:
3719                 CASE_PPC64 (OP_LSHL)
3720                         ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3721                         break;
3722                 case OP_SHL_IMM:
3723                 case OP_ISHL_IMM:
3724                 CASE_PPC64 (OP_LSHL_IMM)
3725                         ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3726                         break;
3727                 case OP_ISHR:
3728                         ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3729                         break;
3730                 case OP_SHR_IMM:
3731                         ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3732                         break;
3733                 case OP_SHR_UN_IMM:
3734                         if (MASK_SHIFT_IMM (ins->inst_imm))
3735                                 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3736                         else
3737                                 ppc_mr (code, ins->dreg, ins->sreg1);
3738                         break;
3739                 case OP_ISHR_UN:
3740                         ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3741                         break;
3742                 case OP_INOT:
3743                 CASE_PPC64 (OP_LNOT)
3744                         ppc_not (code, ins->dreg, ins->sreg1);
3745                         break;
3746                 case OP_INEG:
3747                 CASE_PPC64 (OP_LNEG)
3748                         ppc_neg (code, ins->dreg, ins->sreg1);
3749                         break;
3750                 case OP_IMUL:
3751                 CASE_PPC64 (OP_LMUL)
3752                         ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3753                         break;
3754                 case OP_IMUL_IMM:
3755                 case OP_MUL_IMM:
3756                 CASE_PPC64 (OP_LMUL_IMM)
3757                         if (ppc_is_imm16 (ins->inst_imm)) {
3758                             ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3759                         } else {
3760                             g_assert_not_reached ();
3761                         }
3762                         break;
3763                 case OP_IMUL_OVF:
3764                 CASE_PPC64 (OP_LMUL_OVF)
3765                         /* we annot use mcrxr, since it's not implemented on some processors 
3766                          * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3767                          */
3768                         if (ins->opcode == OP_IMUL_OVF)
3769                                 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3770 #ifdef __mono_ppc64__
3771                         else
3772                                 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3773 #endif
3774                         ppc_mfspr (code, ppc_r0, ppc_xer);
3775                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3776                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3777                         break;
3778                 case OP_IMUL_OVF_UN:
3779                 CASE_PPC64 (OP_LMUL_OVF_UN)
3780                         /* we first multiply to get the high word and compare to 0
3781                          * to set the flags, then the result is discarded and then 
3782                          * we multiply to get the lower * bits result
3783                          */
3784                         if (ins->opcode == OP_IMUL_OVF_UN)
3785                                 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3786 #ifdef __mono_ppc64__
3787                         else
3788                                 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3789 #endif
3790                         ppc_cmpi (code, 0, 0, ppc_r0, 0);
3791                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3792                         ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3793                         break;
3794                 case OP_ICONST:
3795                         ppc_load (code, ins->dreg, ins->inst_c0);
3796                         break;
3797                 case OP_I8CONST: {
3798                         ppc_load (code, ins->dreg, ins->inst_l);
3799                         break;
3800                 }
3801                 case OP_LOAD_GOTADDR:
3802                         /* The PLT implementation depends on this */
3803                         g_assert (ins->dreg == ppc_r30);
3804
3805                         code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3806                         break;
3807                 case OP_GOT_ENTRY:
3808                         // FIXME: Fix max instruction length
3809                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3810                         /* arch_emit_got_access () patches this */
3811                         ppc_load32 (code, ppc_r0, 0);
3812                         ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3813                         break;
3814                 case OP_AOTCONST:
3815                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3816                         ppc_load_sequence (code, ins->dreg, 0);
3817                         break;
3818                 CASE_PPC32 (OP_ICONV_TO_I4)
3819                 CASE_PPC32 (OP_ICONV_TO_U4)
3820                 case OP_MOVE:
3821                         if (ins->dreg != ins->sreg1)
3822                                 ppc_mr (code, ins->dreg, ins->sreg1);
3823                         break;
3824                 case OP_SETLRET: {
3825                         int saved = ins->sreg1;
3826                         if (ins->sreg1 == ppc_r3) {
3827                                 ppc_mr (code, ppc_r0, ins->sreg1);
3828                                 saved = ppc_r0;
3829                         }
3830                         if (ins->sreg2 != ppc_r3)
3831                                 ppc_mr (code, ppc_r3, ins->sreg2);
3832                         if (saved != ppc_r4)
3833                                 ppc_mr (code, ppc_r4, saved);
3834                         break;
3835                 }
3836                 case OP_FMOVE:
3837                         if (ins->dreg != ins->sreg1)
3838                                 ppc_fmr (code, ins->dreg, ins->sreg1);
3839                         break;
3840                 case OP_MOVE_F_TO_I4:
3841                         ppc_stfs (code, ins->sreg1, -4, ppc_r1);
3842                         ppc_ldptr (code, ins->dreg, -4, ppc_r1);
3843                         break;
3844                 case OP_MOVE_I4_TO_F:
3845                         ppc_stw (code, ins->sreg1, -4, ppc_r1);
3846                         ppc_lfs (code, ins->dreg, -4, ppc_r1);
3847                         break;
3848                 case OP_FCONV_TO_R4:
3849                         ppc_frsp (code, ins->dreg, ins->sreg1);
3850                         break;
3851                 case OP_TAILCALL: {
3852                         int i, pos;
3853                         MonoCallInst *call = (MonoCallInst*)ins;
3854
3855                         /*
3856                          * Keep in sync with mono_arch_emit_epilog
3857                          */
3858                         g_assert (!cfg->method->save_lmf);
3859                         /*
3860                          * Note: we can use ppc_r12 here because it is dead anyway:
3861                          * we're leaving the method.
3862                          */
3863                         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3864                                 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3865                                 if (ppc_is_imm16 (ret_offset)) {
3866                                         ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3867                                 } else {
3868                                         ppc_load (code, ppc_r12, ret_offset);
3869                                         ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3870                                 }
3871                                 ppc_mtlr (code, ppc_r0);
3872                         }
3873
3874                         if (ppc_is_imm16 (cfg->stack_usage)) {
3875                                 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3876                         } else {
3877                                 /* cfg->stack_usage is an int, so we can use
3878                                  * an addis/addi sequence here even in 64-bit.  */
3879                                 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3880                                 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3881                         }
3882                         if (!cfg->method->save_lmf) {
3883                                 pos = 0;
3884                                 for (i = 31; i >= 13; --i) {
3885                                         if (cfg->used_int_regs & (1 << i)) {
3886                                                 pos += sizeof (gpointer);
3887                                                 ppc_ldptr (code, i, -pos, ppc_r12);
3888                                         }
3889                                 }
3890                         } else {
3891                                 /* FIXME restore from MonoLMF: though this can't happen yet */
3892                         }
3893
3894                         /* Copy arguments on the stack to our argument area */
3895                         if (call->stack_usage) {
3896                                 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3897                                 /* r12 was clobbered */
3898                                 g_assert (cfg->frame_reg == ppc_sp);
3899                                 if (ppc_is_imm16 (cfg->stack_usage)) {
3900                                         ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3901                                 } else {
3902                                         /* cfg->stack_usage is an int, so we can use
3903                                          * an addis/addi sequence here even in 64-bit.  */
3904                                         ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3905                                         ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3906                                 }
3907                         }
3908
3909                         ppc_mr (code, ppc_sp, ppc_r12);
3910                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3911                         if (cfg->compile_aot) {
3912                                 /* arch_emit_got_access () patches this */
3913                                 ppc_load32 (code, ppc_r0, 0);
3914 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3915                                 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3916                                 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3917 #else
3918                                 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3919 #endif
3920                                 ppc_mtctr (code, ppc_r0);
3921                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3922                         } else {
3923                                 ppc_b (code, 0);
3924                         }
3925                         break;
3926                 }
3927                 case OP_CHECK_THIS:
3928                         /* ensure ins->sreg1 is not NULL */
3929                         ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3930                         break;
3931                 case OP_ARGLIST: {
3932                         long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3933                         if (ppc_is_imm16 (cookie_offset)) {
3934                                 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3935                         } else {
3936                                 ppc_load (code, ppc_r0, cookie_offset);
3937                                 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3938                         }
3939                         ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3940                         break;
3941                 }
3942                 case OP_FCALL:
3943                 case OP_LCALL:
3944                 case OP_VCALL:
3945                 case OP_VCALL2:
3946                 case OP_VOIDCALL:
3947                 case OP_CALL:
3948                         call = (MonoCallInst*)ins;
3949                         if (ins->flags & MONO_INST_HAS_METHOD)
3950                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3951                         else
3952                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3953                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3954                                 ppc_load_func (code, PPC_CALL_REG, 0);
3955                                 ppc_mtlr (code, PPC_CALL_REG);
3956                                 ppc_blrl (code);
3957                         } else {
3958                                 ppc_bl (code, 0);
3959                         }
3960                         /* FIXME: this should be handled somewhere else in the new jit */
3961                         code = emit_move_return_value (cfg, ins, code);
3962                         break;
3963                 case OP_FCALL_REG:
3964                 case OP_LCALL_REG:
3965                 case OP_VCALL_REG:
3966                 case OP_VCALL2_REG:
3967                 case OP_VOIDCALL_REG:
3968                 case OP_CALL_REG:
3969 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3970                         ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3971                         /* FIXME: if we know that this is a method, we
3972                            can omit this load */
3973                         ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
3974                         ppc_mtlr (code, ppc_r0);
3975 #else
3976 #if (_CALL_ELF == 2)
3977                         if (ins->flags & MONO_INST_HAS_METHOD) {
3978                           // Not a global entry point
3979                         } else {
3980                                  // Need to set up r12 with function entry address for global entry point
3981                                  if (ppc_r12 != ins->sreg1) {
3982                                          ppc_mr(code,ppc_r12,ins->sreg1);
3983                                  }
3984                         }
3985 #endif
3986                         ppc_mtlr (code, ins->sreg1);
3987 #endif
3988                         ppc_blrl (code);
3989                         /* FIXME: this should be handled somewhere else in the new jit */
3990                         code = emit_move_return_value (cfg, ins, code);
3991                         break;
3992                 case OP_FCALL_MEMBASE:
3993                 case OP_LCALL_MEMBASE:
3994                 case OP_VCALL_MEMBASE:
3995                 case OP_VCALL2_MEMBASE:
3996                 case OP_VOIDCALL_MEMBASE:
3997                 case OP_CALL_MEMBASE:
3998                         if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
3999                                 /* The trampolines clobber this */
4000                                 ppc_mr (code, ppc_r29, ins->sreg1);
4001                                 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4002                         } else {
4003                                 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4004                         }
4005                         ppc_mtlr (code, ppc_r0);
4006                         ppc_blrl (code);
4007                         /* FIXME: this should be handled somewhere else in the new jit */
4008                         code = emit_move_return_value (cfg, ins, code);
4009                         break;
4010                 case OP_LOCALLOC: {
4011                         guint8 * zero_loop_jump, * zero_loop_start;
4012                         /* keep alignment */
4013                         int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4014                         int area_offset = alloca_waste;
4015                         area_offset &= ~31;
4016                         ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
4017                         /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4018                         ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
4019                         /* use ctr to store the number of words to 0 if needed */
4020                         if (ins->flags & MONO_INST_INIT) {
4021                                 /* we zero 4 bytes at a time:
4022                                  * we add 7 instead of 3 so that we set the counter to
4023                                  * at least 1, otherwise the bdnz instruction will make
4024                                  * it negative and iterate billions of times.
4025                                  */
4026                                 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4027                                 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4028                                 ppc_mtctr (code, ppc_r0);
4029                         }
4030                         ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4031                         ppc_neg (code, ppc_r12, ppc_r12);
4032                         ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
4033
4034                         /* FIXME: make this loop work in 8 byte
4035                            increments on PPC64 */
4036                         if (ins->flags & MONO_INST_INIT) {
4037                                 /* adjust the dest reg by -4 so we can use stwu */
4038                                 /* we actually adjust -8 because we let the loop
4039                                  * run at least once
4040                                  */
4041                                 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4042                                 ppc_li (code, ppc_r12, 0);
4043                                 zero_loop_start = code;
4044                                 ppc_stwu (code, ppc_r12, 4, ins->dreg);
4045                                 zero_loop_jump = code;
4046                                 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4047                                 ppc_patch (zero_loop_jump, zero_loop_start);
4048                         }
4049                         ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4050                         break;
4051                 }
4052                 case OP_THROW: {
4053                         //ppc_break (code);
4054                         ppc_mr (code, ppc_r3, ins->sreg1);
4055                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4056                                              (gpointer)"mono_arch_throw_exception");
4057                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4058                                 ppc_load_func (code, PPC_CALL_REG, 0);
4059                                 ppc_mtlr (code, PPC_CALL_REG);
4060                                 ppc_blrl (code);
4061                         } else {
4062                                 ppc_bl (code, 0);
4063                         }
4064                         break;
4065                 }
4066                 case OP_RETHROW: {
4067                         //ppc_break (code);
4068                         ppc_mr (code, ppc_r3, ins->sreg1);
4069                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4070                                              (gpointer)"mono_arch_rethrow_exception");
4071                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4072                                 ppc_load_func (code, PPC_CALL_REG, 0);
4073                                 ppc_mtlr (code, PPC_CALL_REG);
4074                                 ppc_blrl (code);
4075                         } else {
4076                                 ppc_bl (code, 0);
4077                         }
4078                         break;
4079                 }
4080                 case OP_START_HANDLER: {
4081                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4082                         g_assert (spvar->inst_basereg != ppc_sp);
4083                         code = emit_reserve_param_area (cfg, code);
4084                         ppc_mflr (code, ppc_r0);
4085                         if (ppc_is_imm16 (spvar->inst_offset)) {
4086                                 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4087                         } else {
4088                                 ppc_load (code, ppc_r12, spvar->inst_offset);
4089                                 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
4090                         }
4091                         break;
4092                 }
4093                 case OP_ENDFILTER: {
4094                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4095                         g_assert (spvar->inst_basereg != ppc_sp);
4096                         code = emit_unreserve_param_area (cfg, code);
4097                         if (ins->sreg1 != ppc_r3)
4098                                 ppc_mr (code, ppc_r3, ins->sreg1);
4099                         if (ppc_is_imm16 (spvar->inst_offset)) {
4100                                 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4101                         } else {
4102                                 ppc_load (code, ppc_r12, spvar->inst_offset);
4103                                 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
4104                         }
4105                         ppc_mtlr (code, ppc_r0);
4106                         ppc_blr (code);
4107                         break;
4108                 }
4109                 case OP_ENDFINALLY: {
4110                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4111                         g_assert (spvar->inst_basereg != ppc_sp);
4112                         code = emit_unreserve_param_area (cfg, code);
4113                         ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4114                         ppc_mtlr (code, ppc_r0);
4115                         ppc_blr (code);
4116                         break;
4117                 }
4118                 case OP_CALL_HANDLER: 
4119                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4120                         ppc_bl (code, 0);
4121                         mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4122                         break;
4123                 case OP_LABEL:
4124                         ins->inst_c0 = code - cfg->native_code;
4125                         break;
4126                 case OP_BR:
4127                         /*if (ins->inst_target_bb->native_offset) {
4128                                 ppc_b (code, 0);
4129                                 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
4130                         } else*/ {
4131                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4132                                 ppc_b (code, 0);
4133                         }
4134                         break;
4135                 case OP_BR_REG:
4136                         ppc_mtctr (code, ins->sreg1);
4137                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4138                         break;
4139                 case OP_CEQ:
4140                 case OP_ICEQ:
4141                 CASE_PPC64 (OP_LCEQ)
4142                         ppc_li (code, ins->dreg, 0);
4143                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4144                         ppc_li (code, ins->dreg, 1);
4145                         break;
4146                 case OP_CLT:
4147                 case OP_CLT_UN:
4148                 case OP_ICLT:
4149                 case OP_ICLT_UN:
4150                 CASE_PPC64 (OP_LCLT)
4151                 CASE_PPC64 (OP_LCLT_UN)
4152                         ppc_li (code, ins->dreg, 1);
4153                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4154                         ppc_li (code, ins->dreg, 0);
4155                         break;
4156                 case OP_CGT:
4157                 case OP_CGT_UN:
4158                 case OP_ICGT:
4159                 case OP_ICGT_UN:
4160                 CASE_PPC64 (OP_LCGT)
4161                 CASE_PPC64 (OP_LCGT_UN)
4162                         ppc_li (code, ins->dreg, 1);
4163                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4164                         ppc_li (code, ins->dreg, 0);
4165                         break;
4166                 case OP_COND_EXC_EQ:
4167                 case OP_COND_EXC_NE_UN:
4168                 case OP_COND_EXC_LT:
4169                 case OP_COND_EXC_LT_UN:
4170                 case OP_COND_EXC_GT:
4171                 case OP_COND_EXC_GT_UN:
4172                 case OP_COND_EXC_GE:
4173                 case OP_COND_EXC_GE_UN:
4174                 case OP_COND_EXC_LE:
4175                 case OP_COND_EXC_LE_UN:
4176                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4177                         break;
4178                 case OP_COND_EXC_IEQ:
4179                 case OP_COND_EXC_INE_UN:
4180                 case OP_COND_EXC_ILT:
4181                 case OP_COND_EXC_ILT_UN:
4182                 case OP_COND_EXC_IGT:
4183                 case OP_COND_EXC_IGT_UN:
4184                 case OP_COND_EXC_IGE:
4185                 case OP_COND_EXC_IGE_UN:
4186                 case OP_COND_EXC_ILE:
4187                 case OP_COND_EXC_ILE_UN:
4188                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4189                         break;
4190                 case OP_IBEQ:
4191                 case OP_IBNE_UN:
4192                 case OP_IBLT:
4193                 case OP_IBLT_UN:
4194                 case OP_IBGT:
4195                 case OP_IBGT_UN:
4196                 case OP_IBGE:
4197                 case OP_IBGE_UN:
4198                 case OP_IBLE:
4199                 case OP_IBLE_UN:
4200                         EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4201                         break;
4202
4203                 /* floating point opcodes */
4204                 case OP_R8CONST:
4205                         g_assert (cfg->compile_aot);
4206
4207                         /* FIXME: Optimize this */
4208                         ppc_bl (code, 1);
4209                         ppc_mflr (code, ppc_r12);
4210                         ppc_b (code, 3);
4211                         *(double*)code = *(double*)ins->inst_p0;
4212                         code += 8;
4213                         ppc_lfd (code, ins->dreg, 8, ppc_r12);
4214                         break;
4215                 case OP_R4CONST:
4216                         g_assert_not_reached ();
4217                         break;
4218                 case OP_STORER8_MEMBASE_REG:
4219                         if (ppc_is_imm16 (ins->inst_offset)) {
4220                                 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4221                         } else {
4222                                 if (ppc_is_imm32 (ins->inst_offset)) {
4223                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4224                                         ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4225                                 } else {
4226                                         ppc_load (code, ppc_r0, ins->inst_offset);
4227                                         ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4228                                 }
4229                         }
4230                         break;
4231                 case OP_LOADR8_MEMBASE:
4232                         if (ppc_is_imm16 (ins->inst_offset)) {
4233                                 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4234                         } else {
4235                                 if (ppc_is_imm32 (ins->inst_offset)) {
4236                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4237                                         ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4238                                 } else {
4239                                         ppc_load (code, ppc_r0, ins->inst_offset);
4240                                         ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4241                                 }
4242                         }
4243                         break;
4244                 case OP_STORER4_MEMBASE_REG:
4245                         ppc_frsp (code, ins->sreg1, ins->sreg1);
4246                         if (ppc_is_imm16 (ins->inst_offset)) {
4247                                 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4248                         } else {
4249                                 if (ppc_is_imm32 (ins->inst_offset)) {
4250                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4251                                         ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4252                                 } else {
4253                                         ppc_load (code, ppc_r0, ins->inst_offset);
4254                                         ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4255                                 }
4256                         }
4257                         break;
4258                 case OP_LOADR4_MEMBASE:
4259                         if (ppc_is_imm16 (ins->inst_offset)) {
4260                                 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4261                         } else {
4262                                 if (ppc_is_imm32 (ins->inst_offset)) {
4263                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4264                                         ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4265                                 } else {
4266                                         ppc_load (code, ppc_r0, ins->inst_offset);
4267                                         ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4268                                 }
4269                         }
4270                         break;
4271                 case OP_LOADR4_MEMINDEX:
4272                         ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4273                         break;
4274                 case OP_LOADR8_MEMINDEX:
4275                         ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4276                         break;
4277                 case OP_STORER4_MEMINDEX:
4278                         ppc_frsp (code, ins->sreg1, ins->sreg1);
4279                         ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4280                         break;
4281                 case OP_STORER8_MEMINDEX:
4282                         ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4283                         break;
4284                 case CEE_CONV_R_UN:
4285                 case CEE_CONV_R4: /* FIXME: change precision */
4286                 case CEE_CONV_R8:
4287                         g_assert_not_reached ();
4288                 case OP_FCONV_TO_I1:
4289                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4290                         break;
4291                 case OP_FCONV_TO_U1:
4292                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4293                         break;
4294                 case OP_FCONV_TO_I2:
4295                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4296                         break;
4297                 case OP_FCONV_TO_U2:
4298                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4299                         break;
4300                 case OP_FCONV_TO_I4:
4301                 case OP_FCONV_TO_I:
4302                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4303                         break;
4304                 case OP_FCONV_TO_U4:
4305                 case OP_FCONV_TO_U:
4306                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4307                         break;
4308                 case OP_LCONV_TO_R_UN:
4309                         g_assert_not_reached ();
4310                         /* Implemented as helper calls */
4311                         break;
4312                 case OP_LCONV_TO_OVF_I4_2:
4313                 case OP_LCONV_TO_OVF_I: {
4314 #ifdef __mono_ppc64__
4315                         NOT_IMPLEMENTED;
4316 #else
4317                         guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4318                         // Check if its negative
4319                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4320                         negative_branch = code;
4321                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4322                         // Its positive msword == 0
4323                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4324                         msword_positive_branch = code;
4325                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4326
4327                         ovf_ex_target = code;
4328                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4329                         // Negative
4330                         ppc_patch (negative_branch, code);
4331                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4332                         msword_negative_branch = code;
4333                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4334                         ppc_patch (msword_negative_branch, ovf_ex_target);
4335                         
4336                         ppc_patch (msword_positive_branch, code);
4337                         if (ins->dreg != ins->sreg1)
4338                                 ppc_mr (code, ins->dreg, ins->sreg1);
4339                         break;
4340 #endif
4341                 }
4342                 case OP_SQRT:
4343                         ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4344                         break;
4345                 case OP_FADD:
4346                         ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4347                         break;
4348                 case OP_FSUB:
4349                         ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4350                         break;          
4351                 case OP_FMUL:
4352                         ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4353                         break;          
4354                 case OP_FDIV:
4355                         ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4356                         break;          
4357                 case OP_FNEG:
4358                         ppc_fneg (code, ins->dreg, ins->sreg1);
4359                         break;          
4360                 case OP_FREM:
4361                         /* emulated */
4362                         g_assert_not_reached ();
4363                         break;
4364                 case OP_FCOMPARE:
4365                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4366                         break;
4367                 case OP_FCEQ:
4368                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4369                         ppc_li (code, ins->dreg, 0);
4370                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4371                         ppc_li (code, ins->dreg, 1);
4372                         break;
4373                 case OP_FCLT:
4374                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4375                         ppc_li (code, ins->dreg, 1);
4376                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4377                         ppc_li (code, ins->dreg, 0);
4378                         break;
4379                 case OP_FCLT_UN:
4380                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4381                         ppc_li (code, ins->dreg, 1);
4382                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4383                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4384                         ppc_li (code, ins->dreg, 0);
4385                         break;
4386                 case OP_FCGT:
4387                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4388                         ppc_li (code, ins->dreg, 1);
4389                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4390                         ppc_li (code, ins->dreg, 0);
4391                         break;
4392                 case OP_FCGT_UN:
4393                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4394                         ppc_li (code, ins->dreg, 1);
4395                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4396                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4397                         ppc_li (code, ins->dreg, 0);
4398                         break;
4399                 case OP_FBEQ:
4400                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4401                         break;
4402                 case OP_FBNE_UN:
4403                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4404                         break;
4405                 case OP_FBLT:
4406                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4407                         EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4408                         break;
4409                 case OP_FBLT_UN:
4410                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4411                         EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4412                         break;
4413                 case OP_FBGT:
4414                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4415                         EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4416                         break;
4417                 case OP_FBGT_UN:
4418                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4419                         EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4420                         break;
4421                 case OP_FBGE:
4422                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4423                         EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4424                         break;
4425                 case OP_FBGE_UN:
4426                         EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4427                         break;
4428                 case OP_FBLE:
4429                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4430                         EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4431                         break;
4432                 case OP_FBLE_UN:
4433                         EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4434                         break;
4435                 case OP_CKFINITE:
4436                         g_assert_not_reached ();
4437                 case OP_CHECK_FINITE: {
4438                         ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4439                         ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4440                         ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4441                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4442                         break;
4443                 case OP_JUMP_TABLE:
4444                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4445 #ifdef __mono_ppc64__
4446                         ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4447 #else
4448                         ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4449 #endif
4450                         break;
4451                 }
4452
4453 #ifdef __mono_ppc64__
4454                 case OP_ICONV_TO_I4:
4455                 case OP_SEXT_I4:
4456                         ppc_extsw (code, ins->dreg, ins->sreg1);
4457                         break;
4458                 case OP_ICONV_TO_U4:
4459                 case OP_ZEXT_I4:
4460                         ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4461                         break;
4462                 case OP_ICONV_TO_R4:
4463                 case OP_ICONV_TO_R8:
4464                 case OP_LCONV_TO_R4:
4465                 case OP_LCONV_TO_R8: {
4466                         int tmp;
4467                         if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4468                                 ppc_extsw (code, ppc_r0, ins->sreg1);
4469                                 tmp = ppc_r0;
4470                         } else {
4471                                 tmp = ins->sreg1;
4472                         }
4473                         if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4474                                 ppc_mffgpr (code, ins->dreg, tmp);
4475                         } else {
4476                                 ppc_str (code, tmp, -8, ppc_r1);
4477                                 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4478                         }
4479                         ppc_fcfid (code, ins->dreg, ins->dreg);
4480                         if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4481                                 ppc_frsp (code, ins->dreg, ins->dreg);
4482                         break;
4483                 }
4484                 case OP_LSHR:
4485                         ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4486                         break;
4487                 case OP_LSHR_UN:
4488                         ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4489                         break;
4490                 case OP_COND_EXC_C:
4491                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4492                          */
4493                         ppc_mfspr (code, ppc_r0, ppc_xer);
4494                         ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4495                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4496                         break;
4497                 case OP_COND_EXC_OV:
4498                         ppc_mfspr (code, ppc_r0, ppc_xer);
4499                         ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4500                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4501                         break;
4502                 case OP_LBEQ:
4503                 case OP_LBNE_UN:
4504                 case OP_LBLT:
4505                 case OP_LBLT_UN:
4506                 case OP_LBGT:
4507                 case OP_LBGT_UN:
4508                 case OP_LBGE:
4509                 case OP_LBGE_UN:
4510                 case OP_LBLE:
4511                 case OP_LBLE_UN:
4512                         EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4513                         break;
4514                 case OP_FCONV_TO_I8:
4515                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4516                         break;
4517                 case OP_FCONV_TO_U8:
4518                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4519                         break;
4520                 case OP_STOREI4_MEMBASE_REG:
4521                         if (ppc_is_imm16 (ins->inst_offset)) {
4522                                 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4523                         } else {
4524                                 ppc_load (code, ppc_r0, ins->inst_offset);
4525                                 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4526                         }
4527                         break;
4528                 case OP_STOREI4_MEMINDEX:
4529                         ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4530                         break;
4531                 case OP_ISHR_IMM:
4532                         ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4533                         break;
4534                 case OP_ISHR_UN_IMM:
4535                         if (ins->inst_imm & 0x1f)
4536                                 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4537                         else
4538                                 ppc_mr (code, ins->dreg, ins->sreg1);
4539                         break;
4540 #else
4541                 case OP_ICONV_TO_R4:
4542                 case OP_ICONV_TO_R8: {
4543                         if (cpu_hw_caps & PPC_ISA_64) {
4544                                 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4545                                 ppc_stw (code, ppc_r0, -8, ppc_r1);
4546                                 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4547                                 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4548                                 ppc_fcfid (code, ins->dreg, ins->dreg);
4549                                 if (ins->opcode == OP_ICONV_TO_R4)
4550                                         ppc_frsp (code, ins->dreg, ins->dreg);
4551                                 }
4552                         break;
4553                 }
4554 #endif
4555
4556                 case OP_ATOMIC_ADD_I4:
4557                 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4558                         int location = ins->inst_basereg;
4559                         int addend = ins->sreg2;
4560                         guint8 *loop, *branch;
4561                         g_assert (ins->inst_offset == 0);
4562
4563                         loop = code;
4564                         ppc_sync (code);
4565                         if (ins->opcode == OP_ATOMIC_ADD_I4)
4566                                 ppc_lwarx (code, ppc_r0, 0, location);
4567 #ifdef __mono_ppc64__
4568                         else
4569                                 ppc_ldarx (code, ppc_r0, 0, location);
4570 #endif
4571
4572                         ppc_add (code, ppc_r0, ppc_r0, addend);
4573
4574                         if (ins->opcode == OP_ATOMIC_ADD_I4)
4575                                 ppc_stwcxd (code, ppc_r0, 0, location);
4576 #ifdef __mono_ppc64__
4577                         else
4578                                 ppc_stdcxd (code, ppc_r0, 0, location);
4579 #endif
4580
4581                         branch = code;
4582                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4583                         ppc_patch (branch, loop);
4584
4585                         ppc_sync (code);
4586                         ppc_mr (code, ins->dreg, ppc_r0);
4587                         break;
4588                 }
4589                 case OP_ATOMIC_CAS_I4:
4590                 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4591                         int location = ins->sreg1;
4592                         int value = ins->sreg2;
4593                         int comparand = ins->sreg3;
4594                         guint8 *start, *not_equal, *lost_reservation;
4595
4596                         start = code;
4597                         ppc_sync (code);
4598                         if (ins->opcode == OP_ATOMIC_CAS_I4)
4599                                 ppc_lwarx (code, ppc_r0, 0, location);
4600 #ifdef __mono_ppc64__
4601                         else
4602                                 ppc_ldarx (code, ppc_r0, 0, location);
4603 #endif
4604
4605                         ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4606                         not_equal = code;
4607                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4608
4609                         if (ins->opcode == OP_ATOMIC_CAS_I4)
4610                                 ppc_stwcxd (code, value, 0, location);
4611 #ifdef __mono_ppc64__
4612                         else
4613                                 ppc_stdcxd (code, value, 0, location);
4614 #endif
4615
4616                         lost_reservation = code;
4617                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4618                         ppc_patch (lost_reservation, start);
4619                         ppc_patch (not_equal, code);
4620
4621                         ppc_sync (code);
4622                         ppc_mr (code, ins->dreg, ppc_r0);
4623                         break;
4624                 }
4625                 case OP_GC_SAFE_POINT:
4626                         break;
4627
4628                 default:
4629                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4630                         g_assert_not_reached ();
4631                 }
4632
4633                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4634                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4635                                    mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4636                         g_assert_not_reached ();
4637                 }
4638                
4639                 cpos += max_len;
4640
4641                 last_ins = ins;
4642                 last_offset = offset;
4643         }
4644
4645         cfg->code_len = code - cfg->native_code;
4646 }
4647 #endif /* !DISABLE_JIT */
4648
4649 void
4650 mono_arch_register_lowlevel_calls (void)
4651 {
4652         /* The signature doesn't matter */
4653         mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4654 }
4655
4656 #ifdef __mono_ppc64__
4657 #ifdef _LITTLE_ENDIAN
4658 #define patch_load_sequence(ip,val) do {\
4659                 guint16 *__load = (guint16*)(ip);       \
4660                 g_assert (sizeof (val) == sizeof (gsize)); \
4661                 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff;  \
4662                 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff;  \
4663                 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff;  \
4664                 __load [8] =  ((guint64)(gsize)(val))        & 0xffff;  \
4665         } while (0)
4666 #elif defined _BIG_ENDIAN
4667 #define patch_load_sequence(ip,val) do {\
4668                 guint16 *__load = (guint16*)(ip);       \
4669                 g_assert (sizeof (val) == sizeof (gsize)); \
4670                 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff;  \
4671                 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff;  \
4672                 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff;  \
4673                 __load [9] =  ((guint64)(gsize)(val))        & 0xffff;  \
4674         } while (0)
4675 #else
4676 #error huh?  No endianess defined by compiler
4677 #endif
4678 #else
4679 #define patch_load_sequence(ip,val) do {\
4680                 guint16 *__lis_ori = (guint16*)(ip);    \
4681                 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff;       \
4682                 __lis_ori [3] = ((gulong)(val)) & 0xffff;       \
4683         } while (0)
4684 #endif
4685
4686 #ifndef DISABLE_JIT
4687 void
4688 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4689 {
4690         MonoJumpInfo *patch_info;
4691         gboolean compile_aot = !run_cctors;
4692
4693         error_init (error);
4694
4695         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4696                 unsigned char *ip = patch_info->ip.i + code;
4697                 unsigned char *target;
4698                 gboolean is_fd = FALSE;
4699
4700                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4701                 return_if_nok (error);
4702
4703                 if (compile_aot) {
4704                         switch (patch_info->type) {
4705                         case MONO_PATCH_INFO_BB:
4706                         case MONO_PATCH_INFO_LABEL:
4707                                 break;
4708                         default:
4709                                 /* No need to patch these */
4710                                 continue;
4711                         }
4712                 }
4713
4714                 switch (patch_info->type) {
4715                 case MONO_PATCH_INFO_IP:
4716                         patch_load_sequence (ip, ip);
4717                         continue;
4718                 case MONO_PATCH_INFO_METHOD_REL:
4719                         g_assert_not_reached ();
4720                         *((gpointer *)(ip)) = code + patch_info->data.offset;
4721                         continue;
4722                 case MONO_PATCH_INFO_SWITCH: {
4723                         gpointer *table = (gpointer *)patch_info->data.table->table;
4724                         int i;
4725
4726                         patch_load_sequence (ip, table);
4727
4728                         for (i = 0; i < patch_info->data.table->table_size; i++) {
4729                                 table [i] = (glong)patch_info->data.table->table [i] + code;
4730                         }
4731                         /* we put into the table the absolute address, no need for ppc_patch in this case */
4732                         continue;
4733                 }
4734                 case MONO_PATCH_INFO_METHODCONST:
4735                 case MONO_PATCH_INFO_CLASS:
4736                 case MONO_PATCH_INFO_IMAGE:
4737                 case MONO_PATCH_INFO_FIELD:
4738                 case MONO_PATCH_INFO_VTABLE:
4739                 case MONO_PATCH_INFO_IID:
4740                 case MONO_PATCH_INFO_SFLDA:
4741                 case MONO_PATCH_INFO_LDSTR:
4742                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4743                 case MONO_PATCH_INFO_LDTOKEN:
4744                         /* from OP_AOTCONST : lis + ori */
4745                         patch_load_sequence (ip, target);
4746                         continue;
4747                 case MONO_PATCH_INFO_R4:
4748                 case MONO_PATCH_INFO_R8:
4749                         g_assert_not_reached ();
4750                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4751                         continue;
4752                 case MONO_PATCH_INFO_EXC_NAME:
4753                         g_assert_not_reached ();
4754                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4755                         continue;
4756                 case MONO_PATCH_INFO_NONE:
4757                 case MONO_PATCH_INFO_BB_OVF:
4758                 case MONO_PATCH_INFO_EXC_OVF:
4759                         /* everything is dealt with at epilog output time */
4760                         continue;
4761 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4762                 case MONO_PATCH_INFO_INTERNAL_METHOD:
4763                 case MONO_PATCH_INFO_ABS:
4764                 case MONO_PATCH_INFO_RGCTX_FETCH:
4765                 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4766                         is_fd = TRUE;
4767                         break;
4768 #endif
4769                 default:
4770                         break;
4771                 }
4772                 ppc_patch_full (ip, target, is_fd);
4773         }
4774 }
4775
4776 /*
4777  * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4778  * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4779  * the instruction offset immediate for all the registers.
4780  */
4781 static guint8*
4782 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4783 {
4784         int i;
4785         if (!save_lmf) {
4786                 for (i = 13; i <= 31; i++) {
4787                         if (used_int_regs & (1 << i)) {
4788                                 ppc_str (code, i, pos, base_reg);
4789                                 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4790                                 pos += sizeof (mgreg_t);
4791                         }
4792                 }
4793         } else {
4794                 /* pos is the start of the MonoLMF structure */
4795                 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4796                 for (i = 13; i <= 31; i++) {
4797                         ppc_str (code, i, offset, base_reg);
4798                         mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4799                         offset += sizeof (mgreg_t);
4800                 }
4801                 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4802                 for (i = 14; i < 32; i++) {
4803                         ppc_stfd (code, i, offset, base_reg);
4804                         offset += sizeof (gdouble);
4805                 }
4806         }
4807         return code;
4808 }
4809
4810 /*
4811  * Stack frame layout:
4812  * 
4813  *   ------------------- sp
4814  *      MonoLMF structure or saved registers
4815  *   -------------------
4816  *      spilled regs
4817  *   -------------------
4818  *      locals
4819  *   -------------------
4820  *      optional 8 bytes for tracing
4821  *   -------------------
4822  *      param area             size is cfg->param_area
4823  *   -------------------
4824  *      linkage area           size is PPC_STACK_PARAM_OFFSET
4825  *   ------------------- sp
4826  *      red zone
4827  */
4828 guint8 *
4829 mono_arch_emit_prolog (MonoCompile *cfg)
4830 {
4831         MonoMethod *method = cfg->method;
4832         MonoBasicBlock *bb;
4833         MonoMethodSignature *sig;
4834         MonoInst *inst;
4835         long alloc_size, pos, max_offset, cfa_offset;
4836         int i;
4837         guint8 *code;
4838         CallInfo *cinfo;
4839         int tracing = 0;
4840         int lmf_offset = 0;
4841         int tailcall_struct_index;
4842
4843         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4844                 tracing = 1;
4845
4846         sig = mono_method_signature (method);
4847         cfg->code_size = 512 + sig->param_count * 32;
4848         code = cfg->native_code = g_malloc (cfg->code_size);
4849
4850         cfa_offset = 0;
4851
4852         /* We currently emit unwind info for aot, but don't use it */
4853         mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4854
4855         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4856                 ppc_mflr (code, ppc_r0);
4857                 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4858                 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4859         }
4860
4861         alloc_size = cfg->stack_offset;
4862         pos = 0;
4863
4864         if (!method->save_lmf) {
4865                 for (i = 31; i >= 13; --i) {
4866                         if (cfg->used_int_regs & (1 << i)) {
4867                                 pos += sizeof (mgreg_t);
4868                         }
4869                 }
4870         } else {
4871                 pos += sizeof (MonoLMF);
4872                 lmf_offset = pos;
4873         }
4874         alloc_size += pos;
4875         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4876         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4877                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4878                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4879         }
4880
4881         cfg->stack_usage = alloc_size;
4882         g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4883         if (alloc_size) {
4884                 if (ppc_is_imm16 (-alloc_size)) {
4885                         ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4886                         cfa_offset = alloc_size;
4887                         mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4888                         code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4889                 } else {
4890                         if (pos)
4891                                 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4892                         ppc_load (code, ppc_r0, -alloc_size);
4893                         ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4894                         cfa_offset = alloc_size;
4895                         mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4896                         code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4897                 }
4898         }
4899         if (cfg->frame_reg != ppc_sp) {
4900                 ppc_mr (code, cfg->frame_reg, ppc_sp);
4901                 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4902         }
4903
4904         /* store runtime generic context */
4905         if (cfg->rgctx_var) {
4906                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4907                                 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4908
4909                 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4910         }
4911
4912         /* compute max_offset in order to use short forward jumps
4913          * we always do it on ppc because the immediate displacement
4914          * for jumps is too small 
4915          */
4916         max_offset = 0;
4917         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4918                 MonoInst *ins;
4919                 bb->max_offset = max_offset;
4920
4921                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4922                         max_offset += 6; 
4923
4924                 MONO_BB_FOR_EACH_INS (bb, ins)
4925                         max_offset += ins_native_length (cfg, ins);
4926         }
4927
4928         /* load arguments allocated to register from the stack */
4929         pos = 0;
4930
4931         cinfo = get_call_info (sig);
4932
4933         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4934                 ArgInfo *ainfo = &cinfo->ret;
4935
4936                 inst = cfg->vret_addr;
4937                 g_assert (inst);
4938
4939                 if (ppc_is_imm16 (inst->inst_offset)) {
4940                         ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4941                 } else {
4942                         ppc_load (code, ppc_r12, inst->inst_offset);
4943                         ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4944                 }
4945         }
4946
4947         tailcall_struct_index = 0;
4948         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4949                 ArgInfo *ainfo = cinfo->args + i;
4950                 inst = cfg->args [pos];
4951                 
4952                 if (cfg->verbose_level > 2)
4953                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4954                 if (inst->opcode == OP_REGVAR) {
4955                         if (ainfo->regtype == RegTypeGeneral)
4956                                 ppc_mr (code, inst->dreg, ainfo->reg);
4957                         else if (ainfo->regtype == RegTypeFP)
4958                                 ppc_fmr (code, inst->dreg, ainfo->reg);
4959                         else if (ainfo->regtype == RegTypeBase) {
4960                                 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4961                                 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
4962                         } else
4963                                 g_assert_not_reached ();
4964
4965                         if (cfg->verbose_level > 2)
4966                                 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4967                 } else {
4968                         /* the argument should be put on the stack: FIXME handle size != word  */
4969                         if (ainfo->regtype == RegTypeGeneral) {
4970                                 switch (ainfo->size) {
4971                                 case 1:
4972                                         if (ppc_is_imm16 (inst->inst_offset)) {
4973                                                 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4974                                         } else {
4975                                                 if (ppc_is_imm32 (inst->inst_offset)) {
4976                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4977                                                         ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
4978                                                 } else {
4979                                                         ppc_load (code, ppc_r12, inst->inst_offset);
4980                                                         ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4981                                                 }
4982                                         }
4983                                         break;
4984                                 case 2:
4985                                         if (ppc_is_imm16 (inst->inst_offset)) {
4986                                                 ppc_sth (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_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
4991                                                 } else {
4992                                                         ppc_load (code, ppc_r12, inst->inst_offset);
4993                                                         ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4994                                                 }
4995                                         }
4996                                         break;
4997 #ifdef __mono_ppc64__
4998                                 case 4:
4999                                         if (ppc_is_imm16 (inst->inst_offset)) {
5000                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5001                                         } else {
5002                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5003                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5004                                                         ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
5005                                                 } else {
5006                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5007                                                         ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5008                                                 }
5009                                         }
5010                                         break;
5011                                 case 8:
5012                                         if (ppc_is_imm16 (inst->inst_offset)) {
5013                                                 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5014                                         } else {
5015                                                 ppc_load (code, ppc_r12, inst->inst_offset);
5016                                                 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5017                                         }
5018                                         break;
5019 #else
5020                                 case 8:
5021                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
5022                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5023                                                 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5024                                         } else {
5025                                                 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5026                                                 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5027                                                 ppc_stw (code, ainfo->reg, 0, ppc_r12);
5028                                                 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
5029                                         }
5030                                         break;
5031 #endif
5032                                 default:
5033                                         if (ppc_is_imm16 (inst->inst_offset)) {
5034                                                 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5035                                         } else {
5036                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5037                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5038                                                         ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5039                                                 } else {
5040                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5041                                                         ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5042                                                 }
5043                                         }
5044                                         break;
5045                                 }
5046                         } else if (ainfo->regtype == RegTypeBase) {
5047                                 g_assert (ppc_is_imm16 (ainfo->offset));
5048                                 /* load the previous stack pointer in r12 */
5049                                 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5050                                 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5051                                 switch (ainfo->size) {
5052                                 case 1:
5053                                         if (ppc_is_imm16 (inst->inst_offset)) {
5054                                                 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5055                                         } else {
5056                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5057                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5058                                                         ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5059                                                 } else {
5060                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5061                                                         ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5062                                                 }
5063                                         }
5064                                         break;
5065                                 case 2:
5066                                         if (ppc_is_imm16 (inst->inst_offset)) {
5067                                                 ppc_sth (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_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5072                                                 } else {
5073                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5074                                                         ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5075                                                 }
5076                                         }
5077                                         break;
5078 #ifdef __mono_ppc64__
5079                                 case 4:
5080                                         if (ppc_is_imm16 (inst->inst_offset)) {
5081                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5082                                         } else {
5083                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5084                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5085                                                         ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5086                                                 } else {
5087                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5088                                                         ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5089                                                 }
5090                                         }
5091                                         break;
5092                                 case 8:
5093                                         if (ppc_is_imm16 (inst->inst_offset)) {
5094                                                 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5095                                         } else {
5096                                                 ppc_load (code, ppc_r12, inst->inst_offset);
5097                                                 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5098                                         }
5099                                         break;
5100 #else
5101                                 case 8:
5102                                         g_assert (ppc_is_imm16 (ainfo->offset + 4));
5103                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
5104                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5105                                                 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5106                                                 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5107                                         } else {
5108                                                 /* use r11 to load the 2nd half of the long before we clobber r12.  */
5109                                                 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5110                                                 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5111                                                 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5112                                                 ppc_stw (code, ppc_r0, 0, ppc_r12);
5113                                                 ppc_stw (code, ppc_r11, 4, ppc_r12);
5114                                         }
5115                                         break;
5116 #endif
5117                                 default:
5118                                         if (ppc_is_imm16 (inst->inst_offset)) {
5119                                                 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5120                                         } else {
5121                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5122                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5123                                                         ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5124                                                 } else {
5125                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5126                                                         ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5127                                                 }
5128                                         }
5129                                         break;
5130                                 }
5131                         } else if (ainfo->regtype == RegTypeFP) {
5132                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5133                                 if (ainfo->size == 8)
5134                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5135                                 else if (ainfo->size == 4)
5136                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5137                                 else
5138                                         g_assert_not_reached ();
5139                          } else if (ainfo->regtype == RegTypeFPStructByVal) {
5140                                 int doffset = inst->inst_offset;
5141                                 int soffset = 0;
5142                                 int cur_reg;
5143                                 int size = 0;
5144                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5145                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5146                                 /* FIXME: what if there is no class? */
5147                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5148                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5149                                 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5150                                         if (ainfo->size == 4) {
5151                                                 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5152                                         } else {
5153                                                 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5154                                         }
5155                                         soffset += ainfo->size;
5156                                         doffset += ainfo->size;
5157                                 }
5158                         } else if (ainfo->regtype == RegTypeStructByVal) {
5159                                 int doffset = inst->inst_offset;
5160                                 int soffset = 0;
5161                                 int cur_reg;
5162                                 int size = 0;
5163                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5164                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5165                                 /* FIXME: what if there is no class? */
5166                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5167                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5168                                 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5169 #if __APPLE__
5170                                         /*
5171                                          * Darwin handles 1 and 2 byte
5172                                          * structs specially by
5173                                          * loading h/b into the arg
5174                                          * register.  Only done for
5175                                          * pinvokes.
5176                                          */
5177                                         if (size == 2)
5178                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5179                                         else if (size == 1)
5180                                                 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5181                                         else
5182 #endif
5183                                         {
5184 #ifdef __mono_ppc64__
5185                                                 if (ainfo->bytes) {
5186                                                         g_assert (cur_reg == 0);
5187 #if G_BYTE_ORDER == G_BIG_ENDIAN
5188                                                         ppc_sldi (code, ppc_r0, ainfo->reg,
5189                                                                          (sizeof (gpointer) - ainfo->bytes) * 8);
5190                                                         ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5191 #else
5192                                                         if (mono_class_native_size (inst->klass, NULL) == 1) {
5193                                                           ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5194                                                         } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5195                                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5196                                                         } else if (mono_class_native_size (inst->klass, NULL) == 4) {  // WDS -- maybe <=4?
5197                                                                 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5198                                                         } else {
5199                                                                 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);  // WDS -- Better way?
5200                                                         }
5201 #endif
5202                                                 } else
5203 #endif
5204                                                 {
5205                                                         ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5206                                                                         inst->inst_basereg);
5207                                                 }
5208                                         }
5209                                         soffset += sizeof (gpointer);
5210                                         doffset += sizeof (gpointer);
5211                                 }
5212                                 if (ainfo->vtsize) {
5213                                         /* FIXME: we need to do the shifting here, too */
5214                                         if (ainfo->bytes)
5215                                                 NOT_IMPLEMENTED;
5216                                         /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5217                                         ppc_ldr (code, ppc_r12, 0, ppc_sp);
5218                                         if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5219                                                 code = emit_memcpy (code, size - soffset,
5220                                                         inst->inst_basereg, doffset,
5221                                                         ppc_r12, ainfo->offset + soffset);
5222                                         } else {
5223                                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5224                                                         inst->inst_basereg, doffset,
5225                                                         ppc_r12, ainfo->offset + soffset);
5226                                         }
5227                                 }
5228                         } else if (ainfo->regtype == RegTypeStructByAddr) {
5229                                 /* if it was originally a RegTypeBase */
5230                                 if (ainfo->offset) {
5231                                         /* load the previous stack pointer in r12 */
5232                                         ppc_ldr (code, ppc_r12, 0, ppc_sp);
5233                                         ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5234                                 } else {
5235                                         ppc_mr (code, ppc_r12, ainfo->reg);
5236                                 }
5237
5238                                 if (cfg->tailcall_valuetype_addrs) {
5239                                         MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5240
5241                                         g_assert (ppc_is_imm16 (addr->inst_offset));
5242                                         ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5243
5244                                         tailcall_struct_index++;
5245                                 }
5246
5247                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5248                                 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5249                                 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5250                         } else
5251                                 g_assert_not_reached ();
5252                 }
5253                 pos++;
5254         }
5255
5256         if (method->save_lmf) {
5257                 if (cfg->compile_aot) {
5258                         /* Compute the got address which is needed by the PLT entry */
5259                         code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5260                 }
5261                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
5262                              (gpointer)"mono_tls_get_lmf_addr");
5263                 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5264                         ppc_load_func (code, PPC_CALL_REG, 0);
5265                         ppc_mtlr (code, PPC_CALL_REG);
5266                         ppc_blrl (code);
5267                 } else {
5268                         ppc_bl (code, 0);
5269                 }
5270                 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5271                 /* lmf_offset is the offset from the previous stack pointer,
5272                  * alloc_size is the total stack space allocated, so the offset
5273                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5274                  * The pointer to the struct is put in ppc_r12 (new_lmf).
5275                  * The callee-saved registers are already in the MonoLMF structure
5276                  */
5277                 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5278                 /* ppc_r3 is the result from mono_get_lmf_addr () */
5279                 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5280                 /* new_lmf->previous_lmf = *lmf_addr */
5281                 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5282                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5283                 /* *(lmf_addr) = r12 */
5284                 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5285                 /* save method info */
5286                 if (cfg->compile_aot)
5287                         // FIXME:
5288                         ppc_load (code, ppc_r0, 0);
5289                 else
5290                         ppc_load_ptr (code, ppc_r0, method);
5291                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5292                 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5293                 /* save the current IP */
5294                 if (cfg->compile_aot) {
5295                         ppc_bl (code, 1);
5296                         ppc_mflr (code, ppc_r0);
5297                 } else {
5298                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5299 #ifdef __mono_ppc64__
5300                         ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5301 #else
5302                         ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5303 #endif
5304                 }
5305                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5306         }
5307
5308         if (tracing)
5309                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5310
5311         cfg->code_len = code - cfg->native_code;
5312         g_assert (cfg->code_len <= cfg->code_size);
5313         g_free (cinfo);
5314
5315         return code;
5316 }
5317
5318 void
5319 mono_arch_emit_epilog (MonoCompile *cfg)
5320 {
5321         MonoMethod *method = cfg->method;
5322         int pos, i;
5323         int max_epilog_size = 16 + 20*4;
5324         guint8 *code;
5325
5326         if (cfg->method->save_lmf)
5327                 max_epilog_size += 128;
5328         
5329         if (mono_jit_trace_calls != NULL)
5330                 max_epilog_size += 50;
5331
5332         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5333                 cfg->code_size *= 2;
5334                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5335                 cfg->stat_code_reallocs++;
5336         }
5337
5338         /*
5339          * Keep in sync with OP_JMP
5340          */
5341         code = cfg->native_code + cfg->code_len;
5342
5343         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5344                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5345         }
5346         pos = 0;
5347
5348         if (method->save_lmf) {
5349                 int lmf_offset;
5350                 pos +=  sizeof (MonoLMF);
5351                 lmf_offset = pos;
5352                 /* save the frame reg in r8 */
5353                 ppc_mr (code, ppc_r8, cfg->frame_reg);
5354                 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5355                 /* r5 = previous_lmf */
5356                 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5357                 /* r6 = lmf_addr */
5358                 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5359                 /* *(lmf_addr) = previous_lmf */
5360                 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5361                 /* FIXME: speedup: there is no actual need to restore the registers if
5362                  * we didn't actually change them (idea from Zoltan).
5363                  */
5364                 /* restore iregs */
5365                 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5366                 /* restore fregs */
5367                 /*for (i = 14; i < 32; i++) {
5368                         ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5369                 }*/
5370                 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5371                 /* use the saved copy of the frame reg in r8 */
5372                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5373                         ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5374                         ppc_mtlr (code, ppc_r0);
5375                 }
5376                 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5377         } else {
5378                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5379                         long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5380                         if (ppc_is_imm16 (return_offset)) {
5381                                 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5382                         } else {
5383                                 ppc_load (code, ppc_r12, return_offset);
5384                                 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5385                         }
5386                         ppc_mtlr (code, ppc_r0);
5387                 }
5388                 if (ppc_is_imm16 (cfg->stack_usage)) {
5389                         int offset = cfg->stack_usage;
5390                         for (i = 13; i <= 31; i++) {
5391                                 if (cfg->used_int_regs & (1 << i))
5392                                         offset -= sizeof (mgreg_t);
5393                         }
5394                         if (cfg->frame_reg != ppc_sp)
5395                                 ppc_mr (code, ppc_r12, cfg->frame_reg);
5396                         /* note r31 (possibly the frame register) is restored last */
5397                         for (i = 13; i <= 31; i++) {
5398                                 if (cfg->used_int_regs & (1 << i)) {
5399                                         ppc_ldr (code, i, offset, cfg->frame_reg);
5400                                         offset += sizeof (mgreg_t);
5401                                 }
5402                         }
5403                         if (cfg->frame_reg != ppc_sp)
5404                                 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5405                         else
5406                                 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5407                 } else {
5408                         ppc_load32 (code, ppc_r12, cfg->stack_usage);
5409                         if (cfg->used_int_regs) {
5410                                 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5411                                 for (i = 31; i >= 13; --i) {
5412                                         if (cfg->used_int_regs & (1 << i)) {
5413                                                 pos += sizeof (mgreg_t);
5414                                                 ppc_ldr (code, i, -pos, ppc_r12);
5415                                         }
5416                                 }
5417                                 ppc_mr (code, ppc_sp, ppc_r12);
5418                         } else {
5419                                 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5420                         }
5421                 }
5422
5423         }
5424         ppc_blr (code);
5425
5426         cfg->code_len = code - cfg->native_code;
5427
5428         g_assert (cfg->code_len < cfg->code_size);
5429
5430 }
5431 #endif /* ifndef DISABLE_JIT */
5432
5433 /* remove once throw_exception_by_name is eliminated */
5434 static int
5435 exception_id_by_name (const char *name)
5436 {
5437         if (strcmp (name, "IndexOutOfRangeException") == 0)
5438                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5439         if (strcmp (name, "OverflowException") == 0)
5440                 return MONO_EXC_OVERFLOW;
5441         if (strcmp (name, "ArithmeticException") == 0)
5442                 return MONO_EXC_ARITHMETIC;
5443         if (strcmp (name, "DivideByZeroException") == 0)
5444                 return MONO_EXC_DIVIDE_BY_ZERO;
5445         if (strcmp (name, "InvalidCastException") == 0)
5446                 return MONO_EXC_INVALID_CAST;
5447         if (strcmp (name, "NullReferenceException") == 0)
5448                 return MONO_EXC_NULL_REF;
5449         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5450                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5451         if (strcmp (name, "ArgumentException") == 0)
5452                 return MONO_EXC_ARGUMENT;
5453         g_error ("Unknown intrinsic exception %s\n", name);
5454         return 0;
5455 }
5456
5457 #ifndef DISABLE_JIT
5458 void
5459 mono_arch_emit_exceptions (MonoCompile *cfg)
5460 {
5461         MonoJumpInfo *patch_info;
5462         int i;
5463         guint8 *code;
5464         guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5465         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5466         int max_epilog_size = 50;
5467
5468         for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5469                 exc_throw_pos [i] = NULL;
5470                 exc_throw_found [i] = 0;
5471         }
5472
5473         /* count the number of exception infos */
5474      
5475         /* 
5476          * make sure we have enough space for exceptions
5477          */
5478         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5479                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5480                         i = exception_id_by_name (patch_info->data.target);
5481                         if (!exc_throw_found [i]) {
5482                                 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5483                                 exc_throw_found [i] = TRUE;
5484                         }
5485                 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5486                         max_epilog_size += 12;
5487                 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5488                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5489                         i = exception_id_by_name (ovfj->data.exception);
5490                         if (!exc_throw_found [i]) {
5491                                 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5492                                 exc_throw_found [i] = TRUE;
5493                         }
5494                         max_epilog_size += 8;
5495                 }
5496         }
5497
5498         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5499                 cfg->code_size *= 2;
5500                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5501                 cfg->stat_code_reallocs++;
5502         }
5503
5504         code = cfg->native_code + cfg->code_len;
5505
5506         /* add code to raise exceptions */
5507         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5508                 switch (patch_info->type) {
5509                 case MONO_PATCH_INFO_BB_OVF: {
5510                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5511                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5512                         /* patch the initial jump */
5513                         ppc_patch (ip, code);
5514                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5515                         ppc_b (code, 0);
5516                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5517                         /* jump back to the true target */
5518                         ppc_b (code, 0);
5519                         ip = ovfj->data.bb->native_offset + cfg->native_code;
5520                         ppc_patch (code - 4, ip);
5521                         patch_info->type = MONO_PATCH_INFO_NONE;
5522                         break;
5523                 }
5524                 case MONO_PATCH_INFO_EXC_OVF: {
5525                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5526                         MonoJumpInfo *newji;
5527                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5528                         unsigned char *bcl = code;
5529                         /* patch the initial jump: we arrived here with a call */
5530                         ppc_patch (ip, code);
5531                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5532                         ppc_b (code, 0);
5533                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5534                         /* patch the conditional jump to the right handler */
5535                         /* make it processed next */
5536                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5537                         newji->type = MONO_PATCH_INFO_EXC;
5538                         newji->ip.i = bcl - cfg->native_code;
5539                         newji->data.target = ovfj->data.exception;
5540                         newji->next = patch_info->next;
5541                         patch_info->next = newji;
5542                         patch_info->type = MONO_PATCH_INFO_NONE;
5543                         break;
5544                 }
5545                 case MONO_PATCH_INFO_EXC: {
5546                         MonoClass *exc_class;
5547
5548                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5549                         i = exception_id_by_name (patch_info->data.target);
5550                         if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5551                                 ppc_patch (ip, exc_throw_pos [i]);
5552                                 patch_info->type = MONO_PATCH_INFO_NONE;
5553                                 break;
5554                         } else {
5555                                 exc_throw_pos [i] = code;
5556                         }
5557
5558                         exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5559
5560                         ppc_patch (ip, code);
5561                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5562                         ppc_load (code, ppc_r3, exc_class->type_token);
5563                         /* we got here from a conditional call, so the calling ip is set in lr */
5564                         ppc_mflr (code, ppc_r4);
5565                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5566                         patch_info->data.name = "mono_arch_throw_corlib_exception";
5567                         patch_info->ip.i = code - cfg->native_code;
5568                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5569                                 ppc_load_func (code, PPC_CALL_REG, 0);
5570                                 ppc_mtctr (code, PPC_CALL_REG);
5571                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5572                         } else {
5573                                 ppc_bl (code, 0);
5574                         }
5575                         break;
5576                 }
5577                 default:
5578                         /* do nothing */
5579                         break;
5580                 }
5581         }
5582
5583         cfg->code_len = code - cfg->native_code;
5584
5585         g_assert (cfg->code_len <= cfg->code_size);
5586 }
5587 #endif
5588
5589 #if DEAD_CODE
5590 static int
5591 try_offset_access (void *value, guint32 idx)
5592 {
5593         register void* me __asm__ ("r2");
5594         void ***p = (void***)((char*)me + 284);
5595         int idx1 = idx / 32;
5596         int idx2 = idx % 32;
5597         if (!p [idx1])
5598                 return 0;
5599         if (value != p[idx1][idx2])
5600                 return 0;
5601         return 1;
5602 }
5603 #endif
5604
5605 void
5606 mono_arch_finish_init (void)
5607 {
5608 }
5609
5610 void
5611 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5612 {
5613 }
5614
5615 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5616 #define BR_SIZE 4
5617 #define LOADSTORE_SIZE 4
5618 #define JUMP_IMM_SIZE 12
5619 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5620 #define ENABLE_WRONG_METHOD_CHECK 0
5621
5622 /*
5623  * LOCKING: called with the domain lock held
5624  */
5625 gpointer
5626 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5627                                                                 gpointer fail_tramp)
5628 {
5629         int i;
5630         int size = 0;
5631         guint8 *code, *start;
5632
5633         for (i = 0; i < count; ++i) {
5634                 MonoIMTCheckItem *item = imt_entries [i];
5635                 if (item->is_equals) {
5636                         if (item->check_target_idx) {
5637                                 if (!item->compare_done)
5638                                         item->chunk_size += CMP_SIZE;
5639                                 if (item->has_target_code)
5640                                         item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5641                                 else
5642                                         item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5643                         } else {
5644                                 if (fail_tramp) {
5645                                         item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5646                                         if (!item->has_target_code)
5647                                                 item->chunk_size += LOADSTORE_SIZE;
5648                                 } else {
5649                                         item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5650 #if ENABLE_WRONG_METHOD_CHECK
5651                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5652 #endif
5653                                 }
5654                         }
5655                 } else {
5656                         item->chunk_size += CMP_SIZE + BR_SIZE;
5657                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5658                 }
5659                 size += item->chunk_size;
5660         }
5661         /* the initial load of the vtable address */
5662         size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5663         if (fail_tramp) {
5664                 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5665         } else {
5666                 code = mono_domain_code_reserve (domain, size);
5667         }
5668         start = code;
5669
5670         /*
5671          * We need to save and restore r12 because it might be
5672          * used by the caller as the vtable register, so
5673          * clobbering it will trip up the magic trampoline.
5674          *
5675          * FIXME: Get rid of this by making sure that r12 is
5676          * not used as the vtable register in interface calls.
5677          */
5678         ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5679         ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5680
5681         for (i = 0; i < count; ++i) {
5682                 MonoIMTCheckItem *item = imt_entries [i];
5683                 item->code_target = code;
5684                 if (item->is_equals) {
5685                         if (item->check_target_idx) {
5686                                 if (!item->compare_done) {
5687                                         ppc_load (code, ppc_r0, (gsize)item->key);
5688                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5689                                 }
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                                         ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5696                                         ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5697                                 }
5698                                 ppc_mtctr (code, ppc_r0);
5699                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5700                         } else {
5701                                 if (fail_tramp) {
5702                                         ppc_load (code, ppc_r0, (gulong)item->key);
5703                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5704                                         item->jmp_code = code;
5705                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5706                                         if (item->has_target_code) {
5707                                                 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5708                                         } else {
5709                                                 g_assert (vtable);
5710                                                 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5711                                                 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5712                                         }
5713                                         ppc_mtctr (code, ppc_r0);
5714                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5715                                         ppc_patch (item->jmp_code, code);
5716                                         ppc_load_ptr (code, ppc_r0, fail_tramp);
5717                                         ppc_mtctr (code, ppc_r0);
5718                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5719                                         item->jmp_code = NULL;
5720                                 } else {
5721                                         /* enable the commented code to assert on wrong method */
5722 #if ENABLE_WRONG_METHOD_CHECK
5723                                         ppc_load (code, ppc_r0, (guint32)item->key);
5724                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5725                                         item->jmp_code = code;
5726                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5727 #endif
5728                                         ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5729                                         ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5730                                         ppc_mtctr (code, ppc_r0);
5731                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5732 #if ENABLE_WRONG_METHOD_CHECK
5733                                         ppc_patch (item->jmp_code, code);
5734                                         ppc_break (code);
5735                                         item->jmp_code = NULL;
5736 #endif
5737                                 }
5738                         }
5739                 } else {
5740                         ppc_load (code, ppc_r0, (gulong)item->key);
5741                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5742                         item->jmp_code = code;
5743                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5744                 }
5745         }
5746         /* patch the branches to get to the target items */
5747         for (i = 0; i < count; ++i) {
5748                 MonoIMTCheckItem *item = imt_entries [i];
5749                 if (item->jmp_code) {
5750                         if (item->check_target_idx) {
5751                                 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5752                         }
5753                 }
5754         }
5755
5756         if (!fail_tramp)
5757                 mono_stats.imt_trampolines_size += code - start;
5758         g_assert (code - start <= size);
5759         mono_arch_flush_icache (start, size);
5760
5761         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5762
5763         return start;
5764 }
5765
5766 MonoMethod*
5767 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5768 {
5769         mgreg_t *r = (mgreg_t*)regs;
5770
5771         return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5772 }
5773
5774 MonoVTable*
5775 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5776 {
5777         mgreg_t *r = (mgreg_t*)regs;
5778
5779         return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5780 }
5781
5782 GSList*
5783 mono_arch_get_cie_program (void)
5784 {
5785         GSList *l = NULL;
5786
5787         mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5788
5789         return l;
5790 }
5791
5792 MonoInst*
5793 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5794 {
5795         /* FIXME: */
5796         return NULL;
5797 }
5798
5799 gboolean
5800 mono_arch_print_tree (MonoInst *tree, int arity)
5801 {
5802         return 0;
5803 }
5804
5805 mgreg_t
5806 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5807 {
5808         if (reg == ppc_r1)
5809                 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5810
5811         return ctx->regs [reg];
5812 }
5813
5814 guint32
5815 mono_arch_get_patch_offset (guint8 *code)
5816 {
5817         return 0;
5818 }
5819
5820 /*
5821  * mono_aot_emit_load_got_addr:
5822  *
5823  *   Emit code to load the got address.
5824  * On PPC, the result is placed into r30.
5825  */
5826 guint8*
5827 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5828 {
5829         ppc_bl (code, 1);
5830         ppc_mflr (code, ppc_r30);
5831         if (cfg)
5832                 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5833         else
5834                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5835         /* arch_emit_got_address () patches this */
5836 #if defined(TARGET_POWERPC64)
5837         ppc_nop (code);
5838         ppc_nop (code);
5839         ppc_nop (code);
5840         ppc_nop (code);
5841 #else
5842         ppc_load32 (code, ppc_r0, 0);
5843         ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5844 #endif
5845
5846         return code;
5847 }
5848
5849 /*
5850  * mono_ppc_emit_load_aotconst:
5851  *
5852  *   Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5853  * TARGET from the mscorlib GOT in full-aot code.
5854  * On PPC, the GOT address is assumed to be in r30, and the result is placed into 
5855  * r12.
5856  */
5857 guint8*
5858 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
5859 {
5860         /* Load the mscorlib got address */
5861         ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
5862         *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5863         /* arch_emit_got_access () patches this */
5864         ppc_load32 (code, ppc_r0, 0);
5865         ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
5866
5867         return code;
5868 }
5869
5870 /* Soft Debug support */
5871 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5872
5873 /*
5874  * BREAKPOINTS
5875  */
5876
5877 /*
5878  * mono_arch_set_breakpoint:
5879  *
5880  *   See mini-amd64.c for docs.
5881  */
5882 void
5883 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5884 {
5885         guint8 *code = ip;
5886         guint8 *orig_code = code;
5887
5888         ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
5889         ppc_ldptr (code, ppc_r12, 0, ppc_r12);
5890
5891         g_assert (code - orig_code == BREAKPOINT_SIZE);
5892
5893         mono_arch_flush_icache (orig_code, code - orig_code);
5894 }
5895
5896 /*
5897  * mono_arch_clear_breakpoint:
5898  *
5899  *   See mini-amd64.c for docs.
5900  */
5901 void
5902 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5903 {
5904         guint8 *code = ip;
5905         int i;
5906
5907         for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5908                 ppc_nop (code);
5909
5910         mono_arch_flush_icache (ip, code - ip);
5911 }
5912
5913 /*
5914  * mono_arch_is_breakpoint_event:
5915  *
5916  *   See mini-amd64.c for docs.
5917  */
5918 gboolean
5919 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5920 {
5921         siginfo_t* sinfo = (siginfo_t*) info;
5922         /* Sometimes the address is off by 4 */
5923         if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5924                 return TRUE;
5925         else
5926                 return FALSE;
5927 }
5928
5929 /*
5930  * mono_arch_skip_breakpoint:
5931  *
5932  *   See mini-amd64.c for docs.
5933  */
5934 void
5935 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5936 {
5937         /* skip the ldptr */
5938         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5939 }
5940
5941 /*
5942  * SINGLE STEPPING
5943  */
5944         
5945 /*
5946  * mono_arch_start_single_stepping:
5947  *
5948  *   See mini-amd64.c for docs.
5949  */
5950 void
5951 mono_arch_start_single_stepping (void)
5952 {
5953         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5954 }
5955         
5956 /*
5957  * mono_arch_stop_single_stepping:
5958  *
5959  *   See mini-amd64.c for docs.
5960  */
5961 void
5962 mono_arch_stop_single_stepping (void)
5963 {
5964         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5965 }
5966
5967 /*
5968  * mono_arch_is_single_step_event:
5969  *
5970  *   See mini-amd64.c for docs.
5971  */
5972 gboolean
5973 mono_arch_is_single_step_event (void *info, void *sigctx)
5974 {
5975         siginfo_t* sinfo = (siginfo_t*) info;
5976         /* Sometimes the address is off by 4 */
5977         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5978                 return TRUE;
5979         else
5980                 return FALSE;
5981 }
5982
5983 /*
5984  * mono_arch_skip_single_step:
5985  *
5986  *   See mini-amd64.c for docs.
5987  */
5988 void
5989 mono_arch_skip_single_step (MonoContext *ctx)
5990 {
5991         /* skip the ldptr */
5992         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5993 }
5994
5995 /*
5996  * mono_arch_create_seq_point_info:
5997  *
5998  *   See mini-amd64.c for docs.
5999  */
6000 gpointer
6001 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6002 {
6003         NOT_IMPLEMENTED;
6004         return NULL;
6005 }
6006
6007 void
6008 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6009 {
6010         ext->lmf.previous_lmf = prev_lmf;
6011         /* Mark that this is a MonoLMFExt */
6012         ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6013         ext->lmf.ebp = (gssize)ext;
6014 }
6015
6016 #endif
6017
6018 gboolean
6019 mono_arch_opcode_supported (int opcode)
6020 {
6021         switch (opcode) {
6022         case OP_ATOMIC_ADD_I4:
6023         case OP_ATOMIC_CAS_I4:
6024 #ifdef TARGET_POWERPC64
6025         case OP_ATOMIC_ADD_I8:
6026         case OP_ATOMIC_CAS_I8:
6027 #endif
6028                 return TRUE;
6029         default:
6030                 return FALSE;
6031         }
6032 }
6033
6034
6035 #if 0
6036 // FIXME: To get the test case  finally_block_ending_in_dead_bb  to work properly we need to define the following
6037 // (in mini-ppc.h) and then implement the fuction mono_arch_create_handler_block_trampoline.
6038 //  #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
6039
6040 gpointer
6041 mono_arch_create_handler_block_trampoline (void)
6042 {
6043         . . .
6044 }
6045 #endif