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