60d9475dfe31a8b80b1b5322a8026008b4ad94ee
[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                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4375                         ppc_li (code, ins->dreg, 0);
4376                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4377                         ppc_li (code, ins->dreg, 1);
4378                         break;
4379                 case OP_FCLT:
4380                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4381                         ppc_li (code, ins->dreg, 1);
4382                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4383                         ppc_li (code, ins->dreg, 0);
4384                         break;
4385                 case OP_FCLT_UN:
4386                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4387                         ppc_li (code, ins->dreg, 1);
4388                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4389                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4390                         ppc_li (code, ins->dreg, 0);
4391                         break;
4392                 case OP_FCGT:
4393                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4394                         ppc_li (code, ins->dreg, 1);
4395                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4396                         ppc_li (code, ins->dreg, 0);
4397                         break;
4398                 case OP_FCGT_UN:
4399                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4400                         ppc_li (code, ins->dreg, 1);
4401                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4402                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4403                         ppc_li (code, ins->dreg, 0);
4404                         break;
4405                 case OP_FBEQ:
4406                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4407                         break;
4408                 case OP_FBNE_UN:
4409                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4410                         break;
4411                 case OP_FBLT:
4412                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4413                         EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4414                         break;
4415                 case OP_FBLT_UN:
4416                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4417                         EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4418                         break;
4419                 case OP_FBGT:
4420                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4421                         EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4422                         break;
4423                 case OP_FBGT_UN:
4424                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4425                         EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4426                         break;
4427                 case OP_FBGE:
4428                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4429                         EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4430                         break;
4431                 case OP_FBGE_UN:
4432                         EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4433                         break;
4434                 case OP_FBLE:
4435                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4436                         EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4437                         break;
4438                 case OP_FBLE_UN:
4439                         EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4440                         break;
4441                 case OP_CKFINITE:
4442                         g_assert_not_reached ();
4443                 case OP_CHECK_FINITE: {
4444                         ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4445                         ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4446                         ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4447                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4448                         break;
4449                 case OP_JUMP_TABLE:
4450                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4451 #ifdef __mono_ppc64__
4452                         ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4453 #else
4454                         ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4455 #endif
4456                         break;
4457                 }
4458
4459 #ifdef __mono_ppc64__
4460                 case OP_ICONV_TO_I4:
4461                 case OP_SEXT_I4:
4462                         ppc_extsw (code, ins->dreg, ins->sreg1);
4463                         break;
4464                 case OP_ICONV_TO_U4:
4465                 case OP_ZEXT_I4:
4466                         ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4467                         break;
4468                 case OP_ICONV_TO_R4:
4469                 case OP_ICONV_TO_R8:
4470                 case OP_LCONV_TO_R4:
4471                 case OP_LCONV_TO_R8: {
4472                         int tmp;
4473                         if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4474                                 ppc_extsw (code, ppc_r0, ins->sreg1);
4475                                 tmp = ppc_r0;
4476                         } else {
4477                                 tmp = ins->sreg1;
4478                         }
4479                         if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4480                                 ppc_mffgpr (code, ins->dreg, tmp);
4481                         } else {
4482                                 ppc_str (code, tmp, -8, ppc_r1);
4483                                 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4484                         }
4485                         ppc_fcfid (code, ins->dreg, ins->dreg);
4486                         if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4487                                 ppc_frsp (code, ins->dreg, ins->dreg);
4488                         break;
4489                 }
4490                 case OP_LSHR:
4491                         ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4492                         break;
4493                 case OP_LSHR_UN:
4494                         ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4495                         break;
4496                 case OP_COND_EXC_C:
4497                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4498                          */
4499                         ppc_mfspr (code, ppc_r0, ppc_xer);
4500                         ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4501                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4502                         break;
4503                 case OP_COND_EXC_OV:
4504                         ppc_mfspr (code, ppc_r0, ppc_xer);
4505                         ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4506                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4507                         break;
4508                 case OP_LBEQ:
4509                 case OP_LBNE_UN:
4510                 case OP_LBLT:
4511                 case OP_LBLT_UN:
4512                 case OP_LBGT:
4513                 case OP_LBGT_UN:
4514                 case OP_LBGE:
4515                 case OP_LBGE_UN:
4516                 case OP_LBLE:
4517                 case OP_LBLE_UN:
4518                         EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4519                         break;
4520                 case OP_FCONV_TO_I8:
4521                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4522                         break;
4523                 case OP_FCONV_TO_U8:
4524                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4525                         break;
4526                 case OP_STOREI4_MEMBASE_REG:
4527                         if (ppc_is_imm16 (ins->inst_offset)) {
4528                                 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4529                         } else {
4530                                 ppc_load (code, ppc_r0, ins->inst_offset);
4531                                 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4532                         }
4533                         break;
4534                 case OP_STOREI4_MEMINDEX:
4535                         ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4536                         break;
4537                 case OP_ISHR_IMM:
4538                         ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4539                         break;
4540                 case OP_ISHR_UN_IMM:
4541                         if (ins->inst_imm & 0x1f)
4542                                 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4543                         else
4544                                 ppc_mr (code, ins->dreg, ins->sreg1);
4545                         break;
4546 #else
4547                 case OP_ICONV_TO_R4:
4548                 case OP_ICONV_TO_R8: {
4549                         if (cpu_hw_caps & PPC_ISA_64) {
4550                                 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4551                                 ppc_stw (code, ppc_r0, -8, ppc_r1);
4552                                 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4553                                 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4554                                 ppc_fcfid (code, ins->dreg, ins->dreg);
4555                                 if (ins->opcode == OP_ICONV_TO_R4)
4556                                         ppc_frsp (code, ins->dreg, ins->dreg);
4557                                 }
4558                         break;
4559                 }
4560 #endif
4561
4562                 case OP_ATOMIC_ADD_I4:
4563                 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4564                         int location = ins->inst_basereg;
4565                         int addend = ins->sreg2;
4566                         guint8 *loop, *branch;
4567                         g_assert (ins->inst_offset == 0);
4568
4569                         loop = code;
4570                         ppc_sync (code);
4571                         if (ins->opcode == OP_ATOMIC_ADD_I4)
4572                                 ppc_lwarx (code, ppc_r0, 0, location);
4573 #ifdef __mono_ppc64__
4574                         else
4575                                 ppc_ldarx (code, ppc_r0, 0, location);
4576 #endif
4577
4578                         ppc_add (code, ppc_r0, ppc_r0, addend);
4579
4580                         if (ins->opcode == OP_ATOMIC_ADD_I4)
4581                                 ppc_stwcxd (code, ppc_r0, 0, location);
4582 #ifdef __mono_ppc64__
4583                         else
4584                                 ppc_stdcxd (code, ppc_r0, 0, location);
4585 #endif
4586
4587                         branch = code;
4588                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4589                         ppc_patch (branch, loop);
4590
4591                         ppc_sync (code);
4592                         ppc_mr (code, ins->dreg, ppc_r0);
4593                         break;
4594                 }
4595                 case OP_ATOMIC_CAS_I4:
4596                 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4597                         int location = ins->sreg1;
4598                         int value = ins->sreg2;
4599                         int comparand = ins->sreg3;
4600                         guint8 *start, *not_equal, *lost_reservation;
4601
4602                         start = code;
4603                         ppc_sync (code);
4604                         if (ins->opcode == OP_ATOMIC_CAS_I4)
4605                                 ppc_lwarx (code, ppc_r0, 0, location);
4606 #ifdef __mono_ppc64__
4607                         else
4608                                 ppc_ldarx (code, ppc_r0, 0, location);
4609 #endif
4610
4611                         ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4612                         not_equal = code;
4613                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4614
4615                         if (ins->opcode == OP_ATOMIC_CAS_I4)
4616                                 ppc_stwcxd (code, value, 0, location);
4617 #ifdef __mono_ppc64__
4618                         else
4619                                 ppc_stdcxd (code, value, 0, location);
4620 #endif
4621
4622                         lost_reservation = code;
4623                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4624                         ppc_patch (lost_reservation, start);
4625                         ppc_patch (not_equal, code);
4626
4627                         ppc_sync (code);
4628                         ppc_mr (code, ins->dreg, ppc_r0);
4629                         break;
4630                 }
4631                 case OP_GC_SAFE_POINT:
4632                         break;
4633
4634                 default:
4635                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4636                         g_assert_not_reached ();
4637                 }
4638
4639                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4640                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4641                                    mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4642                         g_assert_not_reached ();
4643                 }
4644                
4645                 cpos += max_len;
4646
4647                 last_ins = ins;
4648                 last_offset = offset;
4649         }
4650
4651         cfg->code_len = code - cfg->native_code;
4652 }
4653 #endif /* !DISABLE_JIT */
4654
4655 void
4656 mono_arch_register_lowlevel_calls (void)
4657 {
4658         /* The signature doesn't matter */
4659         mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4660 }
4661
4662 #ifdef __mono_ppc64__
4663 #ifdef _LITTLE_ENDIAN
4664 #define patch_load_sequence(ip,val) do {\
4665                 guint16 *__load = (guint16*)(ip);       \
4666                 g_assert (sizeof (val) == sizeof (gsize)); \
4667                 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff;  \
4668                 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff;  \
4669                 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff;  \
4670                 __load [8] =  ((guint64)(gsize)(val))        & 0xffff;  \
4671         } while (0)
4672 #elif defined _BIG_ENDIAN
4673 #define patch_load_sequence(ip,val) do {\
4674                 guint16 *__load = (guint16*)(ip);       \
4675                 g_assert (sizeof (val) == sizeof (gsize)); \
4676                 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff;  \
4677                 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff;  \
4678                 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff;  \
4679                 __load [9] =  ((guint64)(gsize)(val))        & 0xffff;  \
4680         } while (0)
4681 #else
4682 #error huh?  No endianess defined by compiler
4683 #endif
4684 #else
4685 #define patch_load_sequence(ip,val) do {\
4686                 guint16 *__lis_ori = (guint16*)(ip);    \
4687                 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff;       \
4688                 __lis_ori [3] = ((gulong)(val)) & 0xffff;       \
4689         } while (0)
4690 #endif
4691
4692 #ifndef DISABLE_JIT
4693 void
4694 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4695 {
4696         MonoJumpInfo *patch_info;
4697         gboolean compile_aot = !run_cctors;
4698
4699         error_init (error);
4700
4701         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4702                 unsigned char *ip = patch_info->ip.i + code;
4703                 unsigned char *target;
4704                 gboolean is_fd = FALSE;
4705
4706                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4707                 return_if_nok (error);
4708
4709                 if (compile_aot) {
4710                         switch (patch_info->type) {
4711                         case MONO_PATCH_INFO_BB:
4712                         case MONO_PATCH_INFO_LABEL:
4713                                 break;
4714                         default:
4715                                 /* No need to patch these */
4716                                 continue;
4717                         }
4718                 }
4719
4720                 switch (patch_info->type) {
4721                 case MONO_PATCH_INFO_IP:
4722                         patch_load_sequence (ip, ip);
4723                         continue;
4724                 case MONO_PATCH_INFO_METHOD_REL:
4725                         g_assert_not_reached ();
4726                         *((gpointer *)(ip)) = code + patch_info->data.offset;
4727                         continue;
4728                 case MONO_PATCH_INFO_SWITCH: {
4729                         gpointer *table = (gpointer *)patch_info->data.table->table;
4730                         int i;
4731
4732                         patch_load_sequence (ip, table);
4733
4734                         for (i = 0; i < patch_info->data.table->table_size; i++) {
4735                                 table [i] = (glong)patch_info->data.table->table [i] + code;
4736                         }
4737                         /* we put into the table the absolute address, no need for ppc_patch in this case */
4738                         continue;
4739                 }
4740                 case MONO_PATCH_INFO_METHODCONST:
4741                 case MONO_PATCH_INFO_CLASS:
4742                 case MONO_PATCH_INFO_IMAGE:
4743                 case MONO_PATCH_INFO_FIELD:
4744                 case MONO_PATCH_INFO_VTABLE:
4745                 case MONO_PATCH_INFO_IID:
4746                 case MONO_PATCH_INFO_SFLDA:
4747                 case MONO_PATCH_INFO_LDSTR:
4748                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4749                 case MONO_PATCH_INFO_LDTOKEN:
4750                         /* from OP_AOTCONST : lis + ori */
4751                         patch_load_sequence (ip, target);
4752                         continue;
4753                 case MONO_PATCH_INFO_R4:
4754                 case MONO_PATCH_INFO_R8:
4755                         g_assert_not_reached ();
4756                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4757                         continue;
4758                 case MONO_PATCH_INFO_EXC_NAME:
4759                         g_assert_not_reached ();
4760                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4761                         continue;
4762                 case MONO_PATCH_INFO_NONE:
4763                 case MONO_PATCH_INFO_BB_OVF:
4764                 case MONO_PATCH_INFO_EXC_OVF:
4765                         /* everything is dealt with at epilog output time */
4766                         continue;
4767 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4768                 case MONO_PATCH_INFO_INTERNAL_METHOD:
4769                 case MONO_PATCH_INFO_ABS:
4770                 case MONO_PATCH_INFO_RGCTX_FETCH:
4771                 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4772                         is_fd = TRUE;
4773                         break;
4774 #endif
4775                 default:
4776                         break;
4777                 }
4778                 ppc_patch_full (ip, target, is_fd);
4779         }
4780 }
4781
4782 /*
4783  * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4784  * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4785  * the instruction offset immediate for all the registers.
4786  */
4787 static guint8*
4788 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4789 {
4790         int i;
4791         if (!save_lmf) {
4792                 for (i = 13; i <= 31; i++) {
4793                         if (used_int_regs & (1 << i)) {
4794                                 ppc_str (code, i, pos, base_reg);
4795                                 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4796                                 pos += sizeof (mgreg_t);
4797                         }
4798                 }
4799         } else {
4800                 /* pos is the start of the MonoLMF structure */
4801                 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4802                 for (i = 13; i <= 31; i++) {
4803                         ppc_str (code, i, offset, base_reg);
4804                         mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4805                         offset += sizeof (mgreg_t);
4806                 }
4807                 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4808                 for (i = 14; i < 32; i++) {
4809                         ppc_stfd (code, i, offset, base_reg);
4810                         offset += sizeof (gdouble);
4811                 }
4812         }
4813         return code;
4814 }
4815
4816 /*
4817  * Stack frame layout:
4818  * 
4819  *   ------------------- sp
4820  *      MonoLMF structure or saved registers
4821  *   -------------------
4822  *      spilled regs
4823  *   -------------------
4824  *      locals
4825  *   -------------------
4826  *      optional 8 bytes for tracing
4827  *   -------------------
4828  *      param area             size is cfg->param_area
4829  *   -------------------
4830  *      linkage area           size is PPC_STACK_PARAM_OFFSET
4831  *   ------------------- sp
4832  *      red zone
4833  */
4834 guint8 *
4835 mono_arch_emit_prolog (MonoCompile *cfg)
4836 {
4837         MonoMethod *method = cfg->method;
4838         MonoBasicBlock *bb;
4839         MonoMethodSignature *sig;
4840         MonoInst *inst;
4841         long alloc_size, pos, max_offset, cfa_offset;
4842         int i;
4843         guint8 *code;
4844         CallInfo *cinfo;
4845         int tracing = 0;
4846         int lmf_offset = 0;
4847         int tailcall_struct_index;
4848
4849         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4850                 tracing = 1;
4851
4852         sig = mono_method_signature (method);
4853         cfg->code_size = 512 + sig->param_count * 32;
4854         code = cfg->native_code = g_malloc (cfg->code_size);
4855
4856         cfa_offset = 0;
4857
4858         /* We currently emit unwind info for aot, but don't use it */
4859         mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4860
4861         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4862                 ppc_mflr (code, ppc_r0);
4863                 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4864                 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4865         }
4866
4867         alloc_size = cfg->stack_offset;
4868         pos = 0;
4869
4870         if (!method->save_lmf) {
4871                 for (i = 31; i >= 13; --i) {
4872                         if (cfg->used_int_regs & (1 << i)) {
4873                                 pos += sizeof (mgreg_t);
4874                         }
4875                 }
4876         } else {
4877                 pos += sizeof (MonoLMF);
4878                 lmf_offset = pos;
4879         }
4880         alloc_size += pos;
4881         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4882         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4883                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4884                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4885         }
4886
4887         cfg->stack_usage = alloc_size;
4888         g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4889         if (alloc_size) {
4890                 if (ppc_is_imm16 (-alloc_size)) {
4891                         ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4892                         cfa_offset = alloc_size;
4893                         mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4894                         code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4895                 } else {
4896                         if (pos)
4897                                 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4898                         ppc_load (code, ppc_r0, -alloc_size);
4899                         ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4900                         cfa_offset = alloc_size;
4901                         mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4902                         code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4903                 }
4904         }
4905         if (cfg->frame_reg != ppc_sp) {
4906                 ppc_mr (code, cfg->frame_reg, ppc_sp);
4907                 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4908         }
4909
4910         /* store runtime generic context */
4911         if (cfg->rgctx_var) {
4912                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4913                                 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4914
4915                 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4916         }
4917
4918         /* compute max_offset in order to use short forward jumps
4919          * we always do it on ppc because the immediate displacement
4920          * for jumps is too small 
4921          */
4922         max_offset = 0;
4923         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4924                 MonoInst *ins;
4925                 bb->max_offset = max_offset;
4926
4927                 MONO_BB_FOR_EACH_INS (bb, ins)
4928                         max_offset += ins_native_length (cfg, ins);
4929         }
4930
4931         /* load arguments allocated to register from the stack */
4932         pos = 0;
4933
4934         cinfo = get_call_info (sig);
4935
4936         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4937                 ArgInfo *ainfo = &cinfo->ret;
4938
4939                 inst = cfg->vret_addr;
4940                 g_assert (inst);
4941
4942                 if (ppc_is_imm16 (inst->inst_offset)) {
4943                         ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4944                 } else {
4945                         ppc_load (code, ppc_r12, inst->inst_offset);
4946                         ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4947                 }
4948         }
4949
4950         tailcall_struct_index = 0;
4951         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4952                 ArgInfo *ainfo = cinfo->args + i;
4953                 inst = cfg->args [pos];
4954                 
4955                 if (cfg->verbose_level > 2)
4956                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4957                 if (inst->opcode == OP_REGVAR) {
4958                         if (ainfo->regtype == RegTypeGeneral)
4959                                 ppc_mr (code, inst->dreg, ainfo->reg);
4960                         else if (ainfo->regtype == RegTypeFP)
4961                                 ppc_fmr (code, inst->dreg, ainfo->reg);
4962                         else if (ainfo->regtype == RegTypeBase) {
4963                                 ppc_ldr (code, ppc_r12, 0, ppc_sp);
4964                                 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
4965                         } else
4966                                 g_assert_not_reached ();
4967
4968                         if (cfg->verbose_level > 2)
4969                                 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4970                 } else {
4971                         /* the argument should be put on the stack: FIXME handle size != word  */
4972                         if (ainfo->regtype == RegTypeGeneral) {
4973                                 switch (ainfo->size) {
4974                                 case 1:
4975                                         if (ppc_is_imm16 (inst->inst_offset)) {
4976                                                 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4977                                         } else {
4978                                                 if (ppc_is_imm32 (inst->inst_offset)) {
4979                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4980                                                         ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
4981                                                 } else {
4982                                                         ppc_load (code, ppc_r12, inst->inst_offset);
4983                                                         ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4984                                                 }
4985                                         }
4986                                         break;
4987                                 case 2:
4988                                         if (ppc_is_imm16 (inst->inst_offset)) {
4989                                                 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4990                                         } else {
4991                                                 if (ppc_is_imm32 (inst->inst_offset)) {
4992                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
4993                                                         ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
4994                                                 } else {
4995                                                         ppc_load (code, ppc_r12, inst->inst_offset);
4996                                                         ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
4997                                                 }
4998                                         }
4999                                         break;
5000 #ifdef __mono_ppc64__
5001                                 case 4:
5002                                         if (ppc_is_imm16 (inst->inst_offset)) {
5003                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5004                                         } else {
5005                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5006                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5007                                                         ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
5008                                                 } else {
5009                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5010                                                         ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5011                                                 }
5012                                         }
5013                                         break;
5014                                 case 8:
5015                                         if (ppc_is_imm16 (inst->inst_offset)) {
5016                                                 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5017                                         } else {
5018                                                 ppc_load (code, ppc_r12, inst->inst_offset);
5019                                                 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5020                                         }
5021                                         break;
5022 #else
5023                                 case 8:
5024                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
5025                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5026                                                 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5027                                         } else {
5028                                                 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5029                                                 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5030                                                 ppc_stw (code, ainfo->reg, 0, ppc_r12);
5031                                                 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
5032                                         }
5033                                         break;
5034 #endif
5035                                 default:
5036                                         if (ppc_is_imm16 (inst->inst_offset)) {
5037                                                 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5038                                         } else {
5039                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5040                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5041                                                         ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5042                                                 } else {
5043                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5044                                                         ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5045                                                 }
5046                                         }
5047                                         break;
5048                                 }
5049                         } else if (ainfo->regtype == RegTypeBase) {
5050                                 g_assert (ppc_is_imm16 (ainfo->offset));
5051                                 /* load the previous stack pointer in r12 */
5052                                 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5053                                 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5054                                 switch (ainfo->size) {
5055                                 case 1:
5056                                         if (ppc_is_imm16 (inst->inst_offset)) {
5057                                                 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5058                                         } else {
5059                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5060                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5061                                                         ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5062                                                 } else {
5063                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5064                                                         ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5065                                                 }
5066                                         }
5067                                         break;
5068                                 case 2:
5069                                         if (ppc_is_imm16 (inst->inst_offset)) {
5070                                                 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5071                                         } else {
5072                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5073                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5074                                                         ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5075                                                 } else {
5076                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5077                                                         ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5078                                                 }
5079                                         }
5080                                         break;
5081 #ifdef __mono_ppc64__
5082                                 case 4:
5083                                         if (ppc_is_imm16 (inst->inst_offset)) {
5084                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5085                                         } else {
5086                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5087                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5088                                                         ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5089                                                 } else {
5090                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5091                                                         ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5092                                                 }
5093                                         }
5094                                         break;
5095                                 case 8:
5096                                         if (ppc_is_imm16 (inst->inst_offset)) {
5097                                                 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5098                                         } else {
5099                                                 ppc_load (code, ppc_r12, inst->inst_offset);
5100                                                 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5101                                         }
5102                                         break;
5103 #else
5104                                 case 8:
5105                                         g_assert (ppc_is_imm16 (ainfo->offset + 4));
5106                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
5107                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5108                                                 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5109                                                 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5110                                         } else {
5111                                                 /* use r11 to load the 2nd half of the long before we clobber r12.  */
5112                                                 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5113                                                 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5114                                                 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5115                                                 ppc_stw (code, ppc_r0, 0, ppc_r12);
5116                                                 ppc_stw (code, ppc_r11, 4, ppc_r12);
5117                                         }
5118                                         break;
5119 #endif
5120                                 default:
5121                                         if (ppc_is_imm16 (inst->inst_offset)) {
5122                                                 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5123                                         } else {
5124                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5125                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5126                                                         ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5127                                                 } else {
5128                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5129                                                         ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5130                                                 }
5131                                         }
5132                                         break;
5133                                 }
5134                         } else if (ainfo->regtype == RegTypeFP) {
5135                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5136                                 if (ainfo->size == 8)
5137                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5138                                 else if (ainfo->size == 4)
5139                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5140                                 else
5141                                         g_assert_not_reached ();
5142                          } else if (ainfo->regtype == RegTypeFPStructByVal) {
5143                                 int doffset = inst->inst_offset;
5144                                 int soffset = 0;
5145                                 int cur_reg;
5146                                 int size = 0;
5147                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5148                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5149                                 /* FIXME: what if there is no class? */
5150                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5151                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5152                                 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5153                                         if (ainfo->size == 4) {
5154                                                 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5155                                         } else {
5156                                                 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5157                                         }
5158                                         soffset += ainfo->size;
5159                                         doffset += ainfo->size;
5160                                 }
5161                         } else if (ainfo->regtype == RegTypeStructByVal) {
5162                                 int doffset = inst->inst_offset;
5163                                 int soffset = 0;
5164                                 int cur_reg;
5165                                 int size = 0;
5166                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5167                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5168                                 /* FIXME: what if there is no class? */
5169                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5170                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5171                                 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5172 #if __APPLE__
5173                                         /*
5174                                          * Darwin handles 1 and 2 byte
5175                                          * structs specially by
5176                                          * loading h/b into the arg
5177                                          * register.  Only done for
5178                                          * pinvokes.
5179                                          */
5180                                         if (size == 2)
5181                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5182                                         else if (size == 1)
5183                                                 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5184                                         else
5185 #endif
5186                                         {
5187 #ifdef __mono_ppc64__
5188                                                 if (ainfo->bytes) {
5189                                                         g_assert (cur_reg == 0);
5190 #if G_BYTE_ORDER == G_BIG_ENDIAN
5191                                                         ppc_sldi (code, ppc_r0, ainfo->reg,
5192                                                                          (sizeof (gpointer) - ainfo->bytes) * 8);
5193                                                         ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5194 #else
5195                                                         if (mono_class_native_size (inst->klass, NULL) == 1) {
5196                                                           ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5197                                                         } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5198                                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5199                                                         } else if (mono_class_native_size (inst->klass, NULL) == 4) {  // WDS -- maybe <=4?
5200                                                                 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5201                                                         } else {
5202                                                                 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);  // WDS -- Better way?
5203                                                         }
5204 #endif
5205                                                 } else
5206 #endif
5207                                                 {
5208                                                         ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5209                                                                         inst->inst_basereg);
5210                                                 }
5211                                         }
5212                                         soffset += sizeof (gpointer);
5213                                         doffset += sizeof (gpointer);
5214                                 }
5215                                 if (ainfo->vtsize) {
5216                                         /* FIXME: we need to do the shifting here, too */
5217                                         if (ainfo->bytes)
5218                                                 NOT_IMPLEMENTED;
5219                                         /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5220                                         ppc_ldr (code, ppc_r12, 0, ppc_sp);
5221                                         if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5222                                                 code = emit_memcpy (code, size - soffset,
5223                                                         inst->inst_basereg, doffset,
5224                                                         ppc_r12, ainfo->offset + soffset);
5225                                         } else {
5226                                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5227                                                         inst->inst_basereg, doffset,
5228                                                         ppc_r12, ainfo->offset + soffset);
5229                                         }
5230                                 }
5231                         } else if (ainfo->regtype == RegTypeStructByAddr) {
5232                                 /* if it was originally a RegTypeBase */
5233                                 if (ainfo->offset) {
5234                                         /* load the previous stack pointer in r12 */
5235                                         ppc_ldr (code, ppc_r12, 0, ppc_sp);
5236                                         ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5237                                 } else {
5238                                         ppc_mr (code, ppc_r12, ainfo->reg);
5239                                 }
5240
5241                                 if (cfg->tailcall_valuetype_addrs) {
5242                                         MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5243
5244                                         g_assert (ppc_is_imm16 (addr->inst_offset));
5245                                         ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5246
5247                                         tailcall_struct_index++;
5248                                 }
5249
5250                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5251                                 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5252                                 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5253                         } else
5254                                 g_assert_not_reached ();
5255                 }
5256                 pos++;
5257         }
5258
5259         if (method->save_lmf) {
5260                 if (cfg->compile_aot) {
5261                         /* Compute the got address which is needed by the PLT entry */
5262                         code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5263                 }
5264                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
5265                              (gpointer)"mono_tls_get_lmf_addr");
5266                 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5267                         ppc_load_func (code, PPC_CALL_REG, 0);
5268                         ppc_mtlr (code, PPC_CALL_REG);
5269                         ppc_blrl (code);
5270                 } else {
5271                         ppc_bl (code, 0);
5272                 }
5273                 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5274                 /* lmf_offset is the offset from the previous stack pointer,
5275                  * alloc_size is the total stack space allocated, so the offset
5276                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5277                  * The pointer to the struct is put in ppc_r12 (new_lmf).
5278                  * The callee-saved registers are already in the MonoLMF structure
5279                  */
5280                 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5281                 /* ppc_r3 is the result from mono_get_lmf_addr () */
5282                 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5283                 /* new_lmf->previous_lmf = *lmf_addr */
5284                 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5285                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5286                 /* *(lmf_addr) = r12 */
5287                 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5288                 /* save method info */
5289                 if (cfg->compile_aot)
5290                         // FIXME:
5291                         ppc_load (code, ppc_r0, 0);
5292                 else
5293                         ppc_load_ptr (code, ppc_r0, method);
5294                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5295                 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5296                 /* save the current IP */
5297                 if (cfg->compile_aot) {
5298                         ppc_bl (code, 1);
5299                         ppc_mflr (code, ppc_r0);
5300                 } else {
5301                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5302 #ifdef __mono_ppc64__
5303                         ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5304 #else
5305                         ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5306 #endif
5307                 }
5308                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5309         }
5310
5311         if (tracing)
5312                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5313
5314         cfg->code_len = code - cfg->native_code;
5315         g_assert (cfg->code_len <= cfg->code_size);
5316         g_free (cinfo);
5317
5318         return code;
5319 }
5320
5321 void
5322 mono_arch_emit_epilog (MonoCompile *cfg)
5323 {
5324         MonoMethod *method = cfg->method;
5325         int pos, i;
5326         int max_epilog_size = 16 + 20*4;
5327         guint8 *code;
5328
5329         if (cfg->method->save_lmf)
5330                 max_epilog_size += 128;
5331         
5332         if (mono_jit_trace_calls != NULL)
5333                 max_epilog_size += 50;
5334
5335         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5336                 cfg->code_size *= 2;
5337                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5338                 cfg->stat_code_reallocs++;
5339         }
5340
5341         /*
5342          * Keep in sync with OP_JMP
5343          */
5344         code = cfg->native_code + cfg->code_len;
5345
5346         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5347                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5348         }
5349         pos = 0;
5350
5351         if (method->save_lmf) {
5352                 int lmf_offset;
5353                 pos +=  sizeof (MonoLMF);
5354                 lmf_offset = pos;
5355                 /* save the frame reg in r8 */
5356                 ppc_mr (code, ppc_r8, cfg->frame_reg);
5357                 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5358                 /* r5 = previous_lmf */
5359                 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5360                 /* r6 = lmf_addr */
5361                 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5362                 /* *(lmf_addr) = previous_lmf */
5363                 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5364                 /* FIXME: speedup: there is no actual need to restore the registers if
5365                  * we didn't actually change them (idea from Zoltan).
5366                  */
5367                 /* restore iregs */
5368                 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5369                 /* restore fregs */
5370                 /*for (i = 14; i < 32; i++) {
5371                         ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5372                 }*/
5373                 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5374                 /* use the saved copy of the frame reg in r8 */
5375                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5376                         ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5377                         ppc_mtlr (code, ppc_r0);
5378                 }
5379                 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5380         } else {
5381                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5382                         long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5383                         if (ppc_is_imm16 (return_offset)) {
5384                                 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5385                         } else {
5386                                 ppc_load (code, ppc_r12, return_offset);
5387                                 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5388                         }
5389                         ppc_mtlr (code, ppc_r0);
5390                 }
5391                 if (ppc_is_imm16 (cfg->stack_usage)) {
5392                         int offset = cfg->stack_usage;
5393                         for (i = 13; i <= 31; i++) {
5394                                 if (cfg->used_int_regs & (1 << i))
5395                                         offset -= sizeof (mgreg_t);
5396                         }
5397                         if (cfg->frame_reg != ppc_sp)
5398                                 ppc_mr (code, ppc_r12, cfg->frame_reg);
5399                         /* note r31 (possibly the frame register) is restored last */
5400                         for (i = 13; i <= 31; i++) {
5401                                 if (cfg->used_int_regs & (1 << i)) {
5402                                         ppc_ldr (code, i, offset, cfg->frame_reg);
5403                                         offset += sizeof (mgreg_t);
5404                                 }
5405                         }
5406                         if (cfg->frame_reg != ppc_sp)
5407                                 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5408                         else
5409                                 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5410                 } else {
5411                         ppc_load32 (code, ppc_r12, cfg->stack_usage);
5412                         if (cfg->used_int_regs) {
5413                                 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5414                                 for (i = 31; i >= 13; --i) {
5415                                         if (cfg->used_int_regs & (1 << i)) {
5416                                                 pos += sizeof (mgreg_t);
5417                                                 ppc_ldr (code, i, -pos, ppc_r12);
5418                                         }
5419                                 }
5420                                 ppc_mr (code, ppc_sp, ppc_r12);
5421                         } else {
5422                                 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5423                         }
5424                 }
5425
5426         }
5427         ppc_blr (code);
5428
5429         cfg->code_len = code - cfg->native_code;
5430
5431         g_assert (cfg->code_len < cfg->code_size);
5432
5433 }
5434 #endif /* ifndef DISABLE_JIT */
5435
5436 /* remove once throw_exception_by_name is eliminated */
5437 static int
5438 exception_id_by_name (const char *name)
5439 {
5440         if (strcmp (name, "IndexOutOfRangeException") == 0)
5441                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5442         if (strcmp (name, "OverflowException") == 0)
5443                 return MONO_EXC_OVERFLOW;
5444         if (strcmp (name, "ArithmeticException") == 0)
5445                 return MONO_EXC_ARITHMETIC;
5446         if (strcmp (name, "DivideByZeroException") == 0)
5447                 return MONO_EXC_DIVIDE_BY_ZERO;
5448         if (strcmp (name, "InvalidCastException") == 0)
5449                 return MONO_EXC_INVALID_CAST;
5450         if (strcmp (name, "NullReferenceException") == 0)
5451                 return MONO_EXC_NULL_REF;
5452         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5453                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5454         if (strcmp (name, "ArgumentException") == 0)
5455                 return MONO_EXC_ARGUMENT;
5456         g_error ("Unknown intrinsic exception %s\n", name);
5457         return 0;
5458 }
5459
5460 #ifndef DISABLE_JIT
5461 void
5462 mono_arch_emit_exceptions (MonoCompile *cfg)
5463 {
5464         MonoJumpInfo *patch_info;
5465         int i;
5466         guint8 *code;
5467         guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5468         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5469         int max_epilog_size = 50;
5470
5471         for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5472                 exc_throw_pos [i] = NULL;
5473                 exc_throw_found [i] = 0;
5474         }
5475
5476         /* count the number of exception infos */
5477      
5478         /* 
5479          * make sure we have enough space for exceptions
5480          */
5481         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5482                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5483                         i = exception_id_by_name (patch_info->data.target);
5484                         if (!exc_throw_found [i]) {
5485                                 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5486                                 exc_throw_found [i] = TRUE;
5487                         }
5488                 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5489                         max_epilog_size += 12;
5490                 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5491                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5492                         i = exception_id_by_name (ovfj->data.exception);
5493                         if (!exc_throw_found [i]) {
5494                                 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5495                                 exc_throw_found [i] = TRUE;
5496                         }
5497                         max_epilog_size += 8;
5498                 }
5499         }
5500
5501         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5502                 cfg->code_size *= 2;
5503                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5504                 cfg->stat_code_reallocs++;
5505         }
5506
5507         code = cfg->native_code + cfg->code_len;
5508
5509         /* add code to raise exceptions */
5510         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5511                 switch (patch_info->type) {
5512                 case MONO_PATCH_INFO_BB_OVF: {
5513                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5514                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5515                         /* patch the initial jump */
5516                         ppc_patch (ip, code);
5517                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5518                         ppc_b (code, 0);
5519                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5520                         /* jump back to the true target */
5521                         ppc_b (code, 0);
5522                         ip = ovfj->data.bb->native_offset + cfg->native_code;
5523                         ppc_patch (code - 4, ip);
5524                         patch_info->type = MONO_PATCH_INFO_NONE;
5525                         break;
5526                 }
5527                 case MONO_PATCH_INFO_EXC_OVF: {
5528                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5529                         MonoJumpInfo *newji;
5530                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5531                         unsigned char *bcl = code;
5532                         /* patch the initial jump: we arrived here with a call */
5533                         ppc_patch (ip, code);
5534                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5535                         ppc_b (code, 0);
5536                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5537                         /* patch the conditional jump to the right handler */
5538                         /* make it processed next */
5539                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5540                         newji->type = MONO_PATCH_INFO_EXC;
5541                         newji->ip.i = bcl - cfg->native_code;
5542                         newji->data.target = ovfj->data.exception;
5543                         newji->next = patch_info->next;
5544                         patch_info->next = newji;
5545                         patch_info->type = MONO_PATCH_INFO_NONE;
5546                         break;
5547                 }
5548                 case MONO_PATCH_INFO_EXC: {
5549                         MonoClass *exc_class;
5550
5551                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5552                         i = exception_id_by_name (patch_info->data.target);
5553                         if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5554                                 ppc_patch (ip, exc_throw_pos [i]);
5555                                 patch_info->type = MONO_PATCH_INFO_NONE;
5556                                 break;
5557                         } else {
5558                                 exc_throw_pos [i] = code;
5559                         }
5560
5561                         exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5562
5563                         ppc_patch (ip, code);
5564                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5565                         ppc_load (code, ppc_r3, exc_class->type_token);
5566                         /* we got here from a conditional call, so the calling ip is set in lr */
5567                         ppc_mflr (code, ppc_r4);
5568                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5569                         patch_info->data.name = "mono_arch_throw_corlib_exception";
5570                         patch_info->ip.i = code - cfg->native_code;
5571                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5572                                 ppc_load_func (code, PPC_CALL_REG, 0);
5573                                 ppc_mtctr (code, PPC_CALL_REG);
5574                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5575                         } else {
5576                                 ppc_bl (code, 0);
5577                         }
5578                         break;
5579                 }
5580                 default:
5581                         /* do nothing */
5582                         break;
5583                 }
5584         }
5585
5586         cfg->code_len = code - cfg->native_code;
5587
5588         g_assert (cfg->code_len <= cfg->code_size);
5589 }
5590 #endif
5591
5592 #if DEAD_CODE
5593 static int
5594 try_offset_access (void *value, guint32 idx)
5595 {
5596         register void* me __asm__ ("r2");
5597         void ***p = (void***)((char*)me + 284);
5598         int idx1 = idx / 32;
5599         int idx2 = idx % 32;
5600         if (!p [idx1])
5601                 return 0;
5602         if (value != p[idx1][idx2])
5603                 return 0;
5604         return 1;
5605 }
5606 #endif
5607
5608 void
5609 mono_arch_finish_init (void)
5610 {
5611 }
5612
5613 void
5614 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5615 {
5616 }
5617
5618 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5619 #define BR_SIZE 4
5620 #define LOADSTORE_SIZE 4
5621 #define JUMP_IMM_SIZE 12
5622 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5623 #define ENABLE_WRONG_METHOD_CHECK 0
5624
5625 /*
5626  * LOCKING: called with the domain lock held
5627  */
5628 gpointer
5629 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5630                                                                 gpointer fail_tramp)
5631 {
5632         int i;
5633         int size = 0;
5634         guint8 *code, *start;
5635
5636         for (i = 0; i < count; ++i) {
5637                 MonoIMTCheckItem *item = imt_entries [i];
5638                 if (item->is_equals) {
5639                         if (item->check_target_idx) {
5640                                 if (!item->compare_done)
5641                                         item->chunk_size += CMP_SIZE;
5642                                 if (item->has_target_code)
5643                                         item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5644                                 else
5645                                         item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5646                         } else {
5647                                 if (fail_tramp) {
5648                                         item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5649                                         if (!item->has_target_code)
5650                                                 item->chunk_size += LOADSTORE_SIZE;
5651                                 } else {
5652                                         item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5653 #if ENABLE_WRONG_METHOD_CHECK
5654                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5655 #endif
5656                                 }
5657                         }
5658                 } else {
5659                         item->chunk_size += CMP_SIZE + BR_SIZE;
5660                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5661                 }
5662                 size += item->chunk_size;
5663         }
5664         /* the initial load of the vtable address */
5665         size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5666         if (fail_tramp) {
5667                 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5668         } else {
5669                 code = mono_domain_code_reserve (domain, size);
5670         }
5671         start = code;
5672
5673         /*
5674          * We need to save and restore r12 because it might be
5675          * used by the caller as the vtable register, so
5676          * clobbering it will trip up the magic trampoline.
5677          *
5678          * FIXME: Get rid of this by making sure that r12 is
5679          * not used as the vtable register in interface calls.
5680          */
5681         ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5682         ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5683
5684         for (i = 0; i < count; ++i) {
5685                 MonoIMTCheckItem *item = imt_entries [i];
5686                 item->code_target = code;
5687                 if (item->is_equals) {
5688                         if (item->check_target_idx) {
5689                                 if (!item->compare_done) {
5690                                         ppc_load (code, ppc_r0, (gsize)item->key);
5691                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5692                                 }
5693                                 item->jmp_code = code;
5694                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5695                                 if (item->has_target_code) {
5696                                         ppc_load_ptr (code, ppc_r0, item->value.target_code);
5697                                 } else {
5698                                         ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5699                                         ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5700                                 }
5701                                 ppc_mtctr (code, ppc_r0);
5702                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5703                         } else {
5704                                 if (fail_tramp) {
5705                                         ppc_load (code, ppc_r0, (gulong)item->key);
5706                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5707                                         item->jmp_code = code;
5708                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5709                                         if (item->has_target_code) {
5710                                                 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5711                                         } else {
5712                                                 g_assert (vtable);
5713                                                 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5714                                                 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5715                                         }
5716                                         ppc_mtctr (code, ppc_r0);
5717                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5718                                         ppc_patch (item->jmp_code, code);
5719                                         ppc_load_ptr (code, ppc_r0, fail_tramp);
5720                                         ppc_mtctr (code, ppc_r0);
5721                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5722                                         item->jmp_code = NULL;
5723                                 } else {
5724                                         /* enable the commented code to assert on wrong method */
5725 #if ENABLE_WRONG_METHOD_CHECK
5726                                         ppc_load (code, ppc_r0, (guint32)item->key);
5727                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5728                                         item->jmp_code = code;
5729                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5730 #endif
5731                                         ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5732                                         ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5733                                         ppc_mtctr (code, ppc_r0);
5734                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5735 #if ENABLE_WRONG_METHOD_CHECK
5736                                         ppc_patch (item->jmp_code, code);
5737                                         ppc_break (code);
5738                                         item->jmp_code = NULL;
5739 #endif
5740                                 }
5741                         }
5742                 } else {
5743                         ppc_load (code, ppc_r0, (gulong)item->key);
5744                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5745                         item->jmp_code = code;
5746                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5747                 }
5748         }
5749         /* patch the branches to get to the target items */
5750         for (i = 0; i < count; ++i) {
5751                 MonoIMTCheckItem *item = imt_entries [i];
5752                 if (item->jmp_code) {
5753                         if (item->check_target_idx) {
5754                                 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5755                         }
5756                 }
5757         }
5758
5759         if (!fail_tramp)
5760                 UnlockedAdd (&mono_stats.imt_trampolines_size, code - start);
5761         g_assert (code - start <= size);
5762         mono_arch_flush_icache (start, size);
5763
5764         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5765
5766         return start;
5767 }
5768
5769 MonoMethod*
5770 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5771 {
5772         mgreg_t *r = (mgreg_t*)regs;
5773
5774         return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5775 }
5776
5777 MonoVTable*
5778 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5779 {
5780         mgreg_t *r = (mgreg_t*)regs;
5781
5782         return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5783 }
5784
5785 GSList*
5786 mono_arch_get_cie_program (void)
5787 {
5788         GSList *l = NULL;
5789
5790         mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5791
5792         return l;
5793 }
5794
5795 MonoInst*
5796 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5797 {
5798         /* FIXME: */
5799         return NULL;
5800 }
5801
5802 mgreg_t
5803 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5804 {
5805         if (reg == ppc_r1)
5806                 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
5807
5808         return ctx->regs [reg];
5809 }
5810
5811 guint32
5812 mono_arch_get_patch_offset (guint8 *code)
5813 {
5814         return 0;
5815 }
5816
5817 /*
5818  * mono_aot_emit_load_got_addr:
5819  *
5820  *   Emit code to load the got address.
5821  * On PPC, the result is placed into r30.
5822  */
5823 guint8*
5824 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5825 {
5826         ppc_bl (code, 1);
5827         ppc_mflr (code, ppc_r30);
5828         if (cfg)
5829                 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5830         else
5831                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5832         /* arch_emit_got_address () patches this */
5833 #if defined(TARGET_POWERPC64)
5834         ppc_nop (code);
5835         ppc_nop (code);
5836         ppc_nop (code);
5837         ppc_nop (code);
5838 #else
5839         ppc_load32 (code, ppc_r0, 0);
5840         ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5841 #endif
5842
5843         return code;
5844 }
5845
5846 /*
5847  * mono_ppc_emit_load_aotconst:
5848  *
5849  *   Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5850  * TARGET from the mscorlib GOT in full-aot code.
5851  * On PPC, the GOT address is assumed to be in r30, and the result is placed into 
5852  * r12.
5853  */
5854 guint8*
5855 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
5856 {
5857         /* Load the mscorlib got address */
5858         ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
5859         *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5860         /* arch_emit_got_access () patches this */
5861         ppc_load32 (code, ppc_r0, 0);
5862         ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
5863
5864         return code;
5865 }
5866
5867 /* Soft Debug support */
5868 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5869
5870 /*
5871  * BREAKPOINTS
5872  */
5873
5874 /*
5875  * mono_arch_set_breakpoint:
5876  *
5877  *   See mini-amd64.c for docs.
5878  */
5879 void
5880 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5881 {
5882         guint8 *code = ip;
5883         guint8 *orig_code = code;
5884
5885         ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
5886         ppc_ldptr (code, ppc_r12, 0, ppc_r12);
5887
5888         g_assert (code - orig_code == BREAKPOINT_SIZE);
5889
5890         mono_arch_flush_icache (orig_code, code - orig_code);
5891 }
5892
5893 /*
5894  * mono_arch_clear_breakpoint:
5895  *
5896  *   See mini-amd64.c for docs.
5897  */
5898 void
5899 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5900 {
5901         guint8 *code = ip;
5902         int i;
5903
5904         for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
5905                 ppc_nop (code);
5906
5907         mono_arch_flush_icache (ip, code - ip);
5908 }
5909
5910 /*
5911  * mono_arch_is_breakpoint_event:
5912  *
5913  *   See mini-amd64.c for docs.
5914  */
5915 gboolean
5916 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5917 {
5918         siginfo_t* sinfo = (siginfo_t*) info;
5919         /* Sometimes the address is off by 4 */
5920         if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5921                 return TRUE;
5922         else
5923                 return FALSE;
5924 }
5925
5926 /*
5927  * mono_arch_skip_breakpoint:
5928  *
5929  *   See mini-amd64.c for docs.
5930  */
5931 void
5932 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5933 {
5934         /* skip the ldptr */
5935         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5936 }
5937
5938 /*
5939  * SINGLE STEPPING
5940  */
5941         
5942 /*
5943  * mono_arch_start_single_stepping:
5944  *
5945  *   See mini-amd64.c for docs.
5946  */
5947 void
5948 mono_arch_start_single_stepping (void)
5949 {
5950         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5951 }
5952         
5953 /*
5954  * mono_arch_stop_single_stepping:
5955  *
5956  *   See mini-amd64.c for docs.
5957  */
5958 void
5959 mono_arch_stop_single_stepping (void)
5960 {
5961         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5962 }
5963
5964 /*
5965  * mono_arch_is_single_step_event:
5966  *
5967  *   See mini-amd64.c for docs.
5968  */
5969 gboolean
5970 mono_arch_is_single_step_event (void *info, void *sigctx)
5971 {
5972         siginfo_t* sinfo = (siginfo_t*) info;
5973         /* Sometimes the address is off by 4 */
5974         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5975                 return TRUE;
5976         else
5977                 return FALSE;
5978 }
5979
5980 /*
5981  * mono_arch_skip_single_step:
5982  *
5983  *   See mini-amd64.c for docs.
5984  */
5985 void
5986 mono_arch_skip_single_step (MonoContext *ctx)
5987 {
5988         /* skip the ldptr */
5989         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5990 }
5991
5992 /*
5993  * mono_arch_create_seq_point_info:
5994  *
5995  *   See mini-amd64.c for docs.
5996  */
5997 gpointer
5998 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5999 {
6000         NOT_IMPLEMENTED;
6001         return NULL;
6002 }
6003
6004 void
6005 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6006 {
6007         ext->lmf.previous_lmf = prev_lmf;
6008         /* Mark that this is a MonoLMFExt */
6009         ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6010         ext->lmf.ebp = (gssize)ext;
6011 }
6012
6013 #endif
6014
6015 gboolean
6016 mono_arch_opcode_supported (int opcode)
6017 {
6018         switch (opcode) {
6019         case OP_ATOMIC_ADD_I4:
6020         case OP_ATOMIC_CAS_I4:
6021 #ifdef TARGET_POWERPC64
6022         case OP_ATOMIC_ADD_I8:
6023         case OP_ATOMIC_CAS_I8:
6024 #endif
6025                 return TRUE;
6026         default:
6027                 return FALSE;
6028         }
6029 }
6030