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