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