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