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