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