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