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