Merge pull request #1896 from meum/patch-1
[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 = in->dreg + 1;
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 = in->dreg + 2;
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 = val->dreg + 1;
1914                         ins->sreg2 = val->dreg + 2;
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, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2415                 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
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, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2421                 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
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, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2427                 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
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, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
2433                 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
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, ins->dreg + 1, ins->sreg1 + 1, 0);
2439                 MONO_EMIT_NEW_UNALU (cfg, OP_PPC_SUBFZE, ins->dreg + 2, ins->sreg1 + 2);
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         return mono_op_imm_to_op (op);
2572 }
2573
2574 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2575
2576 #define compare_opcode_is_unsigned(opcode) \
2577                 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) ||  \
2578                 ((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) ||   \
2579                 ((opcode) >= OP_LBNE_UN && (opcode) <= OP_LBLT_UN) ||   \
2580                 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) ||     \
2581                 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) ||   \
2582                 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN ||      \
2583                  (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN ||    \
2584                  (opcode) == OP_LCLT_UN || (opcode) == OP_LCGT_UN))
2585
2586 /*
2587  * Remove from the instruction list the instructions that can't be
2588  * represented with very simple instructions with no register
2589  * requirements.
2590  */
2591 void
2592 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2593 {
2594         MonoInst *ins, *next, *temp, *last_ins = NULL;
2595         int imm;
2596
2597         MONO_BB_FOR_EACH_INS (bb, ins) {
2598 loop_start:
2599                 switch (ins->opcode) {
2600                 case OP_IDIV_UN_IMM:
2601                 case OP_IDIV_IMM:
2602                 case OP_IREM_IMM:
2603                 case OP_IREM_UN_IMM:
2604                 CASE_PPC64 (OP_LREM_IMM) {
2605                         NEW_INS (cfg, temp, OP_ICONST);
2606                         temp->inst_c0 = ins->inst_imm;
2607                         temp->dreg = mono_alloc_ireg (cfg);
2608                         ins->sreg2 = temp->dreg;
2609                         if (ins->opcode == OP_IDIV_IMM)
2610                                 ins->opcode = OP_IDIV;
2611                         else if (ins->opcode == OP_IREM_IMM)
2612                                 ins->opcode = OP_IREM;
2613                         else if (ins->opcode == OP_IDIV_UN_IMM)
2614                                 ins->opcode = OP_IDIV_UN;
2615                         else if (ins->opcode == OP_IREM_UN_IMM)
2616                                 ins->opcode = OP_IREM_UN;
2617                         else if (ins->opcode == OP_LREM_IMM)
2618                                 ins->opcode = OP_LREM;
2619                         last_ins = temp;
2620                         /* handle rem separately */
2621                         goto loop_start;
2622                 }
2623                 case OP_IREM:
2624                 case OP_IREM_UN:
2625                 CASE_PPC64 (OP_LREM)
2626                 CASE_PPC64 (OP_LREM_UN) {
2627                         MonoInst *mul;
2628                         /* we change a rem dest, src1, src2 to
2629                          * div temp1, src1, src2
2630                          * mul temp2, temp1, src2
2631                          * sub dest, src1, temp2
2632                          */
2633                         if (ins->opcode == OP_IREM || ins->opcode == OP_IREM_UN) {
2634                                 NEW_INS (cfg, mul, OP_IMUL);
2635                                 NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2636                                 ins->opcode = OP_ISUB;
2637                         } else {
2638                                 NEW_INS (cfg, mul, OP_LMUL);
2639                                 NEW_INS (cfg, temp, ins->opcode == OP_LREM? OP_LDIV: OP_LDIV_UN);
2640                                 ins->opcode = OP_LSUB;
2641                         }
2642                         temp->sreg1 = ins->sreg1;
2643                         temp->sreg2 = ins->sreg2;
2644                         temp->dreg = mono_alloc_ireg (cfg);
2645                         mul->sreg1 = temp->dreg;
2646                         mul->sreg2 = ins->sreg2;
2647                         mul->dreg = mono_alloc_ireg (cfg);
2648                         ins->sreg2 = mul->dreg;
2649                         break;
2650                 }
2651                 case OP_IADD_IMM:
2652                 CASE_PPC64 (OP_LADD_IMM)
2653                 case OP_ADD_IMM:
2654                 case OP_ADDCC_IMM:
2655                         if (!ppc_is_imm16 (ins->inst_imm)) {
2656                                 NEW_INS (cfg,  temp, OP_ICONST);
2657                                 temp->inst_c0 = ins->inst_imm;
2658                                 temp->dreg = mono_alloc_ireg (cfg);
2659                                 ins->sreg2 = temp->dreg;
2660                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2661                         }
2662                         break;
2663                 case OP_ISUB_IMM:
2664                 CASE_PPC64 (OP_LSUB_IMM)
2665                 case OP_SUB_IMM:
2666                         if (!ppc_is_imm16 (-ins->inst_imm)) {
2667                                 NEW_INS (cfg, temp, OP_ICONST);
2668                                 temp->inst_c0 = ins->inst_imm;
2669                                 temp->dreg = mono_alloc_ireg (cfg);
2670                                 ins->sreg2 = temp->dreg;
2671                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2672                         }
2673                         break;
2674                 case OP_IAND_IMM:
2675                 case OP_IOR_IMM:
2676                 case OP_IXOR_IMM:
2677                 case OP_LAND_IMM:
2678                 case OP_LOR_IMM:
2679                 case OP_LXOR_IMM:
2680                 case OP_AND_IMM:
2681                 case OP_OR_IMM:
2682                 case OP_XOR_IMM: {
2683                         gboolean is_imm = ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff));
2684 #ifdef __mono_ppc64__
2685                         if (ins->inst_imm & 0xffffffff00000000ULL)
2686                                 is_imm = TRUE;
2687 #endif
2688                         if (is_imm) {
2689                                 NEW_INS (cfg, temp, OP_ICONST);
2690                                 temp->inst_c0 = ins->inst_imm;
2691                                 temp->dreg = mono_alloc_ireg (cfg);
2692                                 ins->sreg2 = temp->dreg;
2693                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2694                         }
2695                         break;
2696                 }
2697                 case OP_ISBB_IMM:
2698                 case OP_IADC_IMM:
2699                 case OP_SBB_IMM:
2700                 case OP_SUBCC_IMM:
2701                 case OP_ADC_IMM:
2702                         NEW_INS (cfg, temp, OP_ICONST);
2703                         temp->inst_c0 = ins->inst_imm;
2704                         temp->dreg = mono_alloc_ireg (cfg);
2705                         ins->sreg2 = temp->dreg;
2706                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2707                         break;
2708                 case OP_COMPARE_IMM:
2709                 case OP_ICOMPARE_IMM:
2710                 CASE_PPC64 (OP_LCOMPARE_IMM)
2711                         next = ins->next;
2712                         /* Branch opts can eliminate the branch */
2713                         if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2714                                 ins->opcode = OP_NOP;
2715                                 break;
2716                         }
2717                         g_assert(next);
2718                         if (compare_opcode_is_unsigned (next->opcode)) {
2719                                 if (!ppc_is_uimm16 (ins->inst_imm)) {
2720                                         NEW_INS (cfg, temp, OP_ICONST);
2721                                         temp->inst_c0 = ins->inst_imm;
2722                                         temp->dreg = mono_alloc_ireg (cfg);
2723                                         ins->sreg2 = temp->dreg;
2724                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2725                                 }
2726                         } else {
2727                                 if (!ppc_is_imm16 (ins->inst_imm)) {
2728                                         NEW_INS (cfg, temp, OP_ICONST);
2729                                         temp->inst_c0 = ins->inst_imm;
2730                                         temp->dreg = mono_alloc_ireg (cfg);
2731                                         ins->sreg2 = temp->dreg;
2732                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2733                                 }
2734                         }
2735                         break;
2736                 case OP_IMUL_IMM:
2737                 case OP_MUL_IMM:
2738                         if (ins->inst_imm == 1) {
2739                                 ins->opcode = OP_MOVE;
2740                                 break;
2741                         }
2742                         if (ins->inst_imm == 0) {
2743                                 ins->opcode = OP_ICONST;
2744                                 ins->inst_c0 = 0;
2745                                 break;
2746                         }
2747                         imm = mono_is_power_of_two (ins->inst_imm);
2748                         if (imm > 0) {
2749                                 ins->opcode = OP_SHL_IMM;
2750                                 ins->inst_imm = imm;
2751                                 break;
2752                         }
2753                         if (!ppc_is_imm16 (ins->inst_imm)) {
2754                                 NEW_INS (cfg, temp, OP_ICONST);
2755                                 temp->inst_c0 = ins->inst_imm;
2756                                 temp->dreg = mono_alloc_ireg (cfg);
2757                                 ins->sreg2 = temp->dreg;
2758                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2759                         }
2760                         break;
2761                 case OP_LOCALLOC_IMM:
2762                         NEW_INS (cfg, temp, OP_ICONST);
2763                         temp->inst_c0 = ins->inst_imm;
2764                         temp->dreg = mono_alloc_ireg (cfg);
2765                         ins->sreg1 = temp->dreg;
2766                         ins->opcode = OP_LOCALLOC;
2767                         break;
2768                 case OP_LOAD_MEMBASE:
2769                 case OP_LOADI4_MEMBASE:
2770                 CASE_PPC64 (OP_LOADI8_MEMBASE)
2771                 case OP_LOADU4_MEMBASE:
2772                 case OP_LOADI2_MEMBASE:
2773                 case OP_LOADU2_MEMBASE:
2774                 case OP_LOADI1_MEMBASE:
2775                 case OP_LOADU1_MEMBASE:
2776                 case OP_LOADR4_MEMBASE:
2777                 case OP_LOADR8_MEMBASE:
2778                 case OP_STORE_MEMBASE_REG:
2779                 CASE_PPC64 (OP_STOREI8_MEMBASE_REG)
2780                 case OP_STOREI4_MEMBASE_REG:
2781                 case OP_STOREI2_MEMBASE_REG:
2782                 case OP_STOREI1_MEMBASE_REG:
2783                 case OP_STORER4_MEMBASE_REG:
2784                 case OP_STORER8_MEMBASE_REG:
2785                         /* we can do two things: load the immed in a register
2786                          * and use an indexed load, or see if the immed can be
2787                          * represented as an ad_imm + a load with a smaller offset
2788                          * that fits. We just do the first for now, optimize later.
2789                          */
2790                         if (ppc_is_imm16 (ins->inst_offset))
2791                                 break;
2792                         NEW_INS (cfg, temp, OP_ICONST);
2793                         temp->inst_c0 = ins->inst_offset;
2794                         temp->dreg = mono_alloc_ireg (cfg);
2795                         ins->sreg2 = temp->dreg;
2796                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2797                         break;
2798                 case OP_STORE_MEMBASE_IMM:
2799                 case OP_STOREI1_MEMBASE_IMM:
2800                 case OP_STOREI2_MEMBASE_IMM:
2801                 case OP_STOREI4_MEMBASE_IMM:
2802                 CASE_PPC64 (OP_STOREI8_MEMBASE_IMM)
2803                         NEW_INS (cfg, temp, OP_ICONST);
2804                         temp->inst_c0 = ins->inst_imm;
2805                         temp->dreg = mono_alloc_ireg (cfg);
2806                         ins->sreg1 = temp->dreg;
2807                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2808                         last_ins = temp;
2809                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
2810                 case OP_R8CONST:
2811                 case OP_R4CONST:
2812                         if (cfg->compile_aot) {
2813                                 /* Keep these in the aot case */
2814                                 break;
2815                         }
2816                         NEW_INS (cfg, temp, OP_ICONST);
2817                         temp->inst_c0 = (gulong)ins->inst_p0;
2818                         temp->dreg = mono_alloc_ireg (cfg);
2819                         ins->inst_basereg = temp->dreg;
2820                         ins->inst_offset = 0;
2821                         ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2822                         last_ins = temp;
2823                         /* make it handle the possibly big ins->inst_offset
2824                          * later optimize to use lis + load_membase
2825                          */
2826                         goto loop_start;
2827                 }
2828                 last_ins = ins;
2829         }
2830         bb->last_ins = last_ins;
2831         bb->max_vreg = cfg->next_vreg;  
2832 }
2833
2834 static guchar*
2835 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2836 {
2837         long offset = cfg->arch.fp_conv_var_offset;
2838         long sub_offset;
2839         /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2840 #ifdef __mono_ppc64__
2841         if (size == 8) {
2842                 ppc_fctidz (code, ppc_f0, sreg);
2843                 sub_offset = 0;
2844         } else
2845 #endif
2846         {
2847                 ppc_fctiwz (code, ppc_f0, sreg);
2848                 sub_offset = 4;
2849         }
2850         if (ppc_is_imm16 (offset + sub_offset)) {
2851                 ppc_stfd (code, ppc_f0, offset, cfg->frame_reg);
2852                 if (size == 8)
2853                         ppc_ldr (code, dreg, offset + sub_offset, cfg->frame_reg);
2854                 else
2855                         ppc_lwz (code, dreg, offset + sub_offset, cfg->frame_reg);
2856         } else {
2857                 ppc_load (code, dreg, offset);
2858                 ppc_add (code, dreg, dreg, cfg->frame_reg);
2859                 ppc_stfd (code, ppc_f0, 0, dreg);
2860                 if (size == 8)
2861                         ppc_ldr (code, dreg, sub_offset, dreg);
2862                 else
2863                         ppc_lwz (code, dreg, sub_offset, dreg);
2864         }
2865         if (!is_signed) {
2866                 if (size == 1)
2867                         ppc_andid (code, dreg, dreg, 0xff);
2868                 else if (size == 2)
2869                         ppc_andid (code, dreg, dreg, 0xffff);
2870 #ifdef __mono_ppc64__
2871                 else if (size == 4)
2872                         ppc_clrldi (code, dreg, dreg, 32);
2873 #endif
2874         } else {
2875                 if (size == 1)
2876                         ppc_extsb (code, dreg, dreg);
2877                 else if (size == 2)
2878                         ppc_extsh (code, dreg, dreg);
2879 #ifdef __mono_ppc64__
2880                 else if (size == 4)
2881                         ppc_extsw (code, dreg, dreg);
2882 #endif
2883         }
2884         return code;
2885 }
2886
2887 typedef struct {
2888         guchar *code;
2889         const guchar *target;
2890         int absolute;
2891         int found;
2892 } PatchData;
2893
2894 #define is_call_imm(diff) ((glong)(diff) >= -33554432 && (glong)(diff) <= 33554431)
2895
2896 static int
2897 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2898 #ifdef __mono_ppc64__
2899         g_assert_not_reached ();
2900 #else
2901         PatchData *pdata = (PatchData*)user_data;
2902         guchar *code = data;
2903         guint32 *thunks = data;
2904         guint32 *endthunks = (guint32*)(code + bsize);
2905         guint32 load [2];
2906         guchar *templ;
2907         int count = 0;
2908         int difflow, diffhigh;
2909
2910         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2911         difflow = (char*)pdata->code - (char*)thunks;
2912         diffhigh = (char*)pdata->code - (char*)endthunks;
2913         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2914                 return 0;
2915
2916         templ = (guchar*)load;
2917         ppc_load_sequence (templ, ppc_r0, pdata->target);
2918
2919         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2920         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2921                 while (thunks < endthunks) {
2922                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2923                         if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2924                                 ppc_patch (pdata->code, (guchar*)thunks);
2925                                 pdata->found = 1;
2926                                 /*{
2927                                         static int num_thunks = 0;
2928                                         num_thunks++;
2929                                         if ((num_thunks % 20) == 0)
2930                                                 g_print ("num_thunks lookup: %d\n", num_thunks);
2931                                 }*/
2932                                 return 1;
2933                         } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2934                                 /* found a free slot instead: emit thunk */
2935                                 code = (guchar*)thunks;
2936                                 ppc_lis (code, ppc_r0, (gulong)(pdata->target) >> 16);
2937                                 ppc_ori (code, ppc_r0, ppc_r0, (gulong)(pdata->target) & 0xffff);
2938                                 ppc_mtctr (code, ppc_r0);
2939                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2940                                 mono_arch_flush_icache ((guchar*)thunks, 16);
2941
2942                                 ppc_patch (pdata->code, (guchar*)thunks);
2943                                 pdata->found = 1;
2944                                 /*{
2945                                         static int num_thunks = 0;
2946                                         num_thunks++;
2947                                         if ((num_thunks % 20) == 0)
2948                                                 g_print ("num_thunks: %d\n", num_thunks);
2949                                 }*/
2950                                 return 1;
2951                         }
2952                         /* skip 16 bytes, the size of the thunk */
2953                         thunks += 4;
2954                         count++;
2955                 }
2956                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2957         }
2958 #endif
2959         return 0;
2960 }
2961
2962 static void
2963 handle_thunk (int absolute, guchar *code, const guchar *target) {
2964         MonoDomain *domain = mono_domain_get ();
2965         PatchData pdata;
2966
2967         pdata.code = code;
2968         pdata.target = target;
2969         pdata.absolute = absolute;
2970         pdata.found = 0;
2971
2972         mono_domain_lock (domain);
2973         mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2974
2975         if (!pdata.found) {
2976                 /* this uses the first available slot */
2977                 pdata.found = 2;
2978                 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2979         }
2980         mono_domain_unlock (domain);
2981
2982         if (pdata.found != 1)
2983                 g_print ("thunk failed for %p from %p\n", target, code);
2984         g_assert (pdata.found == 1);
2985 }
2986
2987 static void
2988 patch_ins (guint8 *code, guint32 ins)
2989 {
2990         *(guint32*)code = ins;
2991         mono_arch_flush_icache (code, 4);
2992 }
2993
2994 void
2995 ppc_patch_full (guchar *code, const guchar *target, gboolean is_fd)
2996 {
2997         guint32 ins = *(guint32*)code;
2998         guint32 prim = ins >> 26;
2999         guint32 ovf;
3000
3001         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
3002         if (prim == 18) {
3003                 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
3004                 gint diff = target - code;
3005                 g_assert (!is_fd);
3006                 if (diff >= 0){
3007                         if (diff <= 33554431){
3008                                 ins = (18 << 26) | (diff) | (ins & 1);
3009                                 patch_ins (code, ins);
3010                                 return;
3011                         }
3012                 } else {
3013                         /* diff between 0 and -33554432 */
3014                         if (diff >= -33554432){
3015                                 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
3016                                 patch_ins (code, ins);
3017                                 return;
3018                         }
3019                 }
3020                 
3021                 if ((glong)target >= 0){
3022                         if ((glong)target <= 33554431){
3023                                 ins = (18 << 26) | ((gulong) target) | (ins & 1) | 2;
3024                                 patch_ins (code, ins);
3025                                 return;
3026                         }
3027                 } else {
3028                         if ((glong)target >= -33554432){
3029                                 ins = (18 << 26) | (((gulong)target) & ~0xfc000000) | (ins & 1) | 2;
3030                                 patch_ins (code, ins);
3031                                 return;
3032                         }
3033                 }
3034
3035                 handle_thunk (TRUE, code, target);
3036                 return;
3037
3038                 g_assert_not_reached ();
3039         }
3040         
3041         
3042         if (prim == 16) {
3043                 g_assert (!is_fd);
3044                 // absolute address
3045                 if (ins & 2) {
3046                         guint32 li = (gulong)target;
3047                         ins = (ins & 0xffff0000) | (ins & 3);
3048                         ovf  = li & 0xffff0000;
3049                         if (ovf != 0 && ovf != 0xffff0000)
3050                                 g_assert_not_reached ();
3051                         li &= 0xffff;
3052                         ins |= li;
3053                         // FIXME: assert the top bits of li are 0
3054                 } else {
3055                         gint diff = target - code;
3056                         ins = (ins & 0xffff0000) | (ins & 3);
3057                         ovf  = diff & 0xffff0000;
3058                         if (ovf != 0 && ovf != 0xffff0000)
3059                                 g_assert_not_reached ();
3060                         diff &= 0xffff;
3061                         ins |= diff;
3062                 }
3063                 patch_ins (code, ins);
3064                 return;
3065         }
3066
3067         if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3068 #ifdef __mono_ppc64__
3069                 guint32 *seq = (guint32*)code;
3070                 guint32 *branch_ins;
3071
3072                 /* the trampoline code will try to patch the blrl, blr, bcctr */
3073                 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3074                         branch_ins = seq;
3075                         if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */
3076                                 code -= 32;
3077                         else
3078                                 code -= 24;
3079                 } else {
3080                         if (ppc_is_load_op (seq [5])
3081 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3082                             /* With function descs we need to do more careful
3083                                matches.  */
3084                             || ppc_opcode (seq [5]) == 31 /* ld || lwz || mr */
3085 #endif
3086                            )
3087                                 branch_ins = seq + 8;
3088                         else
3089                                 branch_ins = seq + 6;
3090                 }
3091
3092                 seq = (guint32*)code;
3093                 /* this is the lis/ori/sldi/oris/ori/(ld/ld|mr/nop)/mtlr/blrl sequence */
3094                 g_assert (mono_ppc_is_direct_call_sequence (branch_ins));
3095
3096                 if (ppc_is_load_op (seq [5])) {
3097                         g_assert (ppc_is_load_op (seq [6]));
3098
3099                         if (!is_fd) {
3100                                 guint8 *buf = (guint8*)&seq [5];
3101                                 ppc_mr (buf, PPC_CALL_REG, ppc_r12);
3102                                 ppc_nop (buf);
3103                         }
3104                 } else {
3105                         if (is_fd)
3106                                 target = mono_get_addr_from_ftnptr ((gpointer)target);
3107                 }
3108
3109                 /* FIXME: make this thread safe */
3110 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3111                 /* FIXME: we're assuming we're using r12 here */
3112                 ppc_load_ptr_sequence (code, ppc_r12, target);
3113 #else
3114                 ppc_load_ptr_sequence (code, PPC_CALL_REG, target);
3115 #endif
3116                 mono_arch_flush_icache ((guint8*)seq, 28);
3117 #else
3118                 guint32 *seq;
3119                 /* the trampoline code will try to patch the blrl, blr, bcctr */
3120                 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
3121                         code -= 12;
3122                 }
3123                 /* this is the lis/ori/mtlr/blrl sequence */
3124                 seq = (guint32*)code;
3125                 g_assert ((seq [0] >> 26) == 15);
3126                 g_assert ((seq [1] >> 26) == 24);
3127                 g_assert ((seq [2] >> 26) == 31);
3128                 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
3129                 /* FIXME: make this thread safe */
3130                 ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16);
3131                 ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff);
3132                 mono_arch_flush_icache (code - 8, 8);
3133 #endif
3134         } else {
3135                 g_assert_not_reached ();
3136         }
3137 //      g_print ("patched with 0x%08x\n", ins);
3138 }
3139
3140 void
3141 ppc_patch (guchar *code, const guchar *target)
3142 {
3143         ppc_patch_full (code, target, FALSE);
3144 }
3145
3146 void
3147 mono_ppc_patch (guchar *code, const guchar *target)
3148 {
3149         ppc_patch (code, target);
3150 }
3151
3152 static guint8*
3153 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
3154 {
3155         switch (ins->opcode) {
3156         case OP_FCALL:
3157         case OP_FCALL_REG:
3158         case OP_FCALL_MEMBASE:
3159                 if (ins->dreg != ppc_f1)
3160                         ppc_fmr (code, ins->dreg, ppc_f1);
3161                 break;
3162         }
3163
3164         return code;
3165 }
3166
3167 static int
3168 ins_native_length (MonoCompile *cfg, MonoInst *ins)
3169 {
3170         return ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3171 }
3172
3173 static guint8*
3174 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3175 {
3176         long size = cfg->param_area;
3177
3178         size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3179         size &= -MONO_ARCH_FRAME_ALIGNMENT;
3180
3181         if (!size)
3182                 return code;
3183
3184         ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3185         if (ppc_is_imm16 (-size)) {
3186                 ppc_stptr_update (code, ppc_r0, -size, ppc_sp);
3187         } else {
3188                 ppc_load (code, ppc_r12, -size);
3189                 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3190         }
3191
3192         return code;
3193 }
3194
3195 static guint8*
3196 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3197 {
3198         long size = cfg->param_area;
3199
3200         size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3201         size &= -MONO_ARCH_FRAME_ALIGNMENT;
3202
3203         if (!size)
3204                 return code;
3205
3206         ppc_ldptr (code, ppc_r0, 0, ppc_sp);
3207         if (ppc_is_imm16 (size)) {
3208                 ppc_stptr_update (code, ppc_r0, size, ppc_sp);
3209         } else {
3210                 ppc_load (code, ppc_r12, size);
3211                 ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
3212         }
3213
3214         return code;
3215 }
3216
3217 #define MASK_SHIFT_IMM(i)       ((i) & MONO_PPC_32_64_CASE (0x1f, 0x3f))
3218
3219 #ifndef DISABLE_JIT
3220 void
3221 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3222 {
3223         MonoInst *ins, *next;
3224         MonoCallInst *call;
3225         guint offset;
3226         guint8 *code = cfg->native_code + cfg->code_len;
3227         MonoInst *last_ins = NULL;
3228         guint last_offset = 0;
3229         int max_len, cpos;
3230         int L;
3231
3232         /* we don't align basic blocks of loops on ppc */
3233
3234         if (cfg->verbose_level > 2)
3235                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3236
3237         cpos = bb->max_offset;
3238
3239         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3240                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3241                 //g_assert (!mono_compile_aot);
3242                 //cpos += 6;
3243                 //if (bb->cil_code)
3244                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3245                 /* this is not thread save, but good enough */
3246                 /* fixme: howto handle overflows? */
3247                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
3248         }
3249
3250         MONO_BB_FOR_EACH_INS (bb, ins) {
3251                 offset = code - cfg->native_code;
3252
3253                 max_len = ins_native_length (cfg, ins);
3254
3255                 if (offset > (cfg->code_size - max_len - 16)) {
3256                         cfg->code_size *= 2;
3257                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3258                         code = cfg->native_code + offset;
3259                 }
3260         //      if (ins->cil_code)
3261         //              g_print ("cil code\n");
3262                 mono_debug_record_line_number (cfg, ins, offset);
3263
3264                 switch (normalize_opcode (ins->opcode)) {
3265                 case OP_RELAXED_NOP:
3266                 case OP_NOP:
3267                 case OP_DUMMY_USE:
3268                 case OP_DUMMY_STORE:
3269                 case OP_NOT_REACHED:
3270                 case OP_NOT_NULL:
3271                         break;
3272                 case OP_IL_SEQ_POINT:
3273                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3274                         break;
3275                 case OP_SEQ_POINT: {
3276                         int i;
3277
3278                         if (cfg->compile_aot)
3279                                 NOT_IMPLEMENTED;
3280
3281                         /* 
3282                          * Read from the single stepping trigger page. This will cause a
3283                          * SIGSEGV when single stepping is enabled.
3284                          * We do this _before_ the breakpoint, so single stepping after
3285                          * a breakpoint is hit will step to the next IL offset.
3286                          */
3287                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3288                                 ppc_load (code, ppc_r12, (gsize)ss_trigger_page);
3289                                 ppc_ldptr (code, ppc_r12, 0, ppc_r12);
3290                         }
3291
3292                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3293
3294                         /* 
3295                          * A placeholder for a possible breakpoint inserted by
3296                          * mono_arch_set_breakpoint ().
3297                          */
3298                         for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
3299                                 ppc_nop (code);
3300                         break;
3301                 }
3302                 case OP_TLS_GET:
3303                         emit_tls_access (code, ins->dreg, ins->inst_offset);
3304                         break;
3305                 case OP_BIGMUL:
3306                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3307                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3308                         ppc_mr (code, ppc_r4, ppc_r0);
3309                         break;
3310                 case OP_BIGMUL_UN:
3311                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
3312                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3313                         ppc_mr (code, ppc_r4, ppc_r0);
3314                         break;
3315                 case OP_MEMORY_BARRIER:
3316                         ppc_sync (code);
3317                         break;
3318                 case OP_STOREI1_MEMBASE_REG:
3319                         if (ppc_is_imm16 (ins->inst_offset)) {
3320                                 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3321                         } else {
3322                                 if (ppc_is_imm32 (ins->inst_offset)) {
3323                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3324                                         ppc_stb (code, ins->sreg1, ins->inst_offset, ppc_r11);
3325                                 } else {
3326                                         ppc_load (code, ppc_r0, ins->inst_offset);
3327                                         ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3328                                 }
3329                         }
3330                         break;
3331                 case OP_STOREI2_MEMBASE_REG:
3332                         if (ppc_is_imm16 (ins->inst_offset)) {
3333                                 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3334                         } else {
3335                                 if (ppc_is_imm32 (ins->inst_offset)) {
3336                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3337                                         ppc_sth (code, ins->sreg1, ins->inst_offset, ppc_r11);
3338                                 } else {
3339                                         ppc_load (code, ppc_r0, ins->inst_offset);
3340                                         ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3341                                 }
3342                         }
3343                         break;
3344                 case OP_STORE_MEMBASE_REG:
3345                         if (ppc_is_imm16 (ins->inst_offset)) {
3346                                 ppc_stptr (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3347                         } else {
3348                                 if (ppc_is_imm32 (ins->inst_offset)) {
3349                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
3350                                         ppc_stptr (code, ins->sreg1, ins->inst_offset, ppc_r11);
3351                                 } else {
3352                                         ppc_load (code, ppc_r0, ins->inst_offset);
3353                                         ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3354                                 }
3355                         }
3356                         break;
3357 #ifdef __mono_ilp32__
3358                 case OP_STOREI8_MEMBASE_REG:
3359                         if (ppc_is_imm16 (ins->inst_offset)) {
3360                                 ppc_str (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3361                         } else {
3362                                 ppc_load (code, ppc_r0, ins->inst_offset);
3363                                 ppc_str_indexed (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3364                         }
3365                         break;
3366 #endif
3367                 case OP_STOREI1_MEMINDEX:
3368                         ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3369                         break;
3370                 case OP_STOREI2_MEMINDEX:
3371                         ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3372                         break;
3373                 case OP_STORE_MEMINDEX:
3374                         ppc_stptr_indexed (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3375                         break;
3376                 case OP_LOADU4_MEM:
3377                         g_assert_not_reached ();
3378                         break;
3379                 case OP_LOAD_MEMBASE:
3380                         if (ppc_is_imm16 (ins->inst_offset)) {
3381                                 ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3382                         } else {
3383                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3384                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3385                                         ppc_ldptr (code, ins->dreg, ins->inst_offset, ins->dreg);
3386                                 } else {
3387                                         ppc_load (code, ppc_r0, ins->inst_offset);
3388                                         ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3389                                 }
3390                         }
3391                         break;
3392                 case OP_LOADI4_MEMBASE:
3393 #ifdef __mono_ppc64__
3394                         if (ppc_is_imm16 (ins->inst_offset)) {
3395                                 ppc_lwa (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3396                         } else {
3397                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3398                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3399                                         ppc_lwa (code, ins->dreg, ins->inst_offset, ins->dreg);
3400                                 } else {
3401                                         ppc_load (code, ppc_r0, ins->inst_offset);
3402                                         ppc_lwax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3403                                 }
3404                         }
3405                         break;
3406 #endif
3407                 case OP_LOADU4_MEMBASE:
3408                         if (ppc_is_imm16 (ins->inst_offset)) {
3409                                 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3410                         } else {
3411                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3412                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3413                                         ppc_lwz (code, ins->dreg, ins->inst_offset, ins->dreg);
3414                                 } else {
3415                                         ppc_load (code, ppc_r0, ins->inst_offset);
3416                                         ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3417                                 }
3418                         }
3419                         break;
3420                 case OP_LOADI1_MEMBASE:
3421                 case OP_LOADU1_MEMBASE:
3422                         if (ppc_is_imm16 (ins->inst_offset)) {
3423                                 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3424                         } else {
3425                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3426                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3427                                         ppc_lbz (code, ins->dreg, ins->inst_offset, ins->dreg);
3428                                 } else {
3429                                         ppc_load (code, ppc_r0, ins->inst_offset);
3430                                         ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3431                                 }
3432                         }
3433                         if (ins->opcode == OP_LOADI1_MEMBASE)
3434                                 ppc_extsb (code, ins->dreg, ins->dreg);
3435                         break;
3436                 case OP_LOADU2_MEMBASE:
3437                         if (ppc_is_imm16 (ins->inst_offset)) {
3438                                 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3439                         } else {
3440                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3441                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3442                                         ppc_lhz (code, ins->dreg, ins->inst_offset, ins->dreg);
3443                                 } else {
3444                                         ppc_load (code, ppc_r0, ins->inst_offset);
3445                                         ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
3446                                 }
3447                         }
3448                         break;
3449                 case OP_LOADI2_MEMBASE:
3450                         if (ppc_is_imm16 (ins->inst_offset)) {
3451                                 ppc_lha (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3452                         } else {
3453                                 if (ppc_is_imm32 (ins->inst_offset) && (ins->dreg > 0)) {
3454                                         ppc_addis (code, ins->dreg, ins->inst_basereg, ppc_ha(ins->inst_offset));
3455                                         ppc_lha (code, ins->dreg, ins->inst_offset, ins->dreg);
3456                                 } else {
3457                                         ppc_load (code, ppc_r0, ins->inst_offset);
3458                                         ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
3459                                 }
3460                         }
3461                         break;
3462 #ifdef __mono_ilp32__
3463                 case OP_LOADI8_MEMBASE:
3464                         if (ppc_is_imm16 (ins->inst_offset)) {
3465                                 ppc_ldr (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3466                         } else {
3467                                 ppc_load (code, ppc_r0, ins->inst_offset);
3468                                 ppc_ldr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3469                         }
3470                         break;
3471 #endif
3472                 case OP_LOAD_MEMINDEX:
3473                         ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3474                         break;
3475                 case OP_LOADI4_MEMINDEX:
3476 #ifdef __mono_ppc64__
3477                         ppc_lwax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3478                         break;
3479 #endif
3480                 case OP_LOADU4_MEMINDEX:
3481                         ppc_lwzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3482                         break;
3483                 case OP_LOADU2_MEMINDEX:
3484                         ppc_lhzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3485                         break;
3486                 case OP_LOADI2_MEMINDEX:
3487                         ppc_lhax (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3488                         break;
3489                 case OP_LOADU1_MEMINDEX:
3490                         ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3491                         break;
3492                 case OP_LOADI1_MEMINDEX:
3493                         ppc_lbzx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3494                         ppc_extsb (code, ins->dreg, ins->dreg);
3495                         break;
3496                 case OP_ICONV_TO_I1:
3497                 CASE_PPC64 (OP_LCONV_TO_I1)
3498                         ppc_extsb (code, ins->dreg, ins->sreg1);
3499                         break;
3500                 case OP_ICONV_TO_I2:
3501                 CASE_PPC64 (OP_LCONV_TO_I2)
3502                         ppc_extsh (code, ins->dreg, ins->sreg1);
3503                         break;
3504                 case OP_ICONV_TO_U1:
3505                 CASE_PPC64 (OP_LCONV_TO_U1)
3506                         ppc_clrlwi (code, ins->dreg, ins->sreg1, 24);
3507                         break;
3508                 case OP_ICONV_TO_U2:
3509                 CASE_PPC64 (OP_LCONV_TO_U2)
3510                         ppc_clrlwi (code, ins->dreg, ins->sreg1, 16);
3511                         break;
3512                 case OP_COMPARE:
3513                 case OP_ICOMPARE:
3514                 CASE_PPC64 (OP_LCOMPARE)
3515                         L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE) ? 0 : 1;
3516                         next = ins->next;
3517                         if (next && compare_opcode_is_unsigned (next->opcode))
3518                                 ppc_cmpl (code, 0, L, ins->sreg1, ins->sreg2);
3519                         else
3520                                 ppc_cmp (code, 0, L, ins->sreg1, ins->sreg2);
3521                         break;
3522                 case OP_COMPARE_IMM:
3523                 case OP_ICOMPARE_IMM:
3524                 CASE_PPC64 (OP_LCOMPARE_IMM)
3525                         L = (sizeof (mgreg_t) == 4 || ins->opcode == OP_ICOMPARE_IMM) ? 0 : 1;
3526                         next = ins->next;
3527                         if (next && compare_opcode_is_unsigned (next->opcode)) {
3528                                 if (ppc_is_uimm16 (ins->inst_imm)) {
3529                                         ppc_cmpli (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3530                                 } else {
3531                                         g_assert_not_reached ();
3532                                 }
3533                         } else {
3534                                 if (ppc_is_imm16 (ins->inst_imm)) {
3535                                         ppc_cmpi (code, 0, L, ins->sreg1, (ins->inst_imm & 0xffff));
3536                                 } else {
3537                                         g_assert_not_reached ();
3538                                 }
3539                         }
3540                         break;
3541                 case OP_BREAK:
3542                         /*
3543                          * gdb does not like encountering a trap in the debugged code. So 
3544                          * instead of emitting a trap, we emit a call a C function and place a 
3545                          * breakpoint there.
3546                          */
3547                         //ppc_break (code);
3548                         ppc_mr (code, ppc_r3, ins->sreg1);
3549                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3550                                              (gpointer)"mono_break");
3551                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
3552                                 ppc_load_func (code, PPC_CALL_REG, 0);
3553                                 ppc_mtlr (code, PPC_CALL_REG);
3554                                 ppc_blrl (code);
3555                         } else {
3556                                 ppc_bl (code, 0);
3557                         }
3558                         break;
3559                 case OP_ADDCC:
3560                 case OP_IADDCC:
3561                         ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3562                         break;
3563                 case OP_IADD:
3564                 CASE_PPC64 (OP_LADD)
3565                         ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
3566                         break;
3567                 case OP_ADC:
3568                 case OP_IADC:
3569                         ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
3570                         break;
3571                 case OP_ADDCC_IMM:
3572                         if (ppc_is_imm16 (ins->inst_imm)) {
3573                                 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3574                         } else {
3575                                 g_assert_not_reached ();
3576                         }
3577                         break;
3578                 case OP_ADD_IMM:
3579                 case OP_IADD_IMM:
3580                 CASE_PPC64 (OP_LADD_IMM)
3581                         if (ppc_is_imm16 (ins->inst_imm)) {
3582                                 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3583                         } else {
3584                                 g_assert_not_reached ();
3585                         }
3586                         break;
3587                 case OP_IADD_OVF:
3588                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3589                          */
3590                         ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
3591                         ppc_mfspr (code, ppc_r0, ppc_xer);
3592                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3593                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3594                         break;
3595                 case OP_IADD_OVF_UN:
3596                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3597                          */
3598                         ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
3599                         ppc_mfspr (code, ppc_r0, ppc_xer);
3600                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3601                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3602                         break;
3603                 case OP_ISUB_OVF:
3604                 CASE_PPC64 (OP_LSUB_OVF)
3605                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3606                          */
3607                         ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
3608                         ppc_mfspr (code, ppc_r0, ppc_xer);
3609                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3610                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3611                         break;
3612                 case OP_ISUB_OVF_UN:
3613                 CASE_PPC64 (OP_LSUB_OVF_UN)
3614                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3615                          */
3616                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3617                         ppc_mfspr (code, ppc_r0, ppc_xer);
3618                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3619                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3620                         break;
3621                 case OP_ADD_OVF_CARRY:
3622                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3623                          */
3624                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3625                         ppc_mfspr (code, ppc_r0, ppc_xer);
3626                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3627                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3628                         break;
3629                 case OP_ADD_OVF_UN_CARRY:
3630                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3631                          */
3632                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3633                         ppc_mfspr (code, ppc_r0, ppc_xer);
3634                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3635                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3636                         break;
3637                 case OP_SUB_OVF_CARRY:
3638                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3639                          */
3640                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3641                         ppc_mfspr (code, ppc_r0, ppc_xer);
3642                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3643                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3644                         break;
3645                 case OP_SUB_OVF_UN_CARRY:
3646                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3647                          */
3648                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3649                         ppc_mfspr (code, ppc_r0, ppc_xer);
3650                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3651                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3652                         break;
3653                 case OP_SUBCC:
3654                 case OP_ISUBCC:
3655                         ppc_subfco (code, ins->dreg, ins->sreg2, ins->sreg1);
3656                         break;
3657                 case OP_ISUB:
3658                 CASE_PPC64 (OP_LSUB)
3659                         ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3660                         break;
3661                 case OP_SBB:
3662                 case OP_ISBB:
3663                         ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3664                         break;
3665                 case OP_SUB_IMM:
3666                 case OP_ISUB_IMM:
3667                 CASE_PPC64 (OP_LSUB_IMM)
3668                         // we add the negated value
3669                         if (ppc_is_imm16 (-ins->inst_imm))
3670                                 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3671                         else {
3672                                 g_assert_not_reached ();
3673                         }
3674                         break;
3675                 case OP_PPC_SUBFIC:
3676                         g_assert (ppc_is_imm16 (ins->inst_imm));
3677                         ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3678                         break;
3679                 case OP_PPC_SUBFZE:
3680                         ppc_subfze (code, ins->dreg, ins->sreg1);
3681                         break;
3682                 case OP_IAND:
3683                 CASE_PPC64 (OP_LAND)
3684                         /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3685                         ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3686                         break;
3687                 case OP_AND_IMM:
3688                 case OP_IAND_IMM:
3689                 CASE_PPC64 (OP_LAND_IMM)
3690                         if (!(ins->inst_imm & 0xffff0000)) {
3691                                 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3692                         } else if (!(ins->inst_imm & 0xffff)) {
3693                                 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3694                         } else {
3695                                 g_assert_not_reached ();
3696                         }
3697                         break;
3698                 case OP_IDIV:
3699                 CASE_PPC64 (OP_LDIV) {
3700                         guint8 *divisor_is_m1;
3701                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3702                          */
3703                         ppc_compare_reg_imm (code, 0, ins->sreg2, -1);
3704                         divisor_is_m1 = code;
3705                         ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3706                         ppc_lis (code, ppc_r0, 0x8000);
3707 #ifdef __mono_ppc64__
3708                         if (ins->opcode == OP_LDIV)
3709                                 ppc_sldi (code, ppc_r0, ppc_r0, 32);
3710 #endif
3711                         ppc_compare (code, 0, ins->sreg1, ppc_r0);
3712                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3713                         ppc_patch (divisor_is_m1, code);
3714                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3715                          */
3716                         if (ins->opcode == OP_IDIV)
3717                                 ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3718 #ifdef __mono_ppc64__
3719                         else
3720                                 ppc_divdod (code, ins->dreg, ins->sreg1, ins->sreg2);
3721 #endif
3722                         ppc_mfspr (code, ppc_r0, ppc_xer);
3723                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3724                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3725                         break;
3726                 }
3727                 case OP_IDIV_UN:
3728                 CASE_PPC64 (OP_LDIV_UN)
3729                         if (ins->opcode == OP_IDIV_UN)
3730                                 ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3731 #ifdef __mono_ppc64__
3732                         else
3733                                 ppc_divduod (code, ins->dreg, ins->sreg1, ins->sreg2);
3734 #endif
3735                         ppc_mfspr (code, ppc_r0, ppc_xer);
3736                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3737                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3738                         break;
3739                 case OP_DIV_IMM:
3740                 case OP_IREM:
3741                 case OP_IREM_UN:
3742                 case OP_REM_IMM:
3743                         g_assert_not_reached ();
3744                 case OP_IOR:
3745                 CASE_PPC64 (OP_LOR)
3746                         ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3747                         break;
3748                 case OP_OR_IMM:
3749                 case OP_IOR_IMM:
3750                 CASE_PPC64 (OP_LOR_IMM)
3751                         if (!(ins->inst_imm & 0xffff0000)) {
3752                                 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3753                         } else if (!(ins->inst_imm & 0xffff)) {
3754                                 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3755                         } else {
3756                                 g_assert_not_reached ();
3757                         }
3758                         break;
3759                 case OP_IXOR:
3760                 CASE_PPC64 (OP_LXOR)
3761                         ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3762                         break;
3763                 case OP_IXOR_IMM:
3764                 case OP_XOR_IMM:
3765                 CASE_PPC64 (OP_LXOR_IMM)
3766                         if (!(ins->inst_imm & 0xffff0000)) {
3767                                 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3768                         } else if (!(ins->inst_imm & 0xffff)) {
3769                                 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3770                         } else {
3771                                 g_assert_not_reached ();
3772                         }
3773                         break;
3774                 case OP_ISHL:
3775                 CASE_PPC64 (OP_LSHL)
3776                         ppc_shift_left (code, ins->dreg, ins->sreg1, ins->sreg2);
3777                         break;
3778                 case OP_SHL_IMM:
3779                 case OP_ISHL_IMM:
3780                 CASE_PPC64 (OP_LSHL_IMM)
3781                         ppc_shift_left_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3782                         break;
3783                 case OP_ISHR:
3784                         ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3785                         break;
3786                 case OP_SHR_IMM:
3787                         ppc_shift_right_arith_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3788                         break;
3789                 case OP_SHR_UN_IMM:
3790                         if (MASK_SHIFT_IMM (ins->inst_imm))
3791                                 ppc_shift_right_imm (code, ins->dreg, ins->sreg1, MASK_SHIFT_IMM (ins->inst_imm));
3792                         else
3793                                 ppc_mr (code, ins->dreg, ins->sreg1);
3794                         break;
3795                 case OP_ISHR_UN:
3796                         ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3797                         break;
3798                 case OP_INOT:
3799                 CASE_PPC64 (OP_LNOT)
3800                         ppc_not (code, ins->dreg, ins->sreg1);
3801                         break;
3802                 case OP_INEG:
3803                 CASE_PPC64 (OP_LNEG)
3804                         ppc_neg (code, ins->dreg, ins->sreg1);
3805                         break;
3806                 case OP_IMUL:
3807                 CASE_PPC64 (OP_LMUL)
3808                         ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3809                         break;
3810                 case OP_IMUL_IMM:
3811                 case OP_MUL_IMM:
3812                 CASE_PPC64 (OP_LMUL_IMM)
3813                         if (ppc_is_imm16 (ins->inst_imm)) {
3814                             ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3815                         } else {
3816                             g_assert_not_reached ();
3817                         }
3818                         break;
3819                 case OP_IMUL_OVF:
3820                 CASE_PPC64 (OP_LMUL_OVF)
3821                         /* we annot use mcrxr, since it's not implemented on some processors 
3822                          * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3823                          */
3824                         if (ins->opcode == OP_IMUL_OVF)
3825                                 ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3826 #ifdef __mono_ppc64__
3827                         else
3828                                 ppc_mulldo (code, ins->dreg, ins->sreg1, ins->sreg2);
3829 #endif
3830                         ppc_mfspr (code, ppc_r0, ppc_xer);
3831                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3832                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3833                         break;
3834                 case OP_IMUL_OVF_UN:
3835                 CASE_PPC64 (OP_LMUL_OVF_UN)
3836                         /* we first multiply to get the high word and compare to 0
3837                          * to set the flags, then the result is discarded and then 
3838                          * we multiply to get the lower * bits result
3839                          */
3840                         if (ins->opcode == OP_IMUL_OVF_UN)
3841                                 ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3842 #ifdef __mono_ppc64__
3843                         else
3844                                 ppc_mulhdu (code, ppc_r0, ins->sreg1, ins->sreg2);
3845 #endif
3846                         ppc_cmpi (code, 0, 0, ppc_r0, 0);
3847                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3848                         ppc_multiply (code, ins->dreg, ins->sreg1, ins->sreg2);
3849                         break;
3850                 case OP_ICONST:
3851                         ppc_load (code, ins->dreg, ins->inst_c0);
3852                         break;
3853                 case OP_I8CONST: {
3854                         ppc_load (code, ins->dreg, ins->inst_l);
3855                         break;
3856                 }
3857                 case OP_LOAD_GOTADDR:
3858                         /* The PLT implementation depends on this */
3859                         g_assert (ins->dreg == ppc_r30);
3860
3861                         code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3862                         break;
3863                 case OP_GOT_ENTRY:
3864                         // FIXME: Fix max instruction length
3865                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3866                         /* arch_emit_got_access () patches this */
3867                         ppc_load32 (code, ppc_r0, 0);
3868                         ppc_ldptr_indexed (code, ins->dreg, ins->inst_basereg, ppc_r0);
3869                         break;
3870                 case OP_AOTCONST:
3871                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3872                         ppc_load_sequence (code, ins->dreg, 0);
3873                         break;
3874                 CASE_PPC32 (OP_ICONV_TO_I4)
3875                 CASE_PPC32 (OP_ICONV_TO_U4)
3876                 case OP_MOVE:
3877                         if (ins->dreg != ins->sreg1)
3878                                 ppc_mr (code, ins->dreg, ins->sreg1);
3879                         break;
3880                 case OP_SETLRET: {
3881                         int saved = ins->sreg1;
3882                         if (ins->sreg1 == ppc_r3) {
3883                                 ppc_mr (code, ppc_r0, ins->sreg1);
3884                                 saved = ppc_r0;
3885                         }
3886                         if (ins->sreg2 != ppc_r3)
3887                                 ppc_mr (code, ppc_r3, ins->sreg2);
3888                         if (saved != ppc_r4)
3889                                 ppc_mr (code, ppc_r4, saved);
3890                         break;
3891                 }
3892                 case OP_FMOVE:
3893                         if (ins->dreg != ins->sreg1)
3894                                 ppc_fmr (code, ins->dreg, ins->sreg1);
3895                         break;
3896                 case OP_MOVE_F_TO_I4:
3897                         ppc_stfs (code, ins->sreg1, -4, ppc_r1);
3898                         ppc_ldptr (code, ins->dreg, -4, ppc_r1);
3899                         break;
3900                 case OP_MOVE_I4_TO_F:
3901                         ppc_stw (code, ins->sreg1, -4, ppc_r1);
3902                         ppc_lfs (code, ins->dreg, -4, ppc_r1);
3903                         break;
3904                 case OP_FCONV_TO_R4:
3905                         ppc_frsp (code, ins->dreg, ins->sreg1);
3906                         break;
3907                 case OP_TAILCALL: {
3908                         int i, pos;
3909                         MonoCallInst *call = (MonoCallInst*)ins;
3910
3911                         /*
3912                          * Keep in sync with mono_arch_emit_epilog
3913                          */
3914                         g_assert (!cfg->method->save_lmf);
3915                         /*
3916                          * Note: we can use ppc_r12 here because it is dead anyway:
3917                          * we're leaving the method.
3918                          */
3919                         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3920                                 long ret_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
3921                                 if (ppc_is_imm16 (ret_offset)) {
3922                                         ppc_ldptr (code, ppc_r0, ret_offset, cfg->frame_reg);
3923                                 } else {
3924                                         ppc_load (code, ppc_r12, ret_offset);
3925                                         ppc_ldptr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
3926                                 }
3927                                 ppc_mtlr (code, ppc_r0);
3928                         }
3929
3930                         if (ppc_is_imm16 (cfg->stack_usage)) {
3931                                 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3932                         } else {
3933                                 /* cfg->stack_usage is an int, so we can use
3934                                  * an addis/addi sequence here even in 64-bit.  */
3935                                 ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3936                                 ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3937                         }
3938                         if (!cfg->method->save_lmf) {
3939                                 pos = 0;
3940                                 for (i = 31; i >= 13; --i) {
3941                                         if (cfg->used_int_regs & (1 << i)) {
3942                                                 pos += sizeof (gpointer);
3943                                                 ppc_ldptr (code, i, -pos, ppc_r12);
3944                                         }
3945                                 }
3946                         } else {
3947                                 /* FIXME restore from MonoLMF: though this can't happen yet */
3948                         }
3949
3950                         /* Copy arguments on the stack to our argument area */
3951                         if (call->stack_usage) {
3952                                 code = emit_memcpy (code, call->stack_usage, ppc_r12, PPC_STACK_PARAM_OFFSET, ppc_sp, PPC_STACK_PARAM_OFFSET);
3953                                 /* r12 was clobbered */
3954                                 g_assert (cfg->frame_reg == ppc_sp);
3955                                 if (ppc_is_imm16 (cfg->stack_usage)) {
3956                                         ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage);
3957                                 } else {
3958                                         /* cfg->stack_usage is an int, so we can use
3959                                          * an addis/addi sequence here even in 64-bit.  */
3960                                         ppc_addis (code, ppc_r12, cfg->frame_reg, ppc_ha(cfg->stack_usage));
3961                                         ppc_addi (code, ppc_r12, ppc_r12, cfg->stack_usage);
3962                                 }
3963                         }
3964
3965                         ppc_mr (code, ppc_sp, ppc_r12);
3966                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3967                         if (cfg->compile_aot) {
3968                                 /* arch_emit_got_access () patches this */
3969                                 ppc_load32 (code, ppc_r0, 0);
3970 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3971                                 ppc_ldptr_indexed (code, ppc_r12, ppc_r30, ppc_r0);
3972                                 ppc_ldptr (code, ppc_r0, 0, ppc_r12);
3973 #else
3974                                 ppc_ldptr_indexed (code, ppc_r0, ppc_r30, ppc_r0);
3975 #endif
3976                                 ppc_mtctr (code, ppc_r0);
3977                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3978                         } else {
3979                                 ppc_b (code, 0);
3980                         }
3981                         break;
3982                 }
3983                 case OP_CHECK_THIS:
3984                         /* ensure ins->sreg1 is not NULL */
3985                         ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
3986                         break;
3987                 case OP_ARGLIST: {
3988                         long cookie_offset = cfg->sig_cookie + cfg->stack_usage;
3989                         if (ppc_is_imm16 (cookie_offset)) {
3990                                 ppc_addi (code, ppc_r0, cfg->frame_reg, cookie_offset);
3991                         } else {
3992                                 ppc_load (code, ppc_r0, cookie_offset);
3993                                 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3994                         }
3995                         ppc_stptr (code, ppc_r0, 0, ins->sreg1);
3996                         break;
3997                 }
3998                 case OP_FCALL:
3999                 case OP_LCALL:
4000                 case OP_VCALL:
4001                 case OP_VCALL2:
4002                 case OP_VOIDCALL:
4003                 case OP_CALL:
4004                         call = (MonoCallInst*)ins;
4005                         if (ins->flags & MONO_INST_HAS_METHOD)
4006                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
4007                         else
4008                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4009                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4010                                 ppc_load_func (code, PPC_CALL_REG, 0);
4011                                 ppc_mtlr (code, PPC_CALL_REG);
4012                                 ppc_blrl (code);
4013                         } else {
4014                                 ppc_bl (code, 0);
4015                         }
4016                         /* FIXME: this should be handled somewhere else in the new jit */
4017                         code = emit_move_return_value (cfg, ins, code);
4018                         break;
4019                 case OP_FCALL_REG:
4020                 case OP_LCALL_REG:
4021                 case OP_VCALL_REG:
4022                 case OP_VCALL2_REG:
4023                 case OP_VOIDCALL_REG:
4024                 case OP_CALL_REG:
4025 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4026                         ppc_ldptr (code, ppc_r0, 0, ins->sreg1);
4027                         /* FIXME: if we know that this is a method, we
4028                            can omit this load */
4029                         ppc_ldptr (code, ppc_r2, 8, ins->sreg1);
4030                         ppc_mtlr (code, ppc_r0);
4031 #else
4032 #if (_CALL_ELF == 2)
4033                         if (ins->flags & MONO_INST_HAS_METHOD) {
4034                           // Not a global entry point
4035                         } else {
4036                                  // Need to set up r12 with function entry address for global entry point
4037                                  if (ppc_r12 != ins->sreg1) {
4038                                          ppc_mr(code,ppc_r12,ins->sreg1);
4039                                  }
4040                         }
4041 #endif
4042                         ppc_mtlr (code, ins->sreg1);
4043 #endif
4044                         ppc_blrl (code);
4045                         /* FIXME: this should be handled somewhere else in the new jit */
4046                         code = emit_move_return_value (cfg, ins, code);
4047                         break;
4048                 case OP_FCALL_MEMBASE:
4049                 case OP_LCALL_MEMBASE:
4050                 case OP_VCALL_MEMBASE:
4051                 case OP_VCALL2_MEMBASE:
4052                 case OP_VOIDCALL_MEMBASE:
4053                 case OP_CALL_MEMBASE:
4054                         if (cfg->compile_aot && ins->sreg1 == ppc_r12) {
4055                                 /* The trampolines clobber this */
4056                                 ppc_mr (code, ppc_r29, ins->sreg1);
4057                                 ppc_ldptr (code, ppc_r0, ins->inst_offset, ppc_r29);
4058                         } else {
4059                                 ppc_ldptr (code, ppc_r0, ins->inst_offset, ins->sreg1);
4060                         }
4061                         ppc_mtlr (code, ppc_r0);
4062                         ppc_blrl (code);
4063                         /* FIXME: this should be handled somewhere else in the new jit */
4064                         code = emit_move_return_value (cfg, ins, code);
4065                         break;
4066                 case OP_LOCALLOC: {
4067                         guint8 * zero_loop_jump, * zero_loop_start;
4068                         /* keep alignment */
4069                         int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
4070                         int area_offset = alloca_waste;
4071                         area_offset &= ~31;
4072                         ppc_addi (code, ppc_r12, ins->sreg1, alloca_waste + 31);
4073                         /* FIXME: should be calculated from MONO_ARCH_FRAME_ALIGNMENT */
4074                         ppc_clear_right_imm (code, ppc_r12, ppc_r12, 4);
4075                         /* use ctr to store the number of words to 0 if needed */
4076                         if (ins->flags & MONO_INST_INIT) {
4077                                 /* we zero 4 bytes at a time:
4078                                  * we add 7 instead of 3 so that we set the counter to
4079                                  * at least 1, otherwise the bdnz instruction will make
4080                                  * it negative and iterate billions of times.
4081                                  */
4082                                 ppc_addi (code, ppc_r0, ins->sreg1, 7);
4083                                 ppc_shift_right_arith_imm (code, ppc_r0, ppc_r0, 2);
4084                                 ppc_mtctr (code, ppc_r0);
4085                         }
4086                         ppc_ldptr (code, ppc_r0, 0, ppc_sp);
4087                         ppc_neg (code, ppc_r12, ppc_r12);
4088                         ppc_stptr_update_indexed (code, ppc_r0, ppc_sp, ppc_r12);
4089
4090                         /* FIXME: make this loop work in 8 byte
4091                            increments on PPC64 */
4092                         if (ins->flags & MONO_INST_INIT) {
4093                                 /* adjust the dest reg by -4 so we can use stwu */
4094                                 /* we actually adjust -8 because we let the loop
4095                                  * run at least once
4096                                  */
4097                                 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
4098                                 ppc_li (code, ppc_r12, 0);
4099                                 zero_loop_start = code;
4100                                 ppc_stwu (code, ppc_r12, 4, ins->dreg);
4101                                 zero_loop_jump = code;
4102                                 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
4103                                 ppc_patch (zero_loop_jump, zero_loop_start);
4104                         }
4105                         ppc_addi (code, ins->dreg, ppc_sp, area_offset);
4106                         break;
4107                 }
4108                 case OP_THROW: {
4109                         //ppc_break (code);
4110                         ppc_mr (code, ppc_r3, ins->sreg1);
4111                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4112                                              (gpointer)"mono_arch_throw_exception");
4113                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4114                                 ppc_load_func (code, PPC_CALL_REG, 0);
4115                                 ppc_mtlr (code, PPC_CALL_REG);
4116                                 ppc_blrl (code);
4117                         } else {
4118                                 ppc_bl (code, 0);
4119                         }
4120                         break;
4121                 }
4122                 case OP_RETHROW: {
4123                         //ppc_break (code);
4124                         ppc_mr (code, ppc_r3, ins->sreg1);
4125                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4126                                              (gpointer)"mono_arch_rethrow_exception");
4127                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4128                                 ppc_load_func (code, PPC_CALL_REG, 0);
4129                                 ppc_mtlr (code, PPC_CALL_REG);
4130                                 ppc_blrl (code);
4131                         } else {
4132                                 ppc_bl (code, 0);
4133                         }
4134                         break;
4135                 }
4136                 case OP_START_HANDLER: {
4137                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4138                         g_assert (spvar->inst_basereg != ppc_sp);
4139                         code = emit_reserve_param_area (cfg, code);
4140                         ppc_mflr (code, ppc_r0);
4141                         if (ppc_is_imm16 (spvar->inst_offset)) {
4142                                 ppc_stptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4143                         } else {
4144                                 ppc_load (code, ppc_r12, spvar->inst_offset);
4145                                 ppc_stptr_indexed (code, ppc_r0, ppc_r12, spvar->inst_basereg);
4146                         }
4147                         break;
4148                 }
4149                 case OP_ENDFILTER: {
4150                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4151                         g_assert (spvar->inst_basereg != ppc_sp);
4152                         code = emit_unreserve_param_area (cfg, code);
4153                         if (ins->sreg1 != ppc_r3)
4154                                 ppc_mr (code, ppc_r3, ins->sreg1);
4155                         if (ppc_is_imm16 (spvar->inst_offset)) {
4156                                 ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4157                         } else {
4158                                 ppc_load (code, ppc_r12, spvar->inst_offset);
4159                                 ppc_ldptr_indexed (code, ppc_r0, spvar->inst_basereg, ppc_r12);
4160                         }
4161                         ppc_mtlr (code, ppc_r0);
4162                         ppc_blr (code);
4163                         break;
4164                 }
4165                 case OP_ENDFINALLY: {
4166                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4167                         g_assert (spvar->inst_basereg != ppc_sp);
4168                         code = emit_unreserve_param_area (cfg, code);
4169                         ppc_ldptr (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
4170                         ppc_mtlr (code, ppc_r0);
4171                         ppc_blr (code);
4172                         break;
4173                 }
4174                 case OP_CALL_HANDLER: 
4175                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4176                         ppc_bl (code, 0);
4177                         mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4178                         break;
4179                 case OP_LABEL:
4180                         ins->inst_c0 = code - cfg->native_code;
4181                         break;
4182                 case OP_BR:
4183                         /*if (ins->inst_target_bb->native_offset) {
4184                                 ppc_b (code, 0);
4185                                 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
4186                         } else*/ {
4187                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4188                                 ppc_b (code, 0);
4189                         }
4190                         break;
4191                 case OP_BR_REG:
4192                         ppc_mtctr (code, ins->sreg1);
4193                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4194                         break;
4195                 case OP_CEQ:
4196                 case OP_ICEQ:
4197                 CASE_PPC64 (OP_LCEQ)
4198                         ppc_li (code, ins->dreg, 0);
4199                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4200                         ppc_li (code, ins->dreg, 1);
4201                         break;
4202                 case OP_CLT:
4203                 case OP_CLT_UN:
4204                 case OP_ICLT:
4205                 case OP_ICLT_UN:
4206                 CASE_PPC64 (OP_LCLT)
4207                 CASE_PPC64 (OP_LCLT_UN)
4208                         ppc_li (code, ins->dreg, 1);
4209                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4210                         ppc_li (code, ins->dreg, 0);
4211                         break;
4212                 case OP_CGT:
4213                 case OP_CGT_UN:
4214                 case OP_ICGT:
4215                 case OP_ICGT_UN:
4216                 CASE_PPC64 (OP_LCGT)
4217                 CASE_PPC64 (OP_LCGT_UN)
4218                         ppc_li (code, ins->dreg, 1);
4219                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4220                         ppc_li (code, ins->dreg, 0);
4221                         break;
4222                 case OP_COND_EXC_EQ:
4223                 case OP_COND_EXC_NE_UN:
4224                 case OP_COND_EXC_LT:
4225                 case OP_COND_EXC_LT_UN:
4226                 case OP_COND_EXC_GT:
4227                 case OP_COND_EXC_GT_UN:
4228                 case OP_COND_EXC_GE:
4229                 case OP_COND_EXC_GE_UN:
4230                 case OP_COND_EXC_LE:
4231                 case OP_COND_EXC_LE_UN:
4232                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
4233                         break;
4234                 case OP_COND_EXC_IEQ:
4235                 case OP_COND_EXC_INE_UN:
4236                 case OP_COND_EXC_ILT:
4237                 case OP_COND_EXC_ILT_UN:
4238                 case OP_COND_EXC_IGT:
4239                 case OP_COND_EXC_IGT_UN:
4240                 case OP_COND_EXC_IGE:
4241                 case OP_COND_EXC_IGE_UN:
4242                 case OP_COND_EXC_ILE:
4243                 case OP_COND_EXC_ILE_UN:
4244                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
4245                         break;
4246                 case OP_IBEQ:
4247                 case OP_IBNE_UN:
4248                 case OP_IBLT:
4249                 case OP_IBLT_UN:
4250                 case OP_IBGT:
4251                 case OP_IBGT_UN:
4252                 case OP_IBGE:
4253                 case OP_IBGE_UN:
4254                 case OP_IBLE:
4255                 case OP_IBLE_UN:
4256                         EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
4257                         break;
4258
4259                 /* floating point opcodes */
4260                 case OP_R8CONST:
4261                         g_assert (cfg->compile_aot);
4262
4263                         /* FIXME: Optimize this */
4264                         ppc_bl (code, 1);
4265                         ppc_mflr (code, ppc_r12);
4266                         ppc_b (code, 3);
4267                         *(double*)code = *(double*)ins->inst_p0;
4268                         code += 8;
4269                         ppc_lfd (code, ins->dreg, 8, ppc_r12);
4270                         break;
4271                 case OP_R4CONST:
4272                         g_assert_not_reached ();
4273                         break;
4274                 case OP_STORER8_MEMBASE_REG:
4275                         if (ppc_is_imm16 (ins->inst_offset)) {
4276                                 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4277                         } else {
4278                                 if (ppc_is_imm32 (ins->inst_offset)) {
4279                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4280                                         ppc_stfd (code, ins->sreg1, ins->inst_offset, ppc_r11);
4281                                 } else {
4282                                         ppc_load (code, ppc_r0, ins->inst_offset);
4283                                         ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4284                                 }
4285                         }
4286                         break;
4287                 case OP_LOADR8_MEMBASE:
4288                         if (ppc_is_imm16 (ins->inst_offset)) {
4289                                 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4290                         } else {
4291                                 if (ppc_is_imm32 (ins->inst_offset)) {
4292                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4293                                         ppc_lfd (code, ins->dreg, ins->inst_offset, ppc_r11);
4294                                 } else {
4295                                         ppc_load (code, ppc_r0, ins->inst_offset);
4296                                         ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4297                                 }
4298                         }
4299                         break;
4300                 case OP_STORER4_MEMBASE_REG:
4301                         ppc_frsp (code, ins->sreg1, ins->sreg1);
4302                         if (ppc_is_imm16 (ins->inst_offset)) {
4303                                 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4304                         } else {
4305                                 if (ppc_is_imm32 (ins->inst_offset)) {
4306                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4307                                         ppc_stfs (code, ins->sreg1, ins->inst_offset, ppc_r11);
4308                                 } else {
4309                                         ppc_load (code, ppc_r0, ins->inst_offset);
4310                                         ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4311                                 }
4312                         }
4313                         break;
4314                 case OP_LOADR4_MEMBASE:
4315                         if (ppc_is_imm16 (ins->inst_offset)) {
4316                                 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
4317                         } else {
4318                                 if (ppc_is_imm32 (ins->inst_offset)) {
4319                                         ppc_addis (code, ppc_r11, ins->inst_destbasereg, ppc_ha(ins->inst_offset));
4320                                         ppc_lfs (code, ins->dreg, ins->inst_offset, ppc_r11);
4321                                 } else {
4322                                         ppc_load (code, ppc_r0, ins->inst_offset);
4323                                         ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
4324                                 }
4325                         }
4326                         break;
4327                 case OP_LOADR4_MEMINDEX:
4328                         ppc_lfsx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4329                         break;
4330                 case OP_LOADR8_MEMINDEX:
4331                         ppc_lfdx (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4332                         break;
4333                 case OP_STORER4_MEMINDEX:
4334                         ppc_frsp (code, ins->sreg1, ins->sreg1);
4335                         ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4336                         break;
4337                 case OP_STORER8_MEMINDEX:
4338                         ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4339                         break;
4340                 case CEE_CONV_R_UN:
4341                 case CEE_CONV_R4: /* FIXME: change precision */
4342                 case CEE_CONV_R8:
4343                         g_assert_not_reached ();
4344                 case OP_FCONV_TO_I1:
4345                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4346                         break;
4347                 case OP_FCONV_TO_U1:
4348                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4349                         break;
4350                 case OP_FCONV_TO_I2:
4351                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4352                         break;
4353                 case OP_FCONV_TO_U2:
4354                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4355                         break;
4356                 case OP_FCONV_TO_I4:
4357                 case OP_FCONV_TO_I:
4358                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4359                         break;
4360                 case OP_FCONV_TO_U4:
4361                 case OP_FCONV_TO_U:
4362                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4363                         break;
4364                 case OP_LCONV_TO_R_UN:
4365                         g_assert_not_reached ();
4366                         /* Implemented as helper calls */
4367                         break;
4368                 case OP_LCONV_TO_OVF_I4_2:
4369                 case OP_LCONV_TO_OVF_I: {
4370 #ifdef __mono_ppc64__
4371                         NOT_IMPLEMENTED;
4372 #else
4373                         guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
4374                         // Check if its negative
4375                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
4376                         negative_branch = code;
4377                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
4378                         // Its positive msword == 0
4379                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
4380                         msword_positive_branch = code;
4381                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
4382
4383                         ovf_ex_target = code;
4384                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
4385                         // Negative
4386                         ppc_patch (negative_branch, code);
4387                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
4388                         msword_negative_branch = code;
4389                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4390                         ppc_patch (msword_negative_branch, ovf_ex_target);
4391                         
4392                         ppc_patch (msword_positive_branch, code);
4393                         if (ins->dreg != ins->sreg1)
4394                                 ppc_mr (code, ins->dreg, ins->sreg1);
4395                         break;
4396 #endif
4397                 }
4398                 case OP_SQRT:
4399                         ppc_fsqrtd (code, ins->dreg, ins->sreg1);
4400                         break;
4401                 case OP_FADD:
4402                         ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
4403                         break;
4404                 case OP_FSUB:
4405                         ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
4406                         break;          
4407                 case OP_FMUL:
4408                         ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
4409                         break;          
4410                 case OP_FDIV:
4411                         ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
4412                         break;          
4413                 case OP_FNEG:
4414                         ppc_fneg (code, ins->dreg, ins->sreg1);
4415                         break;          
4416                 case OP_FREM:
4417                         /* emulated */
4418                         g_assert_not_reached ();
4419                         break;
4420                 case OP_FCOMPARE:
4421                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4422                         break;
4423                 case OP_FCEQ:
4424                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4425                         ppc_li (code, ins->dreg, 0);
4426                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
4427                         ppc_li (code, ins->dreg, 1);
4428                         break;
4429                 case OP_FCLT:
4430                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4431                         ppc_li (code, ins->dreg, 1);
4432                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4433                         ppc_li (code, ins->dreg, 0);
4434                         break;
4435                 case OP_FCLT_UN:
4436                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4437                         ppc_li (code, ins->dreg, 1);
4438                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4439                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
4440                         ppc_li (code, ins->dreg, 0);
4441                         break;
4442                 case OP_FCGT:
4443                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
4444                         ppc_li (code, ins->dreg, 1);
4445                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4446                         ppc_li (code, ins->dreg, 0);
4447                         break;
4448                 case OP_FCGT_UN:
4449                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
4450                         ppc_li (code, ins->dreg, 1);
4451                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
4452                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
4453                         ppc_li (code, ins->dreg, 0);
4454                         break;
4455                 case OP_FBEQ:
4456                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
4457                         break;
4458                 case OP_FBNE_UN:
4459                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
4460                         break;
4461                 case OP_FBLT:
4462                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4463                         EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
4464                         break;
4465                 case OP_FBLT_UN:
4466                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4467                         EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
4468                         break;
4469                 case OP_FBGT:
4470                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4471                         EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
4472                         break;
4473                 case OP_FBGT_UN:
4474                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
4475                         EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
4476                         break;
4477                 case OP_FBGE:
4478                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4479                         EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
4480                         break;
4481                 case OP_FBGE_UN:
4482                         EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
4483                         break;
4484                 case OP_FBLE:
4485                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
4486                         EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
4487                         break;
4488                 case OP_FBLE_UN:
4489                         EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
4490                         break;
4491                 case OP_CKFINITE:
4492                         g_assert_not_reached ();
4493                 case OP_CHECK_FINITE: {
4494                         ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
4495                         ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
4496                         ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
4497                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
4498                         break;
4499                 case OP_JUMP_TABLE:
4500                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4501 #ifdef __mono_ppc64__
4502                         ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
4503 #else
4504                         ppc_load_sequence (code, ins->dreg, (gulong)0x0f0f0f0fL);
4505 #endif
4506                         break;
4507                 }
4508
4509 #ifdef __mono_ppc64__
4510                 case OP_ICONV_TO_I4:
4511                 case OP_SEXT_I4:
4512                         ppc_extsw (code, ins->dreg, ins->sreg1);
4513                         break;
4514                 case OP_ICONV_TO_U4:
4515                 case OP_ZEXT_I4:
4516                         ppc_clrldi (code, ins->dreg, ins->sreg1, 32);
4517                         break;
4518                 case OP_ICONV_TO_R4:
4519                 case OP_ICONV_TO_R8:
4520                 case OP_LCONV_TO_R4:
4521                 case OP_LCONV_TO_R8: {
4522                         int tmp;
4523                         if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_ICONV_TO_R8) {
4524                                 ppc_extsw (code, ppc_r0, ins->sreg1);
4525                                 tmp = ppc_r0;
4526                         } else {
4527                                 tmp = ins->sreg1;
4528                         }
4529                         if (cpu_hw_caps & PPC_MOVE_FPR_GPR) {
4530                                 ppc_mffgpr (code, ins->dreg, tmp);
4531                         } else {
4532                                 ppc_str (code, tmp, -8, ppc_r1);
4533                                 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4534                         }
4535                         ppc_fcfid (code, ins->dreg, ins->dreg);
4536                         if (ins->opcode == OP_ICONV_TO_R4 || ins->opcode == OP_LCONV_TO_R4)
4537                                 ppc_frsp (code, ins->dreg, ins->dreg);
4538                         break;
4539                 }
4540                 case OP_LSHR:
4541                         ppc_srad (code, ins->dreg, ins->sreg1, ins->sreg2);
4542                         break;
4543                 case OP_LSHR_UN:
4544                         ppc_srd (code, ins->dreg, ins->sreg1, ins->sreg2);
4545                         break;
4546                 case OP_COND_EXC_C:
4547                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
4548                          */
4549                         ppc_mfspr (code, ppc_r0, ppc_xer);
4550                         ppc_andisd (code, ppc_r0, ppc_r0, (1 << 13)); /* CA */
4551                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4552                         break;
4553                 case OP_COND_EXC_OV:
4554                         ppc_mfspr (code, ppc_r0, ppc_xer);
4555                         ppc_andisd (code, ppc_r0, ppc_r0, (1 << 14)); /* OV */
4556                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, ins->inst_p1);
4557                         break;
4558                 case OP_LBEQ:
4559                 case OP_LBNE_UN:
4560                 case OP_LBLT:
4561                 case OP_LBLT_UN:
4562                 case OP_LBGT:
4563                 case OP_LBGT_UN:
4564                 case OP_LBGE:
4565                 case OP_LBGE_UN:
4566                 case OP_LBLE:
4567                 case OP_LBLE_UN:
4568                         EMIT_COND_BRANCH (ins, ins->opcode - OP_LBEQ);
4569                         break;
4570                 case OP_FCONV_TO_I8:
4571                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, TRUE);
4572                         break;
4573                 case OP_FCONV_TO_U8:
4574                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 8, FALSE);
4575                         break;
4576                 case OP_STOREI4_MEMBASE_REG:
4577                         if (ppc_is_imm16 (ins->inst_offset)) {
4578                                 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
4579                         } else {
4580                                 ppc_load (code, ppc_r0, ins->inst_offset);
4581                                 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
4582                         }
4583                         break;
4584                 case OP_STOREI4_MEMINDEX:
4585                         ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
4586                         break;
4587                 case OP_ISHR_IMM:
4588                         ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4589                         break;
4590                 case OP_ISHR_UN_IMM:
4591                         if (ins->inst_imm & 0x1f)
4592                                 ppc_srwi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4593                         else
4594                                 ppc_mr (code, ins->dreg, ins->sreg1);
4595                         break;
4596 #else
4597                 case OP_ICONV_TO_R4:
4598                 case OP_ICONV_TO_R8: {
4599                         if (cpu_hw_caps & PPC_ISA_64) {
4600                                 ppc_srawi(code, ppc_r0, ins->sreg1, 31);
4601                                 ppc_stw (code, ppc_r0, -8, ppc_r1);
4602                                 ppc_stw (code, ins->sreg1, -4, ppc_r1);
4603                                 ppc_lfd (code, ins->dreg, -8, ppc_r1);
4604                                 ppc_fcfid (code, ins->dreg, ins->dreg);
4605                                 if (ins->opcode == OP_ICONV_TO_R4)
4606                                         ppc_frsp (code, ins->dreg, ins->dreg);
4607                                 }
4608                         break;
4609                 }
4610 #endif
4611
4612                 case OP_ATOMIC_ADD_I4:
4613                 CASE_PPC64 (OP_ATOMIC_ADD_I8) {
4614                         int location = ins->inst_basereg;
4615                         int addend = ins->sreg2;
4616                         guint8 *loop, *branch;
4617                         g_assert (ins->inst_offset == 0);
4618
4619                         loop = code;
4620                         ppc_sync (code);
4621                         if (ins->opcode == OP_ATOMIC_ADD_I4)
4622                                 ppc_lwarx (code, ppc_r0, 0, location);
4623 #ifdef __mono_ppc64__
4624                         else
4625                                 ppc_ldarx (code, ppc_r0, 0, location);
4626 #endif
4627
4628                         ppc_add (code, ppc_r0, ppc_r0, addend);
4629
4630                         if (ins->opcode == OP_ATOMIC_ADD_I4)
4631                                 ppc_stwcxd (code, ppc_r0, 0, location);
4632 #ifdef __mono_ppc64__
4633                         else
4634                                 ppc_stdcxd (code, ppc_r0, 0, location);
4635 #endif
4636
4637                         branch = code;
4638                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4639                         ppc_patch (branch, loop);
4640
4641                         ppc_sync (code);
4642                         ppc_mr (code, ins->dreg, ppc_r0);
4643                         break;
4644                 }
4645                 case OP_ATOMIC_CAS_I4:
4646                 CASE_PPC64 (OP_ATOMIC_CAS_I8) {
4647                         int location = ins->sreg1;
4648                         int value = ins->sreg2;
4649                         int comparand = ins->sreg3;
4650                         guint8 *start, *not_equal, *lost_reservation;
4651
4652                         start = code;
4653                         ppc_sync (code);
4654                         if (ins->opcode == OP_ATOMIC_CAS_I4)
4655                                 ppc_lwarx (code, ppc_r0, 0, location);
4656 #ifdef __mono_ppc64__
4657                         else
4658                                 ppc_ldarx (code, ppc_r0, 0, location);
4659 #endif
4660
4661                         ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
4662                         not_equal = code;
4663                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4664
4665                         if (ins->opcode == OP_ATOMIC_CAS_I4)
4666                                 ppc_stwcxd (code, value, 0, location);
4667 #ifdef __mono_ppc64__
4668                         else
4669                                 ppc_stdcxd (code, value, 0, location);
4670 #endif
4671
4672                         lost_reservation = code;
4673                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4674                         ppc_patch (lost_reservation, start);
4675                         ppc_patch (not_equal, code);
4676
4677                         ppc_sync (code);
4678                         ppc_mr (code, ins->dreg, ppc_r0);
4679                         break;
4680                 }
4681                 case OP_GC_SAFE_POINT:
4682                         break;
4683
4684                 default:
4685                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4686                         g_assert_not_reached ();
4687                 }
4688
4689                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4690                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
4691                                    mono_inst_name (ins->opcode), max_len, (glong)(code - cfg->native_code - offset));
4692                         g_assert_not_reached ();
4693                 }
4694                
4695                 cpos += max_len;
4696
4697                 last_ins = ins;
4698                 last_offset = offset;
4699         }
4700
4701         cfg->code_len = code - cfg->native_code;
4702 }
4703 #endif /* !DISABLE_JIT */
4704
4705 void
4706 mono_arch_register_lowlevel_calls (void)
4707 {
4708         /* The signature doesn't matter */
4709         mono_register_jit_icall (mono_ppc_throw_exception, "mono_ppc_throw_exception", mono_create_icall_signature ("void"), TRUE);
4710 }
4711
4712 #ifdef __mono_ppc64__
4713 #ifdef _LITTLE_ENDIAN
4714 #define patch_load_sequence(ip,val) do {\
4715                 guint16 *__load = (guint16*)(ip);       \
4716                 g_assert (sizeof (val) == sizeof (gsize)); \
4717                 __load [0] = (((guint64)(gsize)(val)) >> 48) & 0xffff;  \
4718                 __load [2] = (((guint64)(gsize)(val)) >> 32) & 0xffff;  \
4719                 __load [6] = (((guint64)(gsize)(val)) >> 16) & 0xffff;  \
4720                 __load [8] =  ((guint64)(gsize)(val))        & 0xffff;  \
4721         } while (0)
4722 #elif defined _BIG_ENDIAN
4723 #define patch_load_sequence(ip,val) do {\
4724                 guint16 *__load = (guint16*)(ip);       \
4725                 g_assert (sizeof (val) == sizeof (gsize)); \
4726                 __load [1] = (((guint64)(gsize)(val)) >> 48) & 0xffff;  \
4727                 __load [3] = (((guint64)(gsize)(val)) >> 32) & 0xffff;  \
4728                 __load [7] = (((guint64)(gsize)(val)) >> 16) & 0xffff;  \
4729                 __load [9] =  ((guint64)(gsize)(val))        & 0xffff;  \
4730         } while (0)
4731 #else
4732 #error huh?  No endianess defined by compiler
4733 #endif
4734 #else
4735 #define patch_load_sequence(ip,val) do {\
4736                 guint16 *__lis_ori = (guint16*)(ip);    \
4737                 __lis_ori [1] = (((gulong)(val)) >> 16) & 0xffff;       \
4738                 __lis_ori [3] = ((gulong)(val)) & 0xffff;       \
4739         } while (0)
4740 #endif
4741
4742 #ifndef DISABLE_JIT
4743 void
4744 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4745 {
4746         MonoJumpInfo *patch_info;
4747         gboolean compile_aot = !run_cctors;
4748
4749         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4750                 unsigned char *ip = patch_info->ip.i + code;
4751                 unsigned char *target;
4752                 gboolean is_fd = FALSE;
4753
4754                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4755
4756                 if (compile_aot) {
4757                         switch (patch_info->type) {
4758                         case MONO_PATCH_INFO_BB:
4759                         case MONO_PATCH_INFO_LABEL:
4760                                 break;
4761                         default:
4762                                 /* No need to patch these */
4763                                 continue;
4764                         }
4765                 }
4766
4767                 switch (patch_info->type) {
4768                 case MONO_PATCH_INFO_IP:
4769                         patch_load_sequence (ip, ip);
4770                         continue;
4771                 case MONO_PATCH_INFO_METHOD_REL:
4772                         g_assert_not_reached ();
4773                         *((gpointer *)(ip)) = code + patch_info->data.offset;
4774                         continue;
4775                 case MONO_PATCH_INFO_SWITCH: {
4776                         gpointer *table = (gpointer *)patch_info->data.table->table;
4777                         int i;
4778
4779                         patch_load_sequence (ip, table);
4780
4781                         for (i = 0; i < patch_info->data.table->table_size; i++) {
4782                                 table [i] = (glong)patch_info->data.table->table [i] + code;
4783                         }
4784                         /* we put into the table the absolute address, no need for ppc_patch in this case */
4785                         continue;
4786                 }
4787                 case MONO_PATCH_INFO_METHODCONST:
4788                 case MONO_PATCH_INFO_CLASS:
4789                 case MONO_PATCH_INFO_IMAGE:
4790                 case MONO_PATCH_INFO_FIELD:
4791                 case MONO_PATCH_INFO_VTABLE:
4792                 case MONO_PATCH_INFO_IID:
4793                 case MONO_PATCH_INFO_SFLDA:
4794                 case MONO_PATCH_INFO_LDSTR:
4795                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4796                 case MONO_PATCH_INFO_LDTOKEN:
4797                         /* from OP_AOTCONST : lis + ori */
4798                         patch_load_sequence (ip, target);
4799                         continue;
4800                 case MONO_PATCH_INFO_R4:
4801                 case MONO_PATCH_INFO_R8:
4802                         g_assert_not_reached ();
4803                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4804                         continue;
4805                 case MONO_PATCH_INFO_EXC_NAME:
4806                         g_assert_not_reached ();
4807                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4808                         continue;
4809                 case MONO_PATCH_INFO_NONE:
4810                 case MONO_PATCH_INFO_BB_OVF:
4811                 case MONO_PATCH_INFO_EXC_OVF:
4812                         /* everything is dealt with at epilog output time */
4813                         continue;
4814 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4815                 case MONO_PATCH_INFO_INTERNAL_METHOD:
4816                 case MONO_PATCH_INFO_ABS:
4817                 case MONO_PATCH_INFO_RGCTX_FETCH:
4818                 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
4819                         is_fd = TRUE;
4820                         break;
4821 #endif
4822                 default:
4823                         break;
4824                 }
4825                 ppc_patch_full (ip, target, is_fd);
4826         }
4827 }
4828
4829 /*
4830  * Emit code to save the registers in used_int_regs or the registers in the MonoLMF
4831  * structure at positive offset pos from register base_reg. pos is guaranteed to fit into
4832  * the instruction offset immediate for all the registers.
4833  */
4834 static guint8*
4835 save_registers (MonoCompile *cfg, guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs, int cfa_offset)
4836 {
4837         int i;
4838         if (!save_lmf) {
4839                 for (i = 13; i <= 31; i++) {
4840                         if (used_int_regs & (1 << i)) {
4841                                 ppc_str (code, i, pos, base_reg);
4842                                 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4843                                 pos += sizeof (mgreg_t);
4844                         }
4845                 }
4846         } else {
4847                 /* pos is the start of the MonoLMF structure */
4848                 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4849                 for (i = 13; i <= 31; i++) {
4850                         ppc_str (code, i, offset, base_reg);
4851                         mono_emit_unwind_op_offset (cfg, code, i, offset - cfa_offset);
4852                         offset += sizeof (mgreg_t);
4853                 }
4854                 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4855                 for (i = 14; i < 32; i++) {
4856                         ppc_stfd (code, i, offset, base_reg);
4857                         offset += sizeof (gdouble);
4858                 }
4859         }
4860         return code;
4861 }
4862
4863 /*
4864  * Stack frame layout:
4865  * 
4866  *   ------------------- sp
4867  *      MonoLMF structure or saved registers
4868  *   -------------------
4869  *      spilled regs
4870  *   -------------------
4871  *      locals
4872  *   -------------------
4873  *      optional 8 bytes for tracing
4874  *   -------------------
4875  *      param area             size is cfg->param_area
4876  *   -------------------
4877  *      linkage area           size is PPC_STACK_PARAM_OFFSET
4878  *   ------------------- sp
4879  *      red zone
4880  */
4881 guint8 *
4882 mono_arch_emit_prolog (MonoCompile *cfg)
4883 {
4884         MonoMethod *method = cfg->method;
4885         MonoBasicBlock *bb;
4886         MonoMethodSignature *sig;
4887         MonoInst *inst;
4888         long alloc_size, pos, max_offset, cfa_offset;
4889         int i;
4890         guint8 *code;
4891         CallInfo *cinfo;
4892         int tracing = 0;
4893         int lmf_offset = 0;
4894         int tailcall_struct_index;
4895
4896         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4897                 tracing = 1;
4898
4899         sig = mono_method_signature (method);
4900         cfg->code_size = 512 + sig->param_count * 32;
4901         code = cfg->native_code = g_malloc (cfg->code_size);
4902
4903         cfa_offset = 0;
4904
4905         /* We currently emit unwind info for aot, but don't use it */
4906         mono_emit_unwind_op_def_cfa (cfg, code, ppc_r1, 0);
4907
4908         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4909                 ppc_mflr (code, ppc_r0);
4910                 ppc_str (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4911                 mono_emit_unwind_op_offset (cfg, code, ppc_lr, PPC_RET_ADDR_OFFSET);
4912         }
4913
4914         alloc_size = cfg->stack_offset;
4915         pos = 0;
4916
4917         if (!method->save_lmf) {
4918                 for (i = 31; i >= 13; --i) {
4919                         if (cfg->used_int_regs & (1 << i)) {
4920                                 pos += sizeof (mgreg_t);
4921                         }
4922                 }
4923         } else {
4924                 pos += sizeof (MonoLMF);
4925                 lmf_offset = pos;
4926         }
4927         alloc_size += pos;
4928         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4929         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4930                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4931                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4932         }
4933
4934         cfg->stack_usage = alloc_size;
4935         g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4936         if (alloc_size) {
4937                 if (ppc_is_imm16 (-alloc_size)) {
4938                         ppc_str_update (code, ppc_sp, -alloc_size, ppc_sp);
4939                         cfa_offset = alloc_size;
4940                         mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4941                         code = save_registers (cfg, code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs, cfa_offset);
4942                 } else {
4943                         if (pos)
4944                                 ppc_addi (code, ppc_r12, ppc_sp, -pos);
4945                         ppc_load (code, ppc_r0, -alloc_size);
4946                         ppc_str_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4947                         cfa_offset = alloc_size;
4948                         mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size);
4949                         code = save_registers (cfg, code, 0, ppc_r12, method->save_lmf, cfg->used_int_regs, cfa_offset);
4950                 }
4951         }
4952         if (cfg->frame_reg != ppc_sp) {
4953                 ppc_mr (code, cfg->frame_reg, ppc_sp);
4954                 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4955         }
4956
4957         /* store runtime generic context */
4958         if (cfg->rgctx_var) {
4959                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4960                                 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4961
4962                 ppc_stptr (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4963         }
4964
4965         /* compute max_offset in order to use short forward jumps
4966          * we always do it on ppc because the immediate displacement
4967          * for jumps is too small 
4968          */
4969         max_offset = 0;
4970         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4971                 MonoInst *ins;
4972                 bb->max_offset = max_offset;
4973
4974                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4975                         max_offset += 6; 
4976
4977                 MONO_BB_FOR_EACH_INS (bb, ins)
4978                         max_offset += ins_native_length (cfg, ins);
4979         }
4980
4981         /* load arguments allocated to register from the stack */
4982         pos = 0;
4983
4984         cinfo = get_call_info (sig);
4985
4986         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4987                 ArgInfo *ainfo = &cinfo->ret;
4988
4989                 inst = cfg->vret_addr;
4990                 g_assert (inst);
4991
4992                 if (ppc_is_imm16 (inst->inst_offset)) {
4993                         ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4994                 } else {
4995                         ppc_load (code, ppc_r12, inst->inst_offset);
4996                         ppc_stptr_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
4997                 }
4998         }
4999
5000         tailcall_struct_index = 0;
5001         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5002                 ArgInfo *ainfo = cinfo->args + i;
5003                 inst = cfg->args [pos];
5004                 
5005                 if (cfg->verbose_level > 2)
5006                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
5007                 if (inst->opcode == OP_REGVAR) {
5008                         if (ainfo->regtype == RegTypeGeneral)
5009                                 ppc_mr (code, inst->dreg, ainfo->reg);
5010                         else if (ainfo->regtype == RegTypeFP)
5011                                 ppc_fmr (code, inst->dreg, ainfo->reg);
5012                         else if (ainfo->regtype == RegTypeBase) {
5013                                 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5014                                 ppc_ldptr (code, inst->dreg, ainfo->offset, ppc_r12);
5015                         } else
5016                                 g_assert_not_reached ();
5017
5018                         if (cfg->verbose_level > 2)
5019                                 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5020                 } else {
5021                         /* the argument should be put on the stack: FIXME handle size != word  */
5022                         if (ainfo->regtype == RegTypeGeneral) {
5023                                 switch (ainfo->size) {
5024                                 case 1:
5025                                         if (ppc_is_imm16 (inst->inst_offset)) {
5026                                                 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5027                                         } else {
5028                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5029                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5030                                                         ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r12);
5031                                                 } else {
5032                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5033                                                         ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5034                                                 }
5035                                         }
5036                                         break;
5037                                 case 2:
5038                                         if (ppc_is_imm16 (inst->inst_offset)) {
5039                                                 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5040                                         } else {
5041                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5042                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5043                                                         ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r12);
5044                                                 } else {
5045                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5046                                                         ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5047                                                 }
5048                                         }
5049                                         break;
5050 #ifdef __mono_ppc64__
5051                                 case 4:
5052                                         if (ppc_is_imm16 (inst->inst_offset)) {
5053                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5054                                         } else {
5055                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5056                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5057                                                         ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r12);
5058                                                 } else {
5059                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5060                                                         ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5061                                                 }
5062                                         }
5063                                         break;
5064                                 case 8:
5065                                         if (ppc_is_imm16 (inst->inst_offset)) {
5066                                                 ppc_str (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5067                                         } else {
5068                                                 ppc_load (code, ppc_r12, inst->inst_offset);
5069                                                 ppc_str_indexed (code, ainfo->reg, ppc_r12, inst->inst_basereg);
5070                                         }
5071                                         break;
5072 #else
5073                                 case 8:
5074                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
5075                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5076                                                 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
5077                                         } else {
5078                                                 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5079                                                 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5080                                                 ppc_stw (code, ainfo->reg, 0, ppc_r12);
5081                                                 ppc_stw (code, ainfo->reg + 1, 4, ppc_r12);
5082                                         }
5083                                         break;
5084 #endif
5085                                 default:
5086                                         if (ppc_is_imm16 (inst->inst_offset)) {
5087                                                 ppc_stptr (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5088                                         } else {
5089                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5090                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5091                                                         ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r12);
5092                                                 } else {
5093                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5094                                                         ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r12);
5095                                                 }
5096                                         }
5097                                         break;
5098                                 }
5099                         } else if (ainfo->regtype == RegTypeBase) {
5100                                 g_assert (ppc_is_imm16 (ainfo->offset));
5101                                 /* load the previous stack pointer in r12 */
5102                                 ppc_ldr (code, ppc_r12, 0, ppc_sp);
5103                                 ppc_ldptr (code, ppc_r0, ainfo->offset, ppc_r12);
5104                                 switch (ainfo->size) {
5105                                 case 1:
5106                                         if (ppc_is_imm16 (inst->inst_offset)) {
5107                                                 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5108                                         } else {
5109                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5110                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5111                                                         ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r12);
5112                                                 } else {
5113                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5114                                                         ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5115                                                 }
5116                                         }
5117                                         break;
5118                                 case 2:
5119                                         if (ppc_is_imm16 (inst->inst_offset)) {
5120                                                 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5121                                         } else {
5122                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5123                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5124                                                         ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r12);
5125                                                 } else {
5126                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5127                                                         ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5128                                                 }
5129                                         }
5130                                         break;
5131 #ifdef __mono_ppc64__
5132                                 case 4:
5133                                         if (ppc_is_imm16 (inst->inst_offset)) {
5134                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5135                                         } else {
5136                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5137                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5138                                                         ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r12);
5139                                                 } else {
5140                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5141                                                         ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r12);
5142                                                 }
5143                                         }
5144                                         break;
5145                                 case 8:
5146                                         if (ppc_is_imm16 (inst->inst_offset)) {
5147                                                 ppc_str (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5148                                         } else {
5149                                                 ppc_load (code, ppc_r12, inst->inst_offset);
5150                                                 ppc_str_indexed (code, ppc_r0, ppc_r12, inst->inst_basereg);
5151                                         }
5152                                         break;
5153 #else
5154                                 case 8:
5155                                         g_assert (ppc_is_imm16 (ainfo->offset + 4));
5156                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
5157                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5158                                                 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r12);
5159                                                 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
5160                                         } else {
5161                                                 /* use r11 to load the 2nd half of the long before we clobber r12.  */
5162                                                 ppc_lwz (code, ppc_r11, ainfo->offset + 4, ppc_r12);
5163                                                 ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5164                                                 ppc_addi (code, ppc_r12, ppc_r12, inst->inst_offset);
5165                                                 ppc_stw (code, ppc_r0, 0, ppc_r12);
5166                                                 ppc_stw (code, ppc_r11, 4, ppc_r12);
5167                                         }
5168                                         break;
5169 #endif
5170                                 default:
5171                                         if (ppc_is_imm16 (inst->inst_offset)) {
5172                                                 ppc_stptr (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
5173                                         } else {
5174                                                 if (ppc_is_imm32 (inst->inst_offset)) {
5175                                                         ppc_addis (code, ppc_r12, inst->inst_basereg, ppc_ha(inst->inst_offset));
5176                                                         ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r12);
5177                                                 } else {
5178                                                         ppc_load (code, ppc_r12, inst->inst_offset);
5179                                                         ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r12);
5180                                                 }
5181                                         }
5182                                         break;
5183                                 }
5184                         } else if (ainfo->regtype == RegTypeFP) {
5185                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5186                                 if (ainfo->size == 8)
5187                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5188                                 else if (ainfo->size == 4)
5189                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
5190                                 else
5191                                         g_assert_not_reached ();
5192                          } else if (ainfo->regtype == RegTypeFPStructByVal) {
5193                                 int doffset = inst->inst_offset;
5194                                 int soffset = 0;
5195                                 int cur_reg;
5196                                 int size = 0;
5197                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5198                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5199                                 /* FIXME: what if there is no class? */
5200                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5201                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5202                                 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5203                                         if (ainfo->size == 4) {
5204                                                 ppc_stfs (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5205                                         } else {
5206                                                 ppc_stfd (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5207                                         }
5208                                         soffset += ainfo->size;
5209                                         doffset += ainfo->size;
5210                                 }
5211                         } else if (ainfo->regtype == RegTypeStructByVal) {
5212                                 int doffset = inst->inst_offset;
5213                                 int soffset = 0;
5214                                 int cur_reg;
5215                                 int size = 0;
5216                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5217                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->vtregs * sizeof (gpointer)));
5218                                 /* FIXME: what if there is no class? */
5219                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
5220                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
5221                                 for (cur_reg = 0; cur_reg < ainfo->vtregs; ++cur_reg) {
5222 #if __APPLE__
5223                                         /*
5224                                          * Darwin handles 1 and 2 byte
5225                                          * structs specially by
5226                                          * loading h/b into the arg
5227                                          * register.  Only done for
5228                                          * pinvokes.
5229                                          */
5230                                         if (size == 2)
5231                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5232                                         else if (size == 1)
5233                                                 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5234                                         else
5235 #endif
5236                                         {
5237 #ifdef __mono_ppc64__
5238                                                 if (ainfo->bytes) {
5239                                                         g_assert (cur_reg == 0);
5240 #if G_BYTE_ORDER == G_BIG_ENDIAN
5241                                                         ppc_sldi (code, ppc_r0, ainfo->reg,
5242                                                                          (sizeof (gpointer) - ainfo->bytes) * 8);
5243                                                         ppc_stptr (code, ppc_r0, doffset, inst->inst_basereg);
5244 #else
5245                                                         if (mono_class_native_size (inst->klass, NULL) == 1) {
5246                                                           ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5247                                                         } else if (mono_class_native_size (inst->klass, NULL) == 2) {
5248                                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5249                                                         } else if (mono_class_native_size (inst->klass, NULL) == 4) {  // WDS -- maybe <=4?
5250                                                                 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
5251                                                         } else {
5252                                                                 ppc_stptr (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);  // WDS -- Better way?
5253                                                         }
5254 #endif
5255                                                 } else
5256 #endif
5257                                                 {
5258                                                         ppc_stptr (code, ainfo->reg + cur_reg, doffset,
5259                                                                         inst->inst_basereg);
5260                                                 }
5261                                         }
5262                                         soffset += sizeof (gpointer);
5263                                         doffset += sizeof (gpointer);
5264                                 }
5265                                 if (ainfo->vtsize) {
5266                                         /* FIXME: we need to do the shifting here, too */
5267                                         if (ainfo->bytes)
5268                                                 NOT_IMPLEMENTED;
5269                                         /* load the previous stack pointer in r12 (r0 gets overwritten by the memcpy) */
5270                                         ppc_ldr (code, ppc_r12, 0, ppc_sp);
5271                                         if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
5272                                                 code = emit_memcpy (code, size - soffset,
5273                                                         inst->inst_basereg, doffset,
5274                                                         ppc_r12, ainfo->offset + soffset);
5275                                         } else {
5276                                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
5277                                                         inst->inst_basereg, doffset,
5278                                                         ppc_r12, ainfo->offset + soffset);
5279                                         }
5280                                 }
5281                         } else if (ainfo->regtype == RegTypeStructByAddr) {
5282                                 /* if it was originally a RegTypeBase */
5283                                 if (ainfo->offset) {
5284                                         /* load the previous stack pointer in r12 */
5285                                         ppc_ldr (code, ppc_r12, 0, ppc_sp);
5286                                         ppc_ldptr (code, ppc_r12, ainfo->offset, ppc_r12);
5287                                 } else {
5288                                         ppc_mr (code, ppc_r12, ainfo->reg);
5289                                 }
5290
5291                                 if (cfg->tailcall_valuetype_addrs) {
5292                                         MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
5293
5294                                         g_assert (ppc_is_imm16 (addr->inst_offset));
5295                                         ppc_stptr (code, ppc_r12, addr->inst_offset, addr->inst_basereg);
5296
5297                                         tailcall_struct_index++;
5298                                 }
5299
5300                                 g_assert (ppc_is_imm16 (inst->inst_offset));
5301                                 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r12, 0);
5302                                 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
5303                         } else
5304                                 g_assert_not_reached ();
5305                 }
5306                 pos++;
5307         }
5308
5309         if (method->save_lmf) {
5310                 if (lmf_pthread_key != -1) {
5311                         emit_tls_access (code, ppc_r3, lmf_pthread_key);
5312                         if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
5313                                 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5314                 } else {
5315                         if (cfg->compile_aot) {
5316                                 /* Compute the got address which is needed by the PLT entry */
5317                                 code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5318                         }
5319                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
5320                                      (gpointer)"mono_get_lmf_addr");
5321                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
5322                                 ppc_load_func (code, PPC_CALL_REG, 0);
5323                                 ppc_mtlr (code, PPC_CALL_REG);
5324                                 ppc_blrl (code);
5325                         } else {
5326                                 ppc_bl (code, 0);
5327                         }
5328                 }
5329                 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
5330                 /* lmf_offset is the offset from the previous stack pointer,
5331                  * alloc_size is the total stack space allocated, so the offset
5332                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
5333                  * The pointer to the struct is put in ppc_r12 (new_lmf).
5334                  * The callee-saved registers are already in the MonoLMF structure
5335                  */
5336                 ppc_addi (code, ppc_r12, ppc_sp, alloc_size - lmf_offset);
5337                 /* ppc_r3 is the result from mono_get_lmf_addr () */
5338                 ppc_stptr (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5339                 /* new_lmf->previous_lmf = *lmf_addr */
5340                 ppc_ldptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5341                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5342                 /* *(lmf_addr) = r12 */
5343                 ppc_stptr (code, ppc_r12, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
5344                 /* save method info */
5345                 if (cfg->compile_aot)
5346                         // FIXME:
5347                         ppc_load (code, ppc_r0, 0);
5348                 else
5349                         ppc_load_ptr (code, ppc_r0, method);
5350                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r12);
5351                 ppc_stptr (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r12);
5352                 /* save the current IP */
5353                 if (cfg->compile_aot) {
5354                         ppc_bl (code, 1);
5355                         ppc_mflr (code, ppc_r0);
5356                 } else {
5357                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5358 #ifdef __mono_ppc64__
5359                         ppc_load_sequence (code, ppc_r0, (guint64)0x0101010101010101LL);
5360 #else
5361                         ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
5362 #endif
5363                 }
5364                 ppc_stptr (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r12);
5365         }
5366
5367         if (tracing)
5368                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5369
5370         cfg->code_len = code - cfg->native_code;
5371         g_assert (cfg->code_len <= cfg->code_size);
5372         g_free (cinfo);
5373
5374         return code;
5375 }
5376
5377 void
5378 mono_arch_emit_epilog (MonoCompile *cfg)
5379 {
5380         MonoMethod *method = cfg->method;
5381         int pos, i;
5382         int max_epilog_size = 16 + 20*4;
5383         guint8 *code;
5384
5385         if (cfg->method->save_lmf)
5386                 max_epilog_size += 128;
5387         
5388         if (mono_jit_trace_calls != NULL)
5389                 max_epilog_size += 50;
5390
5391         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5392                 max_epilog_size += 50;
5393
5394         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5395                 cfg->code_size *= 2;
5396                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5397                 cfg->stat_code_reallocs++;
5398         }
5399
5400         /*
5401          * Keep in sync with OP_JMP
5402          */
5403         code = cfg->native_code + cfg->code_len;
5404
5405         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5406                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5407         }
5408         pos = 0;
5409
5410         if (method->save_lmf) {
5411                 int lmf_offset;
5412                 pos +=  sizeof (MonoLMF);
5413                 lmf_offset = pos;
5414                 /* save the frame reg in r8 */
5415                 ppc_mr (code, ppc_r8, cfg->frame_reg);
5416                 ppc_addi (code, ppc_r12, cfg->frame_reg, cfg->stack_usage - lmf_offset);
5417                 /* r5 = previous_lmf */
5418                 ppc_ldptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r12);
5419                 /* r6 = lmf_addr */
5420                 ppc_ldptr (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r12);
5421                 /* *(lmf_addr) = previous_lmf */
5422                 ppc_stptr (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
5423                 /* FIXME: speedup: there is no actual need to restore the registers if
5424                  * we didn't actually change them (idea from Zoltan).
5425                  */
5426                 /* restore iregs */
5427                 ppc_ldr_multiple (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r12);
5428                 /* restore fregs */
5429                 /*for (i = 14; i < 32; i++) {
5430                         ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r12);
5431                 }*/
5432                 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5433                 /* use the saved copy of the frame reg in r8 */
5434                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5435                         ppc_ldr (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5436                         ppc_mtlr (code, ppc_r0);
5437                 }
5438                 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5439         } else {
5440                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5441                         long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5442                         if (ppc_is_imm16 (return_offset)) {
5443                                 ppc_ldr (code, ppc_r0, return_offset, cfg->frame_reg);
5444                         } else {
5445                                 ppc_load (code, ppc_r12, return_offset);
5446                                 ppc_ldr_indexed (code, ppc_r0, cfg->frame_reg, ppc_r12);
5447                         }
5448                         ppc_mtlr (code, ppc_r0);
5449                 }
5450                 if (ppc_is_imm16 (cfg->stack_usage)) {
5451                         int offset = cfg->stack_usage;
5452                         for (i = 13; i <= 31; i++) {
5453                                 if (cfg->used_int_regs & (1 << i))
5454                                         offset -= sizeof (mgreg_t);
5455                         }
5456                         if (cfg->frame_reg != ppc_sp)
5457                                 ppc_mr (code, ppc_r12, cfg->frame_reg);
5458                         /* note r31 (possibly the frame register) is restored last */
5459                         for (i = 13; i <= 31; i++) {
5460                                 if (cfg->used_int_regs & (1 << i)) {
5461                                         ppc_ldr (code, i, offset, cfg->frame_reg);
5462                                         offset += sizeof (mgreg_t);
5463                                 }
5464                         }
5465                         if (cfg->frame_reg != ppc_sp)
5466                                 ppc_addi (code, ppc_sp, ppc_r12, cfg->stack_usage);
5467                         else
5468                                 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5469                 } else {
5470                         ppc_load32 (code, ppc_r12, cfg->stack_usage);
5471                         if (cfg->used_int_regs) {
5472                                 ppc_add (code, ppc_r12, cfg->frame_reg, ppc_r12);
5473                                 for (i = 31; i >= 13; --i) {
5474                                         if (cfg->used_int_regs & (1 << i)) {
5475                                                 pos += sizeof (mgreg_t);
5476                                                 ppc_ldr (code, i, -pos, ppc_r12);
5477                                         }
5478                                 }
5479                                 ppc_mr (code, ppc_sp, ppc_r12);
5480                         } else {
5481                                 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r12);
5482                         }
5483                 }
5484
5485         }
5486         ppc_blr (code);
5487
5488         cfg->code_len = code - cfg->native_code;
5489
5490         g_assert (cfg->code_len < cfg->code_size);
5491
5492 }
5493 #endif /* ifndef DISABLE_JIT */
5494
5495 /* remove once throw_exception_by_name is eliminated */
5496 static int
5497 exception_id_by_name (const char *name)
5498 {
5499         if (strcmp (name, "IndexOutOfRangeException") == 0)
5500                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5501         if (strcmp (name, "OverflowException") == 0)
5502                 return MONO_EXC_OVERFLOW;
5503         if (strcmp (name, "ArithmeticException") == 0)
5504                 return MONO_EXC_ARITHMETIC;
5505         if (strcmp (name, "DivideByZeroException") == 0)
5506                 return MONO_EXC_DIVIDE_BY_ZERO;
5507         if (strcmp (name, "InvalidCastException") == 0)
5508                 return MONO_EXC_INVALID_CAST;
5509         if (strcmp (name, "NullReferenceException") == 0)
5510                 return MONO_EXC_NULL_REF;
5511         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5512                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5513         if (strcmp (name, "ArgumentException") == 0)
5514                 return MONO_EXC_ARGUMENT;
5515         g_error ("Unknown intrinsic exception %s\n", name);
5516         return 0;
5517 }
5518
5519 #ifndef DISABLE_JIT
5520 void
5521 mono_arch_emit_exceptions (MonoCompile *cfg)
5522 {
5523         MonoJumpInfo *patch_info;
5524         int i;
5525         guint8 *code;
5526         guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
5527         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
5528         int max_epilog_size = 50;
5529
5530         for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
5531                 exc_throw_pos [i] = NULL;
5532                 exc_throw_found [i] = 0;
5533         }
5534
5535         /* count the number of exception infos */
5536      
5537         /* 
5538          * make sure we have enough space for exceptions
5539          */
5540         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5541                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5542                         i = exception_id_by_name (patch_info->data.target);
5543                         if (!exc_throw_found [i]) {
5544                                 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5545                                 exc_throw_found [i] = TRUE;
5546                         }
5547                 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5548                         max_epilog_size += 12;
5549                 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5550                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5551                         i = exception_id_by_name (ovfj->data.exception);
5552                         if (!exc_throw_found [i]) {
5553                                 max_epilog_size += (2 * PPC_LOAD_SEQUENCE_LENGTH) + 5 * 4;
5554                                 exc_throw_found [i] = TRUE;
5555                         }
5556                         max_epilog_size += 8;
5557                 }
5558         }
5559
5560         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5561                 cfg->code_size *= 2;
5562                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5563                 cfg->stat_code_reallocs++;
5564         }
5565
5566         code = cfg->native_code + cfg->code_len;
5567
5568         /* add code to raise exceptions */
5569         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5570                 switch (patch_info->type) {
5571                 case MONO_PATCH_INFO_BB_OVF: {
5572                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5573                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5574                         /* patch the initial jump */
5575                         ppc_patch (ip, code);
5576                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5577                         ppc_b (code, 0);
5578                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5579                         /* jump back to the true target */
5580                         ppc_b (code, 0);
5581                         ip = ovfj->data.bb->native_offset + cfg->native_code;
5582                         ppc_patch (code - 4, ip);
5583                         patch_info->type = MONO_PATCH_INFO_NONE;
5584                         break;
5585                 }
5586                 case MONO_PATCH_INFO_EXC_OVF: {
5587                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5588                         MonoJumpInfo *newji;
5589                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5590                         unsigned char *bcl = code;
5591                         /* patch the initial jump: we arrived here with a call */
5592                         ppc_patch (ip, code);
5593                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5594                         ppc_b (code, 0);
5595                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5596                         /* patch the conditional jump to the right handler */
5597                         /* make it processed next */
5598                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5599                         newji->type = MONO_PATCH_INFO_EXC;
5600                         newji->ip.i = bcl - cfg->native_code;
5601                         newji->data.target = ovfj->data.exception;
5602                         newji->next = patch_info->next;
5603                         patch_info->next = newji;
5604                         patch_info->type = MONO_PATCH_INFO_NONE;
5605                         break;
5606                 }
5607                 case MONO_PATCH_INFO_EXC: {
5608                         MonoClass *exc_class;
5609
5610                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5611                         i = exception_id_by_name (patch_info->data.target);
5612                         if (exc_throw_pos [i] && !(ip > exc_throw_pos [i] && ip - exc_throw_pos [i] > 50000)) {
5613                                 ppc_patch (ip, exc_throw_pos [i]);
5614                                 patch_info->type = MONO_PATCH_INFO_NONE;
5615                                 break;
5616                         } else {
5617                                 exc_throw_pos [i] = code;
5618                         }
5619
5620                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5621                         g_assert (exc_class);
5622
5623                         ppc_patch (ip, code);
5624                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5625                         ppc_load (code, ppc_r3, exc_class->type_token);
5626                         /* we got here from a conditional call, so the calling ip is set in lr */
5627                         ppc_mflr (code, ppc_r4);
5628                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5629                         patch_info->data.name = "mono_arch_throw_corlib_exception";
5630                         patch_info->ip.i = code - cfg->native_code;
5631                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5632                                 ppc_load_func (code, PPC_CALL_REG, 0);
5633                                 ppc_mtctr (code, PPC_CALL_REG);
5634                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5635                         } else {
5636                                 ppc_bl (code, 0);
5637                         }
5638                         break;
5639                 }
5640                 default:
5641                         /* do nothing */
5642                         break;
5643                 }
5644         }
5645
5646         cfg->code_len = code - cfg->native_code;
5647
5648         g_assert (cfg->code_len <= cfg->code_size);
5649 }
5650 #endif
5651
5652 #if DEAD_CODE
5653 static int
5654 try_offset_access (void *value, guint32 idx)
5655 {
5656         register void* me __asm__ ("r2");
5657         void ***p = (void***)((char*)me + 284);
5658         int idx1 = idx / 32;
5659         int idx2 = idx % 32;
5660         if (!p [idx1])
5661                 return 0;
5662         if (value != p[idx1][idx2])
5663                 return 0;
5664         return 1;
5665 }
5666 #endif
5667
5668 static void
5669 setup_tls_access (void)
5670 {
5671 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5672         size_t conf_size = 0;
5673         char confbuf[128];
5674 #else
5675         /* FIXME for darwin */
5676         guint32 *ins, *code;
5677         guint32 cmplwi_1023, li_0x48, blr_ins;
5678 #endif
5679
5680 #ifdef TARGET_PS3
5681         tls_mode = TLS_MODE_FAILED;
5682 #endif
5683
5684         if (tls_mode == TLS_MODE_FAILED)
5685                 return;
5686         if (g_getenv ("MONO_NO_TLS")) {
5687                 tls_mode = TLS_MODE_FAILED;
5688                 return;
5689         }
5690
5691         if (tls_mode == TLS_MODE_DETECT) {
5692 #if defined(__APPLE__) && defined(__mono_ppc__) && !defined(__mono_ppc64__)
5693                 tls_mode = TLS_MODE_DARWIN_G4;
5694 #elif defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5695                 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5696                 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5697                         tls_mode = TLS_MODE_NPTL;
5698 #elif !defined(TARGET_PS3)
5699                 ins = (guint32*)pthread_getspecific;
5700                 /* uncond branch to the real method */
5701                 if ((*ins >> 26) == 18) {
5702                         gint32 val;
5703                         val = (*ins & ~3) << 6;
5704                         val >>= 6;
5705                         if (*ins & 2) {
5706                                 /* absolute */
5707                                 ins = (guint32*)(long)val;
5708                         } else {
5709                                 ins = (guint32*) ((char*)ins + val);
5710                         }
5711                 }
5712                 code = &cmplwi_1023;
5713                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5714                 code = &li_0x48;
5715                 ppc_li (code, ppc_r4, 0x48);
5716                 code = &blr_ins;
5717                 ppc_blr (code);
5718                 if (*ins == cmplwi_1023) {
5719                         int found_lwz_284 = 0;
5720                         guint32 ptk;
5721                         for (ptk = 0; ptk < 20; ++ptk) {
5722                                 ++ins;
5723                                 if (!*ins || *ins == blr_ins)
5724                                         break;
5725                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5726                                         found_lwz_284 = 1;
5727                                         break;
5728                                 }
5729                         }
5730                         if (!found_lwz_284) {
5731                                 tls_mode = TLS_MODE_FAILED;
5732                                 return;
5733                         }
5734                         tls_mode = TLS_MODE_LTHREADS;
5735                 } else if (*ins == li_0x48) {
5736                         ++ins;
5737                         /* uncond branch to the real method */
5738                         if ((*ins >> 26) == 18) {
5739                                 gint32 val;
5740                                 val = (*ins & ~3) << 6;
5741                                 val >>= 6;
5742                                 if (*ins & 2) {
5743                                         /* absolute */
5744                                         ins = (guint32*)(long)val;
5745                                 } else {
5746                                         ins = (guint32*) ((char*)ins + val);
5747                                 }
5748                                 code = (guint32*)&val;
5749                                 ppc_li (code, ppc_r0, 0x7FF2);
5750                                 if (ins [1] == val) {
5751                                         /* Darwin on G4, implement */
5752                                         tls_mode = TLS_MODE_FAILED;
5753                                         return;
5754                                 } else {
5755                                         code = (guint32*)&val;
5756                                         ppc_mfspr (code, ppc_r3, 104);
5757                                         if (ins [1] != val) {
5758                                                 tls_mode = TLS_MODE_FAILED;
5759                                                 return;
5760                                         }
5761                                         tls_mode = TLS_MODE_DARWIN_G5;
5762                                 }
5763                         } else {
5764                                 tls_mode = TLS_MODE_FAILED;
5765                                 return;
5766                         }
5767                 } else {
5768                         tls_mode = TLS_MODE_FAILED;
5769                         return;
5770                 }
5771 #endif
5772         }
5773 #ifndef TARGET_PS3
5774         if (tls_mode == TLS_MODE_DETECT)
5775                 tls_mode = TLS_MODE_FAILED;
5776         if (tls_mode == TLS_MODE_FAILED)
5777                 return;
5778         if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5779                 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5780         }
5781
5782 #if 0
5783         /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5784            mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5785         if (lmf_pthread_key == -1) {
5786                 guint32 ptk = mono_jit_tls_id;
5787                 if (ptk < 1024) {
5788                         /*g_print ("MonoLMF at: %d\n", ptk);*/
5789                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5790                                 init_tls_failed = 1;
5791                                 return;
5792                         }*/
5793                         lmf_pthread_key = ptk;
5794                 }
5795         }
5796 #endif
5797
5798 #endif
5799 }
5800
5801 void
5802 mono_arch_finish_init (void)
5803 {
5804         setup_tls_access ();
5805 }
5806
5807 void
5808 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5809 {
5810 }
5811
5812 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5813 #define BR_SIZE 4
5814 #define LOADSTORE_SIZE 4
5815 #define JUMP_IMM_SIZE 12
5816 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5817 #define ENABLE_WRONG_METHOD_CHECK 0
5818
5819 /*
5820  * LOCKING: called with the domain lock held
5821  */
5822 gpointer
5823 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5824         gpointer fail_tramp)
5825 {
5826         int i;
5827         int size = 0;
5828         guint8 *code, *start;
5829
5830         for (i = 0; i < count; ++i) {
5831                 MonoIMTCheckItem *item = imt_entries [i];
5832                 if (item->is_equals) {
5833                         if (item->check_target_idx) {
5834                                 if (!item->compare_done)
5835                                         item->chunk_size += CMP_SIZE;
5836                                 if (item->has_target_code)
5837                                         item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5838                                 else
5839                                         item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5840                         } else {
5841                                 if (fail_tramp) {
5842                                         item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5843                                         if (!item->has_target_code)
5844                                                 item->chunk_size += LOADSTORE_SIZE;
5845                                 } else {
5846                                         item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5847 #if ENABLE_WRONG_METHOD_CHECK
5848                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5849 #endif
5850                                 }
5851                         }
5852                 } else {
5853                         item->chunk_size += CMP_SIZE + BR_SIZE;
5854                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5855                 }
5856                 size += item->chunk_size;
5857         }
5858         /* the initial load of the vtable address */
5859         size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5860         if (fail_tramp) {
5861                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5862         } else {
5863                 code = mono_domain_code_reserve (domain, size);
5864         }
5865         start = code;
5866
5867         /*
5868          * We need to save and restore r12 because it might be
5869          * used by the caller as the vtable register, so
5870          * clobbering it will trip up the magic trampoline.
5871          *
5872          * FIXME: Get rid of this by making sure that r12 is
5873          * not used as the vtable register in interface calls.
5874          */
5875         ppc_stptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5876         ppc_load (code, ppc_r12, (gsize)(& (vtable->vtable [0])));
5877
5878         for (i = 0; i < count; ++i) {
5879                 MonoIMTCheckItem *item = imt_entries [i];
5880                 item->code_target = code;
5881                 if (item->is_equals) {
5882                         if (item->check_target_idx) {
5883                                 if (!item->compare_done) {
5884                                         ppc_load (code, ppc_r0, (gsize)item->key);
5885                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5886                                 }
5887                                 item->jmp_code = code;
5888                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5889                                 if (item->has_target_code) {
5890                                         ppc_load_ptr (code, ppc_r0, item->value.target_code);
5891                                 } else {
5892                                         ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5893                                         ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5894                                 }
5895                                 ppc_mtctr (code, ppc_r0);
5896                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5897                         } else {
5898                                 if (fail_tramp) {
5899                                         ppc_load (code, ppc_r0, (gulong)item->key);
5900                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5901                                         item->jmp_code = code;
5902                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5903                                         if (item->has_target_code) {
5904                                                 ppc_load_ptr (code, ppc_r0, item->value.target_code);
5905                                         } else {
5906                                                 g_assert (vtable);
5907                                                 ppc_load_ptr (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5908                                                 ppc_ldptr_indexed (code, ppc_r0, 0, ppc_r0);
5909                                         }
5910                                         ppc_mtctr (code, ppc_r0);
5911                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5912                                         ppc_patch (item->jmp_code, code);
5913                                         ppc_load_ptr (code, ppc_r0, fail_tramp);
5914                                         ppc_mtctr (code, ppc_r0);
5915                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5916                                         item->jmp_code = NULL;
5917                                 } else {
5918                                         /* enable the commented code to assert on wrong method */
5919 #if ENABLE_WRONG_METHOD_CHECK
5920                                         ppc_load (code, ppc_r0, (guint32)item->key);
5921                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5922                                         item->jmp_code = code;
5923                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5924 #endif
5925                                         ppc_ldptr (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r12);
5926                                         ppc_ldptr (code, ppc_r12, PPC_RET_ADDR_OFFSET, ppc_sp);
5927                                         ppc_mtctr (code, ppc_r0);
5928                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5929 #if ENABLE_WRONG_METHOD_CHECK
5930                                         ppc_patch (item->jmp_code, code);
5931                                         ppc_break (code);
5932                                         item->jmp_code = NULL;
5933 #endif
5934                                 }
5935                         }
5936                 } else {
5937                         ppc_load (code, ppc_r0, (gulong)item->key);
5938                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5939                         item->jmp_code = code;
5940                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5941                 }
5942         }
5943         /* patch the branches to get to the target items */
5944         for (i = 0; i < count; ++i) {
5945                 MonoIMTCheckItem *item = imt_entries [i];
5946                 if (item->jmp_code) {
5947                         if (item->check_target_idx) {
5948                                 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5949                         }
5950                 }
5951         }
5952
5953         if (!fail_tramp)
5954                 mono_stats.imt_thunks_size += code - start;
5955         g_assert (code - start <= size);
5956         mono_arch_flush_icache (start, size);
5957
5958         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5959
5960         return start;
5961 }
5962
5963 MonoMethod*
5964 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5965 {
5966         mgreg_t *r = (mgreg_t*)regs;
5967
5968         return (MonoMethod*)(gsize) r [MONO_ARCH_IMT_REG];
5969 }
5970
5971 MonoVTable*
5972 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5973 {
5974         mgreg_t *r = (mgreg_t*)regs;
5975
5976         return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
5977 }
5978
5979 GSList*
5980 mono_arch_get_cie_program (void)
5981 {
5982         GSList *l = NULL;
5983
5984         mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
5985
5986         return l;
5987 }
5988
5989 MonoInst*
5990 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5991 {
5992         /* FIXME: */
5993         return NULL;
5994 }
5995
5996 gboolean
5997 mono_arch_print_tree (MonoInst *tree, int arity)
5998 {
5999         return 0;
6000 }
6001
6002 mgreg_t
6003 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6004 {
6005         if (reg == ppc_r1)
6006                 return (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
6007
6008         g_assert (reg >= ppc_r13);
6009
6010         return ctx->regs [reg - ppc_r13];
6011 }
6012
6013 guint32
6014 mono_arch_get_patch_offset (guint8 *code)
6015 {
6016         return 0;
6017 }
6018
6019 /*
6020  * mono_aot_emit_load_got_addr:
6021  *
6022  *   Emit code to load the got address.
6023  * On PPC, the result is placed into r30.
6024  */
6025 guint8*
6026 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6027 {
6028         ppc_bl (code, 1);
6029         ppc_mflr (code, ppc_r30);
6030         if (cfg)
6031                 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6032         else
6033                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6034         /* arch_emit_got_address () patches this */
6035 #if defined(TARGET_POWERPC64)
6036         ppc_nop (code);
6037         ppc_nop (code);
6038         ppc_nop (code);
6039         ppc_nop (code);
6040 #else
6041         ppc_load32 (code, ppc_r0, 0);
6042         ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
6043 #endif
6044
6045         return code;
6046 }
6047
6048 /*
6049  * mono_ppc_emit_load_aotconst:
6050  *
6051  *   Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6052  * TARGET from the mscorlib GOT in full-aot code.
6053  * On PPC, the GOT address is assumed to be in r30, and the result is placed into 
6054  * r12.
6055  */
6056 guint8*
6057 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, MonoJumpInfoType tramp_type, gconstpointer target)
6058 {
6059         /* Load the mscorlib got address */
6060         ppc_ldptr (code, ppc_r12, sizeof (gpointer), ppc_r30);
6061         *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6062         /* arch_emit_got_access () patches this */
6063         ppc_load32 (code, ppc_r0, 0);
6064         ppc_ldptr_indexed (code, ppc_r12, ppc_r12, ppc_r0);
6065
6066         return code;
6067 }
6068
6069 /* Soft Debug support */
6070 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6071
6072 /*
6073  * BREAKPOINTS
6074  */
6075
6076 /*
6077  * mono_arch_set_breakpoint:
6078  *
6079  *   See mini-amd64.c for docs.
6080  */
6081 void
6082 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6083 {
6084         guint8 *code = ip;
6085         guint8 *orig_code = code;
6086
6087         ppc_load_sequence (code, ppc_r12, (gsize)bp_trigger_page);
6088         ppc_ldptr (code, ppc_r12, 0, ppc_r12);
6089
6090         g_assert (code - orig_code == BREAKPOINT_SIZE);
6091
6092         mono_arch_flush_icache (orig_code, code - orig_code);
6093 }
6094
6095 /*
6096  * mono_arch_clear_breakpoint:
6097  *
6098  *   See mini-amd64.c for docs.
6099  */
6100 void
6101 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6102 {
6103         guint8 *code = ip;
6104         int i;
6105
6106         for (i = 0; i < BREAKPOINT_SIZE / 4; ++i)
6107                 ppc_nop (code);
6108
6109         mono_arch_flush_icache (ip, code - ip);
6110 }
6111
6112 /*
6113  * mono_arch_is_breakpoint_event:
6114  *
6115  *   See mini-amd64.c for docs.
6116  */
6117 gboolean
6118 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6119 {
6120         siginfo_t* sinfo = (siginfo_t*) info;
6121         /* Sometimes the address is off by 4 */
6122         if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6123                 return TRUE;
6124         else
6125                 return FALSE;
6126 }
6127
6128 /*
6129  * mono_arch_skip_breakpoint:
6130  *
6131  *   See mini-amd64.c for docs.
6132  */
6133 void
6134 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6135 {
6136         /* skip the ldptr */
6137         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6138 }
6139
6140 /*
6141  * SINGLE STEPPING
6142  */
6143         
6144 /*
6145  * mono_arch_start_single_stepping:
6146  *
6147  *   See mini-amd64.c for docs.
6148  */
6149 void
6150 mono_arch_start_single_stepping (void)
6151 {
6152         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6153 }
6154         
6155 /*
6156  * mono_arch_stop_single_stepping:
6157  *
6158  *   See mini-amd64.c for docs.
6159  */
6160 void
6161 mono_arch_stop_single_stepping (void)
6162 {
6163         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6164 }
6165
6166 /*
6167  * mono_arch_is_single_step_event:
6168  *
6169  *   See mini-amd64.c for docs.
6170  */
6171 gboolean
6172 mono_arch_is_single_step_event (void *info, void *sigctx)
6173 {
6174         siginfo_t* sinfo = (siginfo_t*) info;
6175         /* Sometimes the address is off by 4 */
6176         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6177                 return TRUE;
6178         else
6179                 return FALSE;
6180 }
6181
6182 /*
6183  * mono_arch_skip_single_step:
6184  *
6185  *   See mini-amd64.c for docs.
6186  */
6187 void
6188 mono_arch_skip_single_step (MonoContext *ctx)
6189 {
6190         /* skip the ldptr */
6191         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6192 }
6193
6194 /*
6195  * mono_arch_create_seq_point_info:
6196  *
6197  *   See mini-amd64.c for docs.
6198  */
6199 gpointer
6200 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6201 {
6202         NOT_IMPLEMENTED;
6203         return NULL;
6204 }
6205
6206 void
6207 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6208 {
6209         ext->lmf.previous_lmf = prev_lmf;
6210         /* Mark that this is a MonoLMFExt */
6211         ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6212         ext->lmf.ebp = (gssize)ext;
6213 }
6214
6215 #endif
6216
6217 gboolean
6218 mono_arch_opcode_supported (int opcode)
6219 {
6220         switch (opcode) {
6221         case OP_ATOMIC_ADD_I4:
6222         case OP_ATOMIC_CAS_I4:
6223 #ifdef TARGET_POWERPC64
6224         case OP_ATOMIC_ADD_I8:
6225         case OP_ATOMIC_CAS_I8:
6226 #endif
6227                 return TRUE;
6228         default:
6229                 return FALSE;
6230         }
6231 }
6232
6233
6234 #if 0
6235 // FIXME: To get the test case  finally_block_ending_in_dead_bb  to work properly we need to define the following
6236 // (in mini-ppc.h) and then implement the fuction mono_arch_create_handler_block_trampoline.
6237 //  #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
6238
6239 gpointer
6240 mono_arch_create_handler_block_trampoline (void)
6241 {
6242         . . .
6243 }
6244 #endif