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