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