Moved ProviderCollectionTest.cs from System assembly to System.Configuration.
[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         gint32 *offsets;
1060         guint32 locals_stack_size, locals_stack_align;
1061
1062         allocate_tailcall_valuetype_addrs (m);
1063
1064         m->flags |= MONO_CFG_HAS_SPILLUP;
1065
1066         /* allow room for the vararg method args: void* and long/double */
1067         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1068                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1069         /* this is bug #60332: remove when #59509 is fixed, so no weird vararg 
1070          * call convs needs to be handled this way.
1071          */
1072         if (m->flags & MONO_CFG_HAS_VARARGS)
1073                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1074         /* gtk-sharp and other broken code will dllimport vararg functions even with
1075          * non-varargs signatures. Since there is little hope people will get this right
1076          * we assume they won't.
1077          */
1078         if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1079                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
1080
1081         header = mono_method_get_header (m->method);
1082
1083         /* 
1084          * We use the frame register also for any method that has
1085          * exception clauses. This way, when the handlers are called,
1086          * the code will reference local variables using the frame reg instead of
1087          * the stack pointer: if we had to restore the stack pointer, we'd
1088          * corrupt the method frames that are already on the stack (since
1089          * filters get called before stack unwinding happens) when the filter
1090          * code would call any method (this also applies to finally etc.).
1091          */ 
1092         if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1093                 frame_reg = ppc_r31;
1094         m->frame_reg = frame_reg;
1095         if (frame_reg != ppc_sp) {
1096                 m->used_int_regs |= 1 << frame_reg;
1097         }
1098
1099         sig = mono_method_signature (m->method);
1100         
1101         offset = 0;
1102         curinst = 0;
1103         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1104                 m->ret->opcode = OP_REGVAR;
1105                 m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1106         } else {
1107                 /* FIXME: handle long values? */
1108                 switch (mono_type_get_underlying_type (sig->ret)->type) {
1109                 case MONO_TYPE_VOID:
1110                         break;
1111                 case MONO_TYPE_R4:
1112                 case MONO_TYPE_R8:
1113                         m->ret->opcode = OP_REGVAR;
1114                         m->ret->inst_c0 = m->ret->dreg = ppc_f1;
1115                         break;
1116                 default:
1117                         m->ret->opcode = OP_REGVAR;
1118                         m->ret->inst_c0 = m->ret->dreg = ppc_r3;
1119                         break;
1120                 }
1121         }
1122         /* local vars are at a positive offset from the stack pointer */
1123         /* 
1124          * also note that if the function uses alloca, we use ppc_r31
1125          * to point at the local variables.
1126          */
1127         offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
1128         /* align the offset to 16 bytes: not sure this is needed here  */
1129         //offset += 16 - 1;
1130         //offset &= ~(16 - 1);
1131
1132         /* add parameter area size for called functions */
1133         offset += m->param_area;
1134         offset += 16 - 1;
1135         offset &= ~(16 - 1);
1136
1137         /* allow room to save the return value */
1138         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
1139                 offset += 8;
1140
1141         /* the MonoLMF structure is stored just below the stack pointer */
1142
1143 #if 0
1144         /* this stuff should not be needed on ppc and the new jit,
1145          * because a call on ppc to the handlers doesn't change the 
1146          * stack pointer and the jist doesn't manipulate the stack pointer
1147          * for operations involving valuetypes.
1148          */
1149         /* reserve space to store the esp */
1150         offset += sizeof (gpointer);
1151
1152         /* this is a global constant */
1153         mono_exc_esp_offset = offset;
1154 #endif
1155         if (sig->call_convention == MONO_CALL_VARARG) {
1156                 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
1157         }
1158
1159         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1160                 offset += sizeof(gpointer) - 1;
1161                 offset &= ~(sizeof(gpointer) - 1);
1162
1163                 if (m->new_ir) {
1164                         m->vret_addr->opcode = OP_REGOFFSET;
1165                         m->vret_addr->inst_basereg = frame_reg;
1166                         m->vret_addr->inst_offset = offset;
1167
1168                         if (G_UNLIKELY (m->verbose_level > 1)) {
1169                                 printf ("vret_addr =");
1170                                 mono_print_ins (m->vret_addr);
1171                         }
1172                 } else {
1173                         inst = m->ret;
1174                         inst->inst_offset = offset;
1175                         inst->opcode = OP_REGOFFSET;
1176                         inst->inst_basereg = frame_reg;
1177                 }
1178
1179                 offset += sizeof(gpointer);
1180                 if (sig->call_convention == MONO_CALL_VARARG)
1181                         m->sig_cookie += sizeof (gpointer);
1182         }
1183
1184         offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
1185         if (locals_stack_align) {
1186                 offset += (locals_stack_align - 1);
1187                 offset &= ~(locals_stack_align - 1);
1188         }
1189         for (i = m->locals_start; i < m->num_varinfo; i++) {
1190                 if (offsets [i] != -1) {
1191                         MonoInst *inst = m->varinfo [i];
1192                         inst->opcode = OP_REGOFFSET;
1193                         inst->inst_basereg = frame_reg;
1194                         inst->inst_offset = offset + offsets [i];
1195                         /*
1196                         g_print ("allocating local %d (%s) to %d\n",
1197                                 i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
1198                         */
1199                 }
1200         }
1201         offset += locals_stack_size;
1202
1203         curinst = 0;
1204         if (sig->hasthis) {
1205                 inst = m->args [curinst];
1206                 if (inst->opcode != OP_REGVAR) {
1207                         inst->opcode = OP_REGOFFSET;
1208                         inst->inst_basereg = frame_reg;
1209                         offset += sizeof (gpointer) - 1;
1210                         offset &= ~(sizeof (gpointer) - 1);
1211                         inst->inst_offset = offset;
1212                         offset += sizeof (gpointer);
1213                         if (sig->call_convention == MONO_CALL_VARARG)
1214                                 m->sig_cookie += sizeof (gpointer);
1215                 }
1216                 curinst++;
1217         }
1218
1219         for (i = 0; i < sig->param_count; ++i) {
1220                 inst = m->args [curinst];
1221                 if (inst->opcode != OP_REGVAR) {
1222                         inst->opcode = OP_REGOFFSET;
1223                         inst->inst_basereg = frame_reg;
1224                         if (sig->pinvoke) {
1225                                 size = mono_type_native_stack_size (sig->params [i], &align);
1226                                 inst->backend.is_pinvoke = 1;
1227                         } else {
1228                                 size = mono_type_size (sig->params [i], &align);
1229                         }
1230                         offset += align - 1;
1231                         offset &= ~(align - 1);
1232                         inst->inst_offset = offset;
1233                         offset += size;
1234                         if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) 
1235                                 m->sig_cookie += size;
1236                 }
1237                 curinst++;
1238         }
1239
1240         /* align the offset to 16 bytes */
1241         offset += 16 - 1;
1242         offset &= ~(16 - 1);
1243
1244         /* change sign? */
1245         m->stack_offset = offset;
1246
1247         if (m->new_ir && sig->call_convention == MONO_CALL_VARARG) {
1248                 CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
1249
1250                 m->sig_cookie = cinfo->sig_cookie.offset;
1251
1252                 g_free(cinfo);
1253         }
1254 }
1255
1256 void
1257 mono_arch_create_vars (MonoCompile *cfg)
1258 {
1259         MonoMethodSignature *sig = mono_method_signature (cfg->method);
1260
1261         if (cfg->new_ir && MONO_TYPE_ISSTRUCT (sig->ret)) {
1262                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1263         }
1264 }
1265
1266 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1267  * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
1268  */
1269
1270 /* 
1271  * take the arguments and generate the arch-specific
1272  * instructions to properly call the function in call.
1273  * This includes pushing, moving arguments to the right register
1274  * etc.
1275  * Issue: who does the spilling if needed, and when?
1276  */
1277 MonoCallInst*
1278 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1279         MonoInst *arg, *in;
1280         MonoMethodSignature *sig;
1281         int i, n;
1282         CallInfo *cinfo;
1283         ArgInfo *ainfo;
1284
1285         sig = call->signature;
1286         n = sig->param_count + sig->hasthis;
1287         
1288         cinfo = calculate_sizes (sig, sig->pinvoke);
1289         if (cinfo->struct_ret)
1290                 call->used_iregs |= 1 << cinfo->struct_ret;
1291
1292         for (i = 0; i < n; ++i) {
1293                 ainfo = cinfo->args + i;
1294                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1295                         MonoInst *sig_arg;
1296                         cfg->disable_aot = TRUE;
1297                                 
1298                         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1299                         sig_arg->inst_p0 = call->signature;
1300                         
1301                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1302                         arg->inst_imm = cinfo->sig_cookie.offset;
1303                         arg->inst_left = sig_arg;
1304                         arg->inst_call = call;
1305                         /* prepend, so they get reversed */
1306                         arg->next = call->out_args;
1307                         call->out_args = arg;
1308                 }
1309                 if (is_virtual && i == 0) {
1310                         /* the argument will be attached to the call instrucion */
1311                         in = call->args [i];
1312                         call->used_iregs |= 1 << ainfo->reg;
1313                 } else {
1314                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1315                         in = call->args [i];
1316                         arg->cil_code = in->cil_code;
1317                         arg->inst_left = in;
1318                         arg->inst_call = call;
1319                         arg->type = in->type;
1320                         /* prepend, so they get reversed */
1321                         arg->next = call->out_args;
1322                         call->out_args = arg;
1323                         if (ainfo->regtype == RegTypeGeneral) {
1324                                 arg->backend.reg3 = ainfo->reg;
1325                                 call->used_iregs |= 1 << ainfo->reg;
1326                                 if (arg->type == STACK_I8)
1327                                         call->used_iregs |= 1 << (ainfo->reg + 1);
1328                         } else if (ainfo->regtype == RegTypeStructByAddr) {
1329                                 if (ainfo->offset) {
1330                                         MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1331                                         arg->opcode = OP_OUTARG_MEMBASE;
1332                                         ai->reg = ainfo->reg;
1333                                         ai->size = sizeof (gpointer);
1334                                         ai->offset = ainfo->offset;
1335                                         arg->backend.data = ai;
1336                                 } else {
1337                                         arg->backend.reg3 = ainfo->reg;
1338                                         call->used_iregs |= 1 << ainfo->reg;
1339                                 }
1340                         } else if (ainfo->regtype == RegTypeStructByVal) {
1341                                 int cur_reg;
1342                                 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1343                                 /* mark the used regs */
1344                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1345                                         call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1346                                 }
1347                                 arg->opcode = OP_OUTARG_VT;
1348                                 ai->reg = ainfo->reg;
1349                                 ai->size = ainfo->size;
1350                                 ai->vtsize = ainfo->vtsize;
1351                                 ai->offset = ainfo->offset;
1352                                 arg->backend.data = ai;
1353                         } else if (ainfo->regtype == RegTypeBase) {
1354                                 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1355                                 arg->opcode = OP_OUTARG_MEMBASE;
1356                                 ai->reg = ainfo->reg;
1357                                 ai->size = ainfo->size;
1358                                 ai->offset = ainfo->offset;
1359                                 arg->backend.data = ai;
1360                         } else if (ainfo->regtype == RegTypeFP) {
1361                                 arg->opcode = OP_OUTARG_R8;
1362                                 arg->backend.reg3 = ainfo->reg;
1363                                 call->used_fregs |= 1 << ainfo->reg;
1364                                 if (ainfo->size == 4) {
1365                                         arg->opcode = OP_OUTARG_R8;
1366                                         /* we reduce the precision */
1367                                         /*MonoInst *conv;
1368                                         MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1369                                         conv->inst_left = arg->inst_left;
1370                                         arg->inst_left = conv;*/
1371                                 }
1372                         } else {
1373                                 g_assert_not_reached ();
1374                         }
1375                 }
1376         }
1377         /*
1378          * Reverse the call->out_args list.
1379          */
1380         {
1381                 MonoInst *prev = NULL, *list = call->out_args, *next;
1382                 while (list) {
1383                         next = list->next;
1384                         list->next = prev;
1385                         prev = list;
1386                         list = next;
1387                 }
1388                 call->out_args = prev;
1389         }
1390
1391         call->stack_usage = cinfo->stack_usage;
1392         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1393         cfg->flags |= MONO_CFG_HAS_CALLS;
1394         /* 
1395          * should set more info in call, such as the stack space
1396          * used by the args that needs to be added back to esp
1397          */
1398
1399         g_free (cinfo);
1400         return call;
1401 }
1402
1403 static void
1404 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1405 {
1406         int sig_reg = mono_alloc_ireg (cfg);
1407
1408         MONO_EMIT_NEW_ICONST (cfg, sig_reg, call->signature);
1409         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1410                         ppc_r1, cinfo->sig_cookie.offset, sig_reg);
1411 }
1412
1413 void
1414 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1415 {
1416         MonoInst *in, *ins;
1417         MonoMethodSignature *sig;
1418         int i, n;
1419         CallInfo *cinfo;
1420
1421         sig = call->signature;
1422         n = sig->param_count + sig->hasthis;
1423         
1424         cinfo = calculate_sizes (sig, sig->pinvoke);
1425
1426         for (i = 0; i < n; ++i) {
1427                 ArgInfo *ainfo = cinfo->args + i;
1428                 MonoType *t;
1429
1430                 if (i >= sig->hasthis)
1431                         t = sig->params [i - sig->hasthis];
1432                 else
1433                         t = &mono_defaults.int_class->byval_arg;
1434                 t = mono_type_get_underlying_type (t);
1435
1436                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1437                         emit_sig_cookie (cfg, call, cinfo);
1438
1439                 in = call->args [i];
1440
1441                 if (ainfo->regtype == RegTypeGeneral) {
1442                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1443                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1444                                 ins->dreg = mono_alloc_ireg (cfg);
1445                                 ins->sreg1 = in->dreg + 1;
1446                                 MONO_ADD_INS (cfg->cbb, ins);
1447                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1448
1449                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1450                                 ins->dreg = mono_alloc_ireg (cfg);
1451                                 ins->sreg1 = in->dreg + 2;
1452                                 MONO_ADD_INS (cfg->cbb, ins);
1453                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1454                         } else {
1455                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1456                                 ins->dreg = mono_alloc_ireg (cfg);
1457                                 ins->sreg1 = in->dreg;
1458                                 MONO_ADD_INS (cfg->cbb, ins);
1459
1460                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1461                         }
1462                 } else if (ainfo->regtype == RegTypeStructByAddr) {
1463                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1464                         ins->opcode = OP_OUTARG_VT;
1465                         ins->sreg1 = in->dreg;
1466                         ins->klass = in->klass;
1467                         ins->inst_p0 = call;
1468                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1469                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1470                         MONO_ADD_INS (cfg->cbb, ins);
1471                 } else if (ainfo->regtype == RegTypeStructByVal) {
1472                         /* this is further handled in mono_arch_emit_outarg_vt () */
1473                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1474                         ins->opcode = OP_OUTARG_VT;
1475                         ins->sreg1 = in->dreg;
1476                         ins->klass = in->klass;
1477                         ins->inst_p0 = call;
1478                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1479                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1480                         MONO_ADD_INS (cfg->cbb, ins);
1481                 } else if (ainfo->regtype == RegTypeBase) {
1482                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1483                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1484                         } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1485                                 if (t->type == MONO_TYPE_R8)
1486                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1487                                 else
1488                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1489                         } else {
1490                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, in->dreg);
1491                         }
1492                 } else if (ainfo->regtype == RegTypeFP) {
1493                         if (t->type == MONO_TYPE_VALUETYPE) {
1494                                 /* this is further handled in mono_arch_emit_outarg_vt () */
1495                                 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1496                                 ins->opcode = OP_OUTARG_VT;
1497                                 ins->sreg1 = in->dreg;
1498                                 ins->klass = in->klass;
1499                                 ins->inst_p0 = call;
1500                                 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1501                                 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1502                                 MONO_ADD_INS (cfg->cbb, ins);
1503
1504                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1505                         } else {
1506                                 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1507                                 ins->dreg = mono_alloc_freg (cfg);
1508                                 ins->sreg1 = in->dreg;
1509                                 MONO_ADD_INS (cfg->cbb, ins);
1510
1511                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, TRUE);
1512                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1513                         }
1514                 } else {
1515                         g_assert_not_reached ();
1516                 }
1517         }
1518
1519         /* Emit the signature cookie in the case that there is no
1520            additional argument */
1521         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1522                 emit_sig_cookie (cfg, call, cinfo);
1523
1524         if (cinfo->struct_ret) {
1525                 MonoInst *vtarg;
1526
1527                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1528                 vtarg->sreg1 = call->vret_var->dreg;
1529                 vtarg->dreg = mono_alloc_preg (cfg);
1530                 MONO_ADD_INS (cfg->cbb, vtarg);
1531
1532                 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1533         }
1534
1535         call->stack_usage = cinfo->stack_usage;
1536         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1537         cfg->flags |= MONO_CFG_HAS_CALLS;
1538
1539         g_free (cinfo);
1540 }
1541
1542 void
1543 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1544 {
1545         MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1546         ArgInfo *ainfo = ins->inst_p1;
1547         int ovf_size = ainfo->vtsize;
1548         int doffset = ainfo->offset;
1549         int i, soffset, dreg;
1550
1551         if (ainfo->regtype == RegTypeStructByVal) {
1552                 guint32 size;
1553                 soffset = 0;
1554                 /*
1555                   Darwin needs some special handling for 1 and 2 byte arguments
1556                 */
1557 #ifdef __APPLE__
1558                 g_assert (ins->klass);
1559                 size =  mono_class_native_size (ins->klass, NULL);
1560                 if (size == 2 || size == 1) {
1561                         int tmpr = mono_alloc_ireg (cfg);
1562                         if (size == 1)
1563                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmpr, src->dreg, soffset);
1564                         else
1565                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmpr, src->dreg, soffset);
1566                         dreg = mono_alloc_ireg (cfg);
1567                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, dreg, tmpr);
1568                         mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, FALSE);
1569                 } else
1570 #endif
1571                         for (i = 0; i < ainfo->size; ++i) {
1572                                 dreg = mono_alloc_ireg (cfg);
1573                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1574                                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1575                                 soffset += sizeof (gpointer);
1576                         }
1577                 if (ovf_size != 0)
1578                         mini_emit_memcpy2 (cfg, ppc_r1, doffset + soffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1579         } else if (ainfo->regtype == RegTypeFP) {
1580                 int tmpr = mono_alloc_freg (cfg);
1581                 if (ainfo->size == 4)
1582                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1583                 else
1584                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1585                 dreg = mono_alloc_freg (cfg);
1586                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1587                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1588         } else {
1589                 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1590                 MonoInst *load;
1591                 guint32 size;
1592
1593                 /* FIXME: alignment? */
1594                 if (call->signature->pinvoke) {
1595                         size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1596                         vtcopy->backend.is_pinvoke = 1;
1597                 } else {
1598                         size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1599                 }
1600                 if (size > 0)
1601                         g_assert (ovf_size > 0);
1602
1603                 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1604                 mini_emit_memcpy2 (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1605
1606                 if (ainfo->offset)
1607                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ppc_r1, ainfo->offset, load->dreg);
1608                 else
1609                         mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1610         }
1611 }
1612
1613 void
1614 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1615 {
1616         MonoType *ret = mono_type_get_underlying_type (mono_method_signature (method)->ret);
1617
1618         if (!ret->byref) {
1619                 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1620                         MonoInst *ins;
1621
1622                         MONO_INST_NEW (cfg, ins, OP_SETLRET);
1623                         ins->sreg1 = val->dreg + 1;
1624                         ins->sreg2 = val->dreg + 2;
1625                         MONO_ADD_INS (cfg->cbb, ins);
1626                         return;
1627                 }
1628                 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1629                         MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1630                         return;
1631                 }
1632         }
1633         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1634 }
1635
1636 /* FIXME: this is just a useless hint: fix the interface to include the opcode */
1637 gboolean
1638 mono_arch_is_inst_imm (gint64 imm)
1639 {
1640        return TRUE;
1641 }
1642
1643 /*
1644  * Allow tracing to work with this interface (with an optional argument)
1645  */
1646
1647 void*
1648 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1649 {
1650         guchar *code = p;
1651
1652         ppc_load (code, ppc_r3, cfg->method);
1653         ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1654         ppc_load (code, ppc_r0, func);
1655         ppc_mtlr (code, ppc_r0);
1656         ppc_blrl (code);
1657         return code;
1658 }
1659
1660 enum {
1661         SAVE_NONE,
1662         SAVE_STRUCT,
1663         SAVE_ONE,
1664         SAVE_TWO,
1665         SAVE_FP
1666 };
1667
1668 void*
1669 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1670 {
1671         guchar *code = p;
1672         int save_mode = SAVE_NONE;
1673         int offset;
1674         MonoMethod *method = cfg->method;
1675         int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1676         int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1677         save_offset += 15;
1678         save_offset &= ~15;
1679         
1680         offset = code - cfg->native_code;
1681         /* we need about 16 instructions */
1682         if (offset > (cfg->code_size - 16 * 4)) {
1683                 cfg->code_size *= 2;
1684                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1685                 code = cfg->native_code + offset;
1686         }
1687 handle_enum:
1688         switch (rtype) {
1689         case MONO_TYPE_VOID:
1690                 /* special case string .ctor icall */
1691                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1692                         save_mode = SAVE_ONE;
1693                 else
1694                         save_mode = SAVE_NONE;
1695                 break;
1696         case MONO_TYPE_I8:
1697         case MONO_TYPE_U8:
1698                 save_mode = SAVE_TWO;
1699                 break;
1700         case MONO_TYPE_R4:
1701         case MONO_TYPE_R8:
1702                 save_mode = SAVE_FP;
1703                 break;
1704         case MONO_TYPE_VALUETYPE:
1705                 save_mode = SAVE_STRUCT;
1706                 break;
1707         default:
1708                 save_mode = SAVE_ONE;
1709                 break;
1710         }
1711
1712         switch (save_mode) {
1713         case SAVE_TWO:
1714                 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1715                 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1716                 if (enable_arguments) {
1717                         ppc_mr (code, ppc_r5, ppc_r4);
1718                         ppc_mr (code, ppc_r4, ppc_r3);
1719                 }
1720                 break;
1721         case SAVE_ONE:
1722                 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1723                 if (enable_arguments) {
1724                         ppc_mr (code, ppc_r4, ppc_r3);
1725                 }
1726                 break;
1727         case SAVE_FP:
1728                 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1729                 if (enable_arguments) {
1730                         /* FIXME: what reg?  */
1731                         ppc_fmr (code, ppc_f3, ppc_f1);
1732                         ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1733                         ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1734                 }
1735                 break;
1736         case SAVE_STRUCT:
1737                 if (enable_arguments) {
1738                         /* FIXME: get the actual address  */
1739                         ppc_mr (code, ppc_r4, ppc_r3);
1740                 }
1741                 break;
1742         case SAVE_NONE:
1743         default:
1744                 break;
1745         }
1746
1747         ppc_load (code, ppc_r3, cfg->method);
1748         ppc_load (code, ppc_r0, func);
1749         ppc_mtlr (code, ppc_r0);
1750         ppc_blrl (code);
1751
1752         switch (save_mode) {
1753         case SAVE_TWO:
1754                 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1755                 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1756                 break;
1757         case SAVE_ONE:
1758                 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1759                 break;
1760         case SAVE_FP:
1761                 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1762                 break;
1763         case SAVE_NONE:
1764         default:
1765                 break;
1766         }
1767
1768         return code;
1769 }
1770 /*
1771  * Conditional branches have a small offset, so if it is likely overflowed,
1772  * we do a branch to the end of the method (uncond branches have much larger
1773  * offsets) where we perform the conditional and jump back unconditionally.
1774  * It's slightly slower, since we add two uncond branches, but it's very simple
1775  * with the current patch implementation and such large methods are likely not
1776  * going to be perf critical anyway.
1777  */
1778 typedef struct {
1779         union {
1780                 MonoBasicBlock *bb;
1781                 const char *exception;
1782         } data;
1783         guint32 ip_offset;
1784         guint16 b0_cond;
1785         guint16 b1_cond;
1786 } MonoOvfJump;
1787
1788 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1789 if (ins->flags & MONO_INST_BRLABEL) { \
1790         if (0 && ins->inst_i0->inst_c0) { \
1791                 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff);  \
1792         } else { \
1793                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1794                 ppc_bc (code, (b0), (b1), 0);   \
1795         } \
1796 } else { \
1797         if (0 && ins->inst_true_bb->native_offset) { \
1798                 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1799         } else { \
1800                 int br_disp = ins->inst_true_bb->max_offset - offset;   \
1801                 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1802                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));    \
1803                         ovfj->data.bb = ins->inst_true_bb;      \
1804                         ovfj->ip_offset = 0;    \
1805                         ovfj->b0_cond = (b0);   \
1806                         ovfj->b1_cond = (b1);   \
1807                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1808                         ppc_b (code, 0);        \
1809                 } else {        \
1810                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1811                         ppc_bc (code, (b0), (b1), 0);   \
1812                 }       \
1813         } \
1814 }
1815
1816 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1817
1818 /* emit an exception if condition is fail
1819  *
1820  * We assign the extra code used to throw the implicit exceptions
1821  * to cfg->bb_exit as far as the big branch handling is concerned
1822  */
1823 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name)            \
1824         do {                                                        \
1825                 int br_disp = cfg->bb_exit->max_offset - offset;        \
1826                 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1827                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));    \
1828                         ovfj->data.exception = (exc_name);      \
1829                         ovfj->ip_offset = code - cfg->native_code;      \
1830                         ovfj->b0_cond = (b0);   \
1831                         ovfj->b1_cond = (b1);   \
1832                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1833                         ppc_bl (code, 0);       \
1834                         cfg->bb_exit->max_offset += 24; \
1835                 } else {        \
1836                         mono_add_patch_info (cfg, code - cfg->native_code,   \
1837                                     MONO_PATCH_INFO_EXC, exc_name);  \
1838                         ppc_bcl (code, (b0), (b1), 0);  \
1839                 }       \
1840         } while (0); 
1841
1842 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1843
1844 void
1845 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1846 {
1847 }
1848
1849 void
1850 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1851 {
1852         MonoInst *ins, *n, *last_ins = NULL;
1853
1854         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1855                 switch (ins->opcode) {
1856                 case OP_MUL_IMM: 
1857                         /* remove unnecessary multiplication with 1 */
1858                         if (ins->inst_imm == 1) {
1859                                 if (ins->dreg != ins->sreg1) {
1860                                         ins->opcode = OP_MOVE;
1861                                 } else {
1862                                         MONO_DELETE_INS (bb, ins);
1863                                         continue;
1864                                 }
1865                         } else {
1866                                 int power2 = mono_is_power_of_two (ins->inst_imm);
1867                                 if (power2 > 0) {
1868                                         ins->opcode = OP_SHL_IMM;
1869                                         ins->inst_imm = power2;
1870                                 }
1871                         }
1872                         break;
1873                 case OP_LOAD_MEMBASE:
1874                 case OP_LOADI4_MEMBASE:
1875                         /* 
1876                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1877                          * OP_LOAD_MEMBASE offset(basereg), reg
1878                          */
1879                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1880                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1881                             ins->inst_basereg == last_ins->inst_destbasereg &&
1882                             ins->inst_offset == last_ins->inst_offset) {
1883                                 if (ins->dreg == last_ins->sreg1) {
1884                                         MONO_DELETE_INS (bb, ins);
1885                                         continue;
1886                                 } else {
1887                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1888                                         ins->opcode = OP_MOVE;
1889                                         ins->sreg1 = last_ins->sreg1;
1890                                 }
1891
1892                         /* 
1893                          * Note: reg1 must be different from the basereg in the second load
1894                          * OP_LOAD_MEMBASE offset(basereg), reg1
1895                          * OP_LOAD_MEMBASE offset(basereg), reg2
1896                          * -->
1897                          * OP_LOAD_MEMBASE offset(basereg), reg1
1898                          * OP_MOVE reg1, reg2
1899                          */
1900                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1901                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1902                               ins->inst_basereg != last_ins->dreg &&
1903                               ins->inst_basereg == last_ins->inst_basereg &&
1904                               ins->inst_offset == last_ins->inst_offset) {
1905
1906                                 if (ins->dreg == last_ins->dreg) {
1907                                         MONO_DELETE_INS (bb, ins);
1908                                         continue;
1909                                 } else {
1910                                         ins->opcode = OP_MOVE;
1911                                         ins->sreg1 = last_ins->dreg;
1912                                 }
1913
1914                                 //g_assert_not_reached ();
1915
1916 #if 0
1917                         /* 
1918                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1919                          * OP_LOAD_MEMBASE offset(basereg), reg
1920                          * -->
1921                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1922                          * OP_ICONST reg, imm
1923                          */
1924                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1925                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1926                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1927                                    ins->inst_offset == last_ins->inst_offset) {
1928                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1929                                 ins->opcode = OP_ICONST;
1930                                 ins->inst_c0 = last_ins->inst_imm;
1931                                 g_assert_not_reached (); // check this rule
1932 #endif
1933                         }
1934                         break;
1935                 case OP_LOADU1_MEMBASE:
1936                 case OP_LOADI1_MEMBASE:
1937                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1938                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1939                                         ins->inst_offset == last_ins->inst_offset) {
1940                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1941                                 ins->sreg1 = last_ins->sreg1;                           
1942                         }
1943                         break;
1944                 case OP_LOADU2_MEMBASE:
1945                 case OP_LOADI2_MEMBASE:
1946                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1947                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1948                                         ins->inst_offset == last_ins->inst_offset) {
1949                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1950                                 ins->sreg1 = last_ins->sreg1;                           
1951                         }
1952                         break;
1953                 case OP_MOVE:
1954                         ins->opcode = OP_MOVE;
1955                         /* 
1956                          * OP_MOVE reg, reg 
1957                          */
1958                         if (ins->dreg == ins->sreg1) {
1959                                 MONO_DELETE_INS (bb, ins);
1960                                 continue;
1961                         }
1962                         /* 
1963                          * OP_MOVE sreg, dreg 
1964                          * OP_MOVE dreg, sreg
1965                          */
1966                         if (last_ins && last_ins->opcode == OP_MOVE &&
1967                             ins->sreg1 == last_ins->dreg &&
1968                             ins->dreg == last_ins->sreg1) {
1969                                 MONO_DELETE_INS (bb, ins);
1970                                 continue;
1971                         }
1972                         break;
1973                 }
1974                 last_ins = ins;
1975                 ins = ins->next;
1976         }
1977         bb->last_ins = last_ins;
1978 }
1979
1980 void
1981 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
1982 {
1983         g_assert (cfg->new_ir);
1984
1985         switch (ins->opcode) {
1986         case OP_ICONV_TO_R_UN: {
1987                 static const guint64 adjust_val = 0x4330000000000000ULL;
1988                 int msw_reg = mono_alloc_ireg (cfg);
1989                 int adj_reg = mono_alloc_freg (cfg);
1990                 int tmp_reg = mono_alloc_freg (cfg);
1991                 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
1992                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
1993                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, ins->sreg1);
1994                 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, &adjust_val);
1995                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
1996                 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
1997                 ins->opcode = OP_NOP;
1998                 break;
1999         }
2000         case OP_ICONV_TO_R4:
2001         case OP_ICONV_TO_R8: {
2002                 /* FIXME: change precision for CEE_CONV_R4 */
2003                 static const guint64 adjust_val = 0x4330000080000000ULL;
2004                 int msw_reg = mono_alloc_ireg (cfg);
2005                 int xored = mono_alloc_ireg (cfg);
2006                 int adj_reg = mono_alloc_freg (cfg);
2007                 int tmp_reg = mono_alloc_freg (cfg);
2008                 MONO_EMIT_NEW_ICONST (cfg, msw_reg, 0x43300000);
2009                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -8, msw_reg);
2010                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, xored, ins->sreg1, 0x80000000);
2011                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ppc_sp, -4, xored);
2012                 MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
2013                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
2014                 MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
2015                 if (ins->opcode == OP_ICONV_TO_R4)
2016                         MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
2017                 ins->opcode = OP_NOP;
2018                 break;
2019         }
2020         case OP_CKFINITE: {
2021                 int msw_reg = mono_alloc_ireg (cfg);
2022                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ppc_sp, -8, ins->sreg1);
2023                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, msw_reg, ppc_sp, -8);
2024                 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_FINITE, -1, msw_reg);
2025                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
2026                 ins->opcode = OP_NOP;
2027                 break;
2028         }
2029         }
2030 }
2031
2032 /* 
2033  * the branch_b0_table should maintain the order of these
2034  * opcodes.
2035 case CEE_BEQ:
2036 case CEE_BGE:
2037 case CEE_BGT:
2038 case CEE_BLE:
2039 case CEE_BLT:
2040 case CEE_BNE_UN:
2041 case CEE_BGE_UN:
2042 case CEE_BGT_UN:
2043 case CEE_BLE_UN:
2044 case CEE_BLT_UN:
2045  */
2046 static const guchar 
2047 branch_b0_table [] = {
2048         PPC_BR_TRUE, 
2049         PPC_BR_FALSE, 
2050         PPC_BR_TRUE, 
2051         PPC_BR_FALSE, 
2052         PPC_BR_TRUE, 
2053         
2054         PPC_BR_FALSE, 
2055         PPC_BR_FALSE, 
2056         PPC_BR_TRUE, 
2057         PPC_BR_FALSE,
2058         PPC_BR_TRUE
2059 };
2060
2061 static const guchar 
2062 branch_b1_table [] = {
2063         PPC_BR_EQ, 
2064         PPC_BR_LT, 
2065         PPC_BR_GT, 
2066         PPC_BR_GT,
2067         PPC_BR_LT, 
2068         
2069         PPC_BR_EQ, 
2070         PPC_BR_LT, 
2071         PPC_BR_GT, 
2072         PPC_BR_GT,
2073         PPC_BR_LT 
2074 };
2075
2076 #define NEW_INS(cfg,dest,op) do {                                       \
2077                 MONO_INST_NEW((cfg), (dest), (op));                     \
2078                 mono_bblock_insert_after_ins (bb, last_ins, (dest));    \
2079         } while (0)
2080
2081 static int
2082 map_to_reg_reg_op (int op)
2083 {
2084         switch (op) {
2085         case OP_ADD_IMM:
2086                 return OP_IADD;
2087         case OP_SUB_IMM:
2088                 return OP_ISUB;
2089         case OP_AND_IMM:
2090                 return OP_IAND;
2091         case OP_COMPARE_IMM:
2092                 return OP_COMPARE;
2093         case OP_ICOMPARE_IMM:
2094                 return OP_ICOMPARE;
2095         case OP_ADDCC_IMM:
2096                 return OP_IADDCC;
2097         case OP_ADC_IMM:
2098                 return OP_IADC;
2099         case OP_SUBCC_IMM:
2100                 return OP_ISUBCC;
2101         case OP_SBB_IMM:
2102                 return OP_ISBB;
2103         case OP_OR_IMM:
2104                 return OP_IOR;
2105         case OP_XOR_IMM:
2106                 return OP_IXOR;
2107         case OP_MUL_IMM:
2108                 return OP_IMUL;
2109         case OP_LOAD_MEMBASE:
2110                 return OP_LOAD_MEMINDEX;
2111         case OP_LOADI4_MEMBASE:
2112                 return OP_LOADI4_MEMINDEX;
2113         case OP_LOADU4_MEMBASE:
2114                 return OP_LOADU4_MEMINDEX;
2115         case OP_LOADU1_MEMBASE:
2116                 return OP_LOADU1_MEMINDEX;
2117         case OP_LOADI2_MEMBASE:
2118                 return OP_LOADI2_MEMINDEX;
2119         case OP_LOADU2_MEMBASE:
2120                 return OP_LOADU2_MEMINDEX;
2121         case OP_LOADI1_MEMBASE:
2122                 return OP_LOADI1_MEMINDEX;
2123         case OP_LOADR4_MEMBASE:
2124                 return OP_LOADR4_MEMINDEX;
2125         case OP_LOADR8_MEMBASE:
2126                 return OP_LOADR8_MEMINDEX;
2127         case OP_STOREI1_MEMBASE_REG:
2128                 return OP_STOREI1_MEMINDEX;
2129         case OP_STOREI2_MEMBASE_REG:
2130                 return OP_STOREI2_MEMINDEX;
2131         case OP_STOREI4_MEMBASE_REG:
2132                 return OP_STOREI4_MEMINDEX;
2133         case OP_STORE_MEMBASE_REG:
2134                 return OP_STORE_MEMINDEX;
2135         case OP_STORER4_MEMBASE_REG:
2136                 return OP_STORER4_MEMINDEX;
2137         case OP_STORER8_MEMBASE_REG:
2138                 return OP_STORER8_MEMINDEX;
2139         case OP_STORE_MEMBASE_IMM:
2140                 return OP_STORE_MEMBASE_REG;
2141         case OP_STOREI1_MEMBASE_IMM:
2142                 return OP_STOREI1_MEMBASE_REG;
2143         case OP_STOREI2_MEMBASE_IMM:
2144                 return OP_STOREI2_MEMBASE_REG;
2145         case OP_STOREI4_MEMBASE_IMM:
2146                 return OP_STOREI4_MEMBASE_REG;
2147         }
2148         return mono_op_imm_to_op (op);
2149 }
2150
2151 //#define map_to_reg_reg_op(op) (cfg->new_ir? mono_op_imm_to_op (op): map_to_reg_reg_op (op))
2152
2153 #define compare_opcode_is_unsigned(opcode) \
2154                 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) ||  \
2155                 (((opcode) >= OP_IBNE_UN && (opcode) <= OP_IBLT_UN) ||  \
2156                 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) ||     \
2157                 ((opcode) >= OP_COND_EXC_INE_UN && (opcode) <= OP_COND_EXC_ILT_UN) ||   \
2158                 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN || (opcode) == OP_ICLT_UN || (opcode) == OP_ICGT_UN)))
2159 /*
2160  * Remove from the instruction list the instructions that can't be
2161  * represented with very simple instructions with no register
2162  * requirements.
2163  */
2164 void
2165 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2166 {
2167         MonoInst *ins, *next, *temp, *last_ins = NULL;
2168         int imm;
2169
2170         /* setup the virtual reg allocator */
2171         if (bb->max_vreg > cfg->rs->next_vreg)
2172                 cfg->rs->next_vreg = bb->max_vreg;
2173
2174         MONO_BB_FOR_EACH_INS (bb, ins) {
2175 loop_start:
2176                 switch (ins->opcode) {
2177                 case OP_IDIV_UN_IMM:
2178                 case OP_IDIV_IMM:
2179                 case OP_IREM_IMM:
2180                 case OP_IREM_UN_IMM:
2181                         NEW_INS (cfg, temp, OP_ICONST);
2182                         temp->inst_c0 = ins->inst_imm;
2183                         temp->dreg = mono_regstate_next_int (cfg->rs);
2184                         ins->sreg2 = temp->dreg;
2185                         if (ins->opcode == OP_IDIV_IMM)
2186                                 ins->opcode = OP_IDIV;
2187                         else if (ins->opcode == OP_IREM_IMM)
2188                                 ins->opcode = OP_IREM;
2189                         else if (ins->opcode == OP_IDIV_UN_IMM)
2190                                 ins->opcode = OP_IDIV_UN;
2191                         else if (ins->opcode == OP_IREM_UN_IMM)
2192                                 ins->opcode = OP_IREM_UN;
2193                         last_ins = temp;
2194                         /* handle rem separately */
2195                         goto loop_start;
2196                 case OP_IREM:
2197                 case OP_IREM_UN: {
2198                         MonoInst *mul;
2199                         /* we change a rem dest, src1, src2 to
2200                          * div temp1, src1, src2
2201                          * mul temp2, temp1, src2
2202                          * sub dest, src1, temp2
2203                          */
2204                         NEW_INS (cfg, mul, OP_IMUL);
2205                         NEW_INS (cfg, temp, ins->opcode == OP_IREM? OP_IDIV: OP_IDIV_UN);
2206                         temp->sreg1 = ins->sreg1;
2207                         temp->sreg2 = ins->sreg2;
2208                         temp->dreg = mono_regstate_next_int (cfg->rs);
2209                         mul->sreg1 = temp->dreg;
2210                         mul->sreg2 = ins->sreg2;
2211                         mul->dreg = mono_regstate_next_int (cfg->rs);
2212                         ins->opcode = OP_ISUB;
2213                         ins->sreg2 = mul->dreg;
2214                         break;
2215                 }
2216                 case OP_IADD_IMM:
2217                 case OP_ADD_IMM:
2218                 case OP_ADDCC_IMM:
2219                         if (!ppc_is_imm16 (ins->inst_imm)) {
2220                                 NEW_INS (cfg,  temp, OP_ICONST);
2221                                 temp->inst_c0 = ins->inst_imm;
2222                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2223                                 ins->sreg2 = temp->dreg;
2224                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2225                         }
2226                         break;
2227                 case OP_ISUB_IMM:
2228                 case OP_SUB_IMM:
2229                         if (!ppc_is_imm16 (-ins->inst_imm)) {
2230                                 NEW_INS (cfg, temp, OP_ICONST);
2231                                 temp->inst_c0 = ins->inst_imm;
2232                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2233                                 ins->sreg2 = temp->dreg;
2234                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2235                         }
2236                         break;
2237                 case OP_IAND_IMM:
2238                 case OP_IOR_IMM:
2239                 case OP_IXOR_IMM:
2240                 case OP_AND_IMM:
2241                 case OP_OR_IMM:
2242                 case OP_XOR_IMM:
2243                         if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2244                                 NEW_INS (cfg, temp, OP_ICONST);
2245                                 temp->inst_c0 = ins->inst_imm;
2246                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2247                                 ins->sreg2 = temp->dreg;
2248                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2249                         }
2250                         break;
2251                 case OP_ISBB_IMM:
2252                 case OP_IADC_IMM:
2253                 case OP_SBB_IMM:
2254                 case OP_SUBCC_IMM:
2255                 case OP_ADC_IMM:
2256                         NEW_INS (cfg, temp, OP_ICONST);
2257                         temp->inst_c0 = ins->inst_imm;
2258                         temp->dreg = mono_regstate_next_int (cfg->rs);
2259                         ins->sreg2 = temp->dreg;
2260                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2261                         break;
2262                 case OP_COMPARE_IMM:
2263                 case OP_ICOMPARE_IMM:
2264                         next = ins->next;
2265                         /* Branch opts can eliminate the branch */
2266                         if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2267                                 ins->opcode = OP_NOP;
2268                                 break;
2269                         }
2270                         g_assert(next);
2271                         if (compare_opcode_is_unsigned (next->opcode)) {
2272                                 if (!ppc_is_uimm16 (ins->inst_imm)) {
2273                                         NEW_INS (cfg, temp, OP_ICONST);
2274                                         temp->inst_c0 = ins->inst_imm;
2275                                         temp->dreg = mono_regstate_next_int (cfg->rs);
2276                                         ins->sreg2 = temp->dreg;
2277                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2278                                 }
2279                         } else {
2280                                 if (!ppc_is_imm16 (ins->inst_imm)) {
2281                                         NEW_INS (cfg, temp, OP_ICONST);
2282                                         temp->inst_c0 = ins->inst_imm;
2283                                         temp->dreg = mono_regstate_next_int (cfg->rs);
2284                                         ins->sreg2 = temp->dreg;
2285                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2286                                 }
2287                         }
2288                         break;
2289                 case OP_IMUL_IMM:
2290                 case OP_MUL_IMM:
2291                         if (ins->inst_imm == 1) {
2292                                 ins->opcode = OP_MOVE;
2293                                 break;
2294                         }
2295                         if (ins->inst_imm == 0) {
2296                                 ins->opcode = OP_ICONST;
2297                                 ins->inst_c0 = 0;
2298                                 break;
2299                         }
2300                         imm = mono_is_power_of_two (ins->inst_imm);
2301                         if (imm > 0) {
2302                                 ins->opcode = OP_SHL_IMM;
2303                                 ins->inst_imm = imm;
2304                                 break;
2305                         }
2306                         if (!ppc_is_imm16 (ins->inst_imm)) {
2307                                 NEW_INS (cfg, temp, OP_ICONST);
2308                                 temp->inst_c0 = ins->inst_imm;
2309                                 temp->dreg = mono_regstate_next_int (cfg->rs);
2310                                 ins->sreg2 = temp->dreg;
2311                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2312                         }
2313                         break;
2314                 case OP_LOCALLOC_IMM:
2315                         NEW_INS (cfg, temp, OP_ICONST);
2316                         temp->inst_c0 = ins->inst_imm;
2317                         temp->dreg = mono_regstate_next_int (cfg->rs);
2318                         ins->sreg1 = temp->dreg;
2319                         ins->opcode = OP_LOCALLOC;
2320                         break;
2321                 case OP_LOAD_MEMBASE:
2322                 case OP_LOADI4_MEMBASE:
2323                 case OP_LOADU4_MEMBASE:
2324                 case OP_LOADI2_MEMBASE:
2325                 case OP_LOADU2_MEMBASE:
2326                 case OP_LOADI1_MEMBASE:
2327                 case OP_LOADU1_MEMBASE:
2328                 case OP_LOADR4_MEMBASE:
2329                 case OP_LOADR8_MEMBASE:
2330                 case OP_STORE_MEMBASE_REG:
2331                 case OP_STOREI4_MEMBASE_REG:
2332                 case OP_STOREI2_MEMBASE_REG:
2333                 case OP_STOREI1_MEMBASE_REG:
2334                 case OP_STORER4_MEMBASE_REG:
2335                 case OP_STORER8_MEMBASE_REG:
2336                         /* we can do two things: load the immed in a register
2337                          * and use an indexed load, or see if the immed can be
2338                          * represented as an ad_imm + a load with a smaller offset
2339                          * that fits. We just do the first for now, optimize later.
2340                          */
2341                         if (ppc_is_imm16 (ins->inst_offset))
2342                                 break;
2343                         NEW_INS (cfg, temp, OP_ICONST);
2344                         temp->inst_c0 = ins->inst_offset;
2345                         temp->dreg = mono_regstate_next_int (cfg->rs);
2346                         ins->sreg2 = temp->dreg;
2347                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2348                         break;
2349                 case OP_STORE_MEMBASE_IMM:
2350                 case OP_STOREI1_MEMBASE_IMM:
2351                 case OP_STOREI2_MEMBASE_IMM:
2352                 case OP_STOREI4_MEMBASE_IMM:
2353                         NEW_INS (cfg, temp, OP_ICONST);
2354                         temp->inst_c0 = ins->inst_imm;
2355                         temp->dreg = mono_regstate_next_int (cfg->rs);
2356                         ins->sreg1 = temp->dreg;
2357                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2358                         last_ins = temp;
2359                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
2360                 case OP_R8CONST:
2361                 case OP_R4CONST:
2362                         NEW_INS (cfg, temp, OP_ICONST);
2363                         temp->inst_c0 = (guint32)ins->inst_p0;
2364                         temp->dreg = mono_regstate_next_int (cfg->rs);
2365                         ins->inst_basereg = temp->dreg;
2366                         ins->inst_offset = 0;
2367                         ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2368                         last_ins = temp;
2369                         /* make it handle the possibly big ins->inst_offset
2370                          * later optimize to use lis + load_membase
2371                          */
2372                         goto loop_start;
2373                 }
2374                 last_ins = ins;
2375         }
2376         bb->last_ins = last_ins;
2377         bb->max_vreg = cfg->rs->next_vreg;
2378         
2379 }
2380
2381 static guchar*
2382 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2383 {
2384         /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
2385         ppc_fctiwz (code, ppc_f0, sreg);
2386         ppc_stfd (code, ppc_f0, -8, ppc_sp);
2387         ppc_lwz (code, dreg, -4, ppc_sp);
2388         if (!is_signed) {
2389                 if (size == 1)
2390                         ppc_andid (code, dreg, dreg, 0xff);
2391                 else if (size == 2)
2392                         ppc_andid (code, dreg, dreg, 0xffff);
2393         } else {
2394                 if (size == 1)
2395                         ppc_extsb (code, dreg, dreg);
2396                 else if (size == 2)
2397                         ppc_extsh (code, dreg, dreg);
2398         }
2399         return code;
2400 }
2401
2402 static unsigned char*
2403 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
2404 {
2405 #if 0
2406         int sreg = tree->sreg1;
2407         x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
2408         if (tree->flags & MONO_INST_INIT) {
2409                 int offset = 0;
2410                 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
2411                         x86_push_reg (code, X86_EAX);
2412                         offset += 4;
2413                 }
2414                 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
2415                         x86_push_reg (code, X86_ECX);
2416                         offset += 4;
2417                 }
2418                 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
2419                         x86_push_reg (code, X86_EDI);
2420                         offset += 4;
2421                 }
2422                 
2423                 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
2424                 if (sreg != X86_ECX)
2425                         x86_mov_reg_reg (code, X86_ECX, sreg, 4);
2426                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
2427                                 
2428                 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
2429                 x86_cld (code);
2430                 x86_prefix (code, X86_REP_PREFIX);
2431                 x86_stosl (code);
2432                 
2433                 if (tree->dreg != X86_EDI && sreg != X86_EDI)
2434                         x86_pop_reg (code, X86_EDI);
2435                 if (tree->dreg != X86_ECX && sreg != X86_ECX)
2436                         x86_pop_reg (code, X86_ECX);
2437                 if (tree->dreg != X86_EAX && sreg != X86_EAX)
2438                         x86_pop_reg (code, X86_EAX);
2439         }
2440 #endif
2441         return code;
2442 }
2443
2444 typedef struct {
2445         guchar *code;
2446         const guchar *target;
2447         int absolute;
2448         int found;
2449 } PatchData;
2450
2451 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2452
2453 static int
2454 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2455         PatchData *pdata = (PatchData*)user_data;
2456         guchar *code = data;
2457         guint32 *thunks = data;
2458         guint32 *endthunks = (guint32*)(code + bsize);
2459         guint32 load [2];
2460         guchar *templ;
2461         int count = 0;
2462         int difflow, diffhigh;
2463
2464         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2465         difflow = (char*)pdata->code - (char*)thunks;
2466         diffhigh = (char*)pdata->code - (char*)endthunks;
2467         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2468                 return 0;
2469
2470         templ = (guchar*)load;
2471         ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
2472         ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2473
2474         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2475         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2476                 while (thunks < endthunks) {
2477                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2478                         if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
2479                                 ppc_patch (pdata->code, (guchar*)thunks);
2480                                 mono_arch_flush_icache (pdata->code, 4);
2481                                 pdata->found = 1;
2482                                 /*{
2483                                         static int num_thunks = 0;
2484                                         num_thunks++;
2485                                         if ((num_thunks % 20) == 0)
2486                                                 g_print ("num_thunks lookup: %d\n", num_thunks);
2487                                 }*/
2488                                 return 1;
2489                         } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
2490                                 /* found a free slot instead: emit thunk */
2491                                 code = (guchar*)thunks;
2492                                 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
2493                                 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
2494                                 ppc_mtctr (code, ppc_r0);
2495                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2496                                 mono_arch_flush_icache ((guchar*)thunks, 16);
2497
2498                                 ppc_patch (pdata->code, (guchar*)thunks);
2499                                 mono_arch_flush_icache (pdata->code, 4);
2500                                 pdata->found = 1;
2501                                 /*{
2502                                         static int num_thunks = 0;
2503                                         num_thunks++;
2504                                         if ((num_thunks % 20) == 0)
2505                                                 g_print ("num_thunks: %d\n", num_thunks);
2506                                 }*/
2507                                 return 1;
2508                         }
2509                         /* skip 16 bytes, the size of the thunk */
2510                         thunks += 4;
2511                         count++;
2512                 }
2513                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2514         }
2515         return 0;
2516 }
2517
2518 static void
2519 handle_thunk (int absolute, guchar *code, const guchar *target) {
2520         MonoDomain *domain = mono_domain_get ();
2521         PatchData pdata;
2522
2523         pdata.code = code;
2524         pdata.target = target;
2525         pdata.absolute = absolute;
2526         pdata.found = 0;
2527
2528         mono_domain_lock (domain);
2529         mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2530
2531         if (!pdata.found) {
2532                 /* this uses the first available slot */
2533                 pdata.found = 2;
2534                 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
2535         }
2536         mono_domain_unlock (domain);
2537
2538         if (pdata.found != 1)
2539                 g_print ("thunk failed for %p from %p\n", target, code);
2540         g_assert (pdata.found == 1);
2541 }
2542
2543 void
2544 ppc_patch (guchar *code, const guchar *target)
2545 {
2546         guint32 ins = *(guint32*)code;
2547         guint32 prim = ins >> 26;
2548         guint32 ovf;
2549
2550         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2551         if (prim == 18) {
2552                 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
2553                 gint diff = target - code;
2554                 if (diff >= 0){
2555                         if (diff <= 33554431){
2556                                 ins = (18 << 26) | (diff) | (ins & 1);
2557                                 *(guint32*)code = ins;
2558                                 return;
2559                         }
2560                 } else {
2561                         /* diff between 0 and -33554432 */
2562                         if (diff >= -33554432){
2563                                 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
2564                                 *(guint32*)code = ins;
2565                                 return;
2566                         }
2567                 }
2568                 
2569                 if ((glong)target >= 0){
2570                         if ((glong)target <= 33554431){
2571                                 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
2572                                 *(guint32*)code = ins;
2573                                 return;
2574                         }
2575                 } else {
2576                         if ((glong)target >= -33554432){
2577                                 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
2578                                 *(guint32*)code = ins;
2579                                 return;
2580                         }
2581                 }
2582
2583                 handle_thunk (TRUE, code, target);
2584                 return;
2585
2586                 g_assert_not_reached ();
2587         }
2588         
2589         
2590         if (prim == 16) {
2591                 // absolute address
2592                 if (ins & 2) {
2593                         guint32 li = (guint32)target;
2594                         ins = (ins & 0xffff0000) | (ins & 3);
2595                         ovf  = li & 0xffff0000;
2596                         if (ovf != 0 && ovf != 0xffff0000)
2597                                 g_assert_not_reached ();
2598                         li &= 0xffff;
2599                         ins |= li;
2600                         // FIXME: assert the top bits of li are 0
2601                 } else {
2602                         gint diff = target - code;
2603                         ins = (ins & 0xffff0000) | (ins & 3);
2604                         ovf  = diff & 0xffff0000;
2605                         if (ovf != 0 && ovf != 0xffff0000)
2606                                 g_assert_not_reached ();
2607                         diff &= 0xffff;
2608                         ins |= diff;
2609                 }
2610                 *(guint32*)code = ins;
2611                 return;
2612         }
2613
2614         if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2615                 guint32 *seq;
2616                 /* the trampoline code will try to patch the blrl, blr, bcctr */
2617                 if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
2618                         code -= 12;
2619                 }
2620                 /* this is the lis/ori/mtlr/blrl sequence */
2621                 seq = (guint32*)code;
2622                 g_assert ((seq [0] >> 26) == 15);
2623                 g_assert ((seq [1] >> 26) == 24);
2624                 g_assert ((seq [2] >> 26) == 31);
2625                 g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
2626                 /* FIXME: make this thread safe */
2627                 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
2628                 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
2629                 mono_arch_flush_icache (code - 8, 8);
2630         } else {
2631                 g_assert_not_reached ();
2632         }
2633 //      g_print ("patched with 0x%08x\n", ins);
2634 }
2635
2636 static guint8*
2637 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2638 {
2639         switch (ins->opcode) {
2640         case OP_FCALL:
2641         case OP_FCALL_REG:
2642         case OP_FCALL_MEMBASE:
2643                 if (ins->dreg != ppc_f1)
2644                         ppc_fmr (code, ins->dreg, ppc_f1);
2645                 break;
2646         }
2647
2648         return code;
2649 }
2650
2651 /*
2652  * emit_load_volatile_arguments:
2653  *
2654  *  Load volatile arguments from the stack to the original input registers.
2655  * Required before a tail call.
2656  */
2657 static guint8*
2658 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2659 {
2660         MonoMethod *method = cfg->method;
2661         MonoMethodSignature *sig;
2662         MonoInst *inst;
2663         CallInfo *cinfo;
2664         guint32 i, pos;
2665         int struct_index = 0;
2666
2667         /* FIXME: Generate intermediate code instead */
2668
2669         sig = mono_method_signature (method);
2670
2671         /* This is the opposite of the code in emit_prolog */
2672
2673         pos = 0;
2674
2675         cinfo = calculate_sizes (sig, sig->pinvoke);
2676
2677         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2678                 ArgInfo *ainfo = &cinfo->ret;
2679                 inst = cfg->vret_addr;
2680                 g_assert (ppc_is_imm16 (inst->inst_offset));
2681                 ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2682         }
2683         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2684                 ArgInfo *ainfo = cinfo->args + i;
2685                 inst = cfg->args [pos];
2686
2687                 g_assert (inst->opcode != OP_REGVAR);
2688                 g_assert (ppc_is_imm16 (inst->inst_offset));
2689
2690                 switch (ainfo->regtype) {
2691                 case RegTypeGeneral:
2692                         switch (ainfo->size) {
2693                                 case 1:
2694                                         ppc_lbz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2695                                         break;
2696                                 case 2:
2697                                         ppc_lhz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2698                                         break;
2699                                 default:
2700                                         ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2701                                         break;
2702                         }
2703                         break;
2704
2705                 case RegTypeFP:
2706                         switch (ainfo->size) {
2707                                 case 4:
2708                                         ppc_lfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2709                                         break;
2710                                 case 8:
2711                                         ppc_lfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
2712                                         break;
2713                                 default:
2714                                         g_assert_not_reached ();
2715                         }
2716                         break;
2717
2718                 case RegTypeBase:
2719                 case RegTypeStructByVal:
2720                         /* FIXME: */
2721                         NOT_IMPLEMENTED;
2722
2723                 case RegTypeStructByAddr: {
2724                         MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
2725
2726                         g_assert (ppc_is_imm16 (addr->inst_offset));
2727                         g_assert (!ainfo->offset);
2728                         ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
2729
2730                         struct_index++;
2731                         break;
2732                 }
2733
2734                 default:
2735                         g_assert_not_reached ();
2736                 }
2737
2738                 pos ++;
2739         }
2740
2741         g_free (cinfo);
2742
2743         return code;
2744 }
2745
2746 void
2747 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2748 {
2749         MonoInst *ins, *next;
2750         MonoCallInst *call;
2751         guint offset;
2752         guint8 *code = cfg->native_code + cfg->code_len;
2753         MonoInst *last_ins = NULL;
2754         guint last_offset = 0;
2755         int max_len, cpos;
2756
2757         /* we don't align basic blocks of loops on ppc */
2758
2759         if (cfg->verbose_level > 2)
2760                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2761
2762         cpos = bb->max_offset;
2763
2764         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2765                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2766                 //g_assert (!mono_compile_aot);
2767                 //cpos += 6;
2768                 //if (bb->cil_code)
2769                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2770                 /* this is not thread save, but good enough */
2771                 /* fixme: howto handle overflows? */
2772                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
2773         }
2774
2775         MONO_BB_FOR_EACH_INS (bb, ins) {
2776                 offset = code - cfg->native_code;
2777
2778                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2779
2780                 if (offset > (cfg->code_size - max_len - 16)) {
2781                         cfg->code_size *= 2;
2782                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2783                         code = cfg->native_code + offset;
2784                 }
2785         //      if (ins->cil_code)
2786         //              g_print ("cil code\n");
2787                 mono_debug_record_line_number (cfg, ins, offset);
2788
2789                 switch (ins->opcode) {
2790                 case OP_NOP:
2791                 case OP_DUMMY_USE:
2792                 case OP_DUMMY_STORE:
2793                 case OP_NOT_REACHED:
2794                 case OP_NOT_NULL:
2795                         break;
2796                 case OP_TLS_GET:
2797                         emit_tls_access (code, ins->dreg, ins->inst_offset);
2798                         break;
2799                 case OP_BIGMUL:
2800                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2801                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2802                         ppc_mr (code, ppc_r4, ppc_r0);
2803                         break;
2804                 case OP_BIGMUL_UN:
2805                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2806                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2807                         ppc_mr (code, ppc_r4, ppc_r0);
2808                         break;
2809                 case OP_MEMORY_BARRIER:
2810                         ppc_sync (code);
2811                         break;
2812                 case OP_STOREI1_MEMBASE_REG:
2813                         if (ppc_is_imm16 (ins->inst_offset)) {
2814                                 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2815                         } else {
2816                                 ppc_load (code, ppc_r0, ins->inst_offset);
2817                                 ppc_stbx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2818                         }
2819                         break;
2820                 case OP_STOREI2_MEMBASE_REG:
2821                         if (ppc_is_imm16 (ins->inst_offset)) {
2822                                 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2823                         } else {
2824                                 ppc_load (code, ppc_r0, ins->inst_offset);
2825                                 ppc_sthx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2826                         }
2827                         break;
2828                 case OP_STORE_MEMBASE_REG:
2829                 case OP_STOREI4_MEMBASE_REG:
2830                         if (ppc_is_imm16 (ins->inst_offset)) {
2831                                 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2832                         } else {
2833                                 ppc_load (code, ppc_r0, ins->inst_offset);
2834                                 ppc_stwx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
2835                         }
2836                         break;
2837                 case OP_STOREI1_MEMINDEX:
2838                         ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2839                         break;
2840                 case OP_STOREI2_MEMINDEX:
2841                         ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2842                         break;
2843                 case OP_STORE_MEMINDEX:
2844                 case OP_STOREI4_MEMINDEX:
2845                         ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2846                         break;
2847                 case OP_LOADU4_MEM:
2848                         g_assert_not_reached ();
2849                         break;
2850                 case OP_LOAD_MEMBASE:
2851                 case OP_LOADI4_MEMBASE:
2852                 case OP_LOADU4_MEMBASE:
2853                         if (ppc_is_imm16 (ins->inst_offset)) {
2854                                 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2855                         } else {
2856                                 ppc_load (code, ppc_r0, ins->inst_offset);
2857                                 ppc_lwzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2858                         }
2859                         break;
2860                 case OP_LOADI1_MEMBASE:
2861                 case OP_LOADU1_MEMBASE:
2862                         if (ppc_is_imm16 (ins->inst_offset)) {
2863                                 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2864                         } else {
2865                                 ppc_load (code, ppc_r0, ins->inst_offset);
2866                                 ppc_lbzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2867                         }
2868                         if (ins->opcode == OP_LOADI1_MEMBASE)
2869                                 ppc_extsb (code, ins->dreg, ins->dreg);
2870                         break;
2871                 case OP_LOADU2_MEMBASE:
2872                         if (ppc_is_imm16 (ins->inst_offset)) {
2873                                 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2874                         } else {
2875                                 ppc_load (code, ppc_r0, ins->inst_offset);
2876                                 ppc_lhzx (code, ins->dreg, ins->inst_basereg, ppc_r0);
2877                         }
2878                         break;
2879                 case OP_LOADI2_MEMBASE:
2880                         if (ppc_is_imm16 (ins->inst_offset)) {
2881                                 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2882                         } else {
2883                                 ppc_load (code, ppc_r0, ins->inst_offset);
2884                                 ppc_lhax (code, ins->dreg, ins->inst_basereg, ppc_r0);
2885                         }
2886                         break;
2887                 case OP_LOAD_MEMINDEX:
2888                 case OP_LOADI4_MEMINDEX:
2889                 case OP_LOADU4_MEMINDEX:
2890                         ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2891                         break;
2892                 case OP_LOADU2_MEMINDEX:
2893                         ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2894                         break;
2895                 case OP_LOADI2_MEMINDEX:
2896                         ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2897                         break;
2898                 case OP_LOADU1_MEMINDEX:
2899                         ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2900                         break;
2901                 case OP_LOADI1_MEMINDEX:
2902                         ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2903                         ppc_extsb (code, ins->dreg, ins->dreg);
2904                         break;
2905                 case OP_ICONV_TO_I1:
2906                         ppc_extsb (code, ins->dreg, ins->sreg1);
2907                         break;
2908                 case OP_ICONV_TO_I2:
2909                         ppc_extsh (code, ins->dreg, ins->sreg1);
2910                         break;
2911                 case OP_ICONV_TO_U1:
2912                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2913                         break;
2914                 case OP_ICONV_TO_U2:
2915                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2916                         break;
2917                 case OP_COMPARE:
2918                 case OP_ICOMPARE:
2919                         next = ins->next;
2920                         if (next && compare_opcode_is_unsigned (next->opcode))
2921                                 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2922                         else
2923                                 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2924                         break;
2925                 case OP_COMPARE_IMM:
2926                 case OP_ICOMPARE_IMM:
2927                         next = ins->next;
2928                         if (next && compare_opcode_is_unsigned (next->opcode)) {
2929                                 if (ppc_is_uimm16 (ins->inst_imm)) {
2930                                         ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2931                                 } else {
2932                                         g_assert_not_reached ();
2933                                 }
2934                         } else {
2935                                 if (ppc_is_imm16 (ins->inst_imm)) {
2936                                         ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2937                                 } else {
2938                                         g_assert_not_reached ();
2939                                 }
2940                         }
2941                         break;
2942                 case OP_BREAK:
2943                         ppc_break (code);
2944                         break;
2945                 case OP_ADDCC:
2946                 case OP_IADDCC:
2947                         ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2948                         break;
2949                 case OP_IADD:
2950                         ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2951                         break;
2952                 case OP_ADC:
2953                 case OP_IADC:
2954                         ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2955                         break;
2956                 case OP_ADDCC_IMM:
2957                         if (ppc_is_imm16 (ins->inst_imm)) {
2958                                 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2959                         } else {
2960                                 g_assert_not_reached ();
2961                         }
2962                         break;
2963                 case OP_ADD_IMM:
2964                 case OP_IADD_IMM:
2965                         if (ppc_is_imm16 (ins->inst_imm)) {
2966                                 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2967                         } else {
2968                                 g_assert_not_reached ();
2969                         }
2970                         break;
2971                 case OP_IADD_OVF:
2972                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2973                          */
2974                         ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2975                         ppc_mfspr (code, ppc_r0, ppc_xer);
2976                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2977                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2978                         break;
2979                 case OP_IADD_OVF_UN:
2980                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2981                          */
2982                         ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2983                         ppc_mfspr (code, ppc_r0, ppc_xer);
2984                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2985                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2986                         break;
2987                 case OP_ISUB_OVF:
2988                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2989                          */
2990                         ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2991                         ppc_mfspr (code, ppc_r0, ppc_xer);
2992                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2993                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2994                         break;
2995                 case OP_ISUB_OVF_UN:
2996                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2997                          */
2998                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2999                         ppc_mfspr (code, ppc_r0, ppc_xer);
3000                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3001                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3002                         break;
3003                 case OP_ADD_OVF_CARRY:
3004                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3005                          */
3006                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3007                         ppc_mfspr (code, ppc_r0, ppc_xer);
3008                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3009                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3010                         break;
3011                 case OP_ADD_OVF_UN_CARRY:
3012                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3013                          */
3014                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
3015                         ppc_mfspr (code, ppc_r0, ppc_xer);
3016                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3017                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3018                         break;
3019                 case OP_SUB_OVF_CARRY:
3020                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3021                          */
3022                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3023                         ppc_mfspr (code, ppc_r0, ppc_xer);
3024                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3025                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3026                         break;
3027                 case OP_SUB_OVF_UN_CARRY:
3028                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3029                          */
3030                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
3031                         ppc_mfspr (code, ppc_r0, ppc_xer);
3032                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
3033                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3034                         break;
3035                 case OP_SUBCC:
3036                 case OP_ISUBCC:
3037                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
3038                         break;
3039                 case OP_ISUB:
3040                         ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
3041                         break;
3042                 case OP_SBB:
3043                 case OP_ISBB:
3044                         ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
3045                         break;
3046                 case OP_SUB_IMM:
3047                 case OP_ISUB_IMM:
3048                         // we add the negated value
3049                         if (ppc_is_imm16 (-ins->inst_imm))
3050                                 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3051                         else {
3052                                 g_assert_not_reached ();
3053                         }
3054                         break;
3055                 case OP_PPC_SUBFIC:
3056                         g_assert (ppc_is_imm16 (ins->inst_imm));
3057                         ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
3058                         break;
3059                 case OP_PPC_SUBFZE:
3060                         ppc_subfze (code, ins->dreg, ins->sreg1);
3061                         break;
3062                 case OP_IAND:
3063                         /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
3064                         ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
3065                         break;
3066                 case OP_AND_IMM:
3067                 case OP_IAND_IMM:
3068                         if (!(ins->inst_imm & 0xffff0000)) {
3069                                 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
3070                         } else if (!(ins->inst_imm & 0xffff)) {
3071                                 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
3072                         } else {
3073                                 g_assert_not_reached ();
3074                         }
3075                         break;
3076                 case OP_IDIV: {
3077                         guint8 *divisor_is_m1;
3078                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3079                          */
3080                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3081                         divisor_is_m1 = code;
3082                         ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
3083                         ppc_lis (code, ppc_r0, 0x8000);
3084                         ppc_cmp (code, 0, 0, ins->sreg1, ppc_r0);
3085                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
3086                         ppc_patch (divisor_is_m1, code);
3087                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3088                          */
3089                         ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
3090                         ppc_mfspr (code, ppc_r0, ppc_xer);
3091                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3092                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3093                         break;
3094                 }
3095                 case OP_IDIV_UN:
3096                         ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
3097                         ppc_mfspr (code, ppc_r0, ppc_xer);
3098                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3099                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3100                         break;
3101                 case OP_DIV_IMM:
3102                 case OP_IREM:
3103                 case OP_IREM_UN:
3104                 case OP_REM_IMM:
3105                         g_assert_not_reached ();
3106                 case OP_IOR:
3107                         ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3108                         break;
3109                 case OP_OR_IMM:
3110                 case OP_IOR_IMM:
3111                         if (!(ins->inst_imm & 0xffff0000)) {
3112                                 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3113                         } else if (!(ins->inst_imm & 0xffff)) {
3114                                 ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
3115                         } else {
3116                                 g_assert_not_reached ();
3117                         }
3118                         break;
3119                 case OP_IXOR:
3120                         ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3121                         break;
3122                 case OP_IXOR_IMM:
3123                 case OP_XOR_IMM:
3124                         if (!(ins->inst_imm & 0xffff0000)) {
3125                                 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
3126                         } else if (!(ins->inst_imm & 0xffff)) {
3127                                 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
3128                         } else {
3129                                 g_assert_not_reached ();
3130                         }
3131                         break;
3132                 case OP_ISHL:
3133                         ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
3134                         break;
3135                 case OP_SHL_IMM:
3136                 case OP_ISHL_IMM:
3137                         ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
3138                         break;
3139                 case OP_ISHR:
3140                         ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
3141                         break;
3142                 case OP_SHR_IMM:
3143                 case OP_ISHR_IMM:
3144                         ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3145                         break;
3146                 case OP_SHR_UN_IMM:
3147                 case OP_ISHR_UN_IMM:
3148                         if (ins->inst_imm)
3149                                 ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
3150                         else
3151                                 ppc_mr (code, ins->dreg, ins->sreg1);
3152                         break;
3153                 case OP_ISHR_UN:
3154                         ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
3155                         break;
3156                 case OP_INOT:
3157                         ppc_not (code, ins->dreg, ins->sreg1);
3158                         break;
3159                 case OP_INEG:
3160                         ppc_neg (code, ins->dreg, ins->sreg1);
3161                         break;
3162                 case OP_IMUL:
3163                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3164                         break;
3165                 case OP_IMUL_IMM:
3166                 case OP_MUL_IMM:
3167                         if (ppc_is_imm16 (ins->inst_imm)) {
3168                             ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
3169                         } else {
3170                             g_assert_not_reached ();
3171                         }
3172                         break;
3173                 case OP_IMUL_OVF:
3174                         /* we annot use mcrxr, since it's not implemented on some processors 
3175                          * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
3176                          */
3177                         ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
3178                         ppc_mfspr (code, ppc_r0, ppc_xer);
3179                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3180                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3181                         break;
3182                 case OP_IMUL_OVF_UN:
3183                         /* we first multiply to get the high word and compare to 0
3184                          * to set the flags, then the result is discarded and then 
3185                          * we multiply to get the lower * bits result
3186                          */
3187                         ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
3188                         ppc_cmpi (code, 0, 0, ppc_r0, 0);
3189                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
3190                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
3191                         break;
3192                 case OP_ICONST:
3193                         ppc_load (code, ins->dreg, ins->inst_c0);
3194                         break;
3195                 case OP_AOTCONST:
3196                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3197                         ppc_lis (code, ins->dreg, 0);
3198                         ppc_ori (code, ins->dreg, ins->dreg, 0);
3199                         break;
3200                 case OP_ICONV_TO_I4:
3201                 case OP_ICONV_TO_U4:
3202                 case OP_MOVE:
3203                         ppc_mr (code, ins->dreg, ins->sreg1);
3204                         break;
3205                 case OP_SETLRET: {
3206                         int saved = ins->sreg1;
3207                         if (ins->sreg1 == ppc_r3) {
3208                                 ppc_mr (code, ppc_r0, ins->sreg1);
3209                                 saved = ppc_r0;
3210                         }
3211                         if (ins->sreg2 != ppc_r3)
3212                                 ppc_mr (code, ppc_r3, ins->sreg2);
3213                         if (saved != ppc_r4)
3214                                 ppc_mr (code, ppc_r4, saved);
3215                         break;
3216                 }
3217                 case OP_FMOVE:
3218                         ppc_fmr (code, ins->dreg, ins->sreg1);
3219                         break;
3220                 case OP_FCONV_TO_R4:
3221                         ppc_frsp (code, ins->dreg, ins->sreg1);
3222                         break;
3223                 case OP_JMP: {
3224                         int i, pos = 0;
3225                         
3226                         /*
3227                          * Keep in sync with mono_arch_emit_epilog
3228                          */
3229                         g_assert (!cfg->method->save_lmf);
3230                         /*
3231                          * Note: we can use ppc_r11 here because it is dead anyway:
3232                          * we're leaving the method.
3233                          */
3234                         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3235                                 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3236                                         ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3237                                 } else {
3238                                         ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3239                                         ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3240                                 }
3241                                 ppc_mtlr (code, ppc_r0);
3242                         }
3243
3244                         code = emit_load_volatile_arguments (cfg, code);
3245
3246                         if (ppc_is_imm16 (cfg->stack_usage)) {
3247                                 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3248                         } else {
3249                                 ppc_load (code, ppc_r11, cfg->stack_usage);
3250                                 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3251                         }
3252                         if (!cfg->method->save_lmf) {
3253                                 /*for (i = 31; i >= 14; --i) {
3254                                         if (cfg->used_float_regs & (1 << i)) {
3255                                                 pos += sizeof (double);
3256                                                 ppc_lfd (code, i, -pos, cfg->frame_reg);
3257                                         }
3258                                 }*/
3259                                 for (i = 31; i >= 13; --i) {
3260                                         if (cfg->used_int_regs & (1 << i)) {
3261                                                 pos += sizeof (gulong);
3262                                                 ppc_lwz (code, i, -pos, cfg->frame_reg);
3263                                         }
3264                                 }
3265                         } else {
3266                                 /* FIXME restore from MonoLMF: though this can't happen yet */
3267                         }
3268                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3269                         ppc_b (code, 0);
3270                         break;
3271                 }
3272                 case OP_CHECK_THIS:
3273                         /* ensure ins->sreg1 is not NULL */
3274                         ppc_lwz (code, ppc_r0, 0, ins->sreg1);
3275                         break;
3276                 case OP_ARGLIST: {
3277                         if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3278                                 ppc_addi (code, ppc_r0, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3279                         } else {
3280                                 ppc_load (code, ppc_r0, cfg->sig_cookie + cfg->stack_usage);
3281                                 ppc_add (code, ppc_r0, cfg->frame_reg, ppc_r0);
3282                         }
3283                         ppc_stw (code, ppc_r0, 0, ins->sreg1);
3284                         break;
3285                 }
3286                 case OP_FCALL:
3287                 case OP_LCALL:
3288                 case OP_VCALL:
3289                 case OP_VCALL2:
3290                 case OP_VOIDCALL:
3291                 case OP_CALL:
3292                         call = (MonoCallInst*)ins;
3293                         if (ins->flags & MONO_INST_HAS_METHOD)
3294                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3295                         else
3296                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3297                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3298                                 ppc_lis (code, ppc_r0, 0);
3299                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3300                                 ppc_mtlr (code, ppc_r0);
3301                                 ppc_blrl (code);
3302                         } else {
3303                                 ppc_bl (code, 0);
3304                         }
3305                         /* FIXME: this should be handled somewhere else in the new jit */
3306                         code = emit_move_return_value (cfg, ins, code);
3307                         break;
3308                 case OP_FCALL_REG:
3309                 case OP_LCALL_REG:
3310                 case OP_VCALL_REG:
3311                 case OP_VCALL2_REG:
3312                 case OP_VOIDCALL_REG:
3313                 case OP_CALL_REG:
3314                         ppc_mtlr (code, ins->sreg1);
3315                         ppc_blrl (code);
3316                         /* FIXME: this should be handled somewhere else in the new jit */
3317                         code = emit_move_return_value (cfg, ins, code);
3318                         break;
3319                 case OP_FCALL_MEMBASE:
3320                 case OP_LCALL_MEMBASE:
3321                 case OP_VCALL_MEMBASE:
3322                 case OP_VCALL2_MEMBASE:
3323                 case OP_VOIDCALL_MEMBASE:
3324                 case OP_CALL_MEMBASE:
3325                         ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
3326                         ppc_mtlr (code, ppc_r0);
3327                         ppc_blrl (code);
3328                         /* FIXME: this should be handled somewhere else in the new jit */
3329                         code = emit_move_return_value (cfg, ins, code);
3330                         break;
3331                 case OP_OUTARG:
3332                         g_assert_not_reached ();
3333                         break;
3334                 case OP_LOCALLOC: {
3335                         guint8 * zero_loop_jump, * zero_loop_start;
3336                         /* keep alignment */
3337                         int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
3338                         int area_offset = alloca_waste;
3339                         area_offset &= ~31;
3340                         ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
3341                         ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
3342                         /* use ctr to store the number of words to 0 if needed */
3343                         if (ins->flags & MONO_INST_INIT) {
3344                                 /* we zero 4 bytes at a time:
3345                                  * we add 7 instead of 3 so that we set the counter to
3346                                  * at least 1, otherwise the bdnz instruction will make
3347                                  * it negative and iterate billions of times.
3348                                  */
3349                                 ppc_addi (code, ppc_r0, ins->sreg1, 7);
3350                                 ppc_srawi (code, ppc_r0, ppc_r0, 2);
3351                                 ppc_mtctr (code, ppc_r0);
3352                         }
3353                         ppc_lwz (code, ppc_r0, 0, ppc_sp);
3354                         ppc_neg (code, ppc_r11, ppc_r11);
3355                         ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3356                         
3357                         if (ins->flags & MONO_INST_INIT) {
3358                                 /* adjust the dest reg by -4 so we can use stwu */
3359                                 /* we actually adjust -8 because we let the loop
3360                                  * run at least once
3361                                  */
3362                                 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 8));
3363                                 ppc_li (code, ppc_r11, 0);
3364                                 zero_loop_start = code;
3365                                 ppc_stwu (code, ppc_r11, 4, ins->dreg);
3366                                 zero_loop_jump = code;
3367                                 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
3368                                 ppc_patch (zero_loop_jump, zero_loop_start);
3369                         }
3370                         ppc_addi (code, ins->dreg, ppc_sp, area_offset);
3371                         break;
3372                 }
3373                 case OP_THROW: {
3374                         //ppc_break (code);
3375                         ppc_mr (code, ppc_r3, ins->sreg1);
3376                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3377                                              (gpointer)"mono_arch_throw_exception");
3378                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3379                                 ppc_lis (code, ppc_r0, 0);
3380                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3381                                 ppc_mtlr (code, ppc_r0);
3382                                 ppc_blrl (code);
3383                         } else {
3384                                 ppc_bl (code, 0);
3385                         }
3386                         break;
3387                 }
3388                 case OP_RETHROW: {
3389                         //ppc_break (code);
3390                         ppc_mr (code, ppc_r3, ins->sreg1);
3391                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3392                                              (gpointer)"mono_arch_rethrow_exception");
3393                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3394                                 ppc_lis (code, ppc_r0, 0);
3395                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3396                                 ppc_mtlr (code, ppc_r0);
3397                                 ppc_blrl (code);
3398                         } else {
3399                                 ppc_bl (code, 0);
3400                         }
3401                         break;
3402                 }
3403                 case OP_START_HANDLER: {
3404                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3405                         ppc_mflr (code, ppc_r0);
3406                         if (ppc_is_imm16 (spvar->inst_offset)) {
3407                                 ppc_stw (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3408                         } else {
3409                                 ppc_load (code, ppc_r11, spvar->inst_offset);
3410                                 ppc_stwx (code, ppc_r0, ppc_r11, spvar->inst_basereg);
3411                         }
3412                         break;
3413                 }
3414                 case OP_ENDFILTER: {
3415                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3416                         if (ins->sreg1 != ppc_r3)
3417                                 ppc_mr (code, ppc_r3, ins->sreg1);
3418                         if (ppc_is_imm16 (spvar->inst_offset)) {
3419                                 ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3420                         } else {
3421                                 ppc_load (code, ppc_r11, spvar->inst_offset);
3422                                 ppc_lwzx (code, ppc_r0, spvar->inst_basereg, ppc_r11);
3423                         }
3424                         ppc_mtlr (code, ppc_r0);
3425                         ppc_blr (code);
3426                         break;
3427                 }
3428                 case OP_ENDFINALLY: {
3429                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3430                         ppc_lwz (code, ppc_r0, spvar->inst_offset, spvar->inst_basereg);
3431                         ppc_mtlr (code, ppc_r0);
3432                         ppc_blr (code);
3433                         break;
3434                 }
3435                 case OP_CALL_HANDLER: 
3436                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3437                         ppc_bl (code, 0);
3438                         break;
3439                 case OP_LABEL:
3440                         ins->inst_c0 = code - cfg->native_code;
3441                         break;
3442                 case OP_BR:
3443                         if (ins->flags & MONO_INST_BRLABEL) {
3444                                 /*if (ins->inst_i0->inst_c0) {
3445                                         ppc_b (code, 0);
3446                                         //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
3447                                 } else*/ {
3448                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3449                                         ppc_b (code, 0);
3450                                 }
3451                         } else {
3452                                 /*if (ins->inst_target_bb->native_offset) {
3453                                         ppc_b (code, 0);
3454                                         //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
3455                                 } else*/ {
3456                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3457                                         ppc_b (code, 0);
3458                                 } 
3459                         }
3460                         break;
3461                 case OP_BR_REG:
3462                         ppc_mtctr (code, ins->sreg1);
3463                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
3464                         break;
3465                 case OP_CEQ:
3466                 case OP_ICEQ:
3467                         ppc_li (code, ins->dreg, 0);
3468                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3469                         ppc_li (code, ins->dreg, 1);
3470                         break;
3471                 case OP_CLT:
3472                 case OP_CLT_UN:
3473                 case OP_ICLT:
3474                 case OP_ICLT_UN:
3475                         ppc_li (code, ins->dreg, 1);
3476                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3477                         ppc_li (code, ins->dreg, 0);
3478                         break;
3479                 case OP_CGT:
3480                 case OP_CGT_UN:
3481                 case OP_ICGT:
3482                 case OP_ICGT_UN:
3483                         ppc_li (code, ins->dreg, 1);
3484                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3485                         ppc_li (code, ins->dreg, 0);
3486                         break;
3487                 case OP_COND_EXC_EQ:
3488                 case OP_COND_EXC_NE_UN:
3489                 case OP_COND_EXC_LT:
3490                 case OP_COND_EXC_LT_UN:
3491                 case OP_COND_EXC_GT:
3492                 case OP_COND_EXC_GT_UN:
3493                 case OP_COND_EXC_GE:
3494                 case OP_COND_EXC_GE_UN:
3495                 case OP_COND_EXC_LE:
3496                 case OP_COND_EXC_LE_UN:
3497                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3498                         break;
3499                 case OP_COND_EXC_IEQ:
3500                 case OP_COND_EXC_INE_UN:
3501                 case OP_COND_EXC_ILT:
3502                 case OP_COND_EXC_ILT_UN:
3503                 case OP_COND_EXC_IGT:
3504                 case OP_COND_EXC_IGT_UN:
3505                 case OP_COND_EXC_IGE:
3506                 case OP_COND_EXC_IGE_UN:
3507                 case OP_COND_EXC_ILE:
3508                 case OP_COND_EXC_ILE_UN:
3509                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3510                         break;
3511                 case OP_COND_EXC_C:
3512                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
3513                          */
3514                         /*ppc_mfspr (code, ppc_r0, ppc_xer);
3515                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3516                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3517                         break;*/
3518                 case OP_COND_EXC_OV:
3519                         /*ppc_mcrxr (code, 0);
3520                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
3521                         break;*/
3522                 case OP_COND_EXC_NC:
3523                 case OP_COND_EXC_NO:
3524                         g_assert_not_reached ();
3525                         break;
3526                 case OP_IBEQ:
3527                 case OP_IBNE_UN:
3528                 case OP_IBLT:
3529                 case OP_IBLT_UN:
3530                 case OP_IBGT:
3531                 case OP_IBGT_UN:
3532                 case OP_IBGE:
3533                 case OP_IBGE_UN:
3534                 case OP_IBLE:
3535                 case OP_IBLE_UN:
3536                         EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3537                         break;
3538
3539                 /* floating point opcodes */
3540                 case OP_R8CONST:
3541                 case OP_R4CONST:
3542                         g_assert_not_reached ();
3543                 case OP_STORER8_MEMBASE_REG:
3544                         if (ppc_is_imm16 (ins->inst_offset)) {
3545                                 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3546                         } else {
3547                                 ppc_load (code, ppc_r0, ins->inst_offset);
3548                                 ppc_stfdx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3549                         }
3550                         break;
3551                 case OP_LOADR8_MEMBASE:
3552                         if (ppc_is_imm16 (ins->inst_offset)) {
3553                                 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3554                         } else {
3555                                 ppc_load (code, ppc_r0, ins->inst_offset);
3556                                 ppc_lfdx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3557                         }
3558                         break;
3559                 case OP_STORER4_MEMBASE_REG:
3560                         ppc_frsp (code, ins->sreg1, ins->sreg1);
3561                         if (ppc_is_imm16 (ins->inst_offset)) {
3562                                 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
3563                         } else {
3564                                 ppc_load (code, ppc_r0, ins->inst_offset);
3565                                 ppc_stfsx (code, ins->sreg1, ins->inst_destbasereg, ppc_r0);
3566                         }
3567                         break;
3568                 case OP_LOADR4_MEMBASE:
3569                         if (ppc_is_imm16 (ins->inst_offset)) {
3570                                 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
3571                         } else {
3572                                 ppc_load (code, ppc_r0, ins->inst_offset);
3573                                 ppc_lfsx (code, ins->dreg, ins->inst_destbasereg, ppc_r0);
3574                         }
3575                         break;
3576                 case OP_LOADR4_MEMINDEX:
3577                         ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3578                         break;
3579                 case OP_LOADR8_MEMINDEX:
3580                         ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
3581                         break;
3582                 case OP_STORER4_MEMINDEX:
3583                         ppc_frsp (code, ins->sreg1, ins->sreg1);
3584                         ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3585                         break;
3586                 case OP_STORER8_MEMINDEX:
3587                         ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
3588                         break;
3589                 case CEE_CONV_R_UN:
3590                 case CEE_CONV_R4: /* FIXME: change precision */
3591                 case CEE_CONV_R8:
3592                         g_assert_not_reached ();
3593                 case OP_FCONV_TO_I1:
3594                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
3595                         break;
3596                 case OP_FCONV_TO_U1:
3597                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
3598                         break;
3599                 case OP_FCONV_TO_I2:
3600                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3601                         break;
3602                 case OP_FCONV_TO_U2:
3603                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3604                         break;
3605                 case OP_FCONV_TO_I4:
3606                 case OP_FCONV_TO_I:
3607                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3608                         break;
3609                 case OP_FCONV_TO_U4:
3610                 case OP_FCONV_TO_U:
3611                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3612                         break;
3613                 case OP_FCONV_TO_I8:
3614                 case OP_FCONV_TO_U8:
3615                         g_assert_not_reached ();
3616                         /* Implemented as helper calls */
3617                         break;
3618                 case OP_LCONV_TO_R_UN:
3619                         g_assert_not_reached ();
3620                         /* Implemented as helper calls */
3621                         break;
3622                 case OP_LCONV_TO_OVF_I4_2:
3623                 case OP_LCONV_TO_OVF_I: {
3624                         guint8 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3625                         // Check if its negative
3626                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3627                         negative_branch = code;
3628                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3629                         // Its positive msword == 0
3630                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3631                         msword_positive_branch = code;
3632                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3633
3634                         ovf_ex_target = code;
3635                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3636                         // Negative
3637                         ppc_patch (negative_branch, code);
3638                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3639                         msword_negative_branch = code;
3640                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3641                         ppc_patch (msword_negative_branch, ovf_ex_target);
3642                         
3643                         ppc_patch (msword_positive_branch, code);
3644                         if (ins->dreg != ins->sreg1)
3645                                 ppc_mr (code, ins->dreg, ins->sreg1);
3646                         break;
3647                 }
3648                 case OP_SQRT:
3649                         ppc_fsqrtd (code, ins->dreg, ins->sreg1);
3650                         break;
3651                 case OP_FADD:
3652                         ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
3653                         break;
3654                 case OP_FSUB:
3655                         ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
3656                         break;          
3657                 case OP_FMUL:
3658                         ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
3659                         break;          
3660                 case OP_FDIV:
3661                         ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
3662                         break;          
3663                 case OP_FNEG:
3664                         ppc_fneg (code, ins->dreg, ins->sreg1);
3665                         break;          
3666                 case OP_FREM:
3667                         /* emulated */
3668                         g_assert_not_reached ();
3669                         break;
3670                 case OP_FCOMPARE:
3671                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3672                         break;
3673                 case OP_FCEQ:
3674                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3675                         ppc_li (code, ins->dreg, 0);
3676                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
3677                         ppc_li (code, ins->dreg, 1);
3678                         break;
3679                 case OP_FCLT:
3680                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3681                         ppc_li (code, ins->dreg, 1);
3682                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3683                         ppc_li (code, ins->dreg, 0);
3684                         break;
3685                 case OP_FCLT_UN:
3686                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3687                         ppc_li (code, ins->dreg, 1);
3688                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3689                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
3690                         ppc_li (code, ins->dreg, 0);
3691                         break;
3692                 case OP_FCGT:
3693                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
3694                         ppc_li (code, ins->dreg, 1);
3695                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3696                         ppc_li (code, ins->dreg, 0);
3697                         break;
3698                 case OP_FCGT_UN:
3699                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
3700                         ppc_li (code, ins->dreg, 1);
3701                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
3702                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
3703                         ppc_li (code, ins->dreg, 0);
3704                         break;
3705                 case OP_FBEQ:
3706                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
3707                         break;
3708                 case OP_FBNE_UN:
3709                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
3710                         break;
3711                 case OP_FBLT:
3712                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3713                         EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
3714                         break;
3715                 case OP_FBLT_UN:
3716                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3717                         EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
3718                         break;
3719                 case OP_FBGT:
3720                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3721                         EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
3722                         break;
3723                 case OP_FBGT_UN:
3724                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
3725                         EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
3726                         break;
3727                 case OP_FBGE:
3728                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3729                         EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
3730                         break;
3731                 case OP_FBGE_UN:
3732                         EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
3733                         break;
3734                 case OP_FBLE:
3735                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
3736                         EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
3737                         break;
3738                 case OP_FBLE_UN:
3739                         EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
3740                         break;
3741                 case OP_CKFINITE:
3742                         g_assert_not_reached ();
3743                 case OP_CHECK_FINITE: {
3744                         ppc_rlwinm (code, ins->sreg1, ins->sreg1, 0, 1, 31);
3745                         ppc_addis (code, ins->sreg1, ins->sreg1, -32752);
3746                         ppc_rlwinmd (code, ins->sreg1, ins->sreg1, 1, 31, 31);
3747                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
3748                         break;
3749                 case OP_JUMP_TABLE:
3750                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3751                         ppc_load (code, ins->dreg, 0x0f0f0f0f);
3752                         break;
3753                 }
3754                 default:
3755                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3756                         g_assert_not_reached ();
3757                 }
3758
3759                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3760                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3761                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3762                         g_assert_not_reached ();
3763                 }
3764                
3765                 cpos += max_len;
3766
3767                 last_ins = ins;
3768                 last_offset = offset;
3769         }
3770
3771         cfg->code_len = code - cfg->native_code;
3772 }
3773
3774 void
3775 mono_arch_register_lowlevel_calls (void)
3776 {
3777 }
3778
3779 #define patch_lis_ori(ip,val) do {\
3780                 guint16 *__lis_ori = (guint16*)(ip);    \
3781                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
3782                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
3783         } while (0)
3784
3785 void
3786 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3787 {
3788         MonoJumpInfo *patch_info;
3789
3790         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3791                 unsigned char *ip = patch_info->ip.i + code;
3792                 unsigned char *target;
3793
3794                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3795
3796                 switch (patch_info->type) {
3797                 case MONO_PATCH_INFO_IP:
3798                         patch_lis_ori (ip, ip);
3799                         continue;
3800                 case MONO_PATCH_INFO_METHOD_REL:
3801                         g_assert_not_reached ();
3802                         *((gpointer *)(ip)) = code + patch_info->data.offset;
3803                         continue;
3804                 case MONO_PATCH_INFO_SWITCH: {
3805                         gpointer *table = (gpointer *)patch_info->data.table->table;
3806                         int i;
3807
3808                         patch_lis_ori (ip, table);
3809
3810                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
3811                                 table [i] = (int)patch_info->data.table->table [i] + code;
3812                         }
3813                         /* we put into the table the absolute address, no need for ppc_patch in this case */
3814                         continue;
3815                 }
3816                 case MONO_PATCH_INFO_METHODCONST:
3817                 case MONO_PATCH_INFO_CLASS:
3818                 case MONO_PATCH_INFO_IMAGE:
3819                 case MONO_PATCH_INFO_FIELD:
3820                 case MONO_PATCH_INFO_VTABLE:
3821                 case MONO_PATCH_INFO_IID:
3822                 case MONO_PATCH_INFO_SFLDA:
3823                 case MONO_PATCH_INFO_LDSTR:
3824                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3825                 case MONO_PATCH_INFO_LDTOKEN:
3826                         /* from OP_AOTCONST : lis + ori */
3827                         patch_lis_ori (ip, target);
3828                         continue;
3829                 case MONO_PATCH_INFO_R4:
3830                 case MONO_PATCH_INFO_R8:
3831                         g_assert_not_reached ();
3832                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3833                         continue;
3834                 case MONO_PATCH_INFO_EXC_NAME:
3835                         g_assert_not_reached ();
3836                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3837                         continue;
3838                 case MONO_PATCH_INFO_NONE:
3839                 case MONO_PATCH_INFO_BB_OVF:
3840                 case MONO_PATCH_INFO_EXC_OVF:
3841                         /* everything is dealt with at epilog output time */
3842                         continue;
3843                 default:
3844                         break;
3845                 }
3846                 ppc_patch (ip, target);
3847         }
3848 }
3849
3850 /*
3851  * Stack frame layout:
3852  * 
3853  *   ------------------- sp
3854  *      MonoLMF structure or saved registers
3855  *   -------------------
3856  *      spilled regs
3857  *   -------------------
3858  *      locals
3859  *   -------------------
3860  *      optional 8 bytes for tracing
3861  *   -------------------
3862  *      param area             size is cfg->param_area
3863  *   -------------------
3864  *      linkage area           size is PPC_STACK_PARAM_OFFSET
3865  *   ------------------- sp
3866  *      red zone
3867  */
3868 guint8 *
3869 mono_arch_emit_prolog (MonoCompile *cfg)
3870 {
3871         MonoMethod *method = cfg->method;
3872         MonoBasicBlock *bb;
3873         MonoMethodSignature *sig;
3874         MonoInst *inst;
3875         int alloc_size, pos, max_offset, i;
3876         guint8 *code;
3877         CallInfo *cinfo;
3878         int tracing = 0;
3879         int lmf_offset = 0;
3880         int tailcall_struct_index;
3881
3882         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3883                 tracing = 1;
3884
3885         sig = mono_method_signature (method);
3886         cfg->code_size = 256 + sig->param_count * 20;
3887         code = cfg->native_code = g_malloc (cfg->code_size);
3888
3889         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3890                 ppc_mflr (code, ppc_r0);
3891                 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3892         }
3893
3894         alloc_size = cfg->stack_offset;
3895         pos = 0;
3896
3897         if (!method->save_lmf) {
3898                 /*for (i = 31; i >= 14; --i) {
3899                         if (cfg->used_float_regs & (1 << i)) {
3900                                 pos += sizeof (gdouble);
3901                                 ppc_stfd (code, i, -pos, ppc_sp);
3902                         }
3903                 }*/
3904                 for (i = 31; i >= 13; --i) {
3905                         if (cfg->used_int_regs & (1 << i)) {
3906                                 pos += sizeof (gulong);
3907                                 ppc_stw (code, i, -pos, ppc_sp);
3908                         }
3909                 }
3910         } else {
3911                 int ofs;
3912                 pos += sizeof (MonoLMF);
3913                 lmf_offset = pos;
3914                 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3915                 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3916                 for (i = 14; i < 32; i++) {
3917                         ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3918                 }
3919         }
3920         alloc_size += pos;
3921         // align to PPC_STACK_ALIGNMENT bytes
3922         if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3923                 alloc_size += PPC_STACK_ALIGNMENT - 1;
3924                 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3925         }
3926
3927         cfg->stack_usage = alloc_size;
3928         g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3929         if (alloc_size) {
3930                 if (ppc_is_imm16 (-alloc_size)) {
3931                         ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3932                 } else {
3933                         ppc_load (code, ppc_r11, -alloc_size);
3934                         ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3935                 }
3936         }
3937         if (cfg->frame_reg != ppc_sp)
3938                 ppc_mr (code, cfg->frame_reg, ppc_sp);
3939
3940         /* compute max_offset in order to use short forward jumps
3941          * we always do it on ppc because the immediate displacement
3942          * for jumps is too small 
3943          */
3944         max_offset = 0;
3945         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3946                 MonoInst *ins;
3947                 bb->max_offset = max_offset;
3948
3949                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3950                         max_offset += 6; 
3951
3952                 MONO_BB_FOR_EACH_INS (bb, ins)
3953                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3954         }
3955
3956         /* load arguments allocated to register from the stack */
3957         pos = 0;
3958
3959         cinfo = calculate_sizes (sig, sig->pinvoke);
3960
3961         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3962                 ArgInfo *ainfo = &cinfo->ret;
3963
3964                 if (cfg->new_ir)
3965                         inst = cfg->vret_addr;
3966                 else
3967                         inst = cfg->ret;
3968                 g_assert (inst);
3969
3970                 if (ppc_is_imm16 (inst->inst_offset)) {
3971                         ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3972                 } else {
3973                         ppc_load (code, ppc_r11, inst->inst_offset);
3974                         ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3975                 }
3976         }
3977
3978         tailcall_struct_index = 0;
3979         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3980                 ArgInfo *ainfo = cinfo->args + i;
3981                 inst = cfg->args [pos];
3982                 
3983                 if (cfg->verbose_level > 2)
3984                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3985                 if (inst->opcode == OP_REGVAR) {
3986                         if (ainfo->regtype == RegTypeGeneral)
3987                                 ppc_mr (code, inst->dreg, ainfo->reg);
3988                         else if (ainfo->regtype == RegTypeFP)
3989                                 ppc_fmr (code, inst->dreg, ainfo->reg);
3990                         else if (ainfo->regtype == RegTypeBase) {
3991                                 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3992                                 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3993                         } else
3994                                 g_assert_not_reached ();
3995
3996                         if (cfg->verbose_level > 2)
3997                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3998                 } else {
3999                         /* the argument should be put on the stack: FIXME handle size != word  */
4000                         if (ainfo->regtype == RegTypeGeneral) {
4001                                 switch (ainfo->size) {
4002                                 case 1:
4003                                         if (ppc_is_imm16 (inst->inst_offset)) {
4004                                                 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4005                                         } else {
4006                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4007                                                 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4008                                         }
4009                                         break;
4010                                 case 2:
4011                                         if (ppc_is_imm16 (inst->inst_offset)) {
4012                                                 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4013                                         } else {
4014                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4015                                                 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4016                                         }
4017                                         break;
4018                                 case 8:
4019                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
4020                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4021                                                 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
4022                                         } else {
4023                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4024                                                 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
4025                                                 ppc_stw (code, ainfo->reg, 0, ppc_r11);
4026                                                 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
4027                                         }
4028                                         break;
4029                                 default:
4030                                         if (ppc_is_imm16 (inst->inst_offset)) {
4031                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4032                                         } else {
4033                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4034                                                 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
4035                                         }
4036                                         break;
4037                                 }
4038                         } else if (ainfo->regtype == RegTypeBase) {
4039                                 /* load the previous stack pointer in r11 */
4040                                 ppc_lwz (code, ppc_r11, 0, ppc_sp);
4041                                 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
4042                                 switch (ainfo->size) {
4043                                 case 1:
4044                                         if (ppc_is_imm16 (inst->inst_offset)) {
4045                                                 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4046                                         } else {
4047                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4048                                                 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4049                                         }
4050                                         break;
4051                                 case 2:
4052                                         if (ppc_is_imm16 (inst->inst_offset)) {
4053                                                 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4054                                         } else {
4055                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4056                                                 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4057                                         }
4058                                         break;
4059                                 case 8:
4060                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
4061                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4062                                                 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
4063                                                 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
4064                                         } else {
4065                                                 /* FIXME */
4066                                                 g_assert_not_reached ();
4067                                         }
4068                                         break;
4069                                 default:
4070                                         if (ppc_is_imm16 (inst->inst_offset)) {
4071                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
4072                                         } else {
4073                                                 ppc_load (code, ppc_r11, inst->inst_offset);
4074                                                 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
4075                                         }
4076                                         break;
4077                                 }
4078                         } else if (ainfo->regtype == RegTypeFP) {
4079                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4080                                 if (ainfo->size == 8)
4081                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4082                                 else if (ainfo->size == 4)
4083                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
4084                                 else
4085                                         g_assert_not_reached ();
4086                         } else if (ainfo->regtype == RegTypeStructByVal) {
4087                                 int doffset = inst->inst_offset;
4088                                 int soffset = 0;
4089                                 int cur_reg;
4090                                 int size = 0;
4091                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4092                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4093                                 /* FIXME: what if there is no class? */
4094                                 if (mono_class_from_mono_type (inst->inst_vtype))
4095                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
4096                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4097 /*
4098 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
4099 register.  Should this case include linux/ppc?
4100 */
4101 #if __APPLE__
4102                                         if (size == 2)
4103                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4104                                         else if (size == 1)
4105                                                 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4106                                         else 
4107 #endif
4108                                                 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
4109                                         soffset += sizeof (gpointer);
4110                                         doffset += sizeof (gpointer);
4111                                 }
4112                                 if (ainfo->vtsize) {
4113                                         /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
4114                                         ppc_lwz (code, ppc_r11, 0, ppc_sp);
4115                                         if ((size & 3) != 0) {
4116                                                 code = emit_memcpy (code, size - soffset,
4117                                                         inst->inst_basereg, doffset,
4118                                                         ppc_r11, ainfo->offset + soffset);
4119                                         } else {
4120                                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer),
4121                                                         inst->inst_basereg, doffset,
4122                                                         ppc_r11, ainfo->offset + soffset);
4123                                         }
4124                                 }
4125                         } else if (ainfo->regtype == RegTypeStructByAddr) {
4126                                 /* if it was originally a RegTypeBase */
4127                                 if (ainfo->offset) {
4128                                         /* load the previous stack pointer in r11 */
4129                                         ppc_lwz (code, ppc_r11, 0, ppc_sp);
4130                                         ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
4131                                 } else {
4132                                         ppc_mr (code, ppc_r11, ainfo->reg);
4133                                 }
4134
4135                                 if (cfg->tailcall_valuetype_addrs) {
4136                                         MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
4137
4138                                         g_assert (ppc_is_imm16 (addr->inst_offset));
4139                                         ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
4140
4141                                         tailcall_struct_index++;
4142                                 }
4143
4144                                 g_assert (ppc_is_imm16 (inst->inst_offset));
4145                                 code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
4146                                 /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
4147                         } else
4148                                 g_assert_not_reached ();
4149                 }
4150                 pos++;
4151         }
4152
4153         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4154                 ppc_load (code, ppc_r3, cfg->domain);
4155                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
4156                 if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4157                         ppc_lis (code, ppc_r0, 0);
4158                         ppc_ori (code, ppc_r0, ppc_r0, 0);
4159                         ppc_mtlr (code, ppc_r0);
4160                         ppc_blrl (code);
4161                 } else {
4162                         ppc_bl (code, 0);
4163                 }
4164         }
4165
4166         if (method->save_lmf) {
4167                 if (lmf_pthread_key != -1) {
4168                         emit_tls_access (code, ppc_r3, lmf_pthread_key);
4169                         if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4170                                 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4171                 } else {
4172                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4173                                      (gpointer)"mono_get_lmf_addr");
4174                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4175                                 ppc_lis (code, ppc_r0, 0);
4176                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
4177                                 ppc_mtlr (code, ppc_r0);
4178                                 ppc_blrl (code);
4179                         } else {
4180                                 ppc_bl (code, 0);
4181                         }
4182                 }
4183                 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
4184                 /* lmf_offset is the offset from the previous stack pointer,
4185                  * alloc_size is the total stack space allocated, so the offset
4186                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4187                  * The pointer to the struct is put in ppc_r11 (new_lmf).
4188                  * The callee-saved registers are already in the MonoLMF structure
4189                  */
4190                 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
4191                 /* ppc_r3 is the result from mono_get_lmf_addr () */
4192                 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4193                 /* new_lmf->previous_lmf = *lmf_addr */
4194                 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4195                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4196                 /* *(lmf_addr) = r11 */
4197                 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
4198                 /* save method info */
4199                 ppc_load (code, ppc_r0, method);
4200                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
4201                 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
4202                 /* save the current IP */
4203                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4204                 ppc_load (code, ppc_r0, 0x01010101);
4205                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
4206         }
4207
4208         if (tracing)
4209                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4210
4211         cfg->code_len = code - cfg->native_code;
4212         g_assert (cfg->code_len < cfg->code_size);
4213         g_free (cinfo);
4214
4215         return code;
4216 }
4217
4218 void
4219 mono_arch_emit_epilog (MonoCompile *cfg)
4220 {
4221         MonoJumpInfo *patch_info;
4222         MonoMethod *method = cfg->method;
4223         int pos, i;
4224         int max_epilog_size = 16 + 20*4;
4225         guint8 *code;
4226
4227         if (cfg->method->save_lmf)
4228                 max_epilog_size += 128;
4229         
4230         if (mono_jit_trace_calls != NULL)
4231                 max_epilog_size += 50;
4232
4233         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4234                 max_epilog_size += 50;
4235
4236         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4237                 cfg->code_size *= 2;
4238                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4239                 mono_jit_stats.code_reallocs++;
4240         }
4241
4242         /*
4243          * Keep in sync with OP_JMP
4244          */
4245         code = cfg->native_code + cfg->code_len;
4246
4247         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4248                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4249         }
4250         pos = 0;
4251
4252         if (method->save_lmf) {
4253                 int lmf_offset;
4254                 pos +=  sizeof (MonoLMF);
4255                 lmf_offset = pos;
4256                 /* save the frame reg in r8 */
4257                 ppc_mr (code, ppc_r8, cfg->frame_reg);
4258                 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4259                 /* r5 = previous_lmf */
4260                 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
4261                 /* r6 = lmf_addr */
4262                 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
4263                 /* *(lmf_addr) = previous_lmf */
4264                 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
4265                 /* FIXME: speedup: there is no actual need to restore the registers if
4266                  * we didn't actually change them (idea from Zoltan).
4267                  */
4268                 /* restore iregs */
4269                 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
4270                 /* restore fregs */
4271                 /*for (i = 14; i < 32; i++) {
4272                         ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
4273                 }*/
4274                 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
4275                 /* use the saved copy of the frame reg in r8 */
4276                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4277                         ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
4278                         ppc_mtlr (code, ppc_r0);
4279                 }
4280                 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
4281         } else {
4282                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
4283                         if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
4284                                 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
4285                         } else {
4286                                 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
4287                                 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
4288                         }
4289                         ppc_mtlr (code, ppc_r0);
4290                 }
4291                 if (ppc_is_imm16 (cfg->stack_usage)) {
4292                         ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
4293                 } else {
4294                         ppc_load (code, ppc_r11, cfg->stack_usage);
4295                         ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
4296                 }
4297
4298                 /*for (i = 31; i >= 14; --i) {
4299                         if (cfg->used_float_regs & (1 << i)) {
4300                                 pos += sizeof (double);
4301                                 ppc_lfd (code, i, -pos, ppc_sp);
4302                         }
4303                 }*/
4304                 for (i = 31; i >= 13; --i) {
4305                         if (cfg->used_int_regs & (1 << i)) {
4306                                 pos += sizeof (gulong);
4307                                 ppc_lwz (code, i, -pos, ppc_sp);
4308                         }
4309                 }
4310         }
4311         ppc_blr (code);
4312
4313         cfg->code_len = code - cfg->native_code;
4314
4315         g_assert (cfg->code_len < cfg->code_size);
4316
4317 }
4318
4319 /* remove once throw_exception_by_name is eliminated */
4320 static int
4321 exception_id_by_name (const char *name)
4322 {
4323         if (strcmp (name, "IndexOutOfRangeException") == 0)
4324                 return MONO_EXC_INDEX_OUT_OF_RANGE;
4325         if (strcmp (name, "OverflowException") == 0)
4326                 return MONO_EXC_OVERFLOW;
4327         if (strcmp (name, "ArithmeticException") == 0)
4328                 return MONO_EXC_ARITHMETIC;
4329         if (strcmp (name, "DivideByZeroException") == 0)
4330                 return MONO_EXC_DIVIDE_BY_ZERO;
4331         if (strcmp (name, "InvalidCastException") == 0)
4332                 return MONO_EXC_INVALID_CAST;
4333         if (strcmp (name, "NullReferenceException") == 0)
4334                 return MONO_EXC_NULL_REF;
4335         if (strcmp (name, "ArrayTypeMismatchException") == 0)
4336                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4337         g_error ("Unknown intrinsic exception %s\n", name);
4338         return 0;
4339 }
4340
4341 void
4342 mono_arch_emit_exceptions (MonoCompile *cfg)
4343 {
4344         MonoJumpInfo *patch_info;
4345         int i;
4346         guint8 *code;
4347         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4348         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4349         int max_epilog_size = 50;
4350
4351         /* count the number of exception infos */
4352      
4353         /* 
4354          * make sure we have enough space for exceptions
4355          * 24 is the simulated call to throw_exception_by_name
4356          */
4357         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4358                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4359                         i = exception_id_by_name (patch_info->data.target);
4360                         if (!exc_throw_found [i]) {
4361                                 max_epilog_size += 24;
4362                                 exc_throw_found [i] = TRUE;
4363                         }
4364                 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
4365                         max_epilog_size += 12;
4366                 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
4367                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4368                         i = exception_id_by_name (ovfj->data.exception);
4369                         if (!exc_throw_found [i]) {
4370                                 max_epilog_size += 24;
4371                                 exc_throw_found [i] = TRUE;
4372                         }
4373                         max_epilog_size += 8;
4374                 }
4375         }
4376
4377         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4378                 cfg->code_size *= 2;
4379                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4380                 mono_jit_stats.code_reallocs++;
4381         }
4382
4383         code = cfg->native_code + cfg->code_len;
4384
4385         /* add code to raise exceptions */
4386         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4387                 switch (patch_info->type) {
4388                 case MONO_PATCH_INFO_BB_OVF: {
4389                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4390                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4391                         /* patch the initial jump */
4392                         ppc_patch (ip, code);
4393                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
4394                         ppc_b (code, 0);
4395                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4396                         /* jump back to the true target */
4397                         ppc_b (code, 0);
4398                         ip = ovfj->data.bb->native_offset + cfg->native_code;
4399                         ppc_patch (code - 4, ip);
4400                         break;
4401                 }
4402                 case MONO_PATCH_INFO_EXC_OVF: {
4403                         MonoOvfJump *ovfj = (MonoOvfJump*)patch_info->data.target;
4404                         MonoJumpInfo *newji;
4405                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4406                         unsigned char *bcl = code;
4407                         /* patch the initial jump: we arrived here with a call */
4408                         ppc_patch (ip, code);
4409                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
4410                         ppc_b (code, 0);
4411                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
4412                         /* patch the conditional jump to the right handler */
4413                         /* make it processed next */
4414                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
4415                         newji->type = MONO_PATCH_INFO_EXC;
4416                         newji->ip.i = bcl - cfg->native_code;
4417                         newji->data.target = ovfj->data.exception;
4418                         newji->next = patch_info->next;
4419                         patch_info->next = newji;
4420                         break;
4421                 }
4422                 case MONO_PATCH_INFO_EXC: {
4423                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4424                         i = exception_id_by_name (patch_info->data.target);
4425                         if (exc_throw_pos [i]) {
4426                                 ppc_patch (ip, exc_throw_pos [i]);
4427                                 patch_info->type = MONO_PATCH_INFO_NONE;
4428                                 break;
4429                         } else {
4430                                 exc_throw_pos [i] = code;
4431                         }
4432                         ppc_patch (ip, code);
4433                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
4434                         ppc_load (code, ppc_r3, patch_info->data.target);
4435                         /* we got here from a conditional call, so the calling ip is set in lr already */
4436                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4437                         patch_info->data.name = "mono_arch_throw_exception_by_name";
4438                         patch_info->ip.i = code - cfg->native_code;
4439                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
4440                                 ppc_lis (code, ppc_r0, 0);
4441                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
4442                                 ppc_mtctr (code, ppc_r0);
4443                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4444                         } else {
4445                                 ppc_b (code, 0);
4446                         }
4447                         break;
4448                 }
4449                 default:
4450                         /* do nothing */
4451                         break;
4452                 }
4453         }
4454
4455         cfg->code_len = code - cfg->native_code;
4456
4457         g_assert (cfg->code_len < cfg->code_size);
4458
4459 }
4460
4461 static int
4462 try_offset_access (void *value, guint32 idx)
4463 {
4464         register void* me __asm__ ("r2");
4465         void ***p = (void***)((char*)me + 284);
4466         int idx1 = idx / 32;
4467         int idx2 = idx % 32;
4468         if (!p [idx1])
4469                 return 0;
4470         if (value != p[idx1][idx2])
4471                 return 0;
4472         return 1;
4473 }
4474
4475 static void
4476 setup_tls_access (void)
4477 {
4478         guint32 ptk;
4479         guint32 *ins, *code;
4480         guint32 cmplwi_1023, li_0x48, blr_ins;
4481         if (tls_mode == TLS_MODE_FAILED)
4482                 return;
4483
4484         if (g_getenv ("MONO_NO_TLS")) {
4485                 tls_mode = TLS_MODE_FAILED;
4486                 return;
4487         }
4488
4489         if (tls_mode == TLS_MODE_DETECT) {
4490                 ins = (guint32*)pthread_getspecific;
4491                 /* uncond branch to the real method */
4492                 if ((*ins >> 26) == 18) {
4493                         gint32 val;
4494                         val = (*ins & ~3) << 6;
4495                         val >>= 6;
4496                         if (*ins & 2) {
4497                                 /* absolute */
4498                                 ins = (guint32*)val;
4499                         } else {
4500                                 ins = (guint32*) ((char*)ins + val);
4501                         }
4502                 }
4503                 code = &cmplwi_1023;
4504                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
4505                 code = &li_0x48;
4506                 ppc_li (code, ppc_r4, 0x48);
4507                 code = &blr_ins;
4508                 ppc_blr (code);
4509                 if (*ins == cmplwi_1023) {
4510                         int found_lwz_284 = 0;
4511                         for (ptk = 0; ptk < 20; ++ptk) {
4512                                 ++ins;
4513                                 if (!*ins || *ins == blr_ins)
4514                                         break;
4515                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
4516                                         found_lwz_284 = 1;
4517                                         break;
4518                                 }
4519                         }
4520                         if (!found_lwz_284) {
4521                                 tls_mode = TLS_MODE_FAILED;
4522                                 return;
4523                         }
4524                         tls_mode = TLS_MODE_LTHREADS;
4525                 } else if (*ins == li_0x48) {
4526                         ++ins;
4527                         /* uncond branch to the real method */
4528                         if ((*ins >> 26) == 18) {
4529                                 gint32 val;
4530                                 val = (*ins & ~3) << 6;
4531                                 val >>= 6;
4532                                 if (*ins & 2) {
4533                                         /* absolute */
4534                                         ins = (guint32*)val;
4535                                 } else {
4536                                         ins = (guint32*) ((char*)ins + val);
4537                                 }
4538                                 code = (guint32*)&val;
4539                                 ppc_li (code, ppc_r0, 0x7FF2);
4540                                 if (ins [1] == val) {
4541                                         /* Darwin on G4, implement */
4542                                         tls_mode = TLS_MODE_FAILED;
4543                                         return;
4544                                 } else {
4545                                         code = (guint32*)&val;
4546                                         ppc_mfspr (code, ppc_r3, 104);
4547                                         if (ins [1] != val) {
4548                                                 tls_mode = TLS_MODE_FAILED;
4549                                                 return;
4550                                         }
4551                                         tls_mode = TLS_MODE_DARWIN_G5;
4552                                 }
4553                         } else {
4554                                 tls_mode = TLS_MODE_FAILED;
4555                                 return;
4556                         }
4557                 } else {
4558                         tls_mode = TLS_MODE_FAILED;
4559                         return;
4560                 }
4561         }
4562         if (monodomain_key == -1) {
4563                 ptk = mono_domain_get_tls_key ();
4564                 if (ptk < 1024) {
4565                         ptk = mono_pthread_key_for_tls (ptk);
4566                         if (ptk < 1024) {
4567                                 monodomain_key = ptk;
4568                         }
4569                 }
4570         }
4571         if (lmf_pthread_key == -1) {
4572                 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
4573                 if (ptk < 1024) {
4574                         /*g_print ("MonoLMF at: %d\n", ptk);*/
4575                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
4576                                 init_tls_failed = 1;
4577                                 return;
4578                         }*/
4579                         lmf_pthread_key = ptk;
4580                 }
4581         }
4582         if (monothread_key == -1) {
4583                 ptk = mono_thread_get_tls_key ();
4584                 if (ptk < 1024) {
4585                         ptk = mono_pthread_key_for_tls (ptk);
4586                         if (ptk < 1024) {
4587                                 monothread_key = ptk;
4588                                 /*g_print ("thread inited: %d\n", ptk);*/
4589                         }
4590                 } else {
4591                         /*g_print ("thread not inited yet %d\n", ptk);*/
4592                 }
4593         }
4594 }
4595
4596 void
4597 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4598 {
4599         setup_tls_access ();
4600 }
4601
4602 void
4603 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4604 {
4605 }
4606
4607 void
4608 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4609 {
4610         int this_dreg = ppc_r3;
4611         
4612         if (vt_reg != -1)
4613                 this_dreg = ppc_r4;
4614
4615         /* add the this argument */
4616         if (this_reg != -1) {
4617                 MonoInst *this;
4618                 MONO_INST_NEW (cfg, this, OP_MOVE);
4619                 this->type = this_type;
4620                 this->sreg1 = this_reg;
4621                 this->dreg = mono_regstate_next_int (cfg->rs);
4622                 mono_bblock_add_inst (cfg->cbb, this);
4623                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4624         }
4625
4626         if (vt_reg != -1) {
4627                 MonoInst *vtarg;
4628                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4629                 vtarg->type = STACK_MP;
4630                 vtarg->sreg1 = vt_reg;
4631                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4632                 mono_bblock_add_inst (cfg->cbb, vtarg);
4633                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
4634         }
4635 }
4636
4637 #ifdef MONO_ARCH_HAVE_IMT
4638
4639 #define CMP_SIZE 12
4640 #define BR_SIZE 4
4641 #define JUMP_IMM_SIZE 12
4642 #define ENABLE_WRONG_METHOD_CHECK 0
4643
4644 /*
4645  * LOCKING: called with the domain lock held
4646  */
4647 gpointer
4648 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4649 {
4650         int i;
4651         int size = 0;
4652         guint8 *code, *start;
4653
4654         for (i = 0; i < count; ++i) {
4655                 MonoIMTCheckItem *item = imt_entries [i];
4656                 if (item->is_equals) {
4657                         if (item->check_target_idx) {
4658                                 if (!item->compare_done)
4659                                         item->chunk_size += CMP_SIZE;
4660                                 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
4661                         } else {
4662                                 item->chunk_size += JUMP_IMM_SIZE;
4663 #if ENABLE_WRONG_METHOD_CHECK
4664                                 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
4665 #endif
4666                         }
4667                 } else {
4668                         item->chunk_size += CMP_SIZE + BR_SIZE;
4669                         imt_entries [item->check_target_idx]->compare_done = TRUE;
4670                 }
4671                 size += item->chunk_size;
4672         }
4673         /* the initial load of the vtable address */
4674         size += 8;
4675         code = mono_code_manager_reserve (domain->code_mp, size);
4676         start = code;
4677         ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
4678         for (i = 0; i < count; ++i) {
4679                 MonoIMTCheckItem *item = imt_entries [i];
4680                 item->code_target = code;
4681                 if (item->is_equals) {
4682                         if (item->check_target_idx) {
4683                                 if (!item->compare_done) {
4684                                         ppc_load (code, ppc_r0, (guint32)item->method);
4685                                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4686                                 }
4687                                 item->jmp_code = code;
4688                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4689                                 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4690                                 ppc_mtctr (code, ppc_r0);
4691                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4692                         } else {
4693                                 /* enable the commented code to assert on wrong method */
4694 #if ENABLE_WRONG_METHOD_CHECK
4695                                 ppc_load (code, ppc_r0, (guint32)item->method);
4696                                 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4697                                 item->jmp_code = code;
4698                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
4699 #endif
4700                                 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->vtable_slot), ppc_r11);
4701                                 ppc_mtctr (code, ppc_r0);
4702                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
4703 #if ENABLE_WRONG_METHOD_CHECK
4704                                 ppc_patch (item->jmp_code, code);
4705                                 ppc_break (code);
4706                                 item->jmp_code = NULL;
4707 #endif
4708                         }
4709                 } else {
4710                         ppc_load (code, ppc_r0, (guint32)item->method);
4711                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
4712                         item->jmp_code = code;
4713                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
4714                 }
4715         }
4716         /* patch the branches to get to the target items */
4717         for (i = 0; i < count; ++i) {
4718                 MonoIMTCheckItem *item = imt_entries [i];
4719                 if (item->jmp_code) {
4720                         if (item->check_target_idx) {
4721                                 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4722                         }
4723                 }
4724         }
4725                 
4726         mono_stats.imt_thunks_size += code - start;
4727         g_assert (code - start <= size);
4728         mono_arch_flush_icache (start, size);
4729         return start;
4730 }
4731
4732 MonoMethod*
4733 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4734 {
4735         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4736 }
4737
4738 MonoObject*
4739 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4740 {
4741         return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4742 }
4743 #endif
4744
4745 MonoInst*
4746 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4747 {
4748         MonoInst *ins = NULL;
4749
4750         /*if (cmethod->klass == mono_defaults.math_class) {
4751                 if (strcmp (cmethod->name, "Sqrt") == 0) {
4752                         MONO_INST_NEW (cfg, ins, OP_SQRT);
4753                         ins->inst_i0 = args [0];
4754                 }
4755         }*/
4756         return ins;
4757 }
4758
4759 MonoInst*
4760 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4761 {
4762         /* FIXME: */
4763         return NULL;
4764 }
4765
4766 gboolean
4767 mono_arch_print_tree (MonoInst *tree, int arity)
4768 {
4769         return 0;
4770 }
4771
4772 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4773 {
4774         MonoInst* ins;
4775
4776         setup_tls_access ();
4777         if (monodomain_key == -1)
4778                 return NULL;
4779         
4780         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4781         ins->inst_offset = monodomain_key;
4782         return ins;
4783 }
4784
4785 MonoInst* 
4786 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4787 {
4788         MonoInst* ins;
4789
4790         setup_tls_access ();
4791         if (monothread_key == -1)
4792                 return NULL;
4793         
4794         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4795         ins->inst_offset = monothread_key;
4796         return ins;
4797 }
4798
4799 gpointer
4800 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4801 {
4802         /* FIXME: implement */
4803         g_assert_not_reached ();
4804 }