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