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