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