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