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