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