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