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