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