2009-06-19 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-ppc.c
1 /*
2  * mini-ppc.c: PowerPC backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *   Andreas Faerber <andreas.faerber@web.de>
8  *
9  * (C) 2003 Ximian, Inc.
10  * (C) 2007-2008 Andreas Faerber
11  */
12 #include "mini.h"
13 #include <string.h>
14
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/debug-helpers.h>
17
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_load_reg ((code), (dreg), off1, ppc_r2);    \
68                 ppc_load_reg ((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_load_reg ((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_load_reg ((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_load_reg ((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_load_reg_update (code, ppc_r0, (unsigned int)sizeof (gpointer), ppc_r11);
172                 ppc_store_reg_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_load_reg (code, ppc_r0, soffset, sreg);
183                 ppc_store_reg (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, gpointer *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_load_reg (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_load_reg (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_load_reg (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, gssize *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_store_reg (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_load_reg (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_load_reg (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_load_reg (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_load_reg (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_load_reg (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_load_reg (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
2951                                 ppc_store_reg (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_load_reg (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_load_reg (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_load_reg (code, ppc_r0, 0, ppc_sp);
3079         if (ppc_is_imm16 (-size)) {
3080                 ppc_store_reg_update (code, ppc_r0, -size, ppc_sp);
3081         } else {
3082                 ppc_load (code, ppc_r11, -size);
3083                 ppc_store_reg_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_load_reg (code, ppc_r0, 0, ppc_sp);
3101         if (ppc_is_imm16 (size)) {
3102                 ppc_store_reg_update (code, ppc_r0, size, ppc_sp);
3103         } else {
3104                 ppc_load (code, ppc_r11, size);
3105                 ppc_store_reg_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_store_reg (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3200                         } else {
3201                                 ppc_load (code, ppc_r0, ins->inst_offset);
3202                                 ppc_store_reg_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_store_reg_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_load_reg (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3220                         } else {
3221                                 ppc_load (code, ppc_r0, ins->inst_offset);
3222                                 ppc_load_reg_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_load_reg_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_load_reg_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_load_reg (code, ppc_r0, ret_offset, cfg->frame_reg);
3692                                 } else {
3693                                         ppc_load (code, ppc_r11, ret_offset);
3694                                         ppc_load_reg_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_load_reg (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_load_reg_indexed (code, ppc_r11, ppc_r30, ppc_r0);
3731                                 ppc_load_reg (code, ppc_r0, 0, ppc_r11);
3732 #else
3733                                 ppc_load_reg_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_load_reg (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_store_reg (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_load_reg (code, ppc_r0, 0, ins->sreg1);
3786                         /* FIXME: if we know that this is a method, we
3787                            can omit this load */
3788                         ppc_load_reg (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_load_reg (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_load_reg (code, ppc_r0, 0, ppc_sp);
3830                         ppc_neg (code, ppc_r11, ppc_r11);
3831                         ppc_store_reg_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_store_reg (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3886                         } else {
3887                                 ppc_load (code, ppc_r11, spvar->inst_offset);
3888                                 ppc_store_reg_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_load_reg (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3900                         } else {
3901                                 ppc_load (code, ppc_r11, spvar->inst_offset);
3902                                 ppc_load_reg_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_load_reg (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_store_reg (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 (guint8* code, int pos, int base_reg, gboolean save_lmf, guint32 used_int_regs)
4504 {
4505         int i;
4506         if (!save_lmf) {
4507                 for (i = 13; i <= 31; i++) {
4508                         if (used_int_regs & (1 << i)) {
4509                                 ppc_store_reg (code, i, pos, base_reg);
4510                                 pos += sizeof (gulong);
4511                         }
4512                 }
4513         } else {
4514                 /* pos is the start of the MonoLMF structure */
4515                 int offset = pos + G_STRUCT_OFFSET (MonoLMF, iregs);
4516                 for (i = 13; i <= 31; i++) {
4517                         ppc_store_reg (code, i, offset, base_reg);
4518                         offset += sizeof (gulong);
4519                 }
4520                 offset = pos + G_STRUCT_OFFSET (MonoLMF, fregs);
4521                 for (i = 14; i < 32; i++) {
4522                         ppc_stfd (code, i, offset, base_reg);
4523                         offset += sizeof (gdouble);
4524                 }
4525         }
4526         return code;
4527 }
4528
4529 /*
4530  * Stack frame layout:
4531  * 
4532  *   ------------------- sp
4533  *      MonoLMF structure or saved registers
4534  *   -------------------
4535  *      spilled regs
4536  *   -------------------
4537  *      locals
4538  *   -------------------
4539  *      optional 8 bytes for tracing
4540  *   -------------------
4541  *      param area             size is cfg->param_area
4542  *   -------------------
4543  *      linkage area           size is PPC_STACK_PARAM_OFFSET
4544  *   ------------------- sp
4545  *      red zone
4546  */
4547 guint8 *
4548 mono_arch_emit_prolog (MonoCompile *cfg)
4549 {
4550         MonoMethod *method = cfg->method;
4551         MonoBasicBlock *bb;
4552         MonoMethodSignature *sig;
4553         MonoInst *inst;
4554         long alloc_size, pos, max_offset;
4555         int i;
4556         guint8 *code;
4557         CallInfo *cinfo;
4558         int tracing = 0;
4559         int lmf_offset = 0;
4560         int tailcall_struct_index;
4561
4562         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4563                 tracing = 1;
4564
4565         sig = mono_method_signature (method);
4566         cfg->code_size = MONO_PPC_32_64_CASE (260, 384) + sig->param_count * 20;
4567         code = cfg->native_code = g_malloc (cfg->code_size);
4568
4569         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4570                 ppc_mflr (code, ppc_r0);
4571                 ppc_store_reg (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
4572         }
4573
4574         alloc_size = cfg->stack_offset;
4575         pos = 0;
4576
4577         if (!method->save_lmf) {
4578                 for (i = 31; i >= 13; --i) {
4579                         if (cfg->used_int_regs & (1 << i)) {
4580                                 pos += sizeof (gulong);
4581                         }
4582                 }
4583         } else {
4584                 pos += sizeof (MonoLMF);
4585                 lmf_offset = pos;
4586         }
4587         alloc_size += pos;
4588         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4589         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4590                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4591                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4592         }
4593
4594         cfg->stack_usage = alloc_size;
4595         g_assert ((alloc_size & (MONO_ARCH_FRAME_ALIGNMENT-1)) == 0);
4596         if (alloc_size) {
4597                 if (ppc_is_imm16 (-alloc_size)) {
4598                         ppc_store_reg_update (code, ppc_sp, -alloc_size, ppc_sp);
4599                         code = save_registers (code, alloc_size - pos, ppc_sp, method->save_lmf, cfg->used_int_regs);
4600                 } else {
4601                         if (pos)
4602                                 ppc_addi (code, ppc_r11, ppc_sp, -pos);
4603                         ppc_load (code, ppc_r0, -alloc_size);
4604                         ppc_store_reg_update_indexed (code, ppc_sp, ppc_sp, ppc_r0);
4605                         code = save_registers (code, 0, ppc_r11, method->save_lmf, cfg->used_int_regs);
4606                 }
4607         }
4608         if (cfg->frame_reg != ppc_sp)
4609                 ppc_mr (code, cfg->frame_reg, ppc_sp);
4610
4611         /* store runtime generic context */
4612         if (cfg->rgctx_var) {
4613                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
4614                                 (cfg->rgctx_var->inst_basereg == ppc_r1 || cfg->rgctx_var->inst_basereg == ppc_r31));
4615
4616                 ppc_store_reg (code, MONO_ARCH_RGCTX_REG, cfg->rgctx_var->inst_offset, cfg->rgctx_var->inst_basereg);
4617         }
4618
4619         /* compute max_offset in order to use short forward jumps
4620          * we always do it on ppc because the immediate displacement
4621          * for jumps is too small 
4622          */
4623         max_offset = 0;
4624         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4625                 MonoInst *ins;
4626                 bb->max_offset = max_offset;
4627
4628                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4629                         max_offset += 6; 
4630
4631                 MONO_BB_FOR_EACH_INS (bb, ins)
4632                         max_offset += ins_native_length (cfg, ins);
4633         }
4634
4635         /* load arguments allocated to register from the stack */
4636         pos = 0;
4637
4638         cinfo = calculate_sizes (sig, sig->pinvoke);
4639
4640         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4641                 ArgInfo *ainfo = &cinfo->ret;
4642
4643                 inst = cfg->vret_addr;
4644                 g_assert (inst);
4645
4646                 if (ppc_is_imm16 (inst->inst_offset)) {
4647                         ppc_store_reg (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4648                 } else {
4649                         ppc_load (code, ppc_r11, inst->inst_offset);
4650                         ppc_store_reg_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4651                 }
4652         }
4653
4654         tailcall_struct_index = 0;
4655         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4656                 ArgInfo *ainfo = cinfo->args + i;
4657                 inst = cfg->args [pos];
4658                 
4659                 if (cfg->verbose_level > 2)
4660                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4661                 if (inst->opcode == OP_REGVAR) {
4662                         if (ainfo->regtype == RegTypeGeneral)
4663                                 ppc_mr (code, inst->dreg, ainfo->reg);
4664                         else if (ainfo->regtype == RegTypeFP)
4665                                 ppc_fmr (code, inst->dreg, ainfo->reg);
4666                         else if (ainfo->regtype == RegTypeBase) {
4667                                 ppc_load_reg (code, ppc_r11, 0, ppc_sp);
4668                                 ppc_load_reg (code, inst->dreg, ainfo->offset, ppc_r11);
4669                         } else
4670                                 g_assert_not_reached ();
4671
4672                         if (cfg->verbose_level > 2)
4673                                 g_print ("Argument %ld assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4674                 } else {
4675                         /* the argument should be put on the stack: FIXME handle size != word  */
4676                         if (ainfo->regtype == RegTypeGeneral) {
4677                                 switch (ainfo->size) {
4678                                 case 1:
4679                                         if (ppc_is_imm16 (inst->inst_offset)) {
4680                                                 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4681                                         } else {
4682                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4683                                                 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4684                                         }
4685                                         break;
4686                                 case 2:
4687                                         if (ppc_is_imm16 (inst->inst_offset)) {
4688                                                 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4689                                         } else {
4690                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4691                                                 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4692                                         }
4693                                         break;
4694 #ifdef __mono_ppc64__
4695                                 case 4:
4696                                         if (ppc_is_imm16 (inst->inst_offset)) {
4697                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4698                                         } else {
4699                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4700                                                 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4701                                         }
4702                                         break;
4703 #else
4704                                 case 8:
4705                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
4706                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4707                                                 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4708                                         } else {
4709                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4710                                                 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4711                                                 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4712                                                 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4713                                         }
4714                                         break;
4715 #endif
4716                                 default:
4717                                         if (ppc_is_imm16 (inst->inst_offset)) {
4718                                                 ppc_store_reg (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4719                                         } else {
4720                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4721                                                 ppc_store_reg_indexed (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4722                                         }
4723                                         break;
4724                                 }
4725                         } else if (ainfo->regtype == RegTypeBase) {
4726                                 /* load the previous stack pointer in r11 */
4727                                 ppc_load_reg (code, ppc_r11, 0, ppc_sp);
4728                                 ppc_load_reg (code, ppc_r0, ainfo->offset, ppc_r11);
4729                                 switch (ainfo->size) {
4730                                 case 1:
4731                                         if (ppc_is_imm16 (inst->inst_offset)) {
4732                                                 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4733                                         } else {
4734                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4735                                                 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4736                                         }
4737                                         break;
4738                                 case 2:
4739                                         if (ppc_is_imm16 (inst->inst_offset)) {
4740                                                 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4741                                         } else {
4742                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4743                                                 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4744                                         }
4745                                         break;
4746 #ifdef __mono_ppc64__
4747                                 case 4:
4748                                         if (ppc_is_imm16 (inst->inst_offset)) {
4749                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4750                                         } else {
4751                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4752                                                 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4753                                         }
4754                                         break;
4755 #else
4756                                 case 8:
4757                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
4758                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4759                                                 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4760                                                 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4761                                         } else {
4762                                                 /* FIXME */
4763                                                 g_assert_not_reached ();
4764                                         }
4765                                         break;
4766 #endif
4767                                 default:
4768                                         if (ppc_is_imm16 (inst->inst_offset)) {
4769                                                 ppc_store_reg (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4770                                         } else {
4771                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4772                                                 ppc_store_reg_indexed (code, ppc_r0, ppc_r11, inst->inst_basereg);
4773                                         }
4774                                         break;
4775                                 }
4776                         } else if (ainfo->regtype == RegTypeFP) {
4777                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4778                                 if (ainfo->size == 8)
4779                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4780                                 else if (ainfo->size == 4)
4781                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4782                                 else
4783                                         g_assert_not_reached ();
4784                         } else if (ainfo->regtype == RegTypeStructByVal) {
4785                                 int doffset = inst->inst_offset;
4786                                 int soffset = 0;
4787                                 int cur_reg;
4788                                 int size = 0;
4789                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4790                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4791                                 /* FIXME: what if there is no class? */
4792                                 if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
4793                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4794                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4795 #if __APPLE__
4796                                         /*
4797                                          * Darwin handles 1 and 2 byte
4798                                          * structs specially by
4799                                          * loading h/b into the arg
4800                                          * register.  Only done for
4801                                          * pinvokes.
4802                                          */
4803                                         if (size == 2)
4804                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4805                                         else if (size == 1)
4806                                                 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4807                                         else
4808 #endif
4809                                         {
4810 #ifdef __mono_ppc64__
4811                                                 if (ainfo->bytes) {
4812                                                         g_assert (cur_reg == 0);
4813                                                         ppc_sldi (code, ppc_r0, ainfo->reg,
4814                                                                         (sizeof (gpointer) - ainfo->bytes) * 8);
4815                                                         ppc_store_reg (code, ppc_r0, doffset, inst->inst_basereg);
4816                                                 } else
4817 #endif
4818                                                 {
4819                                                         ppc_store_reg (code, ainfo->reg + cur_reg, doffset,
4820                                                                         inst->inst_basereg);
4821                                                 }
4822                                         }
4823                                         soffset += sizeof (gpointer);
4824                                         doffset += sizeof (gpointer);
4825                                 }
4826                                 if (ainfo->vtsize) {
4827                                         /* FIXME: we need to do the shifting here, too */
4828                                         if (ainfo->bytes)
4829                                                 NOT_IMPLEMENTED;
4830                                         /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4831                                         ppc_load_reg (code, ppc_r11, 0, ppc_sp);
4832                                         if ((size & MONO_PPC_32_64_CASE (3, 7)) != 0) {
4833                                                 code = emit_memcpy (code, size - soffset,
4834                                                         inst->inst_basereg, doffset,
4835                                                         ppc_r11, ainfo->offset + soffset);
4836                                         } else {
4837                                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4838                                                         inst->inst_basereg, doffset,
4839                                                         ppc_r11, ainfo->offset + soffset);
4840                                         }
4841                                 }
4842                         } else if (ainfo->regtype == RegTypeStructByAddr) {
4843                                 /* if it was originally a RegTypeBase */
4844                                 if (ainfo->offset) {
4845                                         /* load the previous stack pointer in r11 */
4846                                         ppc_load_reg (code, ppc_r11, 0, ppc_sp);
4847                                         ppc_load_reg (code, ppc_r11, ainfo->offset, ppc_r11);
4848                                 } else {
4849                                         ppc_mr (code, ppc_r11, ainfo->reg);
4850                                 }
4851
4852                                 if (cfg->tailcall_valuetype_addrs) {
4853                                         MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4854
4855                                         g_assert (ppc_is_imm16 (addr->inst_offset));
4856                                         ppc_store_reg (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4857
4858                                         tailcall_struct_index++;
4859                                 }
4860
4861                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4862                                 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4863                                 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4864                         } else
4865                                 g_assert_not_reached ();
4866                 }
4867                 pos++;
4868         }
4869
4870         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4871                 ppc_load (code, ppc_r3, cfg->domain);
4872                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4873                 if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4874                         ppc_load_func (code, ppc_r0, 0);
4875                         ppc_mtlr (code, ppc_r0);
4876                         ppc_blrl (code);
4877                 } else {
4878                         ppc_bl (code, 0);
4879                 }
4880         }
4881
4882         if (method->save_lmf) {
4883                 if (lmf_pthread_key != -1) {
4884                         emit_tls_access (code, ppc_r3, lmf_pthread_key);
4885                         if (tls_mode != TLS_MODE_NPTL && G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4886                                 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4887                 } else {
4888                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4889                                      (gpointer)"mono_get_lmf_addr");
4890                         if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
4891                                 ppc_load_func (code, ppc_r0, 0);
4892                                 ppc_mtlr (code, ppc_r0);
4893                                 ppc_blrl (code);
4894                         } else {
4895                                 ppc_bl (code, 0);
4896                         }
4897                 }
4898                 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4899                 /* lmf_offset is the offset from the previous stack pointer,
4900                  * alloc_size is the total stack space allocated, so the offset
4901                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4902                  * The pointer to the struct is put in ppc_r11 (new_lmf).
4903                  * The callee-saved registers are already in the MonoLMF structure
4904                  */
4905                 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4906                 /* ppc_r3 is the result from mono_get_lmf_addr () */
4907                 ppc_store_reg (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4908                 /* new_lmf->previous_lmf = *lmf_addr */
4909                 ppc_load_reg (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4910                 ppc_store_reg (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4911                 /* *(lmf_addr) = r11 */
4912                 ppc_store_reg (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4913                 /* save method info */
4914                 if (cfg->compile_aot)
4915                         // FIXME:
4916                         ppc_load (code, ppc_r0, 0);
4917                 else
4918                         ppc_load (code, ppc_r0, method);
4919                 ppc_store_reg (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4920                 ppc_store_reg (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4921                 /* save the current IP */
4922                 if (cfg->compile_aot) {
4923                         ppc_bl (code, 1);
4924                         ppc_mflr (code, ppc_r0);
4925                 } else {
4926                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4927 #ifdef __mono_ppc64__
4928                         ppc_load_sequence (code, ppc_r0, (gulong)0x0101010101010101L);
4929 #else
4930                         ppc_load_sequence (code, ppc_r0, (gulong)0x01010101L);
4931 #endif
4932                 }
4933                 ppc_store_reg (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4934         }
4935
4936         if (tracing)
4937                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4938
4939         cfg->code_len = code - cfg->native_code;
4940         g_assert (cfg->code_len <= cfg->code_size);
4941         g_free (cinfo);
4942
4943         return code;
4944 }
4945
4946 void
4947 mono_arch_emit_epilog (MonoCompile *cfg)
4948 {
4949         MonoMethod *method = cfg->method;
4950         int pos, i;
4951         int max_epilog_size = 16 + 20*4;
4952         guint8 *code;
4953
4954         if (cfg->method->save_lmf)
4955                 max_epilog_size += 128;
4956         
4957         if (mono_jit_trace_calls != NULL)
4958                 max_epilog_size += 50;
4959
4960         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4961                 max_epilog_size += 50;
4962
4963         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4964                 cfg->code_size *= 2;
4965                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4966                 mono_jit_stats.code_reallocs++;
4967         }
4968
4969         /*
4970          * Keep in sync with OP_JMP
4971          */
4972         code = cfg->native_code + cfg->code_len;
4973
4974         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4975                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4976         }
4977         pos = 0;
4978
4979         if (method->save_lmf) {
4980                 int lmf_offset;
4981                 pos +=  sizeof (MonoLMF);
4982                 lmf_offset = pos;
4983                 /* save the frame reg in r8 */
4984                 ppc_mr (code, ppc_r8, cfg->frame_reg);
4985                 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4986                 /* r5 = previous_lmf */
4987                 ppc_load_reg (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4988                 /* r6 = lmf_addr */
4989                 ppc_load_reg (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4990                 /* *(lmf_addr) = previous_lmf */
4991                 ppc_store_reg (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4992                 /* FIXME: speedup: there is no actual need to restore the registers if
4993                  * we didn't actually change them (idea from Zoltan).
4994                  */
4995                 /* restore iregs */
4996                 ppc_load_multiple_regs (code, ppc_r13, G_STRUCT_OFFSET(MonoLMF, iregs), ppc_r11);
4997                 /* restore fregs */
4998                 /*for (i = 14; i < 32; i++) {
4999                         ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
5000                 }*/
5001                 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
5002                 /* use the saved copy of the frame reg in r8 */
5003                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5004                         ppc_load_reg (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
5005                         ppc_mtlr (code, ppc_r0);
5006                 }
5007                 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
5008         } else {
5009                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
5010                         long return_offset = cfg->stack_usage + PPC_RET_ADDR_OFFSET;
5011                         if (ppc_is_imm16 (return_offset)) {
5012                                 ppc_load_reg (code, ppc_r0, return_offset, cfg->frame_reg);
5013                         } else {
5014                                 ppc_load (code, ppc_r11, return_offset);
5015                                 ppc_load_reg_indexed (code, ppc_r0, cfg->frame_reg, ppc_r11);
5016                         }
5017                         ppc_mtlr (code, ppc_r0);
5018                 }
5019                 if (ppc_is_imm16 (cfg->stack_usage)) {
5020                         int offset = cfg->stack_usage;
5021                         for (i = 13; i <= 31; i++) {
5022                                 if (cfg->used_int_regs & (1 << i))
5023                                         offset -= sizeof (gulong);
5024                         }
5025                         if (cfg->frame_reg != ppc_sp)
5026                                 ppc_mr (code, ppc_r11, cfg->frame_reg);
5027                         /* note r31 (possibly the frame register) is restored last */
5028                         for (i = 13; i <= 31; i++) {
5029                                 if (cfg->used_int_regs & (1 << i)) {
5030                                         ppc_load_reg (code, i, offset, cfg->frame_reg);
5031                                         offset += sizeof (gulong);
5032                                 }
5033                         }
5034                         if (cfg->frame_reg != ppc_sp)
5035                                 ppc_addi (code, ppc_sp, ppc_r11, cfg->stack_usage);
5036                         else
5037                                 ppc_addi (code, ppc_sp, ppc_sp, cfg->stack_usage);
5038                 } else {
5039                         ppc_load (code, ppc_r11, cfg->stack_usage);
5040                         if (cfg->used_int_regs) {
5041                                 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
5042                                 for (i = 31; i >= 13; --i) {
5043                                         if (cfg->used_int_regs & (1 << i)) {
5044                                                 pos += sizeof (gulong);
5045                                                 ppc_load_reg (code, i, -pos, ppc_r11);
5046                                         }
5047                                 }
5048                                 ppc_mr (code, ppc_sp, ppc_r11);
5049                         } else {
5050                                 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
5051                         }
5052                 }
5053
5054         }
5055         ppc_blr (code);
5056
5057         cfg->code_len = code - cfg->native_code;
5058
5059         g_assert (cfg->code_len < cfg->code_size);
5060
5061 }
5062
5063 /* remove once throw_exception_by_name is eliminated */
5064 static int
5065 exception_id_by_name (const char *name)
5066 {
5067         if (strcmp (name, "IndexOutOfRangeException") == 0)
5068                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5069         if (strcmp (name, "OverflowException") == 0)
5070                 return MONO_EXC_OVERFLOW;
5071         if (strcmp (name, "ArithmeticException") == 0)
5072                 return MONO_EXC_ARITHMETIC;
5073         if (strcmp (name, "DivideByZeroException") == 0)
5074                 return MONO_EXC_DIVIDE_BY_ZERO;
5075         if (strcmp (name, "InvalidCastException") == 0)
5076                 return MONO_EXC_INVALID_CAST;
5077         if (strcmp (name, "NullReferenceException") == 0)
5078                 return MONO_EXC_NULL_REF;
5079         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5080                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5081         g_error ("Unknown intrinsic exception %s\n", name);
5082         return 0;
5083 }
5084
5085 void
5086 mono_arch_emit_exceptions (MonoCompile *cfg)
5087 {
5088         MonoJumpInfo *patch_info;
5089         int i;
5090         guint8 *code;
5091         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5092         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5093         int max_epilog_size = 50;
5094
5095         /* count the number of exception infos */
5096      
5097         /* 
5098          * make sure we have enough space for exceptions
5099          * 28 is the simulated call to throw_corlib_exception
5100          */
5101         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5102                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5103                         i = exception_id_by_name (patch_info->data.target);
5104                         if (!exc_throw_found [i]) {
5105                                 max_epilog_size += 28;
5106                                 exc_throw_found [i] = TRUE;
5107                         }
5108                 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
5109                         max_epilog_size += 12;
5110                 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
5111                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5112                         i = exception_id_by_name (ovfj->data.exception);
5113                         if (!exc_throw_found [i]) {
5114                                 max_epilog_size += 28;
5115                                 exc_throw_found [i] = TRUE;
5116                         }
5117                         max_epilog_size += 8;
5118                 }
5119         }
5120
5121         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5122                 cfg->code_size *= 2;
5123                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5124                 mono_jit_stats.code_reallocs++;
5125         }
5126
5127         code = cfg->native_code + cfg->code_len;
5128
5129         /* add code to raise exceptions */
5130         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5131                 switch (patch_info->type) {
5132                 case MONO_PATCH_INFO_BB_OVF: {
5133                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5134                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5135                         /* patch the initial jump */
5136                         ppc_patch (ip, code);
5137                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
5138                         ppc_b (code, 0);
5139                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5140                         /* jump back to the true target */
5141                         ppc_b (code, 0);
5142                         ip = ovfj->data.bb->native_offset + cfg->native_code;
5143                         ppc_patch (code - 4, ip);
5144                         patch_info->type = MONO_PATCH_INFO_NONE;
5145                         break;
5146                 }
5147                 case MONO_PATCH_INFO_EXC_OVF: {
5148                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
5149                         MonoJumpInfo *newji;
5150                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5151                         unsigned char *bcl = code;
5152                         /* patch the initial jump: we arrived here with a call */
5153                         ppc_patch (ip, code);
5154                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
5155                         ppc_b (code, 0);
5156                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
5157                         /* patch the conditional jump to the right handler */
5158                         /* make it processed next */
5159                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
5160                         newji->type = MONO_PATCH_INFO_EXC;
5161                         newji->ip.i = bcl - cfg->native_code;
5162                         newji->data.target = ovfj->data.exception;
5163                         newji->next = patch_info->next;
5164                         patch_info->next = newji;
5165                         patch_info->type = MONO_PATCH_INFO_NONE;
5166                         break;
5167                 }
5168                 case MONO_PATCH_INFO_EXC: {
5169                         MonoClass *exc_class;
5170
5171                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
5172                         i = exception_id_by_name (patch_info->data.target);
5173                         if (exc_throw_pos [i]) {
5174                                 ppc_patch (ip, exc_throw_pos [i]);
5175                                 patch_info->type = MONO_PATCH_INFO_NONE;
5176                                 break;
5177                         } else {
5178                                 exc_throw_pos [i] = code;
5179                         }
5180
5181                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5182                         g_assert (exc_class);
5183
5184                         ppc_patch (ip, code);
5185                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
5186                         ppc_load (code, ppc_r3, exc_class->type_token);
5187                         /* we got here from a conditional call, so the calling ip is set in lr */
5188                         ppc_mflr (code, ppc_r4);
5189                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5190                         patch_info->data.name = "mono_arch_throw_corlib_exception";
5191                         patch_info->ip.i = code - cfg->native_code;
5192                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
5193                                 ppc_load_func (code, ppc_r0, 0);
5194                                 ppc_mtctr (code, ppc_r0);
5195                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5196                         } else {
5197                                 ppc_bl (code, 0);
5198                         }
5199                         break;
5200                 }
5201                 default:
5202                         /* do nothing */
5203                         break;
5204                 }
5205         }
5206
5207         cfg->code_len = code - cfg->native_code;
5208
5209         g_assert (cfg->code_len <= cfg->code_size);
5210 }
5211
5212 #if DEAD_CODE
5213 static int
5214 try_offset_access (void *value, guint32 idx)
5215 {
5216         register void* me __asm__ ("r2");
5217         void ***p = (void***)((char*)me + 284);
5218         int idx1 = idx / 32;
5219         int idx2 = idx % 32;
5220         if (!p [idx1])
5221                 return 0;
5222         if (value != p[idx1][idx2])
5223                 return 0;
5224         return 1;
5225 }
5226 #endif
5227
5228 static void
5229 setup_tls_access (void)
5230 {
5231         guint32 ptk;
5232
5233 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5234         size_t conf_size = 0;
5235         char confbuf[128];
5236 #else
5237         /* FIXME for darwin */
5238         guint32 *ins, *code;
5239         guint32 cmplwi_1023, li_0x48, blr_ins;
5240 #endif
5241
5242         if (tls_mode == TLS_MODE_FAILED)
5243                 return;
5244         if (g_getenv ("MONO_NO_TLS")) {
5245                 tls_mode = TLS_MODE_FAILED;
5246                 return;
5247         }
5248
5249         if (tls_mode == TLS_MODE_DETECT) {
5250 #if defined(__linux__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
5251                 conf_size = confstr ( _CS_GNU_LIBPTHREAD_VERSION, confbuf, sizeof(confbuf));
5252                 if ((conf_size > 4) && (strncmp (confbuf, "NPTL", 4) == 0))
5253                         tls_mode = TLS_MODE_NPTL;
5254                 else
5255                         tls_mode = TLS_MODE_LTHREADS;
5256 #else
5257                 ins = (guint32*)pthread_getspecific;
5258                 /* uncond branch to the real method */
5259                 if ((*ins >> 26) == 18) {
5260                         gint32 val;
5261                         val = (*ins & ~3) << 6;
5262                         val >>= 6;
5263                         if (*ins & 2) {
5264                                 /* absolute */
5265                                 ins = (guint32*)(long)val;
5266                         } else {
5267                                 ins = (guint32*) ((char*)ins + val);
5268                         }
5269                 }
5270                 code = &cmplwi_1023;
5271                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5272                 code = &li_0x48;
5273                 ppc_li (code, ppc_r4, 0x48);
5274                 code = &blr_ins;
5275                 ppc_blr (code);
5276                 if (*ins == cmplwi_1023) {
5277                         int found_lwz_284 = 0;
5278                         for (ptk = 0; ptk < 20; ++ptk) {
5279                                 ++ins;
5280                                 if (!*ins || *ins == blr_ins)
5281                                         break;
5282                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5283                                         found_lwz_284 = 1;
5284                                         break;
5285                                 }
5286                         }
5287                         if (!found_lwz_284) {
5288                                 tls_mode = TLS_MODE_FAILED;
5289                                 return;
5290                         }
5291                         tls_mode = TLS_MODE_LTHREADS;
5292                 } else if (*ins == li_0x48) {
5293                         ++ins;
5294                         /* uncond branch to the real method */
5295                         if ((*ins >> 26) == 18) {
5296                                 gint32 val;
5297                                 val = (*ins & ~3) << 6;
5298                                 val >>= 6;
5299                                 if (*ins & 2) {
5300                                         /* absolute */
5301                                         ins = (guint32*)(long)val;
5302                                 } else {
5303                                         ins = (guint32*) ((char*)ins + val);
5304                                 }
5305                                 code = (guint32*)&val;
5306                                 ppc_li (code, ppc_r0, 0x7FF2);
5307                                 if (ins [1] == val) {
5308                                         /* Darwin on G4, implement */
5309                                         tls_mode = TLS_MODE_FAILED;
5310                                         return;
5311                                 } else {
5312                                         code = (guint32*)&val;
5313                                         ppc_mfspr (code, ppc_r3, 104);
5314                                         if (ins [1] != val) {
5315                                                 tls_mode = TLS_MODE_FAILED;
5316                                                 return;
5317                                         }
5318                                         tls_mode = TLS_MODE_DARWIN_G5;
5319                                 }
5320                         } else {
5321                                 tls_mode = TLS_MODE_FAILED;
5322                                 return;
5323                         }
5324                 } else {
5325                         tls_mode = TLS_MODE_FAILED;
5326                         return;
5327                 }
5328 #endif
5329         }
5330         if ((monodomain_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5331                 monodomain_key = mono_domain_get_tls_offset();
5332         }
5333         /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5334            mono_domain_get_tls_offset returning -1) then use keyed access. */
5335         if (monodomain_key == -1) {
5336                 ptk = mono_domain_get_tls_key ();
5337                 if (ptk < 1024) {
5338                         ptk = mono_pthread_key_for_tls (ptk);
5339                         if (ptk < 1024) {
5340                                 monodomain_key = ptk;
5341                         }
5342                 }
5343         }
5344
5345         if ((lmf_pthread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5346                 lmf_pthread_key = mono_get_lmf_addr_tls_offset();
5347         }
5348         /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5349            mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5350         if (lmf_pthread_key == -1) {
5351                 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5352                 if (ptk < 1024) {
5353                         /*g_print ("MonoLMF at: %d\n", ptk);*/
5354                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5355                                 init_tls_failed = 1;
5356                                 return;
5357                         }*/
5358                         lmf_pthread_key = ptk;
5359                 }
5360         }
5361
5362         if ((monothread_key == -1) && (tls_mode == TLS_MODE_NPTL)) {
5363                 monothread_key = mono_thread_get_tls_offset();
5364         }
5365         /* if not TLS_MODE_NPTL or local dynamic (as indicated by
5366            mono_get_lmf_addr_tls_offset returning -1) then use keyed access. */
5367         if (monothread_key == -1) {
5368                 ptk = mono_thread_get_tls_key ();
5369                 if (ptk < 1024) {
5370                         ptk = mono_pthread_key_for_tls (ptk);
5371                         if (ptk < 1024) {
5372                                 monothread_key = ptk;
5373                                 /*g_print ("thread inited: %d\n", ptk);*/
5374                         }
5375                 } else {
5376                         /*g_print ("thread not inited yet %d\n", ptk);*/
5377                 }
5378         }
5379 }
5380
5381 void
5382 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5383 {
5384         setup_tls_access ();
5385 }
5386
5387 void
5388 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5389 {
5390 }
5391
5392 #ifdef MONO_ARCH_HAVE_IMT
5393
5394 #define CMP_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 4)
5395 #define BR_SIZE 4
5396 #define LOADSTORE_SIZE 4
5397 #define JUMP_IMM_SIZE 12
5398 #define JUMP_IMM32_SIZE (PPC_LOAD_SEQUENCE_LENGTH + 8)
5399 #define ENABLE_WRONG_METHOD_CHECK 0
5400
5401 /*
5402  * LOCKING: called with the domain lock held
5403  */
5404 gpointer
5405 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5406         gpointer fail_tramp)
5407 {
5408         int i;
5409         int size = 0;
5410         guint8 *code, *start;
5411
5412         for (i = 0; i < count; ++i) {
5413                 MonoIMTCheckItem *item = imt_entries [i];
5414                 if (item->is_equals) {
5415                         if (item->check_target_idx) {
5416                                 if (!item->compare_done)
5417                                         item->chunk_size += CMP_SIZE;
5418                                 if (item->has_target_code)
5419                                         item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5420                                 else
5421                                         item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
5422                         } else {
5423                                 if (fail_tramp) {
5424                                         item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5425                                         if (!item->has_target_code)
5426                                                 item->chunk_size += LOADSTORE_SIZE;
5427                                 } else {
5428                                         item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5429 #if ENABLE_WRONG_METHOD_CHECK
5430                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5431 #endif
5432                                 }
5433                         }
5434                 } else {
5435                         item->chunk_size += CMP_SIZE + BR_SIZE;
5436                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5437                 }
5438                 size += item->chunk_size;
5439         }
5440         if (fail_tramp) {
5441                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5442         } else {
5443                 /* the initial load of the vtable address */
5444                 size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5445                 code = mono_domain_code_reserve (domain, size);
5446         }
5447         start = code;
5448         if (!fail_tramp) {
5449                 /*
5450                  * We need to save and restore r11 because it might be
5451                  * used by the caller as the vtable register, so
5452                  * clobbering it will trip up the magic trampoline.
5453                  *
5454                  * FIXME: Get rid of this by making sure that r11 is
5455                  * not used as the vtable register in interface calls.
5456                  */
5457                 ppc_store_reg (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5458                 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5459         }
5460         for (i = 0; i < count; ++i) {
5461                 MonoIMTCheckItem *item = imt_entries [i];
5462                 item->code_target = code;
5463                 if (item->is_equals) {
5464                         if (item->check_target_idx) {
5465                                 if (!item->compare_done) {
5466                                         ppc_load (code, ppc_r0, (gsize)item->key);
5467                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5468                                 }
5469                                 item->jmp_code = code;
5470                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5471                                 if (item->has_target_code) {
5472                                         ppc_load (code, ppc_r0, item->value.target_code);
5473                                 } else {
5474                                         ppc_load_reg (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5475                                         ppc_load_reg (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5476                                 }
5477                                 ppc_mtctr (code, ppc_r0);
5478                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5479                         } else {
5480                                 if (fail_tramp) {
5481                                         ppc_load (code, ppc_r0, (gulong)item->key);
5482                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5483                                         item->jmp_code = code;
5484                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5485                                         if (item->has_target_code) {
5486                                                 ppc_load (code, ppc_r0, item->value.target_code);
5487                                         } else {
5488                                                 g_assert (vtable);
5489                                                 ppc_load (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
5490                                                 ppc_load_reg_indexed (code, ppc_r0, 0, ppc_r0);
5491                                         }
5492                                         ppc_mtctr (code, ppc_r0);
5493                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5494                                         ppc_patch (item->jmp_code, code);
5495                                         ppc_load (code, ppc_r0, fail_tramp);
5496                                         ppc_mtctr (code, ppc_r0);
5497                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5498                                         item->jmp_code = NULL;
5499                                 } else {
5500                                         /* enable the commented code to assert on wrong method */
5501 #if ENABLE_WRONG_METHOD_CHECK
5502                                         ppc_load (code, ppc_r0, (guint32)item->key);
5503                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5504                                         item->jmp_code = code;
5505                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5506 #endif
5507                                         ppc_load_reg (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5508                                         ppc_load_reg (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5509                                         ppc_mtctr (code, ppc_r0);
5510                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5511 #if ENABLE_WRONG_METHOD_CHECK
5512                                         ppc_patch (item->jmp_code, code);
5513                                         ppc_break (code);
5514                                         item->jmp_code = NULL;
5515 #endif
5516                                 }
5517                         }
5518                 } else {
5519                         ppc_load (code, ppc_r0, (gulong)item->key);
5520                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5521                         item->jmp_code = code;
5522                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5523                 }
5524         }
5525         /* patch the branches to get to the target items */
5526         for (i = 0; i < count; ++i) {
5527                 MonoIMTCheckItem *item = imt_entries [i];
5528                 if (item->jmp_code) {
5529                         if (item->check_target_idx) {
5530                                 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5531                         }
5532                 }
5533         }
5534
5535         if (!fail_tramp)
5536                 mono_stats.imt_thunks_size += code - start;
5537         g_assert (code - start <= size);
5538         mono_arch_flush_icache (start, size);
5539         return start;
5540 }
5541
5542 MonoMethod*
5543 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
5544 {
5545         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5546 }
5547
5548 MonoObject*
5549 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
5550 {
5551         return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
5552 }
5553 #endif
5554
5555 MonoVTable*
5556 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
5557 {
5558         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5559 }
5560
5561 MonoInst*
5562 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5563 {
5564         /* FIXME: */
5565         return NULL;
5566 }
5567
5568 gboolean
5569 mono_arch_print_tree (MonoInst *tree, int arity)
5570 {
5571         return 0;
5572 }
5573
5574 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5575 {
5576         MonoInst* ins;
5577
5578         setup_tls_access ();
5579         if (monodomain_key == -1)
5580                 return NULL;
5581         
5582         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5583         ins->inst_offset = monodomain_key;
5584         return ins;
5585 }
5586
5587 MonoInst* 
5588 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5589 {
5590         MonoInst* ins;
5591
5592         setup_tls_access ();
5593         if (monothread_key == -1)
5594                 return NULL;
5595         
5596         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5597         ins->inst_offset = monothread_key;
5598         return ins;
5599 }
5600
5601 gpointer
5602 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5603 {
5604         if (reg == ppc_r1)
5605                 return MONO_CONTEXT_GET_SP (ctx);
5606
5607         g_assert (reg >= ppc_r13);
5608
5609         return (gpointer)ctx->regs [reg - ppc_r13];
5610 }
5611
5612 guint32
5613 mono_arch_get_patch_offset (guint8 *code)
5614 {
5615         return 0;
5616 }
5617
5618 /*
5619  * mono_aot_emit_load_got_addr:
5620  *
5621  *   Emit code to load the got address.
5622  * On PPC, the result is placed into r30.
5623  */
5624 guint8*
5625 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
5626 {
5627         ppc_bl (code, 1);
5628         ppc_mflr (code, ppc_r30);
5629         if (cfg)
5630                 mono_add_patch_info (cfg, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5631         else
5632                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
5633         /* arch_emit_got_address () patches this */
5634 #if defined(TARGET_POWERPC64)
5635         ppc_nop (code);
5636         ppc_nop (code);
5637         ppc_nop (code);
5638         ppc_nop (code);
5639 #else
5640         ppc_load32 (code, ppc_r0, 0);
5641         ppc_add (code, ppc_r30, ppc_r30, ppc_r0);
5642 #endif
5643
5644         return code;
5645 }
5646
5647 /*
5648  * mono_ppc_emit_load_aotconst:
5649  *
5650  *   Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
5651  * TARGET from the mscorlib GOT in full-aot code.
5652  * On PPC, the GOT address is assumed to be in r30, and the result is placed into 
5653  * r11.
5654  */
5655 guint8*
5656 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
5657 {
5658         /* Load the mscorlib got address */
5659         ppc_load_reg (code, ppc_r11, sizeof (gpointer), ppc_r30);
5660         *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
5661         /* arch_emit_got_access () patches this */
5662         ppc_load32 (code, ppc_r0, 0);
5663         ppc_load_reg_indexed (code, ppc_r11, ppc_r11, ppc_r0);
5664
5665         return code;
5666 }