Merge pull request #3028 from lateralusX/jlorenss/threadpool_warning
[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, MonoError *error)
4747 {
4748         MonoJumpInfo *patch_info;
4749         gboolean compile_aot = !run_cctors;
4750
4751         mono_error_init (error);
4752
4753         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4754                 unsigned char *ip = patch_info->ip.i + code;
4755                 unsigned char *target;
4756                 gboolean is_fd = FALSE;
4757
4758                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4759                 return_if_nok (error);
4760
4761                 if (compile_aot) {
4762                         switch (patch_info->type) {
4763                         case MONO_PATCH_INFO_BB:
4764                         case MONO_PATCH_INFO_LABEL:
4765                                 break;
4766                         default:
4767                                 /* No need to patch these */
4768                                 continue;
4769                         }
4770                 }
4771
4772                 switch (patch_info->type) {
4773                 case MONO_PATCH_INFO_IP:
4774                         patch_load_sequence (ip, ip);
4775                         continue;
4776                 case MONO_PATCH_INFO_METHOD_REL:
4777                         g_assert_not_reached ();
4778                         *((gpointer *)(ip)) = code + patch_info->data.offset;
4779                         continue;
4780                 case MONO_PATCH_INFO_SWITCH: {
4781                         gpointer *table = (gpointer *)patch_info->data.table->table;
4782                         int i;
4783
4784                         patch_load_sequence (ip, table);
4785
4786                         for (i = 0; i < patch_info->data.table->table_size; i++) {
4787                                 table [i] = (glong)patch_info->data.table->table [i] + code;
4788                         }
4789                         /* we put into the table the absolute address, no need for ppc_patch in this case */
4790                         continue;
4791                 }
4792                 case MONO_PATCH_INFO_METHODCONST:
4793                 case MONO_PATCH_INFO_CLASS:
4794                 case MONO_PATCH_INFO_IMAGE:
4795                 case MONO_PATCH_INFO_FIELD:
4796                 case MONO_PATCH_INFO_VTABLE:
4797                 case MONO_PATCH_INFO_IID:
4798                 case MONO_PATCH_INFO_SFLDA:
4799                 case MONO_PATCH_INFO_LDSTR:
4800                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4801                 case MONO_PATCH_INFO_LDTOKEN:
4802                         /* from OP_AOTCONST : lis + ori */
4803                         patch_load_sequence (ip, target);
4804                         continue;
4805                 case MONO_PATCH_INFO_R4:
4806                 case MONO_PATCH_INFO_R8:
4807                         g_assert_not_reached ();
4808                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4809                         continue;
4810                 case MONO_PATCH_INFO_EXC_NAME:
4811                         g_assert_not_reached ();
4812                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4813                         continue;
4814                 case MONO_PATCH_INFO_NONE:
4815                 case MONO_PATCH_INFO_BB_OVF:
4816                 case MONO_PATCH_INFO_EXC_OVF:
4817                         /* everything is dealt with at epilog output time */
4818                         continue;
4819 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4820                 case MONO_PATCH_INFO_INTERNAL_METHOD:
4821                 case MONO_PATCH_INFO_ABS:
4822                 case MONO_PATCH_INFO_RGCTX_FETCH:
4823                 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4824                         is_fd = TRUE;
4825                         break;
4826 #endif
4827                 default:
4828                         break;
4829                 }
4830                 ppc_patch_full (ip, target, is_fd);
4831         }
4832 }
4833
4834 /*
4835  * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4836  * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4837  * the instruction offset immediate for all the registers.
4838  */
4839 static guint8*
4840 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4841 {
4842         int i;
4843         if (!save_lmf) {
4844                 for (i = 13; i <= 31; i++) {
4845                         if (used_int_regs & (1 << i)) {
4846                                 ppc_str (code, i, pos, base_reg);
4847                                 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4848                                 pos += sizeof (mgreg_t);
4849                         }
4850                 }
4851         } else {
4852                 /* pos is the start of the MonoLMF structure */
4853                 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4854                 for (i = 13; i <= 31; i++) {
4855                         ppc_str (code, i, offset, base_reg);
4856                         mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4857                         offset += sizeof (mgreg_t);
4858                 }
4859                 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4860                 for (i = 14; i < 32; i++) {
4861                         ppc_stfd (code, i, offset, base_reg);
4862                         offset += sizeof (gdouble);
4863                 }
4864         }
4865         return code;
4866 }
4867
4868 /*
4869  * Stack frame layout:
4870  * 
4871  *   ------------------- sp
4872  *      MonoLMF structure or saved registers
4873  *   -------------------
4874  *      spilled regs
4875  *   -------------------
4876  *      locals
4877  *   -------------------
4878  *      optional 8 bytes for tracing
4879  *   -------------------
4880  *      param area             size is cfg->param_area
4881  *   -------------------
4882  *      linkage area           size is PPC_STACK_PARAM_OFFSET
4883  *   ------------------- sp
4884  *      red zone
4885  */
4886 guint8 *
4887 mono_arch_emit_prolog (MonoCompile *cfg)
4888 {
4889         MonoMethod *method = cfg->method;
4890         MonoBasicBlock *bb;
4891         MonoMethodSignature *sig;
4892         MonoInst *inst;
4893         long alloc_size, pos, max_offset, cfa_offset;
4894         int i;
4895         guint8 *code;
4896         CallInfo *cinfo;
4897         int tracing = 0;
4898         int lmf_offset = 0;
4899         int tailcall_struct_index;
4900
4901         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4902                 tracing = 1;
4903
4904         sig = mono_method_signature (method);
4905         cfg->code_size = 512 + sig->param_count * 32;
4906         code = cfg->native_code = g_malloc (cfg->code_size);
4907
4908         cfa_offset = 0;
4909
4910         /* We currently emit unwind info for aot, but don't use it */
4911         mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4912
4913         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4914                 ppc_mflr (code, ppc_r0);
4915                 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4916                 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4917         }
4918
4919         alloc_size = cfg->stack_offset;
4920         pos = 0;
4921
4922         if (!method->save_lmf) {
4923                 for (i = 31; i >= 13; --i) {
4924                         if (cfg->used_int_regs & (1 << i)) {
4925                                 pos += sizeof (mgreg_t);
4926                         }
4927                 }
4928         } else {
4929                 pos += sizeof (MonoLMF);
4930                 lmf_offset = pos;
4931         }
4932         alloc_size += pos;
4933         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4934         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4935                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4936                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4937         }
4938
4939         cfg->stack_usage = alloc_size;
4940         g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4941         if (alloc_size) {
4942                 if (ppc_is_imm16 (-alloc_size)) {
4943                         ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4944                         cfa_offset = alloc_size;
4945                         mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4946                         code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4947                 } else {
4948                         if (pos)
4949                                 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4950                         ppc_load (code, ppc_r0, -alloc_size);
4951                         ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4952                         cfa_offset = alloc_size;
4953                         mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4954                         code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4955                 }
4956         }
4957         if (cfg->frame_reg != ppc_sp) {
4958                 ppc_mr (code, cfg->frame_reg, ppc_sp);
4959                 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4960         }
4961
4962         /* store runtime generic context */
4963         if (cfg->rgctx_var) {
4964                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4965                                 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4966
4967                 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4968         }
4969
4970         /* compute max_offset in order to use short forward jumps
4971          * we always do it on ppc because the immediate displacement
4972          * for jumps is too small 
4973          */
4974         max_offset = 0;
4975         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4976                 MonoInst *ins;
4977                 bb->max_offset = max_offset;
4978
4979                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4980                         max_offset += 6; 
4981
4982                 MONO_BB_FOR_EACH_INS (bb, ins)
4983                         max_offset += ins_native_length (cfg, ins);
4984         }
4985
4986         /* load arguments allocated to register from the stack */
4987         pos = 0;
4988
4989         cinfo = get_call_info (sig);
4990
4991         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4992                 ArgInfo *ainfo = &cinfo->ret;
4993
4994                 inst = cfg->vret_addr;
4995                 g_assert (inst);
4996
4997                 if (ppc_is_imm16 (inst->inst_offset)) {
4998                         ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4999                 } else {
5000                         ppc_load (code, ppc_r12, inst->inst_offset);
5001                         ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5002                 }
5003         }
5004
5005         tailcall_struct_index = 0;
5006         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5007                 ArgInfo *ainfo = cinfo->args + i;
5008                 inst = cfg->args [pos];
5009                 
5010                 if (cfg->verbose_level > 2)
5011                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
5012                 if (inst->opcode == OP_REGVAR) {
5013                         if (ainfo->regtype == RegTypeGeneral)
5014                                 ppc_mr (code, inst->dreg, ainfo->reg);
5015                         else if (ainfo->regtype == RegTypeFP)
5016                                 ppc_fmr (code, inst->dreg, ainfo->reg);
5017                         else if (ainfo->regtype == RegTypeBase) {
5018                                 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5019                                 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
5020                         } else
5021                                 g_assert_not_reached ();
5022
5023                         if (cfg->verbose_level > 2)
5024                                 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5025                 } else {
5026                         /* the argument should be put on the stack: FIXME handle size != word  */
5027                         if (ainfo->regtype == RegTypeGeneral) {
5028                                 switch (ainfo->size) {
5029                                 case 1:
5030                                         if (ppc_is_imm16 (inst->inst_offset)) {
5031                                                 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5032                                         } else {
5033                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5034                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5035                                                         ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
5036                                                 } else {
5037                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5038                                                         ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5039                                                 }
5040                                         }
5041                                         break;
5042                                 case 2:
5043                                         if (ppc_is_imm16 (inst->inst_offset)) {
5044                                                 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5045                                         } else {
5046                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5047                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5048                                                         ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
5049                                                 } else {
5050                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5051                                                         ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5052                                                 }
5053                                         }
5054                                         break;
5055 #ifdef __mono_ppc64__
5056                                 case 4:
5057                                         if (ppc_is_imm16 (inst->inst_offset)) {
5058                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5059                                         } else {
5060                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5061                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5062                                                         ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
5063                                                 } else {
5064                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5065                                                         ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5066                                                 }
5067                                         }
5068                                         break;
5069                                 case 8:
5070                                         if (ppc_is_imm16 (inst->inst_offset)) {
5071                                                 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5072                                         } else {
5073                                                 ppc_load (code, ppc_r12, inst->inst_offset);
5074                                                 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5075                                         }
5076                                         break;
5077 #else
5078                                 case 8:
5079                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
5080                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5081                                                 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5082                                         } else {
5083                                                 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5084                                                 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5085                                                 ppc_stw (code, ainfo->reg, 0, ppc_r12);
5086                                                 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
5087                                         }
5088                                         break;
5089 #endif
5090                                 default:
5091                                         if (ppc_is_imm16 (inst->inst_offset)) {
5092                                                 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5093                                         } else {
5094                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5095                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5096                                                         ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5097                                                 } else {
5098                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5099                                                         ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5100                                                 }
5101                                         }
5102                                         break;
5103                                 }
5104                         } else if (ainfo->regtype == RegTypeBase) {
5105                                 g_assert (ppc_is_imm16 (ainfo->offset));
5106                                 /* load the previous stack pointer in r12 */
5107                                 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5108                                 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5109                                 switch (ainfo->size) {
5110                                 case 1:
5111                                         if (ppc_is_imm16 (inst->inst_offset)) {
5112                                                 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5113                                         } else {
5114                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5115                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5116                                                         ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5117                                                 } else {
5118                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5119                                                         ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5120                                                 }
5121                                         }
5122                                         break;
5123                                 case 2:
5124                                         if (ppc_is_imm16 (inst->inst_offset)) {
5125                                                 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5126                                         } else {
5127                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5128                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5129                                                         ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5130                                                 } else {
5131                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5132                                                         ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5133                                                 }
5134                                         }
5135                                         break;
5136 #ifdef __mono_ppc64__
5137                                 case 4:
5138                                         if (ppc_is_imm16 (inst->inst_offset)) {
5139                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5140                                         } else {
5141                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5142                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5143                                                         ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5144                                                 } else {
5145                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5146                                                         ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5147                                                 }
5148                                         }
5149                                         break;
5150                                 case 8:
5151                                         if (ppc_is_imm16 (inst->inst_offset)) {
5152                                                 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5153                                         } else {
5154                                                 ppc_load (code, ppc_r12, inst->inst_offset);
5155                                                 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5156                                         }
5157                                         break;
5158 #else
5159                                 case 8:
5160                                         g_assert (ppc_is_imm16 (ainfo->offset + 4));
5161                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
5162                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5163                                                 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5164                                                 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5165                                         } else {
5166                                                 /* use r11 to load the 2nd half of the long before we clobber r12.  */
5167                                                 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5168                                                 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5169                                                 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5170                                                 ppc_stw (code, ppc_r0, 0, ppc_r12);
5171                                                 ppc_stw (code, ppc_r11, 4, ppc_r12);
5172                                         }
5173                                         break;
5174 #endif
5175                                 default:
5176                                         if (ppc_is_imm16 (inst->inst_offset)) {
5177                                                 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5178                                         } else {
5179                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5180                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5181                                                         ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5182                                                 } else {
5183                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5184                                                         ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5185                                                 }
5186                                         }
5187                                         break;
5188                                 }
5189                         } else if (ainfo->regtype == RegTypeFP) {
5190                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5191                                 if (ainfo->size == 8)
5192                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5193                                 else if (ainfo->size == 4)
5194                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5195                                 else
5196                                         g_assert_not_reached ();
5197                          } else if (ainfo->regtype == RegTypeFPStructByVal) {
5198                                 int doffset = inst->inst_offset;
5199                                 int soffset = 0;
5200                                 int cur_reg;
5201                                 int size = 0;
5202                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5203                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5204                                 /* FIXME: what if there is no class? */
5205                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5206                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5207                                 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5208                                         if (ainfo->size == 4) {
5209                                                 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5210                                         } else {
5211                                                 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5212                                         }
5213                                         soffset += ainfo->size;
5214                                         doffset += ainfo->size;
5215                                 }
5216                         } else if (ainfo->regtype == RegTypeStructByVal) {
5217                                 int doffset = inst->inst_offset;
5218                                 int soffset = 0;
5219                                 int cur_reg;
5220                                 int size = 0;
5221                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5222                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5223                                 /* FIXME: what if there is no class? */
5224                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5225                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5226                                 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5227 #if __APPLE__
5228                                         /*
5229                                          * Darwin handles 1 and 2 byte
5230                                          * structs specially by
5231                                          * loading h/b into the arg
5232                                          * register.  Only done for
5233                                          * pinvokes.
5234                                          */
5235                                         if (size == 2)
5236                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5237                                         else if (size == 1)
5238                                                 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5239                                         else
5240 #endif
5241                                         {
5242 #ifdef __mono_ppc64__
5243                                                 if (ainfo->bytes) {
5244                                                         g_assert (cur_reg == 0);
5245 #if G_BYTE_ORDER == G_BIG_ENDIAN
5246                                                         ppc_sldi (code, ppc_r0, ainfo->reg,
5247                                                                          (sizeof (gpointer) - ainfo->bytes) * 8);
5248                                                         ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5249 #else
5250                                                         if (mono_class_native_size (inst->klass, NULL) == 1) {
5251                                                           ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5252                                                         } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5253                                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5254                                                         } else if (mono_class_native_size (inst->klass, NULL) == 4) {  // WDS -- maybe <=4?
5255                                                                 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5256                                                         } else {
5257                                                                 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);  // WDS -- Better way?
5258                                                         }
5259 #endif
5260                                                 } else
5261 #endif
5262                                                 {
5263                                                         ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5264                                                                         inst->inst_basereg);
5265                                                 }
5266                                         }
5267                                         soffset += sizeof (gpointer);
5268                                         doffset += sizeof (gpointer);
5269                                 }
5270                                 if (ainfo->vtsize) {
5271                                         /* FIXME: we need to do the shifting here, too */
5272                                         if (ainfo->bytes)
5273                                                 NOT_IMPLEMENTED;
5274                                         /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5275                                         ppc_ldr (code, ppc_r12, 0, ppc_sp);
5276                                         if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5277                                                 code = emit_memcpy (code, size - soffset,
5278                                                         inst->inst_basereg, doffset,
5279                                                         ppc_r12, ainfo->offset + soffset);
5280                                         } else {
5281                                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5282                                                         inst->inst_basereg, doffset,
5283                                                         ppc_r12, ainfo->offset + soffset);
5284                                         }
5285                                 }
5286                         } else if (ainfo->regtype == RegTypeStructByAddr) {
5287                                 /* if it was originally a RegTypeBase */
5288                                 if (ainfo->offset) {
5289                                         /* load the previous stack pointer in r12 */
5290                                         ppc_ldr (code, ppc_r12, 0, ppc_sp);
5291                                         ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5292                                 } else {
5293                                         ppc_mr (code, ppc_r12, ainfo->reg);
5294                                 }
5295
5296                                 if (cfg->tailcall_valuetype_addrs) {
5297                                         MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5298
5299                                         g_assert (ppc_is_imm16 (addr->inst_offset));
5300                                         ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5301
5302                                         tailcall_struct_index++;
5303                                 }
5304
5305                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5306                                 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5307                                 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5308                         } else
5309                                 g_assert_not_reached ();
5310                 }
5311                 pos++;
5312         }
5313
5314         if (method->save_lmf) {
5315                 if (lmf_pthread_key != -1) {
5316                         emit_tls_access (code, ppc_r3, lmf_pthread_key);
5317                         if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5318                                 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5319                 } else {
5320                         if (cfg->compile_aot) {
5321                                 /* Compute the got address which is needed by the PLT entry */
5322                                 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5323                         }
5324                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
5325                                      (gpointer)"mono_get_lmf_addr");
5326                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5327                                 ppc_load_func (code, PPC_CALL_REG, 0);
5328                                 ppc_mtlr (code, PPC_CALL_REG);
5329                                 ppc_blrl (code);
5330                         } else {
5331                                 ppc_bl (code, 0);
5332                         }
5333                 }
5334                 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5335                 /* lmf_offset is the offset from the previous stack pointer,
5336                  * alloc_size is the total stack space allocated, so the offset
5337                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5338                  * The pointer to the struct is put in ppc_r12 (new_lmf).
5339                  * The callee-saved registers are already in the MonoLMF structure
5340                  */
5341                 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5342                 /* ppc_r3 is the result from mono_get_lmf_addr () */
5343                 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5344                 /* new_lmf->previous_lmf = *lmf_addr */
5345                 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5346                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5347                 /* *(lmf_addr) = r12 */
5348                 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5349                 /* save method info */
5350                 if (cfg->compile_aot)
5351                         // FIXME:
5352                         ppc_load (code, ppc_r0, 0);
5353                 else
5354                         ppc_load_ptr (code, ppc_r0, method);
5355                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5356                 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5357                 /* save the current IP */
5358                 if (cfg->compile_aot) {
5359                         ppc_bl (code, 1);
5360                         ppc_mflr (code, ppc_r0);
5361                 } else {
5362                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5363 #ifdef __mono_ppc64__
5364                         ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5365 #else
5366                         ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5367 #endif
5368                 }
5369                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5370         }
5371
5372         if (tracing)
5373                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5374
5375         cfg->code_len = code - cfg->native_code;
5376         g_assert (cfg->code_len <= cfg->code_size);
5377         g_free (cinfo);
5378
5379         return code;
5380 }
5381
5382 void
5383 mono_arch_emit_epilog (MonoCompile *cfg)
5384 {
5385         MonoMethod *method = cfg->method;
5386         int pos, i;
5387         int max_epilog_size = 16 + 20*4;
5388         guint8 *code;
5389
5390         if (cfg->method->save_lmf)
5391                 max_epilog_size += 128;
5392         
5393         if (mono_jit_trace_calls != NULL)
5394                 max_epilog_size += 50;
5395
5396         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5397                 max_epilog_size += 50;
5398
5399         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5400                 cfg->code_size *= 2;
5401                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5402                 cfg->stat_code_reallocs++;
5403         }
5404
5405         /*
5406          * Keep in sync with OP_JMP
5407          */
5408         code = cfg->native_code + cfg->code_len;
5409
5410         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5411                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5412         }
5413         pos = 0;
5414
5415         if (method->save_lmf) {
5416                 int lmf_offset;
5417                 pos +=  sizeof (MonoLMF);
5418                 lmf_offset = pos;
5419                 /* save the frame reg in r8 */
5420                 ppc_mr (code, ppc_r8, cfg->frame_reg);
5421                 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5422                 /* r5 = previous_lmf */
5423                 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5424                 /* r6 = lmf_addr */
5425                 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5426                 /* *(lmf_addr) = previous_lmf */
5427                 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5428                 /* FIXME: speedup: there is no actual need to restore the registers if
5429                  * we didn't actually change them (idea from Zoltan).
5430                  */
5431                 /* restore iregs */
5432                 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5433                 /* restore fregs */
5434                 /*for (i = 14; i < 32; i++) {
5435                         ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5436                 }*/
5437                 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5438                 /* use the saved copy of the frame reg in r8 */
5439                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5440                         ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5441                         ppc_mtlr (code, ppc_r0);
5442                 }
5443                 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5444         } else {
5445                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5446                         long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5447                         if (ppc_is_imm16 (return_offset)) {
5448                                 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5449                         } else {
5450                                 ppc_load (code, ppc_r12, return_offset);
5451                                 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5452                         }
5453                         ppc_mtlr (code, ppc_r0);
5454                 }
5455                 if (ppc_is_imm16 (cfg->stack_usage)) {
5456                         int offset = cfg->stack_usage;
5457                         for (i = 13; i <= 31; i++) {
5458                                 if (cfg->used_int_regs & (1 << i))
5459                                         offset -= sizeof (mgreg_t);
5460                         }
5461                         if (cfg->frame_reg != ppc_sp)
5462                                 ppc_mr (code, ppc_r12, cfg->frame_reg);
5463                         /* note r31 (possibly the frame register) is restored last */
5464                         for (i = 13; i <= 31; i++) {
5465                                 if (cfg->used_int_regs & (1 << i)) {
5466                                         ppc_ldr (code, i, offset, cfg->frame_reg);
5467                                         offset += sizeof (mgreg_t);
5468                                 }
5469                         }
5470                         if (cfg->frame_reg != ppc_sp)
5471                                 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5472                         else
5473                                 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5474                 } else {
5475                         ppc_load32 (code, ppc_r12, cfg->stack_usage);
5476                         if (cfg->used_int_regs) {
5477                                 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5478                                 for (i = 31; i >= 13; --i) {
5479                                         if (cfg->used_int_regs & (1 << i)) {
5480                                                 pos += sizeof (mgreg_t);
5481                                                 ppc_ldr (code, i, -pos, ppc_r12);
5482                                         }
5483                                 }
5484                                 ppc_mr (code, ppc_sp, ppc_r12);
5485                         } else {
5486                                 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5487                         }
5488                 }
5489
5490         }
5491         ppc_blr (code);
5492
5493         cfg->code_len = code - cfg->native_code;
5494
5495         g_assert (cfg->code_len < cfg->code_size);
5496
5497 }
5498 #endif /* ifndef DISABLE_JIT */
5499
5500 /* remove once throw_exception_by_name is eliminated */
5501 static int
5502 exception_id_by_name (const char *name)
5503 {
5504         if (strcmp (name, "IndexOutOfRangeException") == 0)
5505                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5506         if (strcmp (name, "OverflowException") == 0)
5507                 return MONO_EXC_OVERFLOW;
5508         if (strcmp (name, "ArithmeticException") == 0)
5509                 return MONO_EXC_ARITHMETIC;
5510         if (strcmp (name, "DivideByZeroException") == 0)
5511                 return MONO_EXC_DIVIDE_BY_ZERO;
5512         if (strcmp (name, "InvalidCastException") == 0)
5513                 return MONO_EXC_INVALID_CAST;
5514         if (strcmp (name, "NullReferenceException") == 0)
5515                 return MONO_EXC_NULL_REF;
5516         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5517                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5518         if (strcmp (name, "ArgumentException") == 0)
5519                 return MONO_EXC_ARGUMENT;
5520         g_error ("Unknown intrinsic exception %s\n", name);
5521         return 0;
5522 }
5523
5524 #ifndef DISABLE_JIT
5525 void
5526 mono_arch_emit_exceptions (MonoCompile *cfg)
5527 {
5528         MonoJumpInfo *patch_info;
5529         int i;
5530         guint8 *code;
5531         guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5532         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5533         int max_epilog_size = 50;
5534
5535         for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5536                 exc_throw_pos [i] = NULL;
5537                 exc_throw_found [i] = 0;
5538         }
5539
5540         /* count the number of exception infos */
5541      
5542         /* 
5543          * make sure we have enough space for exceptions
5544          */
5545         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5546                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5547                         i = exception_id_by_name (patch_info->data.target);
5548                         if (!exc_throw_found [i]) {
5549                                 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5550                                 exc_throw_found [i] = TRUE;
5551                         }
5552                 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5553                         max_epilog_size += 12;
5554                 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5555                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5556                         i = exception_id_by_name (ovfj->data.exception);
5557                         if (!exc_throw_found [i]) {
5558                                 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5559                                 exc_throw_found [i] = TRUE;
5560                         }
5561                         max_epilog_size += 8;
5562                 }
5563         }
5564
5565         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5566                 cfg->code_size *= 2;
5567                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5568                 cfg->stat_code_reallocs++;
5569         }
5570
5571         code = cfg->native_code + cfg->code_len;
5572
5573         /* add code to raise exceptions */
5574         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5575                 switch (patch_info->type) {
5576                 case MONO_PATCH_INFO_BB_OVF: {
5577                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5578                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5579                         /* patch the initial jump */
5580                         ppc_patch (ip, code);
5581                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5582                         ppc_b (code, 0);
5583                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5584                         /* jump back to the true target */
5585                         ppc_b (code, 0);
5586                         ip = ovfj->data.bb->native_offset + cfg->native_code;
5587                         ppc_patch (code - 4, ip);
5588                         patch_info->type = MONO_PATCH_INFO_NONE;
5589                         break;
5590                 }
5591                 case MONO_PATCH_INFO_EXC_OVF: {
5592                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5593                         MonoJumpInfo *newji;
5594                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5595                         unsigned char *bcl = code;
5596                         /* patch the initial jump: we arrived here with a call */
5597                         ppc_patch (ip, code);
5598                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5599                         ppc_b (code, 0);
5600                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5601                         /* patch the conditional jump to the right handler */
5602                         /* make it processed next */
5603                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5604                         newji->type = MONO_PATCH_INFO_EXC;
5605                         newji->ip.i = bcl - cfg->native_code;
5606                         newji->data.target = ovfj->data.exception;
5607                         newji->next = patch_info->next;
5608                         patch_info->next = newji;
5609                         patch_info->type = MONO_PATCH_INFO_NONE;
5610                         break;
5611                 }
5612                 case MONO_PATCH_INFO_EXC: {
5613                         MonoClass *exc_class;
5614
5615                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5616                         i = exception_id_by_name (patch_info->data.target);
5617                         if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5618                                 ppc_patch (ip, exc_throw_pos [i]);
5619                                 patch_info->type = MONO_PATCH_INFO_NONE;
5620                                 break;
5621                         } else {
5622                                 exc_throw_pos [i] = code;
5623                         }
5624
5625                         exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5626
5627                         ppc_patch (ip, code);
5628                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5629                         ppc_load (code, ppc_r3, exc_class->type_token);
5630                         /* we got here from a conditional call, so the calling ip is set in lr */
5631                         ppc_mflr (code, ppc_r4);
5632                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5633                         patch_info->data.name = "mono_arch_throw_corlib_exception";
5634                         patch_info->ip.i = code - cfg->native_code;
5635                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5636                                 ppc_load_func (code, PPC_CALL_REG, 0);
5637                                 ppc_mtctr (code, PPC_CALL_REG);
5638                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5639                         } else {
5640                                 ppc_bl (code, 0);
5641                         }
5642                         break;
5643                 }
5644                 default:
5645                         /* do nothing */
5646                         break;
5647                 }
5648         }
5649
5650         cfg->code_len = code - cfg->native_code;
5651
5652         g_assert (cfg->code_len <= cfg->code_size);
5653 }
5654 #endif
5655
5656 #if DEAD_CODE
5657 static int
5658 try_offset_access (void *value, guint32 idx)
5659 {
5660         register void* me __asm__ ("r2");
5661         void ***p = (void***)((char*)me + 284);
5662         int idx1 = idx / 32;
5663         int idx2 = idx % 32;
5664         if (!p [idx1])
5665                 return 0;
5666         if (value != p[idx1][idx2])
5667                 return 0;
5668         return 1;
5669 }
5670 #endif
5671
5672 static void
5673 setup_tls_access (void)
5674 {
5675 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5676         size_t conf_size = 0;
5677         char confbuf[128];
5678 #else
5679         /* FIXME for darwin */
5680         guint32 *ins, *code;
5681         guint32 cmplwi_1023, li_0x48, blr_ins;
5682 #endif
5683
5684 #ifdef TARGET_PS3
5685         tls_mode = TLS_MODE_FAILED;
5686 #endif
5687
5688         if (tls_mode == TLS_MODE_FAILED)
5689                 return;
5690         if (g_getenv ("MONO_NO_TLS")) {
5691                 tls_mode = TLS_MODE_FAILED;
5692                 return;
5693         }
5694
5695         if (tls_mode == TLS_MODE_DETECT) {
5696 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5697                 tls_mode = TLS_MODE_DARWIN_G4;
5698 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5699                 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5700                 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5701                         tls_mode = TLS_MODE_NPTL;
5702 #elif !defined(TARGET_PS3)
5703                 ins = (guint32*)pthread_getspecific;
5704                 /* uncond branch to the real method */
5705                 if ((*ins >> 26) == 18) {
5706                         gint32 val;
5707                         val = (*ins & ~3) << 6;
5708                         val >>= 6;
5709                         if (*ins & 2) {
5710                                 /* absolute */
5711                                 ins = (guint32*)(long)val;
5712                         } else {
5713                                 ins = (guint32*) ((char*)ins + val);
5714                         }
5715                 }
5716                 code = &cmplwi_1023;
5717                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5718                 code = &li_0x48;
5719                 ppc_li (code, ppc_r4, 0x48);
5720                 code = &blr_ins;
5721                 ppc_blr (code);
5722                 if (*ins == cmplwi_1023) {
5723                         int found_lwz_284 = 0;
5724                         guint32 ptk;
5725                         for (ptk = 0; ptk < 20; ++ptk) {
5726                                 ++ins;
5727                                 if (!*ins || *ins == blr_ins)
5728                                         break;
5729                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5730                                         found_lwz_284 = 1;
5731                                         break;
5732                                 }
5733                         }
5734                         if (!found_lwz_284) {
5735                                 tls_mode = TLS_MODE_FAILED;
5736                                 return;
5737                         }
5738                         tls_mode = TLS_MODE_LTHREADS;
5739                 } else if (*ins == li_0x48) {
5740                         ++ins;
5741                         /* uncond branch to the real method */
5742                         if ((*ins >> 26) == 18) {
5743                                 gint32 val;
5744                                 val = (*ins & ~3) << 6;
5745                                 val >>= 6;
5746                                 if (*ins & 2) {
5747                                         /* absolute */
5748                                         ins = (guint32*)(long)val;
5749                                 } else {
5750                                         ins = (guint32*) ((char*)ins + val);
5751                                 }
5752                                 code = (guint32*)&val;
5753                                 ppc_li (code, ppc_r0, 0x7FF2);
5754                                 if (ins [1] == val) {
5755                                         /* Darwin on G4, implement */
5756                                         tls_mode = TLS_MODE_FAILED;
5757                                         return;
5758                                 } else {
5759                                         code = (guint32*)&val;
5760                                         ppc_mfspr (code, ppc_r3, 104);
5761                                         if (ins [1] != val) {
5762                                                 tls_mode = TLS_MODE_FAILED;
5763                                                 return;
5764                                         }
5765                                         tls_mode = TLS_MODE_DARWIN_G5;
5766                                 }
5767                         } else {
5768                                 tls_mode = TLS_MODE_FAILED;
5769                                 return;
5770                         }
5771                 } else {
5772                         tls_mode = TLS_MODE_FAILED;
5773                         return;
5774                 }
5775 #endif
5776         }
5777 #ifndef TARGET_PS3
5778         if (tls_mode == TLS_MODE_DETECT)
5779                 tls_mode = TLS_MODE_FAILED;
5780         if (tls_mode == TLS_MODE_FAILED)
5781                 return;
5782         if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5783                 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5784         }
5785
5786 #if 0
5787         /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5788            mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5789         if (lmf_pthread_key == -1) {
5790                 guint32 ptk = mono_jit_tls_id;
5791                 if (ptk < 1024) {
5792                         /*g_print ("MonoLMF at: %d\n", ptk);*/
5793                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5794                                 init_tls_failed = 1;
5795                                 return;
5796                         }*/
5797                         lmf_pthread_key = ptk;
5798                 }
5799         }
5800 #endif
5801
5802 #endif
5803 }
5804
5805 void
5806 mono_arch_finish_init (void)
5807 {
5808         setup_tls_access ();
5809 }
5810
5811 void
5812 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5813 {
5814 }
5815
5816 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5817 #define BR_SIZE 4
5818 #define LOADSTORE_SIZE 4
5819 #define JUMP_IMM_SIZE 12
5820 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5821 #define ENABLE_WRONG_METHOD_CHECK 0
5822
5823 /*
5824  * LOCKING: called with the domain lock held
5825  */
5826 gpointer
5827 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5828         gpointer fail_tramp)
5829 {
5830         int i;
5831         int size = 0;
5832         guint8 *code, *start;
5833
5834         for (i = 0; i < count; ++i) {
5835                 MonoIMTCheckItem *item = imt_entries [i];
5836                 if (item->is_equals) {
5837                         if (item->check_target_idx) {
5838                                 if (!item->compare_done)
5839                                         item->chunk_size += CMP_SIZE;
5840                                 if (item->has_target_code)
5841                                         item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5842                                 else
5843                                         item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5844                         } else {
5845                                 if (fail_tramp) {
5846                                         item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5847                                         if (!item->has_target_code)
5848                                                 item->chunk_size += LOADSTORE_SIZE;
5849                                 } else {
5850                                         item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5851 #if ENABLE_WRONG_METHOD_CHECK
5852                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5853 #endif
5854                                 }
5855                         }
5856                 } else {
5857                         item->chunk_size += CMP_SIZE + BR_SIZE;
5858                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5859                 }
5860                 size += item->chunk_size;
5861         }
5862         /* the initial load of the vtable address */
5863         size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5864         if (fail_tramp) {
5865                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5866         } else {
5867                 code = mono_domain_code_reserve (domain, size);
5868         }
5869         start = code;
5870
5871         /*
5872          * We need to save and restore r12 because it might be
5873          * used by the caller as the vtable register, so
5874          * clobbering it will trip up the magic trampoline.
5875          *
5876          * FIXME: Get rid of this by making sure that r12 is
5877          * not used as the vtable register in interface calls.
5878          */
5879         ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5880         ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5881
5882         for (i = 0; i < count; ++i) {
5883                 MonoIMTCheckItem *item = imt_entries [i];
5884                 item->code_target = code;
5885                 if (item->is_equals) {
5886                         if (item->check_target_idx) {
5887                                 if (!item->compare_done) {
5888                                         ppc_load (code, ppc_r0, (gsize)item->key);
5889                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5890                                 }
5891                                 item->jmp_code = code;
5892                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5893                                 if (item->has_target_code) {
5894                                         ppc_load_ptr (code, ppc_r0, item->value.target_code);
5895                                 } else {
5896                                         ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5897                                         ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5898                                 }
5899                                 ppc_mtctr (code, ppc_r0);
5900                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5901                         } else {
5902                                 if (fail_tramp) {
5903                                         ppc_load (code, ppc_r0, (gulong)item->key);
5904                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5905                                         item->jmp_code = code;
5906                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5907                                         if (item->has_target_code) {
5908                                                 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5909                                         } else {
5910                                                 g_assert (vtable);
5911                                                 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5912                                                 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5913                                         }
5914                                         ppc_mtctr (code, ppc_r0);
5915                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5916                                         ppc_patch (item->jmp_code, code);
5917                                         ppc_load_ptr (code, ppc_r0, fail_tramp);
5918                                         ppc_mtctr (code, ppc_r0);
5919                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5920                                         item->jmp_code = NULL;
5921                                 } else {
5922                                         /* enable the commented code to assert on wrong method */
5923 #if ENABLE_WRONG_METHOD_CHECK
5924                                         ppc_load (code, ppc_r0, (guint32)item->key);
5925                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5926                                         item->jmp_code = code;
5927                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5928 #endif
5929                                         ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5930                                         ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5931                                         ppc_mtctr (code, ppc_r0);
5932                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5933 #if ENABLE_WRONG_METHOD_CHECK
5934                                         ppc_patch (item->jmp_code, code);
5935                                         ppc_break (code);
5936                                         item->jmp_code = NULL;
5937 #endif
5938                                 }
5939                         }
5940                 } else {
5941                         ppc_load (code, ppc_r0, (gulong)item->key);
5942                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5943                         item->jmp_code = code;
5944                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5945                 }
5946         }
5947         /* patch the branches to get to the target items */
5948         for (i = 0; i < count; ++i) {
5949                 MonoIMTCheckItem *item = imt_entries [i];
5950                 if (item->jmp_code) {
5951                         if (item->check_target_idx) {
5952                                 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5953                         }
5954                 }
5955         }
5956
5957         if (!fail_tramp)
5958                 mono_stats.imt_thunks_size += code - start;
5959         g_assert (code - start <= size);
5960         mono_arch_flush_icache (start, size);
5961
5962         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5963
5964         return start;
5965 }
5966
5967 MonoMethod*
5968 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5969 {
5970         mgreg_t *r = (mgreg_t*)regs;
5971
5972         return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5973 }
5974
5975 MonoVTable*
5976 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5977 {
5978         mgreg_t *r = (mgreg_t*)regs;
5979
5980         return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5981 }
5982
5983 GSList*
5984 mono_arch_get_cie_program (void)
5985 {
5986         GSList *l = NULL;
5987
5988         mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5989
5990         return l;
5991 }
5992
5993 MonoInst*
5994 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5995 {
5996         /* FIXME: */
5997         return NULL;
5998 }
5999
6000 gboolean
6001 mono_arch_print_tree (MonoInst *tree, int arity)
6002 {
6003         return 0;
6004 }
6005
6006 mgreg_t
6007 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6008 {
6009         if (reg == ppc_r1)
6010                 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
6011
6012         g_assert (reg >= ppc_r13);
6013
6014         return ctx->regs [reg - ppc_r13];
6015 }
6016
6017 guint32
6018 mono_arch_get_patch_offset (guint8 *code)
6019 {
6020         return 0;
6021 }
6022
6023 /*
6024  * mono_aot_emit_load_got_addr:
6025  *
6026  *   Emit code to load the got address.
6027  * On PPC, the result is placed into r30.
6028  */
6029 guint8*
6030 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6031 {
6032         ppc_bl (code, 1);
6033         ppc_mflr (code, ppc_r30);
6034         if (cfg)
6035                 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6036         else
6037                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6038         /* arch_emit_got_address () patches this */
6039 #if defined(TARGET_POWERPC64)
6040         ppc_nop (code);
6041         ppc_nop (code);
6042         ppc_nop (code);
6043         ppc_nop (code);
6044 #else
6045         ppc_load32 (code, ppc_r0, 0);
6046         ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
6047 #endif
6048
6049         return code;
6050 }
6051
6052 /*
6053  * mono_ppc_emit_load_aotconst:
6054  *
6055  *   Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6056  * TARGET from the mscorlib GOT in full-aot code.
6057  * On PPC, the GOT address is assumed to be in r30, and the result is placed into 
6058  * r12.
6059  */
6060 guint8*
6061 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
6062 {
6063         /* Load the mscorlib got address */
6064         ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
6065         *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6066         /* arch_emit_got_access () patches this */
6067         ppc_load32 (code, ppc_r0, 0);
6068         ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
6069
6070         return code;
6071 }
6072
6073 /* Soft Debug support */
6074 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6075
6076 /*
6077  * BREAKPOINTS
6078  */
6079
6080 /*
6081  * mono_arch_set_breakpoint:
6082  *
6083  *   See mini-amd64.c for docs.
6084  */
6085 void
6086 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6087 {
6088         guint8 *code = ip;
6089         guint8 *orig_code = code;
6090
6091         ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
6092         ppc_ldptr (code, ppc_r12, 0, ppc_r12);
6093
6094         g_assert (code - orig_code == BREAKPOINT_SIZE);
6095
6096         mono_arch_flush_icache (orig_code, code - orig_code);
6097 }
6098
6099 /*
6100  * mono_arch_clear_breakpoint:
6101  *
6102  *   See mini-amd64.c for docs.
6103  */
6104 void
6105 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6106 {
6107         guint8 *code = ip;
6108         int i;
6109
6110         for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6111                 ppc_nop (code);
6112
6113         mono_arch_flush_icache (ip, code - ip);
6114 }
6115
6116 /*
6117  * mono_arch_is_breakpoint_event:
6118  *
6119  *   See mini-amd64.c for docs.
6120  */
6121 gboolean
6122 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6123 {
6124         siginfo_t* sinfo = (siginfo_t*) info;
6125         /* Sometimes the address is off by 4 */
6126         if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6127                 return TRUE;
6128         else
6129                 return FALSE;
6130 }
6131
6132 /*
6133  * mono_arch_skip_breakpoint:
6134  *
6135  *   See mini-amd64.c for docs.
6136  */
6137 void
6138 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6139 {
6140         /* skip the ldptr */
6141         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6142 }
6143
6144 /*
6145  * SINGLE STEPPING
6146  */
6147         
6148 /*
6149  * mono_arch_start_single_stepping:
6150  *
6151  *   See mini-amd64.c for docs.
6152  */
6153 void
6154 mono_arch_start_single_stepping (void)
6155 {
6156         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6157 }
6158         
6159 /*
6160  * mono_arch_stop_single_stepping:
6161  *
6162  *   See mini-amd64.c for docs.
6163  */
6164 void
6165 mono_arch_stop_single_stepping (void)
6166 {
6167         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6168 }
6169
6170 /*
6171  * mono_arch_is_single_step_event:
6172  *
6173  *   See mini-amd64.c for docs.
6174  */
6175 gboolean
6176 mono_arch_is_single_step_event (void *info, void *sigctx)
6177 {
6178         siginfo_t* sinfo = (siginfo_t*) info;
6179         /* Sometimes the address is off by 4 */
6180         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6181                 return TRUE;
6182         else
6183                 return FALSE;
6184 }
6185
6186 /*
6187  * mono_arch_skip_single_step:
6188  *
6189  *   See mini-amd64.c for docs.
6190  */
6191 void
6192 mono_arch_skip_single_step (MonoContext *ctx)
6193 {
6194         /* skip the ldptr */
6195         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6196 }
6197
6198 /*
6199  * mono_arch_create_seq_point_info:
6200  *
6201  *   See mini-amd64.c for docs.
6202  */
6203 gpointer
6204 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6205 {
6206         NOT_IMPLEMENTED;
6207         return NULL;
6208 }
6209
6210 void
6211 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6212 {
6213         ext->lmf.previous_lmf = prev_lmf;
6214         /* Mark that this is a MonoLMFExt */
6215         ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6216         ext->lmf.ebp = (gssize)ext;
6217 }
6218
6219 #endif
6220
6221 gboolean
6222 mono_arch_opcode_supported (int opcode)
6223 {
6224         switch (opcode) {
6225         case OP_ATOMIC_ADD_I4:
6226         case OP_ATOMIC_CAS_I4:
6227 #ifdef TARGET_POWERPC64
6228         case OP_ATOMIC_ADD_I8:
6229         case OP_ATOMIC_CAS_I8:
6230 #endif
6231                 return TRUE;
6232         default:
6233                 return FALSE;
6234         }
6235 }
6236
6237
6238 #if 0
6239 // FIXME: To get the test case  finally_block_ending_in_dead_bb  to work properly we need to define the following
6240 // (in mini-ppc.h) and then implement the fuction mono_arch_create_handler_block_trampoline.
6241 //  #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
6242
6243 gpointer
6244 mono_arch_create_handler_block_trampoline (void)
6245 {
6246         . . .
6247 }
6248 #endif