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