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