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