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