New test.
[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-g4.h"
19 #include "trace.h"
20 #ifdef __APPLE__
21 #include <sys/sysctl.h>
22 #endif
23
24 #define FORCE_INDIR_CALL 1
25
26 enum {
27         TLS_MODE_DETECT,
28         TLS_MODE_FAILED,
29         TLS_MODE_LTHREADS,
30         TLS_MODE_NPTL,
31         TLS_MODE_DARWIN_G4,
32         TLS_MODE_DARWIN_G5
33 };
34
35 int mono_exc_esp_offset = 0;
36 static int tls_mode = TLS_MODE_DETECT;
37 static int lmf_pthread_key = -1;
38 static int monothread_key = -1;
39 static int monodomain_key = -1;
40
41 static int
42 offsets_from_pthread_key (guint32 key, int *offset2)
43 {
44         int idx1 = key / 32;
45         int idx2 = key % 32;
46         *offset2 = idx2 * sizeof (gpointer);
47         return 284 + idx1 * sizeof (gpointer);
48 }
49
50 #define emit_linuxthreads_tls(code,dreg,key) do {\
51                 int off1, off2; \
52                 off1 = offsets_from_pthread_key ((key), &off2); \
53                 ppc_lwz ((code), (dreg), off1, ppc_r2); \
54                 ppc_lwz ((code), (dreg), off2, (dreg)); \
55         } while (0);
56
57 #define emit_darwing5_tls(code,dreg,key) do {\
58                 int off1 = 0x48 + key * sizeof (gpointer);      \
59                 ppc_mfspr ((code), (dreg), 104);        \
60                 ppc_lwz ((code), (dreg), off1, (dreg)); \
61         } while (0);
62
63 /* FIXME: ensure the sc call preserves all but r3 */
64 #define emit_darwing4_tls(code,dreg,key) do {\
65                 int off1 = 0x48 + key * sizeof (gpointer);      \
66                 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r11, ppc_r3); \
67                 ppc_li ((code), ppc_r0, 0x7FF2);        \
68                 ppc_sc ((code));        \
69                 ppc_lwz ((code), (dreg), off1, ppc_r3); \
70                 if ((dreg) != ppc_r3) ppc_mr ((code), ppc_r3, ppc_r11); \
71         } while (0);
72
73 #define emit_tls_access(code,dreg,key) do {     \
74                 switch (tls_mode) {     \
75                 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break;    \
76                 case TLS_MODE_DARWIN_G5: emit_darwing5_tls(code,dreg,key); break;       \
77                 case TLS_MODE_DARWIN_G4: emit_darwing4_tls(code,dreg,key); break;       \
78                 default: g_assert_not_reached ();       \
79                 }       \
80         } while (0)
81
82 const char*
83 mono_arch_regname (int reg) {
84         static const char rnames[][4] = {
85                 "r0", "sp", "r2", "r3", "r4",
86                 "r5", "r6", "r7", "r8", "r9",
87                 "r10", "r11", "r12", "r13", "r14",
88                 "r15", "r16", "r17", "r18", "r19",
89                 "r20", "r21", "r22", "r23", "r24",
90                 "r25", "r26", "r27", "r28", "r29",
91                 "r30", "r31"
92         };
93         if (reg >= 0 && reg < 32)
94                 return rnames [reg];
95         return "unknown";
96 }
97
98 const char*
99 mono_arch_fregname (int reg) {
100         static const char rnames[][4] = {
101                 "f0", "f1", "f2", "f3", "f4",
102                 "f5", "f6", "f7", "f8", "f9",
103                 "f10", "f11", "f12", "f13", "f14",
104                 "f15", "f16", "f17", "f18", "f19",
105                 "f20", "f21", "f22", "f23", "f24",
106                 "f25", "f26", "f27", "f28", "f29",
107                 "f30", "f31"
108         };
109         if (reg >= 0 && reg < 32)
110                 return rnames [reg];
111         return "unknown";
112 }
113
114 /* this function overwrites r0, r11, r12 */
115 static guint8*
116 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
117 {
118         /* unrolled, use the counter in big */
119         if (size > sizeof (gpointer) * 5) {
120                 int shifted = size >> 2;
121                 guint8 *copy_loop_start, *copy_loop_jump;
122
123                 ppc_load (code, ppc_r0, shifted);
124                 ppc_mtctr (code, ppc_r0);
125                 g_assert (sreg == ppc_r11);
126                 ppc_addi (code, ppc_r12, dreg, (doffset - 4));
127                 ppc_addi (code, ppc_r11, sreg, (soffset - 4));
128                 copy_loop_start = code;
129                 ppc_lwzu (code, ppc_r0, ppc_r11, 4);
130                 ppc_stwu (code, ppc_r0, 4, ppc_r12);
131                 copy_loop_jump = code;
132                 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
133                 ppc_patch (copy_loop_jump, copy_loop_start);
134                 size -= shifted * 4;
135                 doffset = soffset = 0;
136                 dreg = ppc_r12;
137         }
138         while (size >= 4) {
139                 ppc_lwz (code, ppc_r0, soffset, sreg);
140                 ppc_stw (code, ppc_r0, doffset, dreg);
141                 size -= 4;
142                 soffset += 4;
143                 doffset += 4;
144         }
145         while (size >= 2) {
146                 ppc_lhz (code, ppc_r0, soffset, sreg);
147                 ppc_sth (code, ppc_r0, doffset, dreg);
148                 size -= 2;
149                 soffset += 2;
150                 doffset += 2;
151         }
152         while (size >= 1) {
153                 ppc_lbz (code, ppc_r0, soffset, sreg);
154                 ppc_stb (code, ppc_r0, doffset, dreg);
155                 size -= 1;
156                 soffset += 1;
157                 doffset += 1;
158         }
159         return code;
160 }
161
162 /*
163  * mono_arch_get_argument_info:
164  * @csig:  a method signature
165  * @param_count: the number of parameters to consider
166  * @arg_info: an array to store the result infos
167  *
168  * Gathers information on parameters such as size, alignment and
169  * padding. arg_info should be large enought to hold param_count + 1 entries. 
170  *
171  * Returns the size of the activation frame.
172  */
173 int
174 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
175 {
176         int k, frame_size = 0;
177         int size, align, pad;
178         int offset = 8;
179
180         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
181                 frame_size += sizeof (gpointer);
182                 offset += 4;
183         }
184
185         arg_info [0].offset = offset;
186
187         if (csig->hasthis) {
188                 frame_size += sizeof (gpointer);
189                 offset += 4;
190         }
191
192         arg_info [0].size = frame_size;
193
194         for (k = 0; k < param_count; k++) {
195                 
196                 if (csig->pinvoke)
197                         size = mono_type_native_stack_size (csig->params [k], &align);
198                 else
199                         size = mono_type_stack_size (csig->params [k], &align);
200
201                 /* ignore alignment for now */
202                 align = 1;
203
204                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
205                 arg_info [k].pad = pad;
206                 frame_size += size;
207                 arg_info [k + 1].pad = 0;
208                 arg_info [k + 1].size = size;
209                 offset += pad;
210                 arg_info [k + 1].offset = offset;
211                 offset += size;
212         }
213
214         align = MONO_ARCH_FRAME_ALIGNMENT;
215         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
216         arg_info [k].pad = pad;
217
218         return frame_size;
219 }
220
221 /*
222  * Initialize the cpu to execute managed code.
223  */
224 void
225 mono_arch_cpu_init (void)
226 {
227 }
228
229 /*
230  * This function returns the optimizations supported on this cpu.
231  */
232 guint32
233 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
234 {
235         guint32 opts = 0;
236
237         /* no ppc-specific optimizations yet */
238         *exclude_mask = 0;
239         return opts;
240 }
241
242 static gboolean
243 is_regsize_var (MonoType *t) {
244         if (t->byref)
245                 return TRUE;
246         t = mono_type_get_underlying_type (t);
247         switch (t->type) {
248         case MONO_TYPE_I4:
249         case MONO_TYPE_U4:
250         case MONO_TYPE_I:
251         case MONO_TYPE_U:
252         case MONO_TYPE_PTR:
253         case MONO_TYPE_FNPTR:
254                 return TRUE;
255         case MONO_TYPE_OBJECT:
256         case MONO_TYPE_STRING:
257         case MONO_TYPE_CLASS:
258         case MONO_TYPE_SZARRAY:
259         case MONO_TYPE_ARRAY:
260                 return TRUE;
261         case MONO_TYPE_GENERICINST:
262                 if (!mono_type_generic_inst_is_valuetype (t))
263                         return TRUE;
264                 return FALSE;
265         case MONO_TYPE_VALUETYPE:
266                 return FALSE;
267         }
268         return FALSE;
269 }
270
271 GList *
272 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
273 {
274         GList *vars = NULL;
275         int i;
276
277         for (i = 0; i < cfg->num_varinfo; i++) {
278                 MonoInst *ins = cfg->varinfo [i];
279                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
280
281                 /* unused vars */
282                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
283                         continue;
284
285                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
286                         continue;
287
288                 /* we can only allocate 32 bit values */
289                 if (is_regsize_var (ins->inst_vtype)) {
290                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
291                         g_assert (i == vmv->idx);
292                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
293                 }
294         }
295
296         return vars;
297 }
298
299 GList *
300 mono_arch_get_global_int_regs (MonoCompile *cfg)
301 {
302         GList *regs = NULL;
303         int i, top = 32;
304         if (cfg->frame_reg != ppc_sp)
305                 top = 31;
306         for (i = 13; i < top; ++i)
307                 regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
308
309         return regs;
310 }
311
312 /*
313  * mono_arch_regalloc_cost:
314  *
315  *  Return the cost, in number of memory references, of the action of 
316  * allocating the variable VMV into a register during global register
317  * allocation.
318  */
319 guint32
320 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
321 {
322         /* FIXME: */
323         return 2;
324 }
325
326 typedef struct {
327         long int type;
328         long int value;
329 } AuxVec;
330
331 void
332 mono_arch_flush_icache (guint8 *code, gint size)
333 {
334         guint8 *p, *endp, *start;
335         static int cachelinesize = 0;
336         static int cachelineinc = 16;
337
338         if (!cachelinesize) {
339 #ifdef __APPLE__
340                 int mib [3], len;
341                 mib [0] = CTL_HW;
342                 mib [1] = HW_CACHELINE;
343                 len = sizeof (cachelinesize);
344                 if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
345                         perror ("sysctl");
346                         cachelinesize = 128;
347                 } else {
348                         cachelineinc = cachelinesize;
349                         /*g_print ("setting cl size to %d\n", cachelinesize);*/
350                 }
351 #elif defined(__linux__)
352                 /* sadly this will work only with 2.6 kernels... */
353                 FILE* f = fopen ("/proc/self/auxv", "rb");
354                 if (f) {
355                         AuxVec vec;
356                         while (fread (&vec, sizeof (vec), 1, f) == 1) {
357                                 if (vec.type == 19) {
358                                         cachelinesize = vec.value;
359                                         break;
360                                 }
361                         }
362                         fclose (f);
363                 }
364                 if (!cachelinesize)
365                         cachelinesize = 128;
366 #else
367 #warning Need a way to get cache line size
368                 cachelinesize = 128;
369 #endif
370         }
371         p = start = code;
372         endp = p + size;
373         start = (guint8*)((guint32)start & ~(cachelinesize - 1));
374         /* use dcbf for smp support, later optimize for UP, see pem._64bit.d20030611.pdf page 211 */
375         if (1) {
376                 for (p = start; p < endp; p += cachelineinc) {
377                         asm ("dcbf 0,%0;" : : "r"(p) : "memory");
378                 }
379         } else {
380                 for (p = start; p < endp; p += cachelineinc) {
381                         asm ("dcbst 0,%0;" : : "r"(p) : "memory");
382                 }
383         }
384         asm ("sync");
385         p = code;
386         for (p = start; p < endp; p += cachelineinc) {
387                 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
388         }
389         asm ("sync");
390         asm ("isync");
391 }
392
393 #define NOT_IMPLEMENTED(x) \
394                 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
395
396 #ifdef __APPLE__
397 #define ALWAYS_ON_STACK(s) s
398 #define FP_ALSO_IN_REG(s) s
399 #else
400 #define ALWAYS_ON_STACK(s)
401 #define FP_ALSO_IN_REG(s)
402 #define ALIGN_DOUBLES
403 #endif
404
405 enum {
406         RegTypeGeneral,
407         RegTypeBase,
408         RegTypeFP,
409         RegTypeStructByVal,
410         RegTypeStructByAddr
411 };
412
413 typedef struct {
414         gint32  offset;
415         guint16 vtsize; /* in param area */
416         guint8  reg;
417         guint8  regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
418         guint8  size    : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
419 } ArgInfo;
420
421 typedef struct {
422         int nargs;
423         guint32 stack_usage;
424         guint32 struct_ret;
425         ArgInfo ret;
426         ArgInfo sig_cookie;
427         ArgInfo args [1];
428 } CallInfo;
429
430 #define DEBUG(a)
431
432 static void inline
433 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
434 {
435         if (simple) {
436                 if (*gr >= 3 + PPC_NUM_REG_ARGS) {
437                         ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
438                         ainfo->reg = ppc_sp; /* in the caller */
439                         ainfo->regtype = RegTypeBase;
440                         *stack_size += 4;
441                 } else {
442                         ALWAYS_ON_STACK (*stack_size += 4);
443                         ainfo->reg = *gr;
444                 }
445         } else {
446                 if (*gr >= 3 + PPC_NUM_REG_ARGS - 1) {
447 #ifdef ALIGN_DOUBLES
448                         //*stack_size += (*stack_size % 8);
449 #endif
450                         ainfo->offset = PPC_STACK_PARAM_OFFSET + *stack_size;
451                         ainfo->reg = ppc_sp; /* in the caller */
452                         ainfo->regtype = RegTypeBase;
453                         *stack_size += 8;
454                 } else {
455 #ifdef ALIGN_DOUBLES
456                 if (!((*gr) & 1))
457                         (*gr) ++;
458 #endif
459                         ALWAYS_ON_STACK (*stack_size += 8);
460                         ainfo->reg = *gr;
461                 }
462                 (*gr) ++;
463         }
464         (*gr) ++;
465 }
466
467 #if __APPLE__
468 /* size == 4 is checked already */
469 static gboolean
470 has_only_a_r4_field (MonoClass *klass)
471 {
472         gpointer iter;
473         MonoClassField *f;
474         iter = NULL;
475         while ((f = mono_class_get_fields (klass, &iter))) {
476                 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
477                         if (!f->type->byref && f->type->type == MONO_TYPE_R4)
478                                 return TRUE;
479                         return FALSE;
480                 }
481         }
482         return FALSE;
483 }
484 #endif
485
486 static CallInfo*
487 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
488 {
489         guint i, fr, gr;
490         int n = sig->hasthis + sig->param_count;
491         guint32 simpletype;
492         guint32 stack_size = 0;
493         CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
494
495         fr = PPC_FIRST_FPARG_REG;
496         gr = PPC_FIRST_ARG_REG;
497
498         /* FIXME: handle returning a struct */
499         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
500                 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
501                 cinfo->struct_ret = PPC_FIRST_ARG_REG;
502         }
503
504         n = 0;
505         if (sig->hasthis) {
506                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
507                 n++;
508         }
509         DEBUG(printf("params: %d\n", sig->param_count));
510         for (i = 0; i < sig->param_count; ++i) {
511                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
512                         /* Prevent implicit arguments and sig_cookie from
513                            being passed in registers */
514                         gr = PPC_LAST_ARG_REG + 1;
515                         /* Emit the signature cookie just before the implicit arguments */
516                         add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
517                 }
518                 DEBUG(printf("param %d: ", i));
519                 if (sig->params [i]->byref) {
520                         DEBUG(printf("byref\n"));
521                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
522                         n++;
523                         continue;
524                 }
525                 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
526                 switch (simpletype) {
527                 case MONO_TYPE_BOOLEAN:
528                 case MONO_TYPE_I1:
529                 case MONO_TYPE_U1:
530                         cinfo->args [n].size = 1;
531                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
532                         n++;
533                         break;
534                 case MONO_TYPE_CHAR:
535                 case MONO_TYPE_I2:
536                 case MONO_TYPE_U2:
537                         cinfo->args [n].size = 2;
538                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
539                         n++;
540                         break;
541                 case MONO_TYPE_I4:
542                 case MONO_TYPE_U4:
543                         cinfo->args [n].size = 4;
544                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
545                         n++;
546                         break;
547                 case MONO_TYPE_I:
548                 case MONO_TYPE_U:
549                 case MONO_TYPE_PTR:
550                 case MONO_TYPE_FNPTR:
551                 case MONO_TYPE_CLASS:
552                 case MONO_TYPE_OBJECT:
553                 case MONO_TYPE_STRING:
554                 case MONO_TYPE_SZARRAY:
555                 case MONO_TYPE_ARRAY:
556                         cinfo->args [n].size = sizeof (gpointer);
557                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
558                         n++;
559                         break;
560                 case MONO_TYPE_GENERICINST:
561                         if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
562                                 cinfo->args [n].size = sizeof (gpointer);
563                                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
564                                 n++;
565                                 break;
566                         }
567                         /* Fall through */
568                 case MONO_TYPE_VALUETYPE: {
569                         gint size;
570                         MonoClass *klass;
571                         klass = mono_class_from_mono_type (sig->params [i]);
572                         if (is_pinvoke)
573                             size = mono_class_native_size (klass, NULL);
574                         else
575                             size = mono_class_value_size (klass, NULL);
576 #if __APPLE__
577                         if (size == 4 && has_only_a_r4_field (klass)) {
578                                 cinfo->args [n].size = 4;
579
580                                 /* It was 7, now it is 8 in LinuxPPC */
581                                 if (fr <= PPC_LAST_FPARG_REG) {
582                                         cinfo->args [n].regtype = RegTypeFP;
583                                         cinfo->args [n].reg = fr;
584                                         fr ++;
585                                         FP_ALSO_IN_REG (gr ++);
586                                         ALWAYS_ON_STACK (stack_size += 4);
587                                 } else {
588                                         cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
589                                         cinfo->args [n].regtype = RegTypeBase;
590                                         cinfo->args [n].reg = ppc_sp; /* in the caller*/
591                                         stack_size += 4;
592                                 }
593                                 n++;
594                                 break;
595                         }
596 #endif
597                         DEBUG(printf ("load %d bytes struct\n",
598                                       mono_class_native_size (sig->params [i]->data.klass, NULL)));
599 #if PPC_PASS_STRUCTS_BY_VALUE
600                         {
601                                 int align_size = size;
602                                 int nwords = 0;
603                                 align_size += (sizeof (gpointer) - 1);
604                                 align_size &= ~(sizeof (gpointer) - 1);
605                                 nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
606                                 cinfo->args [n].regtype = RegTypeStructByVal;
607                                 if (gr > PPC_LAST_ARG_REG || (size >= 3 && size % 4 != 0)) {
608                                         cinfo->args [n].size = 0;
609                                         cinfo->args [n].vtsize = nwords;
610                                 } else {
611                                         int rest = PPC_LAST_ARG_REG - gr + 1;
612                                         int n_in_regs = rest >= nwords? nwords: rest;
613                                         cinfo->args [n].size = n_in_regs;
614                                         cinfo->args [n].vtsize = nwords - n_in_regs;
615                                         cinfo->args [n].reg = gr;
616                                         gr += n_in_regs;
617                                 }
618                                 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
619                                 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
620                                 stack_size += nwords * sizeof (gpointer);
621                         }
622 #else
623                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
624                         cinfo->args [n].regtype = RegTypeStructByAddr;
625 #endif
626                         n++;
627                         break;
628                 }
629                 case MONO_TYPE_TYPEDBYREF: {
630                         int size = sizeof (MonoTypedRef);
631                         /* keep in sync or merge with the valuetype case */
632 #if PPC_PASS_STRUCTS_BY_VALUE
633                         {
634                                 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
635                                 cinfo->args [n].regtype = RegTypeStructByVal;
636                                 if (gr <= PPC_LAST_ARG_REG) {
637                                         int rest = PPC_LAST_ARG_REG - gr + 1;
638                                         int n_in_regs = rest >= nwords? nwords: rest;
639                                         cinfo->args [n].size = n_in_regs;
640                                         cinfo->args [n].vtsize = nwords - n_in_regs;
641                                         cinfo->args [n].reg = gr;
642                                         gr += n_in_regs;
643                                 } else {
644                                         cinfo->args [n].size = 0;
645                                         cinfo->args [n].vtsize = nwords;
646                                 }
647                                 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
648                                 /*g_print ("offset for arg %d at %d\n", n, PPC_STACK_PARAM_OFFSET + stack_size);*/
649                                 stack_size += nwords * sizeof (gpointer);
650                         }
651 #else
652                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
653                         cinfo->args [n].regtype = RegTypeStructByAddr;
654 #endif
655                         n++;
656                         break;
657                 }
658                 case MONO_TYPE_U8:
659                 case MONO_TYPE_I8:
660                         cinfo->args [n].size = 8;
661                         add_general (&gr, &stack_size, cinfo->args + n, FALSE);
662                         n++;
663                         break;
664                 case MONO_TYPE_R4:
665                         cinfo->args [n].size = 4;
666
667                         /* It was 7, now it is 8 in LinuxPPC */
668                         if (fr <= PPC_LAST_FPARG_REG) {
669                                 cinfo->args [n].regtype = RegTypeFP;
670                                 cinfo->args [n].reg = fr;
671                                 fr ++;
672                                 FP_ALSO_IN_REG (gr ++);
673                                 ALWAYS_ON_STACK (stack_size += 4);
674                         } else {
675                                 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
676                                 cinfo->args [n].regtype = RegTypeBase;
677                                 cinfo->args [n].reg = ppc_sp; /* in the caller*/
678                                 stack_size += 4;
679                         }
680                         n++;
681                         break;
682                 case MONO_TYPE_R8:
683                         cinfo->args [n].size = 8;
684                         /* It was 7, now it is 8 in LinuxPPC */
685                         if (fr <= PPC_LAST_FPARG_REG) {
686                                 cinfo->args [n].regtype = RegTypeFP;
687                                 cinfo->args [n].reg = fr;
688                                 fr ++;
689                                 FP_ALSO_IN_REG (gr += 2);
690                                 ALWAYS_ON_STACK (stack_size += 8);
691                         } else {
692                                 cinfo->args [n].offset = PPC_STACK_PARAM_OFFSET + stack_size;
693                                 cinfo->args [n].regtype = RegTypeBase;
694                                 cinfo->args [n].reg = ppc_sp; /* in the caller*/
695                                 stack_size += 8;
696                         }
697                         n++;
698                         break;
699                 default:
700                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
701                 }
702         }
703
704         {
705                 simpletype = mono_type_get_underlying_type (sig->ret)->type;
706                 switch (simpletype) {
707                 case MONO_TYPE_BOOLEAN:
708                 case MONO_TYPE_I1:
709                 case MONO_TYPE_U1:
710                 case MONO_TYPE_I2:
711                 case MONO_TYPE_U2:
712                 case MONO_TYPE_CHAR:
713                 case MONO_TYPE_I4:
714                 case MONO_TYPE_U4:
715                 case MONO_TYPE_I:
716                 case MONO_TYPE_U:
717                 case MONO_TYPE_PTR:
718                 case MONO_TYPE_FNPTR:
719                 case MONO_TYPE_CLASS:
720                 case MONO_TYPE_OBJECT:
721                 case MONO_TYPE_SZARRAY:
722                 case MONO_TYPE_ARRAY:
723                 case MONO_TYPE_STRING:
724                         cinfo->ret.reg = ppc_r3;
725                         break;
726                 case MONO_TYPE_U8:
727                 case MONO_TYPE_I8:
728                         cinfo->ret.reg = ppc_r3;
729                         break;
730                 case MONO_TYPE_R4:
731                 case MONO_TYPE_R8:
732                         cinfo->ret.reg = ppc_f1;
733                         cinfo->ret.regtype = RegTypeFP;
734                         break;
735                 case MONO_TYPE_GENERICINST:
736                         if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
737                                 cinfo->ret.reg = ppc_r3;
738                                 break;
739                         }
740                         break;
741                 case MONO_TYPE_VALUETYPE:
742                         break;
743                 case MONO_TYPE_TYPEDBYREF:
744                 case MONO_TYPE_VOID:
745                         break;
746                 default:
747                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
748                 }
749         }
750
751         /* align stack size to 16 */
752         DEBUG (printf ("      stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
753         stack_size = (stack_size + 15) & ~15;
754
755         cinfo->stack_usage = stack_size;
756         return cinfo;
757 }
758
759
760 /*
761  * Set var information according to the calling convention. ppc version.
762  * The locals var stuff should most likely be split in another method.
763  */
764 void
765 mono_arch_allocate_vars (MonoCompile *m)
766 {
767         MonoMethodSignature *sig;
768         MonoMethodHeader *header;
769         MonoInst *inst;
770         int i, offset, size, align, curinst;
771         int frame_reg = ppc_sp;
772
773         m->flags |= MONO_CFG_HAS_SPILLUP;
774
775         /* allow room for the vararg method args: void* and long/double */
776         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
777                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
778         /* this is bug #60332: remove when #59509 is fixed, so no weird vararg 
779          * call convs needs to be handled this way.
780          */
781         if (m->flags & MONO_CFG_HAS_VARARGS)
782                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
783         /* gtk-sharp and other broken code will dllimport vararg functions even with
784          * non-varargs signatures. Since there is little hope people will get this right
785          * we assume they won't.
786          */
787         if (m->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
788                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
789
790         header = mono_method_get_header (m->method);
791
792         /* 
793          * We use the frame register also for any method that has
794          * exception clauses. This way, when the handlers are called,
795          * the code will reference local variables using the frame reg instead of
796          * the stack pointer: if we had to restore the stack pointer, we'd
797          * corrupt the method frames that are already on the stack (since
798          * filters get called before stack unwinding happens) when the filter
799          * code would call any method (this also applies to finally etc.).
800          */ 
801         if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
802                 frame_reg = ppc_r31;
803         m->frame_reg = frame_reg;
804         if (frame_reg != ppc_sp) {
805                 m->used_int_regs |= 1 << frame_reg;
806         }
807
808         sig = mono_method_signature (m->method);
809         
810         offset = 0;
811         curinst = 0;
812         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
813                 m->ret->opcode = OP_REGVAR;
814                 m->ret->inst_c0 = ppc_r3;
815         } else {
816                 /* FIXME: handle long and FP values */
817                 switch (mono_type_get_underlying_type (sig->ret)->type) {
818                 case MONO_TYPE_VOID:
819                         break;
820                 default:
821                         m->ret->opcode = OP_REGVAR;
822                         m->ret->inst_c0 = ppc_r3;
823                         break;
824                 }
825         }
826         /* local vars are at a positive offset from the stack pointer */
827         /* 
828          * also note that if the function uses alloca, we use ppc_r31
829          * to point at the local variables.
830          */
831         offset = PPC_MINIMAL_STACK_SIZE; /* linkage area */
832         /* align the offset to 16 bytes: not sure this is needed here  */
833         //offset += 16 - 1;
834         //offset &= ~(16 - 1);
835
836         /* add parameter area size for called functions */
837         offset += m->param_area;
838         offset += 16 - 1;
839         offset &= ~(16 - 1);
840
841         /* allow room to save the return value */
842         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
843                 offset += 8;
844
845         /* the MonoLMF structure is stored just below the stack pointer */
846
847 #if 0
848         /* this stuff should not be needed on ppc and the new jit,
849          * because a call on ppc to the handlers doesn't change the 
850          * stack pointer and the jist doesn't manipulate the stack pointer
851          * for operations involving valuetypes.
852          */
853         /* reserve space to store the esp */
854         offset += sizeof (gpointer);
855
856         /* this is a global constant */
857         mono_exc_esp_offset = offset;
858 #endif
859         if (sig->call_convention == MONO_CALL_VARARG) {
860                 m->sig_cookie = PPC_STACK_PARAM_OFFSET;
861         }
862
863         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
864                 inst = m->ret;
865                 offset += sizeof(gpointer) - 1;
866                 offset &= ~(sizeof(gpointer) - 1);
867                 inst->inst_offset = offset;
868                 inst->opcode = OP_REGOFFSET;
869                 inst->inst_basereg = frame_reg;
870                 offset += sizeof(gpointer);
871                 if (sig->call_convention == MONO_CALL_VARARG)
872                         m->sig_cookie += sizeof (gpointer);
873         }
874
875         curinst = m->locals_start;
876         for (i = curinst; i < m->num_varinfo; ++i) {
877                 inst = m->varinfo [i];
878                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
879                         continue;
880
881                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
882                 * pinvoke wrappers when they call functions returning structure */
883                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
884                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
885                 else
886                         size = mono_type_size (inst->inst_vtype, &align);
887
888                 offset += align - 1;
889                 offset &= ~(align - 1);
890                 inst->inst_offset = offset;
891                 inst->opcode = OP_REGOFFSET;
892                 inst->inst_basereg = frame_reg;
893                 offset += size;
894                 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
895         }
896
897         curinst = 0;
898         if (sig->hasthis) {
899                 inst = m->varinfo [curinst];
900                 if (inst->opcode != OP_REGVAR) {
901                         inst->opcode = OP_REGOFFSET;
902                         inst->inst_basereg = frame_reg;
903                         offset += sizeof (gpointer) - 1;
904                         offset &= ~(sizeof (gpointer) - 1);
905                         inst->inst_offset = offset;
906                         offset += sizeof (gpointer);
907                         if (sig->call_convention == MONO_CALL_VARARG)
908                                 m->sig_cookie += sizeof (gpointer);
909                 }
910                 curinst++;
911         }
912
913         for (i = 0; i < sig->param_count; ++i) {
914                 inst = m->varinfo [curinst];
915                 if (inst->opcode != OP_REGVAR) {
916                         inst->opcode = OP_REGOFFSET;
917                         inst->inst_basereg = frame_reg;
918                         size = mono_type_size (sig->params [i], &align);
919                         offset += align - 1;
920                         offset &= ~(align - 1);
921                         inst->inst_offset = offset;
922                         offset += size;
923                         if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) 
924                                 m->sig_cookie += size;
925                 }
926                 curinst++;
927         }
928
929         /* align the offset to 16 bytes */
930         offset += 16 - 1;
931         offset &= ~(16 - 1);
932
933         /* change sign? */
934         m->stack_offset = offset;
935
936 }
937
938 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
939  * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
940  */
941
942 /* 
943  * take the arguments and generate the arch-specific
944  * instructions to properly call the function in call.
945  * This includes pushing, moving arguments to the right register
946  * etc.
947  * Issue: who does the spilling if needed, and when?
948  */
949 MonoCallInst*
950 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
951         MonoInst *arg, *in;
952         MonoMethodSignature *sig;
953         int i, n;
954         CallInfo *cinfo;
955         ArgInfo *ainfo;
956
957         sig = call->signature;
958         n = sig->param_count + sig->hasthis;
959         
960         cinfo = calculate_sizes (sig, sig->pinvoke);
961         if (cinfo->struct_ret)
962                 call->used_iregs |= 1 << cinfo->struct_ret;
963
964         for (i = 0; i < n; ++i) {
965                 ainfo = cinfo->args + i;
966                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
967                         MonoInst *sig_arg;
968                         cfg->disable_aot = TRUE;
969                                 
970                         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
971                         sig_arg->inst_p0 = call->signature;
972                         
973                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
974                         arg->inst_imm = cinfo->sig_cookie.offset;
975                         arg->inst_left = sig_arg;
976                         
977                         /* prepend, so they get reversed */
978                         arg->next = call->out_args;
979                         call->out_args = arg;
980                 }
981                 if (is_virtual && i == 0) {
982                         /* the argument will be attached to the call instrucion */
983                         in = call->args [i];
984                         call->used_iregs |= 1 << ainfo->reg;
985                 } else {
986                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
987                         in = call->args [i];
988                         arg->cil_code = in->cil_code;
989                         arg->inst_left = in;
990                         arg->inst_call = call;
991                         arg->type = in->type;
992                         /* prepend, we'll need to reverse them later */
993                         arg->next = call->out_args;
994                         call->out_args = arg;
995                         if (ainfo->regtype == RegTypeGeneral) {
996                                 arg->backend.reg3 = ainfo->reg;
997                                 call->used_iregs |= 1 << ainfo->reg;
998                                 if (arg->type == STACK_I8)
999                                         call->used_iregs |= 1 << (ainfo->reg + 1);
1000                         } else if (ainfo->regtype == RegTypeStructByAddr) {
1001                                 /* FIXME: where si the data allocated? */
1002                                 arg->backend.reg3 = ainfo->reg;
1003                                 call->used_iregs |= 1 << ainfo->reg;
1004                         } else if (ainfo->regtype == RegTypeStructByVal) {
1005                                 int cur_reg;
1006                                 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1007                                 /* mark the used regs */
1008                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1009                                         call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1010                                 }
1011                                 arg->opcode = OP_OUTARG_VT;
1012                                 ai->reg = ainfo->reg;
1013                                 ai->size = ainfo->size;
1014                                 ai->vtsize = ainfo->vtsize;
1015                                 ai->offset = ainfo->offset;
1016                                 arg->backend.data = ai;
1017                         } else if (ainfo->regtype == RegTypeBase) {
1018                                 MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
1019                                 arg->opcode = OP_OUTARG_MEMBASE;
1020                                 ai->reg = ainfo->reg;
1021                                 ai->size = ainfo->size;
1022                                 ai->offset = ainfo->offset;
1023                                 arg->backend.data = ai;
1024                         } else if (ainfo->regtype == RegTypeFP) {
1025                                 arg->opcode = OP_OUTARG_R8;
1026                                 arg->backend.reg3 = ainfo->reg;
1027                                 call->used_fregs |= 1 << ainfo->reg;
1028                                 if (ainfo->size == 4) {
1029                                         arg->opcode = OP_OUTARG_R8;
1030                                         /* we reduce the precision */
1031                                         /*MonoInst *conv;
1032                                         MONO_INST_NEW (cfg, conv, OP_FCONV_TO_R4);
1033                                         conv->inst_left = arg->inst_left;
1034                                         arg->inst_left = conv;*/
1035                                 }
1036                         } else {
1037                                 g_assert_not_reached ();
1038                         }
1039                 }
1040         }
1041         /*
1042          * Reverse the call->out_args list.
1043          */
1044         {
1045                 MonoInst *prev = NULL, *list = call->out_args, *next;
1046                 while (list) {
1047                         next = list->next;
1048                         list->next = prev;
1049                         prev = list;
1050                         list = next;
1051                 }
1052                 call->out_args = prev;
1053         }
1054         call->stack_usage = cinfo->stack_usage;
1055         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1056         cfg->flags |= MONO_CFG_HAS_CALLS;
1057         /* 
1058          * should set more info in call, such as the stack space
1059          * used by the args that needs to be added back to esp
1060          */
1061
1062         g_free (cinfo);
1063         return call;
1064 }
1065
1066 /*
1067  * Allow tracing to work with this interface (with an optional argument)
1068  */
1069
1070 void*
1071 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1072 {
1073         guchar *code = p;
1074
1075         ppc_load (code, ppc_r3, cfg->method);
1076         ppc_li (code, ppc_r4, 0); /* NULL ebp for now */
1077         ppc_load (code, ppc_r0, func);
1078         ppc_mtlr (code, ppc_r0);
1079         ppc_blrl (code);
1080         return code;
1081 }
1082
1083 enum {
1084         SAVE_NONE,
1085         SAVE_STRUCT,
1086         SAVE_ONE,
1087         SAVE_TWO,
1088         SAVE_FP
1089 };
1090
1091 void*
1092 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1093 {
1094         guchar *code = p;
1095         int save_mode = SAVE_NONE;
1096         int offset;
1097         MonoMethod *method = cfg->method;
1098         int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1099         int save_offset = PPC_STACK_PARAM_OFFSET + cfg->param_area;
1100         save_offset += 15;
1101         save_offset &= ~15;
1102         
1103         offset = code - cfg->native_code;
1104         /* we need about 16 instructions */
1105         if (offset > (cfg->code_size - 16 * 4)) {
1106                 cfg->code_size *= 2;
1107                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1108                 code = cfg->native_code + offset;
1109         }
1110 handle_enum:
1111         switch (rtype) {
1112         case MONO_TYPE_VOID:
1113                 /* special case string .ctor icall */
1114                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1115                         save_mode = SAVE_ONE;
1116                 else
1117                         save_mode = SAVE_NONE;
1118                 break;
1119         case MONO_TYPE_I8:
1120         case MONO_TYPE_U8:
1121                 save_mode = SAVE_TWO;
1122                 break;
1123         case MONO_TYPE_R4:
1124         case MONO_TYPE_R8:
1125                 save_mode = SAVE_FP;
1126                 break;
1127         case MONO_TYPE_VALUETYPE:
1128                 save_mode = SAVE_STRUCT;
1129                 break;
1130         default:
1131                 save_mode = SAVE_ONE;
1132                 break;
1133         }
1134
1135         switch (save_mode) {
1136         case SAVE_TWO:
1137                 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1138                 ppc_stw (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1139                 if (enable_arguments) {
1140                         ppc_mr (code, ppc_r5, ppc_r4);
1141                         ppc_mr (code, ppc_r4, ppc_r3);
1142                 }
1143                 break;
1144         case SAVE_ONE:
1145                 ppc_stw (code, ppc_r3, save_offset, cfg->frame_reg);
1146                 if (enable_arguments) {
1147                         ppc_mr (code, ppc_r4, ppc_r3);
1148                 }
1149                 break;
1150         case SAVE_FP:
1151                 ppc_stfd (code, ppc_f1, save_offset, cfg->frame_reg);
1152                 if (enable_arguments) {
1153                         /* FIXME: what reg?  */
1154                         ppc_fmr (code, ppc_f3, ppc_f1);
1155                         ppc_lwz (code, ppc_r4, save_offset, cfg->frame_reg);
1156                         ppc_lwz (code, ppc_r5, save_offset + 4, cfg->frame_reg);
1157                 }
1158                 break;
1159         case SAVE_STRUCT:
1160                 if (enable_arguments) {
1161                         /* FIXME: get the actual address  */
1162                         ppc_mr (code, ppc_r4, ppc_r3);
1163                 }
1164                 break;
1165         case SAVE_NONE:
1166         default:
1167                 break;
1168         }
1169
1170         ppc_load (code, ppc_r3, cfg->method);
1171         ppc_load (code, ppc_r0, func);
1172         ppc_mtlr (code, ppc_r0);
1173         ppc_blrl (code);
1174
1175         switch (save_mode) {
1176         case SAVE_TWO:
1177                 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1178                 ppc_lwz (code, ppc_r4, save_offset + 4, cfg->frame_reg);
1179                 break;
1180         case SAVE_ONE:
1181                 ppc_lwz (code, ppc_r3, save_offset, cfg->frame_reg);
1182                 break;
1183         case SAVE_FP:
1184                 ppc_lfd (code, ppc_f1, save_offset, cfg->frame_reg);
1185                 break;
1186         case SAVE_NONE:
1187         default:
1188                 break;
1189         }
1190
1191         return code;
1192 }
1193 /*
1194  * Conditional branches have a small offset, so if it is likely overflowed,
1195  * we do a branch to the end of the method (uncond branches have much larger
1196  * offsets) where we perform the conditional and jump back unconditionally.
1197  * It's slightly slower, since we add two uncond branches, but it's very simple
1198  * with the current patch implementation and such large methods are likely not
1199  * going to be perf critical anyway.
1200  */
1201 typedef struct {
1202         union {
1203                 MonoBasicBlock *bb;
1204                 const char *exception;
1205         } data;
1206         guint32 ip_offset;
1207         guint16 b0_cond;
1208         guint16 b1_cond;
1209 } MonoOvfJump;
1210
1211 #define EMIT_COND_BRANCH_FLAGS(ins,b0,b1) \
1212 if (ins->flags & MONO_INST_BRLABEL) { \
1213         if (0 && ins->inst_i0->inst_c0) { \
1214                 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffff);  \
1215         } else { \
1216                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1217                 ppc_bc (code, (b0), (b1), 0);   \
1218         } \
1219 } else { \
1220         if (0 && ins->inst_true_bb->native_offset) { \
1221                 ppc_bc (code, (b0), (b1), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffff); \
1222         } else { \
1223                 int br_disp = ins->inst_true_bb->max_offset - offset;   \
1224                 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1225                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));    \
1226                         ovfj->data.bb = ins->inst_true_bb;      \
1227                         ovfj->ip_offset = 0;    \
1228                         ovfj->b0_cond = (b0);   \
1229                         ovfj->b1_cond = (b1);   \
1230                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB_OVF, ovfj); \
1231                         ppc_b (code, 0);        \
1232                 } else {        \
1233                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1234                         ppc_bc (code, (b0), (b1), 0);   \
1235                 }       \
1236         } \
1237 }
1238
1239 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_b0_table [(cond)], branch_b1_table [(cond)])
1240
1241 /* emit an exception if condition is fail
1242  *
1243  * We assign the extra code used to throw the implicit exceptions
1244  * to cfg->bb_exit as far as the big branch handling is concerned
1245  */
1246 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(b0,b1,exc_name)            \
1247         do {                                                        \
1248                 int br_disp = cfg->bb_exit->max_offset - offset;        \
1249                 if (!ppc_is_imm16 (br_disp + 1024) || ! ppc_is_imm16 (ppc_is_imm16 (br_disp - 1024))) { \
1250                         MonoOvfJump *ovfj = mono_mempool_alloc (cfg->mempool, sizeof (MonoOvfJump));    \
1251                         ovfj->data.exception = (exc_name);      \
1252                         ovfj->ip_offset = code - cfg->native_code;      \
1253                         ovfj->b0_cond = (b0);   \
1254                         ovfj->b1_cond = (b1);   \
1255                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_OVF, ovfj); \
1256                         ppc_bl (code, 0);       \
1257                         cfg->bb_exit->max_offset += 24; \
1258                 } else {        \
1259                         mono_add_patch_info (cfg, code - cfg->native_code,   \
1260                                     MONO_PATCH_INFO_EXC, exc_name);  \
1261                         ppc_bcl (code, (b0), (b1), 0);  \
1262                 }       \
1263         } while (0); 
1264
1265 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_b0_table [(cond)], branch_b1_table [(cond)], (exc_name))
1266
1267 static void
1268 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1269 {
1270         MonoInst *ins, *last_ins = NULL;
1271         ins = bb->code;
1272
1273         while (ins) {
1274
1275                 switch (ins->opcode) {
1276                 case OP_MUL_IMM: 
1277                         /* remove unnecessary multiplication with 1 */
1278                         if (ins->inst_imm == 1) {
1279                                 if (ins->dreg != ins->sreg1) {
1280                                         ins->opcode = OP_MOVE;
1281                                 } else {
1282                                         last_ins->next = ins->next;                             
1283                                         ins = ins->next;                                
1284                                         continue;
1285                                 }
1286                         } else {
1287                                 int power2 = mono_is_power_of_two (ins->inst_imm);
1288                                 if (power2 > 0) {
1289                                         ins->opcode = OP_SHL_IMM;
1290                                         ins->inst_imm = power2;
1291                                 }
1292                         }
1293                         break;
1294                 case OP_LOAD_MEMBASE:
1295                 case OP_LOADI4_MEMBASE:
1296                         /* 
1297                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1298                          * OP_LOAD_MEMBASE offset(basereg), reg
1299                          */
1300                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1301                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1302                             ins->inst_basereg == last_ins->inst_destbasereg &&
1303                             ins->inst_offset == last_ins->inst_offset) {
1304                                 if (ins->dreg == last_ins->sreg1) {
1305                                         last_ins->next = ins->next;                             
1306                                         ins = ins->next;                                
1307                                         continue;
1308                                 } else {
1309                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1310                                         ins->opcode = OP_MOVE;
1311                                         ins->sreg1 = last_ins->sreg1;
1312                                 }
1313
1314                         /* 
1315                          * Note: reg1 must be different from the basereg in the second load
1316                          * OP_LOAD_MEMBASE offset(basereg), reg1
1317                          * OP_LOAD_MEMBASE offset(basereg), reg2
1318                          * -->
1319                          * OP_LOAD_MEMBASE offset(basereg), reg1
1320                          * OP_MOVE reg1, reg2
1321                          */
1322                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1323                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1324                               ins->inst_basereg != last_ins->dreg &&
1325                               ins->inst_basereg == last_ins->inst_basereg &&
1326                               ins->inst_offset == last_ins->inst_offset) {
1327
1328                                 if (ins->dreg == last_ins->dreg) {
1329                                         last_ins->next = ins->next;                             
1330                                         ins = ins->next;                                
1331                                         continue;
1332                                 } else {
1333                                         ins->opcode = OP_MOVE;
1334                                         ins->sreg1 = last_ins->dreg;
1335                                 }
1336
1337                                 //g_assert_not_reached ();
1338
1339 #if 0
1340                         /* 
1341                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1342                          * OP_LOAD_MEMBASE offset(basereg), reg
1343                          * -->
1344                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1345                          * OP_ICONST reg, imm
1346                          */
1347                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1348                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1349                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1350                                    ins->inst_offset == last_ins->inst_offset) {
1351                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1352                                 ins->opcode = OP_ICONST;
1353                                 ins->inst_c0 = last_ins->inst_imm;
1354                                 g_assert_not_reached (); // check this rule
1355 #endif
1356                         }
1357                         break;
1358                 case OP_LOADU1_MEMBASE:
1359                 case OP_LOADI1_MEMBASE:
1360                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1361                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1362                                         ins->inst_offset == last_ins->inst_offset) {
1363                                 if (ins->dreg == last_ins->sreg1) {
1364                                         last_ins->next = ins->next;                             
1365                                         ins = ins->next;                                
1366                                         continue;
1367                                 } else {
1368                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1369                                         ins->opcode = OP_MOVE;
1370                                         ins->sreg1 = last_ins->sreg1;
1371                                 }
1372                         }
1373                         break;
1374                 case OP_LOADU2_MEMBASE:
1375                 case OP_LOADI2_MEMBASE:
1376                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1377                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1378                                         ins->inst_offset == last_ins->inst_offset) {
1379                                 if (ins->dreg == last_ins->sreg1) {
1380                                         last_ins->next = ins->next;                             
1381                                         ins = ins->next;                                
1382                                         continue;
1383                                 } else {
1384                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1385                                         ins->opcode = OP_MOVE;
1386                                         ins->sreg1 = last_ins->sreg1;
1387                                 }
1388                         }
1389                         break;
1390                 case CEE_CONV_I4:
1391                 case CEE_CONV_U4:
1392                 case OP_MOVE:
1393                 case OP_SETREG:
1394                         ins->opcode = OP_MOVE;
1395                         /* 
1396                          * OP_MOVE reg, reg 
1397                          */
1398                         if (ins->dreg == ins->sreg1) {
1399                                 if (last_ins)
1400                                         last_ins->next = ins->next;                             
1401                                 ins = ins->next;
1402                                 continue;
1403                         }
1404                         /* 
1405                          * OP_MOVE sreg, dreg 
1406                          * OP_MOVE dreg, sreg
1407                          */
1408                         if (last_ins && last_ins->opcode == OP_MOVE &&
1409                             ins->sreg1 == last_ins->dreg &&
1410                             ins->dreg == last_ins->sreg1) {
1411                                 last_ins->next = ins->next;                             
1412                                 ins = ins->next;                                
1413                                 continue;
1414                         }
1415                         break;
1416                 }
1417                 last_ins = ins;
1418                 ins = ins->next;
1419         }
1420         bb->last_ins = last_ins;
1421 }
1422
1423 /* 
1424  * the branch_b0_table should maintain the order of these
1425  * opcodes.
1426 case CEE_BEQ:
1427 case CEE_BGE:
1428 case CEE_BGT:
1429 case CEE_BLE:
1430 case CEE_BLT:
1431 case CEE_BNE_UN:
1432 case CEE_BGE_UN:
1433 case CEE_BGT_UN:
1434 case CEE_BLE_UN:
1435 case CEE_BLT_UN:
1436  */
1437 static const guchar 
1438 branch_b0_table [] = {
1439         PPC_BR_TRUE, 
1440         PPC_BR_FALSE, 
1441         PPC_BR_TRUE, 
1442         PPC_BR_FALSE, 
1443         PPC_BR_TRUE, 
1444         
1445         PPC_BR_FALSE, 
1446         PPC_BR_FALSE, 
1447         PPC_BR_TRUE, 
1448         PPC_BR_FALSE,
1449         PPC_BR_TRUE
1450 };
1451
1452 static const guchar 
1453 branch_b1_table [] = {
1454         PPC_BR_EQ, 
1455         PPC_BR_LT, 
1456         PPC_BR_GT, 
1457         PPC_BR_GT,
1458         PPC_BR_LT, 
1459         
1460         PPC_BR_EQ, 
1461         PPC_BR_LT, 
1462         PPC_BR_GT, 
1463         PPC_BR_GT,
1464         PPC_BR_LT 
1465 };
1466
1467 static const char*const * ins_spec = ppcg4;
1468
1469 static void
1470 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1471 {
1472         if (ins == NULL) {
1473                 ins = bb->code;
1474                 bb->code = to_insert;
1475                 to_insert->next = ins;
1476         } else {
1477                 to_insert->next = ins->next;
1478                 ins->next = to_insert;
1479         }
1480 }
1481
1482 #define NEW_INS(cfg,dest,op) do {       \
1483                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
1484                 (dest)->opcode = (op);  \
1485                 insert_after_ins (bb, last_ins, (dest)); \
1486         } while (0)
1487
1488 static int
1489 map_to_reg_reg_op (int op)
1490 {
1491         switch (op) {
1492         case OP_ADD_IMM:
1493                 return CEE_ADD;
1494         case OP_SUB_IMM:
1495                 return CEE_SUB;
1496         case OP_AND_IMM:
1497                 return CEE_AND;
1498         case OP_COMPARE_IMM:
1499                 return OP_COMPARE;
1500         case OP_ADDCC_IMM:
1501                 return OP_ADDCC;
1502         case OP_ADC_IMM:
1503                 return OP_ADC;
1504         case OP_SUBCC_IMM:
1505                 return OP_SUBCC;
1506         case OP_SBB_IMM:
1507                 return OP_SBB;
1508         case OP_OR_IMM:
1509                 return CEE_OR;
1510         case OP_XOR_IMM:
1511                 return CEE_XOR;
1512         case OP_MUL_IMM:
1513                 return CEE_MUL;
1514         case OP_LOAD_MEMBASE:
1515                 return OP_LOAD_MEMINDEX;
1516         case OP_LOADI4_MEMBASE:
1517                 return OP_LOADI4_MEMINDEX;
1518         case OP_LOADU4_MEMBASE:
1519                 return OP_LOADU4_MEMINDEX;
1520         case OP_LOADU1_MEMBASE:
1521                 return OP_LOADU1_MEMINDEX;
1522         case OP_LOADI2_MEMBASE:
1523                 return OP_LOADI2_MEMINDEX;
1524         case OP_LOADU2_MEMBASE:
1525                 return OP_LOADU2_MEMINDEX;
1526         case OP_LOADI1_MEMBASE:
1527                 return OP_LOADI1_MEMINDEX;
1528         case OP_LOADR4_MEMBASE:
1529                 return OP_LOADR4_MEMINDEX;
1530         case OP_LOADR8_MEMBASE:
1531                 return OP_LOADR8_MEMINDEX;
1532         case OP_STOREI1_MEMBASE_REG:
1533                 return OP_STOREI1_MEMINDEX;
1534         case OP_STOREI2_MEMBASE_REG:
1535                 return OP_STOREI2_MEMINDEX;
1536         case OP_STOREI4_MEMBASE_REG:
1537                 return OP_STOREI4_MEMINDEX;
1538         case OP_STORE_MEMBASE_REG:
1539                 return OP_STORE_MEMINDEX;
1540         case OP_STORER4_MEMBASE_REG:
1541                 return OP_STORER4_MEMINDEX;
1542         case OP_STORER8_MEMBASE_REG:
1543                 return OP_STORER8_MEMINDEX;
1544         case OP_STORE_MEMBASE_IMM:
1545                 return OP_STORE_MEMBASE_REG;
1546         case OP_STOREI1_MEMBASE_IMM:
1547                 return OP_STOREI1_MEMBASE_REG;
1548         case OP_STOREI2_MEMBASE_IMM:
1549                 return OP_STOREI2_MEMBASE_REG;
1550         case OP_STOREI4_MEMBASE_IMM:
1551                 return OP_STOREI4_MEMBASE_REG;
1552         }
1553         g_assert_not_reached ();
1554 }
1555
1556 #define compare_opcode_is_unsigned(opcode) \
1557                 (((opcode) >= CEE_BNE_UN && (opcode) <= CEE_BLT_UN) ||  \
1558                 ((opcode) >= OP_COND_EXC_NE_UN && (opcode) <= OP_COND_EXC_LT_UN) ||     \
1559                 ((opcode) == OP_CLT_UN || (opcode) == OP_CGT_UN))
1560 /*
1561  * Remove from the instruction list the instructions that can't be
1562  * represented with very simple instructions with no register
1563  * requirements.
1564  */
1565 static void
1566 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1567 {
1568         MonoInst *ins, *next, *temp, *last_ins = NULL;
1569         int imm;
1570
1571         /* setup the virtual reg allocator */
1572         if (bb->max_ireg > cfg->rs->next_vireg)
1573                 cfg->rs->next_vireg = bb->max_ireg;
1574
1575         ins = bb->code;
1576         while (ins) {
1577 loop_start:
1578                 switch (ins->opcode) {
1579                 case OP_ADD_IMM:
1580                 case OP_ADDCC_IMM:
1581                         if (!ppc_is_imm16 (ins->inst_imm)) {
1582                                 NEW_INS (cfg, temp, OP_ICONST);
1583                                 temp->inst_c0 = ins->inst_imm;
1584                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1585                                 ins->sreg2 = temp->dreg;
1586                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1587                         }
1588                         break;
1589                 case OP_SUB_IMM:
1590                         if (!ppc_is_imm16 (-ins->inst_imm)) {
1591                                 NEW_INS (cfg, temp, OP_ICONST);
1592                                 temp->inst_c0 = ins->inst_imm;
1593                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1594                                 ins->sreg2 = temp->dreg;
1595                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1596                         }
1597                         break;
1598                 case OP_AND_IMM:
1599                 case OP_OR_IMM:
1600                 case OP_XOR_IMM:
1601                         if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
1602                                 NEW_INS (cfg, temp, OP_ICONST);
1603                                 temp->inst_c0 = ins->inst_imm;
1604                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1605                                 ins->sreg2 = temp->dreg;
1606                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1607                         }
1608                         break;
1609                 case OP_SBB_IMM:
1610                 case OP_SUBCC_IMM:
1611                 case OP_ADC_IMM:
1612                         NEW_INS (cfg, temp, OP_ICONST);
1613                         temp->inst_c0 = ins->inst_imm;
1614                         temp->dreg = mono_regstate_next_int (cfg->rs);
1615                         ins->sreg2 = temp->dreg;
1616                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1617                         break;
1618                 case OP_COMPARE_IMM:
1619                         if (compare_opcode_is_unsigned (ins->next->opcode)) {
1620                                 if (!ppc_is_uimm16 (ins->inst_imm)) {
1621                                         NEW_INS (cfg, temp, OP_ICONST);
1622                                         temp->inst_c0 = ins->inst_imm;
1623                                         temp->dreg = mono_regstate_next_int (cfg->rs);
1624                                         ins->sreg2 = temp->dreg;
1625                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1626                                 }
1627                         } else {
1628                                 if (!ppc_is_imm16 (ins->inst_imm)) {
1629                                         NEW_INS (cfg, temp, OP_ICONST);
1630                                         temp->inst_c0 = ins->inst_imm;
1631                                         temp->dreg = mono_regstate_next_int (cfg->rs);
1632                                         ins->sreg2 = temp->dreg;
1633                                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1634                                 }
1635                         }
1636                         break;
1637                 case OP_MUL_IMM:
1638                         if (ins->inst_imm == 1) {
1639                                 ins->opcode = OP_MOVE;
1640                                 break;
1641                         }
1642                         if (ins->inst_imm == 0) {
1643                                 ins->opcode = OP_ICONST;
1644                                 ins->inst_c0 = 0;
1645                                 break;
1646                         }
1647                         imm = mono_is_power_of_two (ins->inst_imm);
1648                         if (imm > 0) {
1649                                 ins->opcode = OP_SHL_IMM;
1650                                 ins->inst_imm = imm;
1651                                 break;
1652                         }
1653                         if (!ppc_is_imm16 (ins->inst_imm)) {
1654                                 NEW_INS (cfg, temp, OP_ICONST);
1655                                 temp->inst_c0 = ins->inst_imm;
1656                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1657                                 ins->sreg2 = temp->dreg;
1658                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1659                         }
1660                         break;
1661                 case OP_LOAD_MEMBASE:
1662                 case OP_LOADI4_MEMBASE:
1663                 case OP_LOADU4_MEMBASE:
1664                 case OP_LOADI2_MEMBASE:
1665                 case OP_LOADU2_MEMBASE:
1666                 case OP_LOADI1_MEMBASE:
1667                 case OP_LOADU1_MEMBASE:
1668                 case OP_LOADR4_MEMBASE:
1669                 case OP_LOADR8_MEMBASE:
1670                 case OP_STORE_MEMBASE_REG:
1671                 case OP_STOREI4_MEMBASE_REG:
1672                 case OP_STOREI2_MEMBASE_REG:
1673                 case OP_STOREI1_MEMBASE_REG:
1674                 case OP_STORER4_MEMBASE_REG:
1675                 case OP_STORER8_MEMBASE_REG:
1676                         /* we can do two things: load the immed in a register
1677                          * and use an indexed load, or see if the immed can be
1678                          * represented as an ad_imm + a load with a smaller offset
1679                          * that fits. We just do the first for now, optimize later.
1680                          */
1681                         if (ppc_is_imm16 (ins->inst_offset))
1682                                 break;
1683                         NEW_INS (cfg, temp, OP_ICONST);
1684                         temp->inst_c0 = ins->inst_offset;
1685                         temp->dreg = mono_regstate_next_int (cfg->rs);
1686                         ins->sreg2 = temp->dreg;
1687                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1688                         break;
1689                 case OP_STORE_MEMBASE_IMM:
1690                 case OP_STOREI1_MEMBASE_IMM:
1691                 case OP_STOREI2_MEMBASE_IMM:
1692                 case OP_STOREI4_MEMBASE_IMM:
1693                         NEW_INS (cfg, temp, OP_ICONST);
1694                         temp->inst_c0 = ins->inst_imm;
1695                         temp->dreg = mono_regstate_next_int (cfg->rs);
1696                         ins->sreg1 = temp->dreg;
1697                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1698                         last_ins = temp;
1699                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
1700                 }
1701                 last_ins = ins;
1702                 ins = ins->next;
1703         }
1704         bb->last_ins = last_ins;
1705         bb->max_ireg = cfg->rs->next_vireg;
1706         
1707 }
1708
1709 void
1710 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1711 {
1712         if (!bb->code)
1713                 return;
1714         mono_arch_lowering_pass (cfg, bb);
1715         mono_local_regalloc (cfg, bb);
1716 }
1717
1718 static guchar*
1719 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1720 {
1721         /* sreg is a float, dreg is an integer reg. ppc_f0 is used a scratch */
1722         ppc_fctiwz (code, ppc_f0, sreg);
1723         ppc_stfd (code, ppc_f0, -8, ppc_sp);
1724         ppc_lwz (code, dreg, -4, ppc_sp);
1725         if (!is_signed) {
1726                 if (size == 1)
1727                         ppc_andid (code, dreg, dreg, 0xff);
1728                 else if (size == 2)
1729                         ppc_andid (code, dreg, dreg, 0xffff);
1730         } else {
1731                 if (size == 1)
1732                         ppc_extsb (code, dreg, dreg);
1733                 else if (size == 2)
1734                         ppc_extsh (code, dreg, dreg);
1735         }
1736         return code;
1737 }
1738
1739 static unsigned char*
1740 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1741 {
1742 #if 0
1743         int sreg = tree->sreg1;
1744         x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1745         if (tree->flags & MONO_INST_INIT) {
1746                 int offset = 0;
1747                 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1748                         x86_push_reg (code, X86_EAX);
1749                         offset += 4;
1750                 }
1751                 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1752                         x86_push_reg (code, X86_ECX);
1753                         offset += 4;
1754                 }
1755                 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1756                         x86_push_reg (code, X86_EDI);
1757                         offset += 4;
1758                 }
1759                 
1760                 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1761                 if (sreg != X86_ECX)
1762                         x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1763                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1764                                 
1765                 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1766                 x86_cld (code);
1767                 x86_prefix (code, X86_REP_PREFIX);
1768                 x86_stosl (code);
1769                 
1770                 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1771                         x86_pop_reg (code, X86_EDI);
1772                 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1773                         x86_pop_reg (code, X86_ECX);
1774                 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1775                         x86_pop_reg (code, X86_EAX);
1776         }
1777 #endif
1778         return code;
1779 }
1780
1781 typedef struct {
1782         guchar *code;
1783         guchar *target;
1784         int absolute;
1785         int found;
1786 } PatchData;
1787
1788 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1789
1790 static int
1791 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1792         PatchData *pdata = (PatchData*)user_data;
1793         guchar *code = data;
1794         guint32 *thunks = data;
1795         guint32 *endthunks = (guint32*)(code + bsize);
1796         guint32 load [2];
1797         guchar *templ;
1798         int i, count = 0;
1799         int difflow, diffhigh;
1800
1801         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1802         difflow = (char*)pdata->code - (char*)thunks;
1803         diffhigh = (char*)pdata->code - (char*)endthunks;
1804         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1805                 return 0;
1806
1807         templ = (guchar*)load;
1808         ppc_lis (templ, ppc_r0, (guint32)(pdata->target) >> 16);
1809         ppc_ori (templ, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1810
1811         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1812         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1813                 while (thunks < endthunks) {
1814                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1815                         if ((thunks [0] == load [0]) && (thunks [1] == load [1])) {
1816                                 ppc_patch (pdata->code, (guchar*)thunks);
1817                                 mono_arch_flush_icache (pdata->code, 4);
1818                                 pdata->found = 1;
1819                                 /*{
1820                                         static int num_thunks = 0;
1821                                         num_thunks++;
1822                                         if ((num_thunks % 20) == 0)
1823                                                 g_print ("num_thunks lookup: %d\n", num_thunks);
1824                                 }*/
1825                                 return 1;
1826                         } else if ((thunks [0] == 0) && (thunks [1] == 0)) {
1827                                 /* found a free slot instead: emit thunk */
1828                                 code = (guchar*)thunks;
1829                                 ppc_lis (code, ppc_r0, (guint32)(pdata->target) >> 16);
1830                                 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(pdata->target) & 0xffff);
1831                                 ppc_mtctr (code, ppc_r0);
1832                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
1833                                 mono_arch_flush_icache ((guchar*)thunks, 16);
1834
1835                                 ppc_patch (pdata->code, (guchar*)thunks);
1836                                 mono_arch_flush_icache (pdata->code, 4);
1837                                 pdata->found = 1;
1838                                 /*{
1839                                         static int num_thunks = 0;
1840                                         num_thunks++;
1841                                         if ((num_thunks % 20) == 0)
1842                                                 g_print ("num_thunks: %d\n", num_thunks);
1843                                 }*/
1844                                 return 1;
1845                         }
1846                         /* skip 16 bytes, the size of the thunk */
1847                         thunks += 4;
1848                         count++;
1849                 }
1850                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1851         }
1852         return 0;
1853 }
1854
1855 static void
1856 handle_thunk (int absolute, guchar *code, guchar *target) {
1857         MonoDomain *domain = mono_domain_get ();
1858         PatchData pdata;
1859
1860         pdata.code = code;
1861         pdata.target = target;
1862         pdata.absolute = absolute;
1863         pdata.found = 0;
1864
1865         mono_domain_lock (domain);
1866         mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1867
1868         if (!pdata.found) {
1869                 /* this uses the first available slot */
1870                 pdata.found = 2;
1871                 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1872         }
1873         mono_domain_unlock (domain);
1874
1875         if (pdata.found != 1)
1876                 g_print ("thunk failed for %p from %p\n", target, code);
1877         g_assert (pdata.found == 1);
1878 }
1879
1880 void
1881 ppc_patch (guchar *code, guchar *target)
1882 {
1883         guint32 ins = *(guint32*)code;
1884         guint32 prim = ins >> 26;
1885         guint32 ovf;
1886
1887         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1888         if (prim == 18) {
1889                 // prefer relative branches, they are more position independent (e.g. for AOT compilation).
1890                 gint diff = target - code;
1891                 if (diff >= 0){
1892                         if (diff <= 33554431){
1893                                 ins = (18 << 26) | (diff) | (ins & 1);
1894                                 *(guint32*)code = ins;
1895                                 return;
1896                         }
1897                 } else {
1898                         /* diff between 0 and -33554432 */
1899                         if (diff >= -33554432){
1900                                 ins = (18 << 26) | (diff & ~0xfc000000) | (ins & 1);
1901                                 *(guint32*)code = ins;
1902                                 return;
1903                         }
1904                 }
1905                 
1906                 if ((glong)target >= 0){
1907                         if ((glong)target <= 33554431){
1908                                 ins = (18 << 26) | ((guint32) target) | (ins & 1) | 2;
1909                                 *(guint32*)code = ins;
1910                                 return;
1911                         }
1912                 } else {
1913                         if ((glong)target >= -33554432){
1914                                 ins = (18 << 26) | (((guint32)target) & ~0xfc000000) | (ins & 1) | 2;
1915                                 *(guint32*)code = ins;
1916                                 return;
1917                         }
1918                 }
1919
1920                 handle_thunk (TRUE, code, target);
1921                 return;
1922
1923                 g_assert_not_reached ();
1924         }
1925         
1926         
1927         if (prim == 16) {
1928                 // absolute address
1929                 if (ins & 2) {
1930                         guint32 li = (guint32)target;
1931                         ins = (ins & 0xffff0000) | (ins & 3);
1932                         ovf  = li & 0xffff0000;
1933                         if (ovf != 0 && ovf != 0xffff0000)
1934                                 g_assert_not_reached ();
1935                         li &= 0xffff;
1936                         ins |= li;
1937                         // FIXME: assert the top bits of li are 0
1938                 } else {
1939                         gint diff = target - code;
1940                         ins = (ins & 0xffff0000) | (ins & 3);
1941                         ovf  = diff & 0xffff0000;
1942                         if (ovf != 0 && ovf != 0xffff0000)
1943                                 g_assert_not_reached ();
1944                         diff &= 0xffff;
1945                         ins |= diff;
1946                 }
1947                 *(guint32*)code = ins;
1948                 return;
1949         }
1950
1951         if (prim == 15 || ins == 0x4e800021) {
1952                 guint32 *seq;
1953                 /* the trampoline code will try to patch the blrl */
1954                 if (ins == 0x4e800021) {
1955                         code -= 12;
1956                 }
1957                 /* this is the lis/ori/mtlr/blrl sequence */
1958                 seq = (guint32*)code;
1959                 g_assert ((seq [0] >> 26) == 15);
1960                 g_assert ((seq [1] >> 26) == 24);
1961                 g_assert ((seq [2] >> 26) == 31);
1962                 g_assert (seq [3] == 0x4e800021);
1963                 /* FIXME: make this thread safe */
1964                 ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
1965                 ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
1966                 mono_arch_flush_icache (code - 8, 8);
1967         } else {
1968                 g_assert_not_reached ();
1969         }
1970 //      g_print ("patched with 0x%08x\n", ins);
1971 }
1972
1973 void
1974 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1975 {
1976         MonoInst *ins;
1977         MonoCallInst *call;
1978         guint offset;
1979         guint8 *code = cfg->native_code + cfg->code_len;
1980         MonoInst *last_ins = NULL;
1981         guint last_offset = 0;
1982         int max_len, cpos;
1983
1984         if (cfg->opt & MONO_OPT_PEEPHOLE)
1985                 peephole_pass (cfg, bb);
1986
1987         /* we don't align basic blocks of loops on ppc */
1988
1989         if (cfg->verbose_level > 2)
1990                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1991
1992         cpos = bb->max_offset;
1993
1994         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1995                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1996                 //g_assert (!mono_compile_aot);
1997                 //cpos += 6;
1998                 //if (bb->cil_code)
1999                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2000                 /* this is not thread save, but good enough */
2001                 /* fixme: howto handle overflows? */
2002                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
2003         }
2004
2005         ins = bb->code;
2006         while (ins) {
2007                 offset = code - cfg->native_code;
2008
2009                 max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
2010
2011                 if (offset > (cfg->code_size - max_len - 16)) {
2012                         cfg->code_size *= 2;
2013                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2014                         code = cfg->native_code + offset;
2015                 }
2016         //      if (ins->cil_code)
2017         //              g_print ("cil code\n");
2018                 mono_debug_record_line_number (cfg, ins, offset);
2019
2020                 switch (ins->opcode) {
2021                 case OP_TLS_GET:
2022                         emit_tls_access (code, ins->dreg, ins->inst_offset);
2023                         break;
2024                 case OP_BIGMUL:
2025                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2026                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2027                         ppc_mr (code, ppc_r4, ppc_r0);
2028                         break;
2029                 case OP_BIGMUL_UN:
2030                         ppc_mullw (code, ppc_r0, ins->sreg1, ins->sreg2);
2031                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2032                         ppc_mr (code, ppc_r4, ppc_r0);
2033                         break;
2034                 case OP_MEMORY_BARRIER:
2035                         ppc_sync (code);
2036                         break;
2037                 case OP_STOREI1_MEMBASE_REG:
2038                         if (ppc_is_imm16 (ins->inst_offset)) {
2039                                 ppc_stb (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2040                         } else {
2041                                 g_assert_not_reached ();
2042                         }
2043                         break;
2044                 case OP_STOREI2_MEMBASE_REG:
2045                         if (ppc_is_imm16 (ins->inst_offset)) {
2046                                 ppc_sth (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2047                         } else {
2048                                 g_assert_not_reached ();
2049                         }
2050                         break;
2051                 case OP_STORE_MEMBASE_REG:
2052                 case OP_STOREI4_MEMBASE_REG:
2053                         if (ppc_is_imm16 (ins->inst_offset)) {
2054                                 ppc_stw (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2055                         } else {
2056                                 g_assert_not_reached ();
2057                         }
2058                         break;
2059                 case OP_STOREI1_MEMINDEX:
2060                         ppc_stbx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2061                         break;
2062                 case OP_STOREI2_MEMINDEX:
2063                         ppc_sthx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2064                         break;
2065                 case OP_STORE_MEMINDEX:
2066                 case OP_STOREI4_MEMINDEX:
2067                         ppc_stwx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2068                         break;
2069                 case CEE_LDIND_I:
2070                 case CEE_LDIND_I4:
2071                 case CEE_LDIND_U4:
2072                         g_assert_not_reached ();
2073                         //x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2074                         break;
2075                 case OP_LOADU4_MEM:
2076                         g_assert_not_reached ();
2077                         break;
2078                 case OP_LOAD_MEMBASE:
2079                 case OP_LOADI4_MEMBASE:
2080                 case OP_LOADU4_MEMBASE:
2081                         if (ppc_is_imm16 (ins->inst_offset)) {
2082                                 ppc_lwz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2083                         } else {
2084                                 g_assert_not_reached ();
2085                         }
2086                         break;
2087                 case OP_LOADI1_MEMBASE:
2088                 case OP_LOADU1_MEMBASE:
2089                         if (ppc_is_imm16 (ins->inst_offset)) {
2090                                 ppc_lbz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2091                         } else {
2092                                 g_assert_not_reached ();
2093                         }
2094                         if (ins->opcode == OP_LOADI1_MEMBASE)
2095                                 ppc_extsb (code, ins->dreg, ins->dreg);
2096                         break;
2097                 case OP_LOADU2_MEMBASE:
2098                         if (ppc_is_imm16 (ins->inst_offset)) {
2099                                 ppc_lhz (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2100                         } else {
2101                                 g_assert_not_reached ();
2102                         }
2103                         break;
2104                 case OP_LOADI2_MEMBASE:
2105                         if (ppc_is_imm16 (ins->inst_offset)) {
2106                                 ppc_lha (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2107                         } else {
2108                                 g_assert_not_reached ();
2109                         }
2110                         break;
2111                 case OP_LOAD_MEMINDEX:
2112                 case OP_LOADI4_MEMINDEX:
2113                 case OP_LOADU4_MEMINDEX:
2114                         ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2115                         break;
2116                 case OP_LOADU2_MEMINDEX:
2117                         ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2118                         break;
2119                 case OP_LOADI2_MEMINDEX:
2120                         ppc_lhax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2121                         break;
2122                 case OP_LOADU1_MEMINDEX:
2123                         ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2124                         break;
2125                 case OP_LOADI1_MEMINDEX:
2126                         ppc_lbzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2127                         ppc_extsb (code, ins->dreg, ins->dreg);
2128                         break;
2129                 case CEE_CONV_I1:
2130                         ppc_extsb (code, ins->dreg, ins->sreg1);
2131                         break;
2132                 case CEE_CONV_I2:
2133                         ppc_extsh (code, ins->dreg, ins->sreg1);
2134                         break;
2135                 case CEE_CONV_U1:
2136                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 24, 31);
2137                         break;
2138                 case CEE_CONV_U2:
2139                         ppc_rlwinm (code, ins->dreg, ins->sreg1, 0, 16, 31);
2140                         break;
2141                 case OP_COMPARE:
2142                         if (ins->next && compare_opcode_is_unsigned (ins->next->opcode))
2143                                 ppc_cmpl (code, 0, 0, ins->sreg1, ins->sreg2);
2144                         else
2145                                 ppc_cmp (code, 0, 0, ins->sreg1, ins->sreg2);
2146                         break;
2147                 case OP_COMPARE_IMM:
2148                         if (ins->next && compare_opcode_is_unsigned (ins->next->opcode)) {
2149                                 if (ppc_is_uimm16 (ins->inst_imm)) {
2150                                         ppc_cmpli (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2151                                 } else {
2152                                         g_assert_not_reached ();
2153                                 }
2154                         } else {
2155                                 if (ppc_is_imm16 (ins->inst_imm)) {
2156                                         ppc_cmpi (code, 0, 0, ins->sreg1, (ins->inst_imm & 0xffff));
2157                                 } else {
2158                                         g_assert_not_reached ();
2159                                 }
2160                         }
2161                         break;
2162                 case CEE_BREAK:
2163                         ppc_break (code);
2164                         break;
2165                 case OP_ADDCC:
2166                         ppc_addc (code, ins->dreg, ins->sreg1, ins->sreg2);
2167                         break;
2168                 case CEE_ADD:
2169                         ppc_add (code, ins->dreg, ins->sreg1, ins->sreg2);
2170                         break;
2171                 case OP_ADC:
2172                         ppc_adde (code, ins->dreg, ins->sreg1, ins->sreg2);
2173                         break;
2174                 case OP_ADDCC_IMM:
2175                         if (ppc_is_imm16 (ins->inst_imm)) {
2176                                 ppc_addic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2177                         } else {
2178                                 g_assert_not_reached ();
2179                         }
2180                         break;
2181                 case OP_ADD_IMM:
2182                         if (ppc_is_imm16 (ins->inst_imm)) {
2183                                 ppc_addi (code, ins->dreg, ins->sreg1, ins->inst_imm);
2184                         } else {
2185                                 g_assert_not_reached ();
2186                         }
2187                         break;
2188                 case CEE_ADD_OVF:
2189                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2190                          */
2191                         ppc_addo (code, ins->dreg, ins->sreg1, ins->sreg2);
2192                         ppc_mfspr (code, ppc_r0, ppc_xer);
2193                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2194                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2195                         break;
2196                 case CEE_ADD_OVF_UN:
2197                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2198                          */
2199                         ppc_addco (code, ins->dreg, ins->sreg1, ins->sreg2);
2200                         ppc_mfspr (code, ppc_r0, ppc_xer);
2201                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2202                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2203                         break;
2204                 case CEE_SUB_OVF:
2205                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2206                          */
2207                         ppc_subfo (code, ins->dreg, ins->sreg2, ins->sreg1);
2208                         ppc_mfspr (code, ppc_r0, ppc_xer);
2209                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2210                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2211                         break;
2212                 case CEE_SUB_OVF_UN:
2213                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2214                          */
2215                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2216                         ppc_mfspr (code, ppc_r0, ppc_xer);
2217                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2218                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2219                         break;
2220                 case OP_ADD_OVF_CARRY:
2221                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2222                          */
2223                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2224                         ppc_mfspr (code, ppc_r0, ppc_xer);
2225                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2226                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2227                         break;
2228                 case OP_ADD_OVF_UN_CARRY:
2229                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2230                          */
2231                         ppc_addeo (code, ins->dreg, ins->sreg1, ins->sreg2);
2232                         ppc_mfspr (code, ppc_r0, ppc_xer);
2233                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2234                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2235                         break;
2236                 case OP_SUB_OVF_CARRY:
2237                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2238                          */
2239                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2240                         ppc_mfspr (code, ppc_r0, ppc_xer);
2241                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2242                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2243                         break;
2244                 case OP_SUB_OVF_UN_CARRY:
2245                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2246                          */
2247                         ppc_subfeo (code, ins->dreg, ins->sreg2, ins->sreg1);
2248                         ppc_mfspr (code, ppc_r0, ppc_xer);
2249                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<13));
2250                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2251                         break;
2252                 case OP_SUBCC:
2253                         ppc_subfc (code, ins->dreg, ins->sreg2, ins->sreg1);
2254                         break;
2255                 case CEE_SUB:
2256                         ppc_subf (code, ins->dreg, ins->sreg2, ins->sreg1);
2257                         break;
2258                 case OP_SBB:
2259                         ppc_subfe (code, ins->dreg, ins->sreg2, ins->sreg1);
2260                         break;
2261                 case OP_SUB_IMM:
2262                         // we add the negated value
2263                         if (ppc_is_imm16 (-ins->inst_imm))
2264                                 ppc_addi (code, ins->dreg, ins->sreg1, -ins->inst_imm);
2265                         else {
2266                                 g_assert_not_reached ();
2267                         }
2268                         break;
2269                 case OP_PPC_SUBFIC:
2270                         g_assert (ppc_is_imm16 (ins->inst_imm));
2271                         ppc_subfic (code, ins->dreg, ins->sreg1, ins->inst_imm);
2272                         break;
2273                 case OP_PPC_SUBFZE:
2274                         ppc_subfze (code, ins->dreg, ins->sreg1);
2275                         break;
2276                 case CEE_AND:
2277                         /* FIXME: the ppc macros as inconsistent here: put dest as the first arg! */
2278                         ppc_and (code, ins->sreg1, ins->dreg, ins->sreg2);
2279                         break;
2280                 case OP_AND_IMM:
2281                         if (!(ins->inst_imm & 0xffff0000)) {
2282                                 ppc_andid (code, ins->sreg1, ins->dreg, ins->inst_imm);
2283                         } else if (!(ins->inst_imm & 0xffff)) {
2284                                 ppc_andisd (code, ins->sreg1, ins->dreg, ((guint32)ins->inst_imm >> 16));
2285                         } else {
2286                                 g_assert_not_reached ();
2287                         }
2288                         break;
2289                 case CEE_DIV: {
2290                         guint32 *divisor_is_m1;
2291                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2292                          */
2293                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2294                         divisor_is_m1 = code;
2295                         ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2296                         ppc_lis (code, ppc_r11, 0x8000);
2297                         ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2298                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2299                         ppc_patch (divisor_is_m1, code);
2300                          /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2301                          */
2302                         ppc_divwod (code, ins->dreg, ins->sreg1, ins->sreg2);
2303                         ppc_mfspr (code, ppc_r0, ppc_xer);
2304                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2305                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2306                         break;
2307                 }
2308                 case CEE_DIV_UN:
2309                         ppc_divwuod (code, ins->dreg, ins->sreg1, ins->sreg2);
2310                         ppc_mfspr (code, ppc_r0, ppc_xer);
2311                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2312                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2313                         break;
2314                 case OP_DIV_IMM:
2315                         g_assert_not_reached ();
2316 #if 0
2317                         ppc_load (code, ppc_r11, ins->inst_imm);
2318                         ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
2319                         ppc_mfspr (code, ppc_r0, ppc_xer);
2320                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2321                         /* FIXME: use OverflowException for 0x80000000/-1 */
2322                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2323                         break;
2324 #endif
2325                 case CEE_REM: {
2326                         guint32 *divisor_is_m1;
2327                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2328                         divisor_is_m1 = code;
2329                         ppc_bc (code, PPC_BR_FALSE | PPC_BR_LIKELY, PPC_BR_EQ, 0);
2330                         ppc_lis (code, ppc_r11, 0x8000);
2331                         ppc_cmp (code, 0, 0, ins->sreg1, ppc_r11);
2332                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
2333                         ppc_patch (divisor_is_m1, code);
2334                         ppc_divwod (code, ppc_r11, ins->sreg1, ins->sreg2);
2335                         ppc_mfspr (code, ppc_r0, ppc_xer);
2336                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2337                         /* FIXME: use OverflowException for 0x80000000/-1 */
2338                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2339                         ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2340                         ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2341                         break;
2342                 }
2343                 case CEE_REM_UN:
2344                         ppc_divwuod (code, ppc_r11, ins->sreg1, ins->sreg2);
2345                         ppc_mfspr (code, ppc_r0, ppc_xer);
2346                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2347                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
2348                         ppc_mullw (code, ppc_r11, ppc_r11, ins->sreg2);
2349                         ppc_subf (code, ins->dreg, ppc_r11, ins->sreg1);
2350                         break;
2351                 case OP_REM_IMM:
2352                         g_assert_not_reached ();
2353                 case CEE_OR:
2354                         ppc_or (code, ins->dreg, ins->sreg1, ins->sreg2);
2355                         break;
2356                 case OP_OR_IMM:
2357                         if (!(ins->inst_imm & 0xffff0000)) {
2358                                 ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2359                         } else if (!(ins->inst_imm & 0xffff)) {
2360                                 ppc_oris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2361                         } else {
2362                                 g_assert_not_reached ();
2363                         }
2364                         break;
2365                 case CEE_XOR:
2366                         ppc_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
2367                         break;
2368                 case OP_XOR_IMM:
2369                         if (!(ins->inst_imm & 0xffff0000)) {
2370                                 ppc_xori (code, ins->sreg1, ins->dreg, ins->inst_imm);
2371                         } else if (!(ins->inst_imm & 0xffff)) {
2372                                 ppc_xoris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
2373                         } else {
2374                                 g_assert_not_reached ();
2375                         }
2376                         break;
2377                 case CEE_SHL:
2378                         ppc_slw (code, ins->sreg1, ins->dreg, ins->sreg2);
2379                         break;
2380                 case OP_SHL_IMM:
2381                         ppc_rlwinm (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f), 0, (31 - (ins->inst_imm & 0x1f)));
2382                         break;
2383                 case CEE_SHR:
2384                         ppc_sraw (code, ins->dreg, ins->sreg1, ins->sreg2);
2385                         break;
2386                 case OP_SHR_IMM:
2387                         ppc_srawi (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2388                         break;
2389                 case OP_SHR_UN_IMM:
2390                         ppc_rlwinm (code, ins->dreg, ins->sreg1, (32 - (ins->inst_imm & 0x1f)), (ins->inst_imm & 0x1f), 31);
2391                         break;
2392                 case CEE_SHR_UN:
2393                         ppc_srw (code, ins->dreg, ins->sreg1, ins->sreg2);
2394                         break;
2395                 case CEE_NOT:
2396                         ppc_not (code, ins->dreg, ins->sreg1);
2397                         break;
2398                 case CEE_NEG:
2399                         ppc_neg (code, ins->dreg, ins->sreg1);
2400                         break;
2401                 case CEE_MUL:
2402                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2403                         break;
2404                 case OP_MUL_IMM:
2405                         if (ppc_is_imm16 (ins->inst_imm)) {
2406                             ppc_mulli (code, ins->dreg, ins->sreg1, ins->inst_imm);
2407                         } else {
2408                             g_assert_not_reached ();
2409                         }
2410                         break;
2411                 case CEE_MUL_OVF:
2412                         /* we annot use mcrxr, since it's not implemented on some processors 
2413                          * XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
2414                          */
2415                         ppc_mullwo (code, ins->dreg, ins->sreg1, ins->sreg2);
2416                         ppc_mfspr (code, ppc_r0, ppc_xer);
2417                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2418                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2419                         break;
2420                 case CEE_MUL_OVF_UN:
2421                         /* we first multiply to get the high word and compare to 0
2422                          * to set the flags, then the result is discarded and then 
2423                          * we multiply to get the lower * bits result
2424                          */
2425                         ppc_mulhwu (code, ppc_r0, ins->sreg1, ins->sreg2);
2426                         ppc_cmpi (code, 0, 0, ppc_r0, 0);
2427                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BNE_UN - CEE_BEQ, "OverflowException");
2428                         ppc_mullw (code, ins->dreg, ins->sreg1, ins->sreg2);
2429                         break;
2430                 case OP_ICONST:
2431                 case OP_SETREGIMM:
2432                         ppc_load (code, ins->dreg, ins->inst_c0);
2433                         break;
2434                 case OP_AOTCONST:
2435                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2436                         ppc_lis (code, ins->dreg, 0);
2437                         ppc_ori (code, ins->dreg, ins->dreg, 0);
2438                         break;
2439                 case CEE_CONV_I4:
2440                 case CEE_CONV_U4:
2441                 case OP_MOVE:
2442                 case OP_SETREG:
2443                         ppc_mr (code, ins->dreg, ins->sreg1);
2444                         break;
2445                 case OP_SETLRET: {
2446                         int saved = ins->sreg1;
2447                         if (ins->sreg1 == ppc_r3) {
2448                                 ppc_mr (code, ppc_r0, ins->sreg1);
2449                                 saved = ppc_r0;
2450                         }
2451                         if (ins->sreg2 != ppc_r3)
2452                                 ppc_mr (code, ppc_r3, ins->sreg2);
2453                         if (saved != ppc_r4)
2454                                 ppc_mr (code, ppc_r4, saved);
2455                         break;
2456                 }
2457                 case OP_SETFREG:
2458                 case OP_FMOVE:
2459                         ppc_fmr (code, ins->dreg, ins->sreg1);
2460                         break;
2461                 case OP_FCONV_TO_R4:
2462                         ppc_frsp (code, ins->dreg, ins->sreg1);
2463                         break;
2464                 case CEE_JMP: {
2465                         int i, pos = 0;
2466                         
2467                         /*
2468                          * Keep in sync with mono_arch_emit_epilog
2469                          */
2470                         g_assert (!cfg->method->save_lmf);
2471                         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
2472                                 if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
2473                                         ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
2474                                 } else {
2475                                         ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
2476                                         ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
2477                                 }
2478                                 ppc_mtlr (code, ppc_r0);
2479                         }
2480                         if (ppc_is_imm16 (cfg->stack_usage)) {
2481                                 ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
2482                         } else {
2483                                 ppc_load (code, ppc_r11, cfg->stack_usage);
2484                                 ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
2485                         }
2486                         if (!cfg->method->save_lmf) {
2487                                 /*for (i = 31; i >= 14; --i) {
2488                                         if (cfg->used_float_regs & (1 << i)) {
2489                                                 pos += sizeof (double);
2490                                                 ppc_lfd (code, i, -pos, cfg->frame_reg);
2491                                         }
2492                                 }*/
2493                                 for (i = 31; i >= 13; --i) {
2494                                         if (cfg->used_int_regs & (1 << i)) {
2495                                                 pos += sizeof (gulong);
2496                                                 ppc_lwz (code, i, -pos, cfg->frame_reg);
2497                                         }
2498                                 }
2499                         } else {
2500                                 /* FIXME restore from MonoLMF: though this can't happen yet */
2501                         }
2502                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2503                         ppc_b (code, 0);
2504                         break;
2505                 }
2506                 case OP_CHECK_THIS:
2507                         /* ensure ins->sreg1 is not NULL */
2508                         ppc_lwz (code, ppc_r0, 0, ins->sreg1);
2509                         break;
2510                 case OP_ARGLIST: {
2511                         if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2512                                 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2513                         } else {
2514                                 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2515                                 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2516                         }
2517                         ppc_stw (code, ppc_r11, 0, ins->sreg1);
2518                         break;
2519                 }
2520                 case OP_FCALL:
2521                 case OP_LCALL:
2522                 case OP_VCALL:
2523                 case OP_VOIDCALL:
2524                 case CEE_CALL:
2525                         call = (MonoCallInst*)ins;
2526                         if (ins->flags & MONO_INST_HAS_METHOD)
2527                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2528                         else
2529                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2530                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2531                                 ppc_lis (code, ppc_r0, 0);
2532                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
2533                                 ppc_mtlr (code, ppc_r0);
2534                                 ppc_blrl (code);
2535                         } else {
2536                                 ppc_bl (code, 0);
2537                         }
2538                         break;
2539                 case OP_FCALL_REG:
2540                 case OP_LCALL_REG:
2541                 case OP_VCALL_REG:
2542                 case OP_VOIDCALL_REG:
2543                 case OP_CALL_REG:
2544                         ppc_mtlr (code, ins->sreg1);
2545                         ppc_blrl (code);
2546                         break;
2547                 case OP_FCALL_MEMBASE:
2548                 case OP_LCALL_MEMBASE:
2549                 case OP_VCALL_MEMBASE:
2550                 case OP_VOIDCALL_MEMBASE:
2551                 case OP_CALL_MEMBASE:
2552                         ppc_lwz (code, ppc_r0, ins->inst_offset, ins->sreg1);
2553                         ppc_mtlr (code, ppc_r0);
2554                         ppc_blrl (code);
2555                         break;
2556                 case OP_OUTARG:
2557                         g_assert_not_reached ();
2558                         break;
2559                 case OP_LOCALLOC: {
2560                         guint32 * zero_loop_jump, * zero_loop_start;
2561                         /* keep alignment */
2562                         int alloca_waste = PPC_STACK_PARAM_OFFSET + cfg->param_area + 31;
2563                         int area_offset = alloca_waste;
2564                         area_offset &= ~31;
2565                         ppc_addi (code, ppc_r11, ins->sreg1, alloca_waste + 31);
2566                         ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 0, 27);
2567                         /* use ctr to store the number of words to 0 if needed */
2568                         if (ins->flags & MONO_INST_INIT) {
2569                                 /* we zero 4 bytes at a time */
2570                                 ppc_addi (code, ppc_r0, ins->sreg1, 3);
2571                                 ppc_srawi (code, ppc_r0, ppc_r0, 2);
2572                                 ppc_mtctr (code, ppc_r0);
2573                         }
2574                         ppc_lwz (code, ppc_r0, 0, ppc_sp);
2575                         ppc_neg (code, ppc_r11, ppc_r11);
2576                         ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
2577                         
2578                         if (ins->flags & MONO_INST_INIT) {
2579                                 /* adjust the dest reg by -4 so we can use stwu */
2580                                 ppc_addi (code, ins->dreg, ppc_sp, (area_offset - 4));
2581                                 ppc_li (code, ppc_r11, 0);
2582                                 zero_loop_start = code;
2583                                 ppc_stwu (code, ppc_r11, 4, ins->dreg);
2584                                 zero_loop_jump = code;
2585                                 ppc_bc (code, PPC_BR_DEC_CTR_NONZERO, 0, 0);
2586                                 ppc_patch (zero_loop_jump, zero_loop_start);
2587                         }
2588                         ppc_addi (code, ins->dreg, ppc_sp, area_offset);
2589                         break;
2590                 }
2591                 case CEE_RET:
2592                         ppc_blr (code);
2593                         break;
2594                 case CEE_THROW: {
2595                         //ppc_break (code);
2596                         ppc_mr (code, ppc_r3, ins->sreg1);
2597                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2598                                              (gpointer)"mono_arch_throw_exception");
2599                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2600                                 ppc_lis (code, ppc_r0, 0);
2601                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
2602                                 ppc_mtlr (code, ppc_r0);
2603                                 ppc_blrl (code);
2604                         } else {
2605                                 ppc_bl (code, 0);
2606                         }
2607                         break;
2608                 }
2609                 case OP_RETHROW: {
2610                         //ppc_break (code);
2611                         ppc_mr (code, ppc_r3, ins->sreg1);
2612                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2613                                              (gpointer)"mono_arch_rethrow_exception");
2614                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
2615                                 ppc_lis (code, ppc_r0, 0);
2616                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
2617                                 ppc_mtlr (code, ppc_r0);
2618                                 ppc_blrl (code);
2619                         } else {
2620                                 ppc_bl (code, 0);
2621                         }
2622                         break;
2623                 }
2624                 case OP_START_HANDLER:
2625                         ppc_mflr (code, ppc_r0);
2626                         if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2627                                 ppc_stw (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2628                         } else {
2629                                 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2630                                 ppc_stwx (code, ppc_r0, ppc_r11, ins->inst_left->inst_basereg);
2631                         }
2632                         break;
2633                 case OP_ENDFILTER:
2634                         if (ins->sreg1 != ppc_r3)
2635                                 ppc_mr (code, ppc_r3, ins->sreg1);
2636                         if (ppc_is_imm16 (ins->inst_left->inst_offset)) {
2637                                 ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2638                         } else {
2639                                 ppc_load (code, ppc_r11, ins->inst_left->inst_offset);
2640                                 ppc_lwzx (code, ppc_r0, ins->inst_left->inst_basereg, ppc_r11);
2641                         }
2642                         ppc_mtlr (code, ppc_r0);
2643                         ppc_blr (code);
2644                         break;
2645                 case CEE_ENDFINALLY:
2646                         ppc_lwz (code, ppc_r0, ins->inst_left->inst_offset, ins->inst_left->inst_basereg);
2647                         ppc_mtlr (code, ppc_r0);
2648                         ppc_blr (code);
2649                         break;
2650                 case OP_CALL_HANDLER: 
2651                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2652                         ppc_bl (code, 0);
2653                         break;
2654                 case OP_LABEL:
2655                         ins->inst_c0 = code - cfg->native_code;
2656                         break;
2657                 case CEE_BR:
2658                         //g_print ("target: %p, next: %p, curr: %p, last: %p\n", ins->inst_target_bb, bb->next_bb, ins, bb->last_ins);
2659                         //if ((ins->inst_target_bb == bb->next_bb) && ins == bb->last_ins)
2660                         //break;
2661                         if (ins->flags & MONO_INST_BRLABEL) {
2662                                 /*if (ins->inst_i0->inst_c0) {
2663                                         ppc_b (code, 0);
2664                                         //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2665                                 } else*/ {
2666                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2667                                         ppc_b (code, 0);
2668                                 }
2669                         } else {
2670                                 /*if (ins->inst_target_bb->native_offset) {
2671                                         ppc_b (code, 0);
2672                                         //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2673                                 } else*/ {
2674                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2675                                         ppc_b (code, 0);
2676                                 } 
2677                         }
2678                         break;
2679                 case OP_BR_REG:
2680                         ppc_mtctr (code, ins->sreg1);
2681                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
2682                         break;
2683                 case OP_CEQ:
2684                         ppc_li (code, ins->dreg, 0);
2685                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2686                         ppc_li (code, ins->dreg, 1);
2687                         break;
2688                 case OP_CLT:
2689                 case OP_CLT_UN:
2690                         ppc_li (code, ins->dreg, 1);
2691                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2692                         ppc_li (code, ins->dreg, 0);
2693                         break;
2694                 case OP_CGT:
2695                 case OP_CGT_UN:
2696                         ppc_li (code, ins->dreg, 1);
2697                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2698                         ppc_li (code, ins->dreg, 0);
2699                         break;
2700                 case OP_COND_EXC_EQ:
2701                 case OP_COND_EXC_NE_UN:
2702                 case OP_COND_EXC_LT:
2703                 case OP_COND_EXC_LT_UN:
2704                 case OP_COND_EXC_GT:
2705                 case OP_COND_EXC_GT_UN:
2706                 case OP_COND_EXC_GE:
2707                 case OP_COND_EXC_GE_UN:
2708                 case OP_COND_EXC_LE:
2709                 case OP_COND_EXC_LE_UN:
2710                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2711                         break;
2712                 case OP_COND_EXC_C:
2713                         /* check XER [0-3] (SO, OV, CA): we can't use mcrxr
2714                          */
2715                         /*ppc_mfspr (code, ppc_r0, ppc_xer);
2716                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
2717                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2718                         break;*/
2719                 case OP_COND_EXC_OV:
2720                         /*ppc_mcrxr (code, 0);
2721                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BGT - CEE_BEQ, ins->inst_p1);
2722                         break;*/
2723                 case OP_COND_EXC_NC:
2724                 case OP_COND_EXC_NO:
2725                         g_assert_not_reached ();
2726                         break;
2727                 case CEE_BEQ:
2728                 case CEE_BNE_UN:
2729                 case CEE_BLT:
2730                 case CEE_BLT_UN:
2731                 case CEE_BGT:
2732                 case CEE_BGT_UN:
2733                 case CEE_BGE:
2734                 case CEE_BGE_UN:
2735                 case CEE_BLE:
2736                 case CEE_BLE_UN:
2737                         EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2738                         break;
2739
2740                 /* floating point opcodes */
2741                 case OP_R8CONST:
2742                         ppc_load (code, ppc_r11, ins->inst_p0);
2743                         ppc_lfd (code, ins->dreg, 0, ppc_r11);
2744                         break;
2745                 case OP_R4CONST:
2746                         ppc_load (code, ppc_r11, ins->inst_p0);
2747                         ppc_lfs (code, ins->dreg, 0, ppc_r11);
2748                         break;
2749                 case OP_STORER8_MEMBASE_REG:
2750                         if (ppc_is_imm16 (ins->inst_offset)) {
2751                                 ppc_stfd (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2752                         } else {
2753                                 g_assert_not_reached ();
2754                         }
2755                         break;
2756                 case OP_LOADR8_MEMBASE:
2757                         if (ppc_is_imm16 (ins->inst_offset)) {
2758                                 ppc_lfd (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2759                         } else {
2760                                 g_assert_not_reached ();
2761                         }
2762                         break;
2763                 case OP_STORER4_MEMBASE_REG:
2764                         ppc_frsp (code, ins->sreg1, ins->sreg1);
2765                         if (ppc_is_imm16 (ins->inst_offset)) {
2766                                 ppc_stfs (code, ins->sreg1, ins->inst_offset, ins->inst_destbasereg);
2767                         } else {
2768                                 g_assert_not_reached ();
2769                         }
2770                         break;
2771                 case OP_LOADR4_MEMBASE:
2772                         if (ppc_is_imm16 (ins->inst_offset)) {
2773                                 ppc_lfs (code, ins->dreg, ins->inst_offset, ins->inst_basereg);
2774                         } else {
2775                                 g_assert_not_reached ();
2776                         }
2777                         break;
2778                 case OP_LOADR4_MEMINDEX:
2779                         ppc_lfsx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2780                         break;
2781                 case OP_LOADR8_MEMINDEX:
2782                         ppc_lfdx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
2783                         break;
2784                 case OP_STORER4_MEMINDEX:
2785                         ppc_frsp (code, ins->sreg1, ins->sreg1);
2786                         ppc_stfsx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2787                         break;
2788                 case OP_STORER8_MEMINDEX:
2789                         ppc_stfdx (code, ins->sreg1, ins->sreg2, ins->inst_destbasereg);
2790                         break;
2791                 case CEE_CONV_R_UN: {
2792                         static const guint64 adjust_val = 0x4330000000000000ULL;
2793                         ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2794                         ppc_stw (code, ppc_r0, -8, ppc_sp);
2795                         ppc_stw (code, ins->sreg1, -4, ppc_sp);
2796                         ppc_load (code, ppc_r11, &adjust_val);
2797                         ppc_lfd (code, ins->dreg, -8, ppc_sp);
2798                         ppc_lfd (code, ppc_f0, 0, ppc_r11);
2799                         ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2800                         break;
2801                 }
2802                 case CEE_CONV_R4: /* FIXME: change precision */
2803                 case CEE_CONV_R8: {
2804                         static const guint64 adjust_val = 0x4330000080000000ULL;
2805                         // addis is special for ppc_r0
2806                         ppc_addis (code, ppc_r0, ppc_r0, 0x4330);
2807                         ppc_stw (code, ppc_r0, -8, ppc_sp);
2808                         ppc_xoris (code, ins->sreg1, ppc_r11, 0x8000);
2809                         ppc_stw (code, ppc_r11, -4, ppc_sp);
2810                         ppc_lfd (code, ins->dreg, -8, ppc_sp);
2811                         ppc_load (code, ppc_r11, &adjust_val);
2812                         ppc_lfd (code, ppc_f0, 0, ppc_r11);
2813                         ppc_fsub (code, ins->dreg, ins->dreg, ppc_f0);
2814                         break;
2815                 }
2816                 case OP_FCONV_TO_I1:
2817                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2818                         break;
2819                 case OP_FCONV_TO_U1:
2820                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2821                         break;
2822                 case OP_FCONV_TO_I2:
2823                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2824                         break;
2825                 case OP_FCONV_TO_U2:
2826                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2827                         break;
2828                 case OP_FCONV_TO_I4:
2829                 case OP_FCONV_TO_I:
2830                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2831                         break;
2832                 case OP_FCONV_TO_U4:
2833                 case OP_FCONV_TO_U:
2834                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2835                         break;
2836                 case OP_FCONV_TO_I8:
2837                 case OP_FCONV_TO_U8:
2838                         g_assert_not_reached ();
2839                         /* Implemented as helper calls */
2840                         break;
2841                 case OP_LCONV_TO_R_UN:
2842                         g_assert_not_reached ();
2843                         /* Implemented as helper calls */
2844                         break;
2845                 case OP_LCONV_TO_OVF_I: {
2846                         guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2847                         // Check if its negative
2848                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2849                         negative_branch = code;
2850                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2851                         // Its positive msword == 0
2852                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2853                         msword_positive_branch = code;
2854                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2855
2856                         ovf_ex_target = code;
2857                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2858                         // Negative
2859                         ppc_patch (negative_branch, code);
2860                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2861                         msword_negative_branch = code;
2862                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2863                         ppc_patch (msword_negative_branch, ovf_ex_target);
2864                         
2865                         ppc_patch (msword_positive_branch, code);
2866                         if (ins->dreg != ins->sreg1)
2867                                 ppc_mr (code, ins->dreg, ins->sreg1);
2868                         break;
2869                 }
2870                 case OP_SQRT:
2871                         ppc_fsqrtd (code, ins->dreg, ins->sreg1);
2872                         break;
2873                 case OP_FADD:
2874                         ppc_fadd (code, ins->dreg, ins->sreg1, ins->sreg2);
2875                         break;
2876                 case OP_FSUB:
2877                         ppc_fsub (code, ins->dreg, ins->sreg1, ins->sreg2);
2878                         break;          
2879                 case OP_FMUL:
2880                         ppc_fmul (code, ins->dreg, ins->sreg1, ins->sreg2);
2881                         break;          
2882                 case OP_FDIV:
2883                         ppc_fdiv (code, ins->dreg, ins->sreg1, ins->sreg2);
2884                         break;          
2885                 case OP_FNEG:
2886                         ppc_fneg (code, ins->dreg, ins->sreg1);
2887                         break;          
2888                 case OP_FREM:
2889                         /* emulated */
2890                         g_assert_not_reached ();
2891                         break;
2892                 case OP_FCOMPARE:
2893                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2894                         break;
2895                 case OP_FCEQ:
2896                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2897                         ppc_li (code, ins->dreg, 0);
2898                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 2);
2899                         ppc_li (code, ins->dreg, 1);
2900                         break;
2901                 case OP_FCLT:
2902                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2903                         ppc_li (code, ins->dreg, 1);
2904                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2905                         ppc_li (code, ins->dreg, 0);
2906                         break;
2907                 case OP_FCLT_UN:
2908                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2909                         ppc_li (code, ins->dreg, 1);
2910                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2911                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 2);
2912                         ppc_li (code, ins->dreg, 0);
2913                         break;
2914                 case OP_FCGT:
2915                         ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
2916                         ppc_li (code, ins->dreg, 1);
2917                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2918                         ppc_li (code, ins->dreg, 0);
2919                         break;
2920                 case OP_FCGT_UN:
2921                         ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
2922                         ppc_li (code, ins->dreg, 1);
2923                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 3);
2924                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_GT, 2);
2925                         ppc_li (code, ins->dreg, 0);
2926                         break;
2927                 case OP_FBEQ:
2928                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2929                         break;
2930                 case OP_FBNE_UN:
2931                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2932                         break;
2933                 case OP_FBLT:
2934                         EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
2935                         break;
2936                 case OP_FBLT_UN:
2937                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
2938                         EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
2939                         break;
2940                 case OP_FBGT:
2941                         EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
2942                         break;
2943                 case OP_FBGT_UN:
2944                         EMIT_COND_BRANCH_FLAGS (ins, PPC_BR_TRUE, PPC_BR_SO);
2945                         EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
2946                         break;
2947                 case OP_FBGE:
2948                         EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
2949                         break;
2950                 case OP_FBGE_UN:
2951                         EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
2952                         break;
2953                 case OP_FBLE:
2954                         EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
2955                         break;
2956                 case OP_FBLE_UN:
2957                         EMIT_COND_BRANCH (ins, CEE_BLE_UN - CEE_BEQ);
2958                         break;
2959                 case CEE_CKFINITE: {
2960                         ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2961                         ppc_lwz (code, ppc_r11, -8, ppc_sp);
2962                         ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
2963                         ppc_addis (code, ppc_r11, ppc_r11, -32752);
2964                         ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
2965                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
2966                         break;
2967                 }
2968                 default:
2969                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2970                         g_assert_not_reached ();
2971                 }
2972
2973                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
2974                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2975                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
2976                         g_assert_not_reached ();
2977                 }
2978                
2979                 cpos += max_len;
2980
2981                 last_ins = ins;
2982                 last_offset = offset;
2983                 
2984                 ins = ins->next;
2985         }
2986
2987         cfg->code_len = code - cfg->native_code;
2988 }
2989
2990 void
2991 mono_arch_register_lowlevel_calls (void)
2992 {
2993 }
2994
2995 #define patch_lis_ori(ip,val) do {\
2996                 guint16 *__lis_ori = (guint16*)(ip);    \
2997                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
2998                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
2999         } while (0)
3000
3001 void
3002 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3003 {
3004         MonoJumpInfo *patch_info;
3005
3006         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3007                 unsigned char *ip = patch_info->ip.i + code;
3008                 const unsigned char *target;
3009
3010                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3011
3012                 switch (patch_info->type) {
3013                 case MONO_PATCH_INFO_IP:
3014                         patch_lis_ori (ip, ip);
3015                         continue;
3016                 case MONO_PATCH_INFO_METHOD_REL:
3017                         g_assert_not_reached ();
3018                         *((gpointer *)(ip)) = code + patch_info->data.offset;
3019                         continue;
3020                 case MONO_PATCH_INFO_SWITCH: {
3021                         gpointer *table = (gpointer *)patch_info->data.table->table;
3022                         int i;
3023
3024                         patch_lis_ori (ip, table);
3025
3026                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
3027                                 table [i] = (int)patch_info->data.table->table [i] + code;
3028                         }
3029                         /* we put into the table the absolute address, no need for ppc_patch in this case */
3030                         continue;
3031                 }
3032                 case MONO_PATCH_INFO_METHODCONST:
3033                 case MONO_PATCH_INFO_CLASS:
3034                 case MONO_PATCH_INFO_IMAGE:
3035                 case MONO_PATCH_INFO_FIELD:
3036                 case MONO_PATCH_INFO_VTABLE:
3037                 case MONO_PATCH_INFO_IID:
3038                 case MONO_PATCH_INFO_SFLDA:
3039                 case MONO_PATCH_INFO_LDSTR:
3040                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3041                 case MONO_PATCH_INFO_LDTOKEN:
3042                         /* from OP_AOTCONST : lis + ori */
3043                         patch_lis_ori (ip, target);
3044                         continue;
3045                 case MONO_PATCH_INFO_R4:
3046                 case MONO_PATCH_INFO_R8:
3047                         g_assert_not_reached ();
3048                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3049                         continue;
3050                 case MONO_PATCH_INFO_EXC_NAME:
3051                         g_assert_not_reached ();
3052                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3053                         continue;
3054                 case MONO_PATCH_INFO_NONE:
3055                 case MONO_PATCH_INFO_BB_OVF:
3056                 case MONO_PATCH_INFO_EXC_OVF:
3057                         /* everything is dealt with at epilog output time */
3058                         continue;
3059                 default:
3060                         break;
3061                 }
3062                 ppc_patch (ip, target);
3063         }
3064 }
3065
3066 /*
3067  * Stack frame layout:
3068  * 
3069  *   ------------------- sp
3070  *      MonoLMF structure or saved registers
3071  *   -------------------
3072  *      spilled regs
3073  *   -------------------
3074  *      locals
3075  *   -------------------
3076  *      optional 8 bytes for tracing
3077  *   -------------------
3078  *      param area             size is cfg->param_area
3079  *   -------------------
3080  *      linkage area           size is PPC_STACK_PARAM_OFFSET
3081  *   ------------------- sp
3082  *      red zone
3083  */
3084 guint8 *
3085 mono_arch_emit_prolog (MonoCompile *cfg)
3086 {
3087         MonoMethod *method = cfg->method;
3088         MonoBasicBlock *bb;
3089         MonoMethodSignature *sig;
3090         MonoInst *inst;
3091         int alloc_size, pos, max_offset, i;
3092         guint8 *code;
3093         CallInfo *cinfo;
3094         int tracing = 0;
3095         int lmf_offset = 0;
3096
3097         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3098                 tracing = 1;
3099
3100         sig = mono_method_signature (method);
3101         cfg->code_size = 256 + sig->param_count * 20;
3102         code = cfg->native_code = g_malloc (cfg->code_size);
3103
3104         if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3105                 ppc_mflr (code, ppc_r0);
3106                 ppc_stw (code, ppc_r0, PPC_RET_ADDR_OFFSET, ppc_sp);
3107         }
3108
3109         alloc_size = cfg->stack_offset;
3110         pos = 0;
3111
3112         if (!method->save_lmf) {
3113                 /*for (i = 31; i >= 14; --i) {
3114                         if (cfg->used_float_regs & (1 << i)) {
3115                                 pos += sizeof (gdouble);
3116                                 ppc_stfd (code, i, -pos, ppc_sp);
3117                         }
3118                 }*/
3119                 for (i = 31; i >= 13; --i) {
3120                         if (cfg->used_int_regs & (1 << i)) {
3121                                 pos += sizeof (gulong);
3122                                 ppc_stw (code, i, -pos, ppc_sp);
3123                         }
3124                 }
3125         } else {
3126                 int ofs;
3127                 pos += sizeof (MonoLMF);
3128                 lmf_offset = pos;
3129                 ofs = -pos + G_STRUCT_OFFSET(MonoLMF, iregs);
3130                 ppc_stmw (code, ppc_r13, ppc_r1, ofs);
3131                 for (i = 14; i < 32; i++) {
3132                         ppc_stfd (code, i, (-pos + G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble))), ppc_r1);
3133                 }
3134         }
3135         alloc_size += pos;
3136         // align to PPC_STACK_ALIGNMENT bytes
3137         if (alloc_size & (PPC_STACK_ALIGNMENT - 1)) {
3138                 alloc_size += PPC_STACK_ALIGNMENT - 1;
3139                 alloc_size &= ~(PPC_STACK_ALIGNMENT - 1);
3140         }
3141
3142         cfg->stack_usage = alloc_size;
3143         g_assert ((alloc_size & (PPC_STACK_ALIGNMENT-1)) == 0);
3144         if (alloc_size) {
3145                 if (ppc_is_imm16 (-alloc_size)) {
3146                         ppc_stwu (code, ppc_sp, -alloc_size, ppc_sp);
3147                 } else {
3148                         ppc_load (code, ppc_r11, -alloc_size);
3149                         ppc_stwux (code, ppc_sp, ppc_sp, ppc_r11);
3150                 }
3151         }
3152         if (cfg->frame_reg != ppc_sp)
3153                 ppc_mr (code, cfg->frame_reg, ppc_sp);
3154
3155         /* compute max_offset in order to use short forward jumps
3156          * we always do it on ppc because the immediate displacement
3157          * for jumps is too small 
3158          */
3159         max_offset = 0;
3160         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3161                 MonoInst *ins = bb->code;
3162                 bb->max_offset = max_offset;
3163
3164                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3165                         max_offset += 6; 
3166
3167                 while (ins) {
3168                         max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
3169                         ins = ins->next;
3170                 }
3171         }
3172
3173         /* load arguments allocated to register from the stack */
3174         pos = 0;
3175
3176         cinfo = calculate_sizes (sig, sig->pinvoke);
3177
3178         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3179                 ArgInfo *ainfo = &cinfo->ret;
3180                 inst = cfg->ret;
3181                 if (ppc_is_imm16 (inst->inst_offset)) {
3182                         ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3183                 } else {
3184                         ppc_load (code, ppc_r11, inst->inst_offset);
3185                         ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3186                 }
3187         }
3188         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3189                 ArgInfo *ainfo = cinfo->args + i;
3190                 inst = cfg->varinfo [pos];
3191                 
3192                 if (cfg->verbose_level > 2)
3193                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3194                 if (inst->opcode == OP_REGVAR) {
3195                         if (ainfo->regtype == RegTypeGeneral)
3196                                 ppc_mr (code, inst->dreg, ainfo->reg);
3197                         else if (ainfo->regtype == RegTypeFP)
3198                                 ppc_fmr (code, inst->dreg, ainfo->reg);
3199                         else if (ainfo->regtype == RegTypeBase) {
3200                                 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3201                                 ppc_lwz (code, inst->dreg, ainfo->offset, ppc_r11);
3202                         } else
3203                                 g_assert_not_reached ();
3204
3205                         if (cfg->verbose_level > 2)
3206                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3207                 } else {
3208                         /* the argument should be put on the stack: FIXME handle size != word  */
3209                         if (ainfo->regtype == RegTypeGeneral) {
3210                                 switch (ainfo->size) {
3211                                 case 1:
3212                                         if (ppc_is_imm16 (inst->inst_offset)) {
3213                                                 ppc_stb (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3214                                         } else {
3215                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3216                                                 ppc_stbx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3217                                         }
3218                                         break;
3219                                 case 2:
3220                                         if (ppc_is_imm16 (inst->inst_offset)) {
3221                                                 ppc_sth (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3222                                         } else {
3223                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3224                                                 ppc_sthx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3225                                         }
3226                                         break;
3227                                 case 8:
3228                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
3229                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3230                                                 ppc_stw (code, ainfo->reg + 1, inst->inst_offset + 4, inst->inst_basereg);
3231                                         } else {
3232                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3233                                                 ppc_add (code, ppc_r11, ppc_r11, inst->inst_basereg);
3234                                                 ppc_stw (code, ainfo->reg, 0, ppc_r11);
3235                                                 ppc_stw (code, ainfo->reg + 1, 4, ppc_r11);
3236                                         }
3237                                         break;
3238                                 default:
3239                                         if (ppc_is_imm16 (inst->inst_offset)) {
3240                                                 ppc_stw (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3241                                         } else {
3242                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3243                                                 ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
3244                                         }
3245                                         break;
3246                                 }
3247                         } else if (ainfo->regtype == RegTypeBase) {
3248                                 /* load the previous stack pointer in r11 */
3249                                 ppc_lwz (code, ppc_r11, 0, ppc_sp);
3250                                 ppc_lwz (code, ppc_r0, ainfo->offset, ppc_r11);
3251                                 switch (ainfo->size) {
3252                                 case 1:
3253                                         if (ppc_is_imm16 (inst->inst_offset)) {
3254                                                 ppc_stb (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3255                                         } else {
3256                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3257                                                 ppc_stbx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3258                                         }
3259                                         break;
3260                                 case 2:
3261                                         if (ppc_is_imm16 (inst->inst_offset)) {
3262                                                 ppc_sth (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3263                                         } else {
3264                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3265                                                 ppc_sthx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3266                                         }
3267                                         break;
3268                                 case 8:
3269                                         if (ppc_is_imm16 (inst->inst_offset + 4)) {
3270                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3271                                                 ppc_lwz (code, ppc_r0, ainfo->offset + 4, ppc_r11);
3272                                                 ppc_stw (code, ppc_r0, inst->inst_offset + 4, inst->inst_basereg);
3273                                         } else {
3274                                                 /* FIXME */
3275                                                 g_assert_not_reached ();
3276                                         }
3277                                         break;
3278                                 default:
3279                                         if (ppc_is_imm16 (inst->inst_offset)) {
3280                                                 ppc_stw (code, ppc_r0, inst->inst_offset, inst->inst_basereg);
3281                                         } else {
3282                                                 ppc_load (code, ppc_r11, inst->inst_offset);
3283                                                 ppc_stwx (code, ppc_r0, ppc_r11, inst->inst_basereg);
3284                                         }
3285                                         break;
3286                                 }
3287                         } else if (ainfo->regtype == RegTypeFP) {
3288                                 g_assert (ppc_is_imm16 (inst->inst_offset));
3289                                 if (ainfo->size == 8)
3290                                         ppc_stfd (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3291                                 else if (ainfo->size == 4)
3292                                         ppc_stfs (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
3293                                 else
3294                                         g_assert_not_reached ();
3295                         } else if (ainfo->regtype == RegTypeStructByVal) {
3296                                 int doffset = inst->inst_offset;
3297                                 int soffset = 0;
3298                                 int cur_reg;
3299                                 int size = 0;
3300                                 g_assert (ppc_is_imm16 (inst->inst_offset));
3301                                 g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3302                                 if (mono_class_from_mono_type (inst->inst_vtype))
3303                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3304                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3305 /*
3306 Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
3307 register.  Should this case include linux/ppc?
3308 */
3309 #if __APPLE__
3310                                         if (size == 2)
3311                                                 ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3312                                         else if (size == 1)
3313                                                 ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3314                                         else 
3315 #endif
3316                                                 ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
3317                                         soffset += sizeof (gpointer);
3318                                         doffset += sizeof (gpointer);
3319                                 }
3320                                 if (ainfo->vtsize) {
3321                                         /* load the previous stack pointer in r11 (r0 gets overwritten by the memcpy) */
3322                                         ppc_lwz (code, ppc_r11, 0, ppc_sp);
3323                                         /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3324                                         code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
3325                                 }
3326                         } else if (ainfo->regtype == RegTypeStructByAddr) {
3327                                 g_assert (ppc_is_imm16 (inst->inst_offset));
3328                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3329                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3330                         } else
3331                                 g_assert_not_reached ();
3332                 }
3333                 pos++;
3334         }
3335
3336         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3337                 ppc_load (code, ppc_r3, cfg->domain);
3338                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3339                 ppc_bl (code, 0);
3340         }
3341
3342         if (method->save_lmf) {
3343                 if (lmf_pthread_key != -1) {
3344                         emit_tls_access (code, ppc_r3, lmf_pthread_key);
3345                         if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
3346                                 ppc_addi (code, ppc_r3, ppc_r3, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3347                 } else {
3348                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3349                                      (gpointer)"mono_get_lmf_addr");
3350                         if (FORCE_INDIR_CALL || cfg->method->dynamic) {
3351                                 ppc_lis (code, ppc_r0, 0);
3352                                 ppc_ori (code, ppc_r0, ppc_r0, 0);
3353                                 ppc_mtlr (code, ppc_r0);
3354                                 ppc_blrl (code);
3355                         } else {
3356                                 ppc_bl (code, 0);
3357                         }
3358                 }
3359                 /* we build the MonoLMF structure on the stack - see mini-ppc.h */
3360                 /* lmf_offset is the offset from the previous stack pointer,
3361                  * alloc_size is the total stack space allocated, so the offset
3362                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3363                  * The pointer to the struct is put in ppc_r11 (new_lmf).
3364                  * The callee-saved registers are already in the MonoLMF structure
3365                  */
3366                 ppc_addi (code, ppc_r11, ppc_sp, alloc_size - lmf_offset);
3367                 /* ppc_r3 is the result from mono_get_lmf_addr () */
3368                 ppc_stw (code, ppc_r3, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3369                 /* new_lmf->previous_lmf = *lmf_addr */
3370                 ppc_lwz (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3371                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3372                 /* *(lmf_addr) = r11 */
3373                 ppc_stw (code, ppc_r11, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r3);
3374                 /* save method info */
3375                 ppc_load (code, ppc_r0, method);
3376                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, method), ppc_r11);
3377                 ppc_stw (code, ppc_sp, G_STRUCT_OFFSET(MonoLMF, ebp), ppc_r11);
3378                 /* save the current IP */
3379                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3380                 ppc_load (code, ppc_r0, 0x01010101);
3381                 ppc_stw (code, ppc_r0, G_STRUCT_OFFSET(MonoLMF, eip), ppc_r11);
3382         }
3383
3384         if (tracing)
3385                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3386
3387         cfg->code_len = code - cfg->native_code;
3388         g_assert (cfg->code_len < cfg->code_size);
3389         g_free (cinfo);
3390
3391         return code;
3392 }
3393
3394 void
3395 mono_arch_emit_epilog (MonoCompile *cfg)
3396 {
3397         MonoJumpInfo *patch_info;
3398         MonoMethod *method = cfg->method;
3399         int pos, i;
3400         int max_epilog_size = 16 + 20*4;
3401         guint8 *code;
3402
3403         if (cfg->method->save_lmf)
3404                 max_epilog_size += 128;
3405         
3406         if (mono_jit_trace_calls != NULL)
3407                 max_epilog_size += 50;
3408
3409         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3410                 max_epilog_size += 50;
3411
3412         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3413                 cfg->code_size *= 2;
3414                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3415                 mono_jit_stats.code_reallocs++;
3416         }
3417
3418         /*
3419          * Keep in sync with CEE_JMP
3420          */
3421         code = cfg->native_code + cfg->code_len;
3422
3423         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3424                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3425         }
3426         pos = 0;
3427
3428         if (method->save_lmf) {
3429                 int lmf_offset;
3430                 pos +=  sizeof (MonoLMF);
3431                 lmf_offset = pos;
3432                 /* save the frame reg in r8 */
3433                 ppc_mr (code, ppc_r8, cfg->frame_reg);
3434                 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3435                 /* r5 = previous_lmf */
3436                 ppc_lwz (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r11);
3437                 /* r6 = lmf_addr */
3438                 ppc_lwz (code, ppc_r6, G_STRUCT_OFFSET(MonoLMF, lmf_addr), ppc_r11);
3439                 /* *(lmf_addr) = previous_lmf */
3440                 ppc_stw (code, ppc_r5, G_STRUCT_OFFSET(MonoLMF, previous_lmf), ppc_r6);
3441                 /* FIXME: speedup: there is no actual need to restore the registers if
3442                  * we didn't actually change them (idea from Zoltan).
3443                  */
3444                 /* restore iregs */
3445                 ppc_lmw (code, ppc_r13, ppc_r11, G_STRUCT_OFFSET(MonoLMF, iregs));
3446                 /* restore fregs */
3447                 /*for (i = 14; i < 32; i++) {
3448                         ppc_lfd (code, i, G_STRUCT_OFFSET(MonoLMF, fregs) + ((i-14) * sizeof (gdouble)), ppc_r11);
3449                 }*/
3450                 g_assert (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET));
3451                 /* use the saved copy of the frame reg in r8 */
3452                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3453                         ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, ppc_r8);
3454                         ppc_mtlr (code, ppc_r0);
3455                 }
3456                 ppc_addic (code, ppc_sp, ppc_r8, cfg->stack_usage);
3457         } else {
3458                 if (1 || cfg->flags & MONO_CFG_HAS_CALLS) {
3459                         if (ppc_is_imm16 (cfg->stack_usage + PPC_RET_ADDR_OFFSET)) {
3460                                 ppc_lwz (code, ppc_r0, cfg->stack_usage + PPC_RET_ADDR_OFFSET, cfg->frame_reg);
3461                         } else {
3462                                 ppc_load (code, ppc_r11, cfg->stack_usage + PPC_RET_ADDR_OFFSET);
3463                                 ppc_lwzx (code, ppc_r0, cfg->frame_reg, ppc_r11);
3464                         }
3465                         ppc_mtlr (code, ppc_r0);
3466                 }
3467                 if (ppc_is_imm16 (cfg->stack_usage)) {
3468                         ppc_addic (code, ppc_sp, cfg->frame_reg, cfg->stack_usage);
3469                 } else {
3470                         ppc_load (code, ppc_r11, cfg->stack_usage);
3471                         ppc_add (code, ppc_sp, cfg->frame_reg, ppc_r11);
3472                 }
3473
3474                 /*for (i = 31; i >= 14; --i) {
3475                         if (cfg->used_float_regs & (1 << i)) {
3476                                 pos += sizeof (double);
3477                                 ppc_lfd (code, i, -pos, ppc_sp);
3478                         }
3479                 }*/
3480                 for (i = 31; i >= 13; --i) {
3481                         if (cfg->used_int_regs & (1 << i)) {
3482                                 pos += sizeof (gulong);
3483                                 ppc_lwz (code, i, -pos, ppc_sp);
3484                         }
3485                 }
3486         }
3487         ppc_blr (code);
3488
3489         cfg->code_len = code - cfg->native_code;
3490
3491         g_assert (cfg->code_len < cfg->code_size);
3492
3493 }
3494
3495 /* remove once throw_exception_by_name is eliminated */
3496 static int
3497 exception_id_by_name (const char *name)
3498 {
3499         if (strcmp (name, "IndexOutOfRangeException") == 0)
3500                 return MONO_EXC_INDEX_OUT_OF_RANGE;
3501         if (strcmp (name, "OverflowException") == 0)
3502                 return MONO_EXC_OVERFLOW;
3503         if (strcmp (name, "ArithmeticException") == 0)
3504                 return MONO_EXC_ARITHMETIC;
3505         if (strcmp (name, "DivideByZeroException") == 0)
3506                 return MONO_EXC_DIVIDE_BY_ZERO;
3507         if (strcmp (name, "InvalidCastException") == 0)
3508                 return MONO_EXC_INVALID_CAST;
3509         if (strcmp (name, "NullReferenceException") == 0)
3510                 return MONO_EXC_NULL_REF;
3511         if (strcmp (name, "ArrayTypeMismatchException") == 0)
3512                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3513         g_error ("Unknown intrinsic exception %s\n", name);
3514         return 0;
3515 }
3516
3517 void
3518 mono_arch_emit_exceptions (MonoCompile *cfg)
3519 {
3520         MonoJumpInfo *patch_info;
3521         int nthrows, i;
3522         guint8 *code;
3523         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3524         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3525         guint32 code_size;
3526         int exc_count = 0;
3527         int max_epilog_size = 50;
3528
3529         /* count the number of exception infos */
3530      
3531         /* 
3532          * make sure we have enough space for exceptions
3533          * 24 is the simulated call to throw_exception_by_name
3534          */
3535         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3536                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3537                         i = exception_id_by_name (patch_info->data.target);
3538                         if (!exc_throw_found [i]) {
3539                                 max_epilog_size += 12;
3540                                 exc_throw_found [i] = TRUE;
3541                         }
3542                 } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
3543                         max_epilog_size += 12;
3544                 else if (patch_info->type == MONO_PATCH_INFO_EXC_OVF) {
3545                         MonoOvfJump *ovfj = patch_info->data.target;
3546                         i = exception_id_by_name (ovfj->data.exception);
3547                         if (!exc_throw_found [i]) {
3548                                 max_epilog_size += 12;
3549                                 exc_throw_found [i] = TRUE;
3550                         }
3551                         max_epilog_size += 8;
3552                 }
3553         }
3554
3555         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3556                 cfg->code_size *= 2;
3557                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3558                 mono_jit_stats.code_reallocs++;
3559         }
3560
3561         code = cfg->native_code + cfg->code_len;
3562
3563         /* add code to raise exceptions */
3564         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3565                 switch (patch_info->type) {
3566                 case MONO_PATCH_INFO_BB_OVF: {
3567                         MonoOvfJump *ovfj = patch_info->data.target;
3568                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
3569                         /* patch the initial jump */
3570                         ppc_patch (ip, code);
3571                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 2);
3572                         ppc_b (code, 0);
3573                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3574                         /* jump back to the true target */
3575                         ppc_b (code, 0);
3576                         ip = ovfj->data.bb->native_offset + cfg->native_code;
3577                         ppc_patch (code - 4, ip);
3578                         break;
3579                 }
3580                 case MONO_PATCH_INFO_EXC_OVF: {
3581                         MonoOvfJump *ovfj = patch_info->data.target;
3582                         MonoJumpInfo *newji;
3583                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
3584                         unsigned char *bcl = code;
3585                         /* patch the initial jump: we arrived here with a call */
3586                         ppc_patch (ip, code);
3587                         ppc_bc (code, ovfj->b0_cond, ovfj->b1_cond, 0);
3588                         ppc_b (code, 0);
3589                         ppc_patch (code - 4, ip + 4); /* jump back after the initiali branch */
3590                         /* patch the conditional jump to the right handler */
3591                         /* make it processed next */
3592                         newji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
3593                         newji->type = MONO_PATCH_INFO_EXC;
3594                         newji->ip.i = bcl - cfg->native_code;
3595                         newji->data.target = ovfj->data.exception;
3596                         newji->next = patch_info->next;
3597                         patch_info->next = newji;
3598                         break;
3599                 }
3600                 case MONO_PATCH_INFO_EXC: {
3601                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
3602                         i = exception_id_by_name (patch_info->data.target);
3603                         if (exc_throw_pos [i]) {
3604                                 ppc_patch (ip, exc_throw_pos [i]);
3605                                 patch_info->type = MONO_PATCH_INFO_NONE;
3606                                 break;
3607                         } else {
3608                                 exc_throw_pos [i] = code;
3609                         }
3610                         ppc_patch (ip, code);
3611                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3612                         ppc_load (code, ppc_r3, patch_info->data.target);
3613                         /* we got here from a conditional call, so the calling ip is set in lr already */
3614                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3615                         patch_info->data.name = "mono_arch_throw_exception_by_name";
3616                         patch_info->ip.i = code - cfg->native_code;
3617                         ppc_b (code, 0);
3618                         break;
3619                 }
3620                 default:
3621                         /* do nothing */
3622                         break;
3623                 }
3624         }
3625
3626         cfg->code_len = code - cfg->native_code;
3627
3628         g_assert (cfg->code_len < cfg->code_size);
3629
3630 }
3631
3632 static int
3633 try_offset_access (void *value, guint32 idx)
3634 {
3635         register void* me __asm__ ("r2");
3636         void ***p = (void***)((char*)me + 284);
3637         int idx1 = idx / 32;
3638         int idx2 = idx % 32;
3639         if (!p [idx1])
3640                 return 0;
3641         if (value != p[idx1][idx2])
3642                 return 0;
3643         return 1;
3644 }
3645
3646 static void
3647 setup_tls_access (void)
3648 {
3649         guint32 ptk;
3650         guint32 *ins, *code;
3651         guint32 cmplwi_1023, li_0x48, blr_ins;
3652         if (tls_mode == TLS_MODE_FAILED)
3653                 return;
3654
3655         if (g_getenv ("MONO_NO_TLS")) {
3656                 tls_mode = TLS_MODE_FAILED;
3657                 return;
3658         }
3659
3660         if (tls_mode == TLS_MODE_DETECT) {
3661                 ins = (guint32*)pthread_getspecific;
3662                 /* uncond branch to the real method */
3663                 if ((*ins >> 26) == 18) {
3664                         gint32 val;
3665                         val = (*ins & ~3) << 6;
3666                         val >>= 6;
3667                         if (*ins & 2) {
3668                                 /* absolute */
3669                                 ins = (guint32*)val;
3670                         } else {
3671                                 ins = (guint32*) ((char*)ins + val);
3672                         }
3673                 }
3674                 code = &cmplwi_1023;
3675                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
3676                 code = &li_0x48;
3677                 ppc_li (code, ppc_r4, 0x48);
3678                 code = &blr_ins;
3679                 ppc_blr (code);
3680                 if (*ins == cmplwi_1023) {
3681                         int found_lwz_284 = 0;
3682                         for (ptk = 0; ptk < 20; ++ptk) {
3683                                 ++ins;
3684                                 if (!*ins || *ins == blr_ins)
3685                                         break;
3686                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
3687                                         found_lwz_284 = 1;
3688                                         break;
3689                                 }
3690                         }
3691                         if (!found_lwz_284) {
3692                                 tls_mode = TLS_MODE_FAILED;
3693                                 return;
3694                         }
3695                         tls_mode = TLS_MODE_LTHREADS;
3696                 } else if (*ins == li_0x48) {
3697                         ++ins;
3698                         /* uncond branch to the real method */
3699                         if ((*ins >> 26) == 18) {
3700                                 gint32 val;
3701                                 val = (*ins & ~3) << 6;
3702                                 val >>= 6;
3703                                 if (*ins & 2) {
3704                                         /* absolute */
3705                                         ins = (guint32*)val;
3706                                 } else {
3707                                         ins = (guint32*) ((char*)ins + val);
3708                                 }
3709                                 code = &val;
3710                                 ppc_li (code, ppc_r0, 0x7FF2);
3711                                 if (ins [1] == val) {
3712                                         /* Darwin on G4, implement */
3713                                         tls_mode = TLS_MODE_FAILED;
3714                                         return;
3715                                 } else {
3716                                         code = &val;
3717                                         ppc_mfspr (code, ppc_r3, 104);
3718                                         if (ins [1] != val) {
3719                                                 tls_mode = TLS_MODE_FAILED;
3720                                                 return;
3721                                         }
3722                                         tls_mode = TLS_MODE_DARWIN_G5;
3723                                 }
3724                         } else {
3725                                 tls_mode = TLS_MODE_FAILED;
3726                                 return;
3727                         }
3728                 } else {
3729                         tls_mode = TLS_MODE_FAILED;
3730                         return;
3731                 }
3732         }
3733         if (monodomain_key == -1) {
3734                 ptk = mono_domain_get_tls_key ();
3735                 if (ptk < 1024) {
3736                         ptk = mono_pthread_key_for_tls (ptk);
3737                         if (ptk < 1024) {
3738                                 monodomain_key = ptk;
3739                         }
3740                 }
3741         }
3742         if (lmf_pthread_key == -1) {
3743                 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
3744                 if (ptk < 1024) {
3745                         /*g_print ("MonoLMF at: %d\n", ptk);*/
3746                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
3747                                 init_tls_failed = 1;
3748                                 return;
3749                         }*/
3750                         lmf_pthread_key = ptk;
3751                 }
3752         }
3753         if (monothread_key == -1) {
3754                 ptk = mono_thread_get_tls_key ();
3755                 if (ptk < 1024) {
3756                         ptk = mono_pthread_key_for_tls (ptk);
3757                         if (ptk < 1024) {
3758                                 monothread_key = ptk;
3759                                 /*g_print ("thread inited: %d\n", ptk);*/
3760                         }
3761                 } else {
3762                         /*g_print ("thread not inited yet %d\n", ptk);*/
3763                 }
3764         }
3765 }
3766
3767 void
3768 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3769 {
3770         setup_tls_access ();
3771 }
3772
3773 void
3774 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3775 {
3776 }
3777
3778 void
3779 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3780 {
3781         int this_dreg = ppc_r3;
3782         
3783         if (vt_reg != -1)
3784                 this_dreg = ppc_r4;
3785
3786         /* add the this argument */
3787         if (this_reg != -1) {
3788                 MonoInst *this;
3789                 MONO_INST_NEW (cfg, this, OP_SETREG);
3790                 this->type = this_type;
3791                 this->sreg1 = this_reg;
3792                 this->dreg = mono_regstate_next_int (cfg->rs);
3793                 mono_bblock_add_inst (cfg->cbb, this);
3794                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3795         }
3796
3797         if (vt_reg != -1) {
3798                 MonoInst *vtarg;
3799                 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3800                 vtarg->type = STACK_MP;
3801                 vtarg->sreg1 = vt_reg;
3802                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3803                 mono_bblock_add_inst (cfg->cbb, vtarg);
3804                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ppc_r3, FALSE);
3805         }
3806 }
3807
3808 MonoInst*
3809 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3810 {
3811         MonoInst *ins = NULL;
3812
3813         if (cmethod->klass == mono_defaults.thread_class &&
3814                         strcmp (cmethod->name, "MemoryBarrier") == 0) {
3815                 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3816         }
3817         /*if (cmethod->klass == mono_defaults.math_class) {
3818                 if (strcmp (cmethod->name, "Sqrt") == 0) {
3819                         MONO_INST_NEW (cfg, ins, OP_SQRT);
3820                         ins->inst_i0 = args [0];
3821                 }
3822         }*/
3823         return ins;
3824 }
3825
3826 gboolean
3827 mono_arch_print_tree (MonoInst *tree, int arity)
3828 {
3829         return 0;
3830 }
3831
3832 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3833 {
3834         MonoInst* ins;
3835
3836         setup_tls_access ();
3837         if (monodomain_key == -1)
3838                 return NULL;
3839         
3840         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3841         ins->inst_offset = monodomain_key;
3842         return ins;
3843 }
3844
3845 MonoInst* 
3846 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3847 {
3848         MonoInst* ins;
3849
3850         setup_tls_access ();
3851         if (monothread_key == -1)
3852                 return NULL;
3853         
3854         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
3855         ins->inst_offset = monothread_key;
3856         return ins;
3857 }
3858