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