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