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