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