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