3d44cbe7d5ff7a7d0b3a361f13234c694fdd920c
[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 #include <mono/utils/mono-mmap.h>
21
22 #include <mono/arch/mips/mips-codegen.h>
23
24 #include "mini-mips.h"
25 #include "cpu-mips.h"
26 #include "trace.h"
27 #include "ir-emit.h"
28
29 #define SAVE_FP_REGS            0
30 #define SAVE_ALL_REGS           0
31
32 #define SAVE_LMF                1
33 #define ALWAYS_USE_FP           1
34 #define ALWAYS_SAVE_RA          1       /* call-handler & switch currently clobber ra */
35
36 #define PROMOTE_R4_TO_R8        1       /* promote single values in registers to doubles */
37 #define USE_MUL                 1       /* use mul instead of mult/mflo for multiply */
38
39 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
40 #define mips_call(c,D,v) do {   \
41                 guint32 _target = (guint32)(v); \
42                 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
43                         mips_load_const (c, D, _target); \
44                         mips_jalr (c, D, mips_ra); \
45                 } \
46                 else { \
47                         mips_jumpl (c, _target >> 2); \
48                 } \
49                 mips_nop (c); \
50         } while (0)
51
52 enum {
53         TLS_MODE_DETECT,
54         TLS_MODE_FAILED,
55         TLS_MODE_LTHREADS,
56         TLS_MODE_NPTL
57 };
58
59 /* This mutex protects architecture specific caches */
60 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
61 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
62 static CRITICAL_SECTION mini_arch_mutex;
63
64 int mono_exc_esp_offset = 0;
65 static int tls_mode = TLS_MODE_DETECT;
66 static int lmf_pthread_key = -1;
67 static int monothread_key = -1;
68 static int monodomain_key = -1;
69
70 /* Whenever the host is little-endian */
71 static int little_endian;
72 /* Index of ms word/register */
73 static int ls_word_idx;
74 /* Index of ls word/register */
75 static int ms_word_idx;
76 /* Same for offsets */
77 static int ls_word_offset;
78 static int ms_word_offset;
79
80 /*
81  * The code generated for sequence points reads from this location, which is
82  * made read-only when single stepping is enabled.
83  */
84 static gpointer ss_trigger_page;
85
86 /* Enabled breakpoints read from this trigger page */
87 static gpointer bp_trigger_page;
88
89 #undef DEBUG
90 #define DEBUG(a) if (cfg->verbose_level > 1) a
91 #undef DEBUG
92 #define DEBUG(a) a
93 #undef DEBUG
94 #define DEBUG(a)
95
96 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name)            \
97         do {                                                        \
98                 code = mips_emit_exc_by_name (code, exc_name);  \
99                 cfg->bb_exit->max_offset += 16;                         \
100         } while (0) 
101
102
103 #define emit_linuxthreads_tls(code,dreg,key) do {\
104                 int off1, off2; \
105                 off1 = offsets_from_pthread_key ((key), &off2); \
106                 g_assert_not_reached ();                \
107                 ppc_lwz ((code), (dreg), off1, ppc_r2); \
108                 ppc_lwz ((code), (dreg), off2, (dreg)); \
109         } while (0);
110
111
112 #define emit_tls_access(code,dreg,key) do {     \
113                 switch (tls_mode) {     \
114                 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break;    \
115                 default: g_assert_not_reached ();       \
116                 }       \
117         } while (0)
118
119 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
120                 MonoInst *inst;                            \
121                 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
122                 inst->type = STACK_R8;                     \
123                 inst->dreg = (dr);                     \
124                 inst->inst_p0 = (void*)(addr);         \
125                 mono_bblock_add_inst (cfg->cbb, inst); \
126         } while (0)
127
128 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
129                                        || ((ins)->opcode == OP_ICOMPARE) \
130                                        || ((ins)->opcode == OP_LCOMPARE)))
131 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
132                                            || ((ins)->opcode == OP_ICOMPARE_IMM) \
133                                            || ((ins)->opcode == OP_LCOMPARE_IMM)))
134
135 #define INS_REWRITE(ins, op, _s1, _s2)  do { \
136                         int s1 = _s1;                   \
137                         int s2 = _s2;                   \
138                         ins->opcode = (op);             \
139                         ins->sreg1 = (s1);              \
140                         ins->sreg2 = (s2);              \
141         } while (0);
142
143 #define INS_REWRITE_IMM(ins, op, _s1, _imm)     do { \
144                         int s1 = _s1;                   \
145                         ins->opcode = (op);             \
146                         ins->sreg1 = (s1);              \
147                         ins->inst_imm = (_imm);         \
148         } while (0);
149
150
151 typedef struct InstList InstList;
152
153 struct InstList {
154         InstList *prev;
155         InstList *next;
156         MonoInst *data;
157 };
158
159 typedef enum {
160         ArgInIReg,
161         ArgOnStack,
162         ArgInFReg,
163         ArgStructByVal,
164         ArgStructByAddr
165 } ArgStorage;
166
167 typedef struct {
168         gint32  offset;
169         guint16 vtsize; /* in param area */
170         guint8  reg;
171         ArgStorage storage;
172         guint8  size    : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
173 } ArgInfo;
174
175 typedef struct {
176         int nargs;
177         int gr;
178         int fr;
179         gboolean gr_passed;
180         gboolean on_stack;
181         gboolean vtype_retaddr;
182         int stack_size;
183         guint32 stack_usage;
184         guint32 struct_ret;
185         ArgInfo ret;
186         ArgInfo sig_cookie;
187         ArgInfo args [1];
188 } CallInfo;
189
190 void patch_lui_addiu(guint32 *ip, guint32 val);
191 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
192 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
193 void mips_adjust_stackframe(MonoCompile *cfg);
194 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
195 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
196
197
198 /* Not defined in asm/cachectl.h */
199 int cacheflush(char *addr, int nbytes, int cache);
200
201 void
202 mono_arch_flush_icache (guint8 *code, gint size)
203 {
204         /* Linux/MIPS specific */
205         cacheflush ((char*)code, size, BCACHE);
206 }
207
208 void
209 mono_arch_flush_register_windows (void)
210 {
211 }
212
213 gboolean 
214 mono_arch_is_inst_imm (gint64 imm)
215 {
216         return TRUE;
217 }
218
219 static guint8 *
220 mips_emit_exc_by_name(guint8 *code, const char *name)
221 {
222         gpointer addr;
223         MonoClass *exc_class;
224
225         exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
226         g_assert (exc_class);
227
228         mips_load_const (code, mips_a0, exc_class->type_token);
229         addr = mono_get_throw_corlib_exception ();
230         mips_call (code, mips_t9, addr);
231         return code;
232 }
233
234
235 guint8 *
236 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
237 {
238         if (mips_is_imm16 (v))
239                 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
240         else {
241 #if SIZEOF_REGISTER == 8
242                 if (v != (long) v) {
243                         /* v is not a sign-extended 32-bit value */
244                         mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
245                         mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
246                         mips_dsll (code, dreg, dreg, 16);
247                         mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
248                         mips_dsll (code, dreg, dreg, 16);
249                         mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
250                         return code;
251                 }
252 #endif
253                 if (((guint32)v) & (1 << 15)) {
254                         mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
255                 }
256                 else {
257                         mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
258                 }
259                 if (((guint32)v) & 0xffff)
260                         mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
261         }
262         return code;
263 }
264
265 guint8 *
266 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
267 {
268         g_assert (ins);
269         if (cfg->arch.long_branch) {
270                 int br_offset = 5;
271
272                 /* Invert test and emit branch around jump */
273                 switch (op) {
274                 case OP_MIPS_BEQ:
275                         mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
276                         mips_nop (code);
277                         break;
278                 case OP_MIPS_BNE:
279                         mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
280                         mips_nop (code);
281                         break;
282                 case OP_MIPS_BGEZ:
283                         mips_bltz (code, ins->sreg1, br_offset);
284                         mips_nop (code);
285                         break;
286                 case OP_MIPS_BGTZ:
287                         mips_blez (code, ins->sreg1, br_offset);
288                         mips_nop (code);
289                         break;
290                 case OP_MIPS_BLEZ:
291                         mips_bgtz (code, ins->sreg1, br_offset);
292                         mips_nop (code);
293                         break;
294                 case OP_MIPS_BLTZ:
295                         mips_bgez (code, ins->sreg1, br_offset);
296                         mips_nop (code);
297                         break;
298                 default:
299                         g_assert_not_reached ();
300                 }
301                 mono_add_patch_info (cfg, code - cfg->native_code,
302                                      MONO_PATCH_INFO_BB, ins->inst_true_bb);
303                 mips_lui (code, mips_at, mips_zero, 0);
304                 mips_addiu (code, mips_at, mips_at, 0);
305                 mips_jr (code, mips_at);
306                 mips_nop (code);
307         }
308         else {
309                 mono_add_patch_info (cfg, code - cfg->native_code,
310                                      MONO_PATCH_INFO_BB, ins->inst_true_bb);
311                 switch (op) {
312                 case OP_MIPS_BEQ:
313                         mips_beq (code, ins->sreg1, ins->sreg2, 0);
314                         mips_nop (code);
315                         break;
316                 case OP_MIPS_BNE:
317                         mips_bne (code, ins->sreg1, ins->sreg2, 0);
318                         mips_nop (code);
319                         break;
320                 case OP_MIPS_BGEZ:
321                         mips_bgez (code, ins->sreg1, 0);
322                         mips_nop (code);
323                         break;
324                 case OP_MIPS_BGTZ:
325                         mips_bgtz (code, ins->sreg1, 0);
326                         mips_nop (code);
327                         break;
328                 case OP_MIPS_BLEZ:
329                         mips_blez (code, ins->sreg1, 0);
330                         mips_nop (code);
331                         break;
332                 case OP_MIPS_BLTZ:
333                         mips_bltz (code, ins->sreg1, 0);
334                         mips_nop (code);
335                         break;
336                 default:
337                         g_assert_not_reached ();
338                 }
339         }
340         return (code);
341 }
342
343 /* XXX - big-endian dependent? */
344 void
345 patch_lui_addiu(guint32 *ip, guint32 val)
346 {
347         guint16 *__lui_addiu = (guint16*)(void *)(ip);
348
349 #if 0
350         printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
351                 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
352         fflush (stdout);
353 #endif
354         if (((guint32)(val)) & (1 << 15))
355                 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
356         else
357                 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
358         __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
359         mono_arch_flush_icache ((guint8 *)ip, 8);
360 }
361
362 guint32 trap_target;
363 void
364 mips_patch (guint32 *code, guint32 target)
365 {
366         guint32 ins = *code;
367         guint32 op = ins >> 26;
368         guint32 diff, offset;
369
370         g_assert (trap_target != target);
371         //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
372         switch (op) {
373         case 0x00: /* jr ra */
374                 if (ins == 0x3e00008)
375                         break;
376                 g_assert_not_reached ();
377                 break;
378         case 0x02: /* j */
379         case 0x03: /* jal */
380                 g_assert (!(target & 0x03));
381                 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
382                 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
383                 *code = ins;
384                 mono_arch_flush_icache ((guint8 *)code, 4);
385                 break;
386         case 0x01: /* BLTZ */
387         case 0x04: /* BEQ */
388         case 0x05: /* BNE */
389         case 0x06: /* BLEZ */
390         case 0x07: /* BGTZ */
391         case 0x11: /* bc1t */
392                 diff = target - (guint32)(code + 1);
393                 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
394                 g_assert (!(diff & 0x03));
395                 offset = ((gint32)diff) >> 2;
396                 g_assert (((int)offset) == ((int)(short)offset));
397                 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
398                 *code = ins;
399                 mono_arch_flush_icache ((guint8 *)code, 4);
400                 break;
401         case 0x0f: /* LUI / ADDIU pair */
402                 g_assert ((code[1] >> 26) == 0x9);
403                 patch_lui_addiu (code, target);
404                 mono_arch_flush_icache ((guint8 *)code, 8);
405                 break;
406
407         default:
408                 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
409                 g_assert_not_reached ();
410         }
411 }
412
413 #if 0
414 static int
415 offsets_from_pthread_key (guint32 key, int *offset2)
416 {
417         int idx1 = key / 32;
418         int idx2 = key % 32;
419         *offset2 = idx2 * sizeof (gpointer);
420         return 284 + idx1 * sizeof (gpointer);
421 }
422 #endif
423
424 const char*
425 mono_arch_regname (int reg) {
426 #if _MIPS_SIM == _ABIO32
427         static const char * rnames[] = {
428                 "zero", "at", "v0", "v1",
429                 "a0", "a1", "a2", "a3",
430                 "t0", "t1", "t2", "t3",
431                 "t4", "t5", "t6", "t7",
432                 "s0", "s1", "s2", "s3",
433                 "s4", "s5", "s6", "s7",
434                 "t8", "t9", "k0", "k1",
435                 "gp", "sp", "fp", "ra"
436         };
437 #elif _MIPS_SIM == _ABIN32
438         static const char * rnames[] = {
439                 "zero", "at", "v0", "v1",
440                 "a0", "a1", "a2", "a3",
441                 "a4", "a5", "a6", "a7",
442                 "t0", "t1", "t2", "t3",
443                 "s0", "s1", "s2", "s3",
444                 "s4", "s5", "s6", "s7",
445                 "t8", "t9", "k0", "k1",
446                 "gp", "sp", "fp", "ra"
447         };
448 #endif
449         if (reg >= 0 && reg < 32)
450                 return rnames [reg];
451         return "unknown";
452 }
453
454 const char*
455 mono_arch_fregname (int reg) {
456         static const char * rnames[] = {
457                 "f0", "f1", "f2", "f3",
458                 "f4", "f5", "f6", "f7",
459                 "f8", "f9", "f10", "f11",
460                 "f12", "f13", "f14", "f15",
461                 "f16", "f17", "f18", "f19",
462                 "f20", "f21", "f22", "f23",
463                 "f24", "f25", "f26", "f27",
464                 "f28", "f29", "f30", "f31"
465         };
466         if (reg >= 0 && reg < 32)
467                 return rnames [reg];
468         return "unknown";
469 }
470
471 /* this function overwrites at */
472 static guint8*
473 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
474 {
475         /* XXX write a loop, not an unrolled loop */
476         while (size > 0) {
477                 mips_lw (code, mips_at, sreg, soffset);
478                 mips_sw (code, mips_at, dreg, doffset);
479                 size -= 4;
480                 soffset += 4;
481                 doffset += 4;
482         }
483         return code;
484 }
485
486 /*
487  * mono_arch_get_argument_info:
488  * @csig:  a method signature
489  * @param_count: the number of parameters to consider
490  * @arg_info: an array to store the result infos
491  *
492  * Gathers information on parameters such as size, alignment and
493  * padding. arg_info should be large enought to hold param_count + 1 entries. 
494  *
495  * Returns the size of the activation frame.
496  */
497 int
498 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
499 {
500         int k, frame_size = 0;
501         guint32 size, align, pad;
502         int offset = 0;
503
504         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
505                 frame_size += sizeof (gpointer);
506                 offset += 4;
507         }
508
509         arg_info [0].offset = offset;
510
511         if (csig->hasthis) {
512                 frame_size += sizeof (gpointer);
513                 offset += 4;
514         }
515
516         arg_info [0].size = frame_size;
517
518         for (k = 0; k < param_count; k++) {
519                 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
520
521                 /* ignore alignment for now */
522                 align = 1;
523
524                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
525                 arg_info [k].pad = pad;
526                 frame_size += size;
527                 arg_info [k + 1].pad = 0;
528                 arg_info [k + 1].size = size;
529                 offset += pad;
530                 arg_info [k + 1].offset = offset;
531                 offset += size;
532         }
533
534         align = MONO_ARCH_FRAME_ALIGNMENT;
535         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
536         arg_info [k].pad = pad;
537
538         return frame_size;
539 }
540
541
542 gpointer
543 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
544 {
545         g_assert(regs);
546         return (gpointer)regs [mips_a0];
547 }
548
549 /*
550  * Initialize the cpu to execute managed code.
551  */
552 void
553 mono_arch_cpu_init (void)
554 {
555 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
556         little_endian = 1;
557         ls_word_idx = 0;
558         ms_word_idx = 1;
559 #else
560         ls_word_idx = 1;
561         ms_word_idx = 0;
562 #endif
563
564         ls_word_offset = ls_word_idx * 4;
565         ms_word_offset = ms_word_idx * 4;
566 }
567
568 /*
569  * Initialize architecture specific code.
570  */
571 void
572 mono_arch_init (void)
573 {
574         InitializeCriticalSection (&mini_arch_mutex);
575
576         ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
577         bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
578         mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
579 }
580
581 /*
582  * Cleanup architecture specific code.
583  */
584 void
585 mono_arch_cleanup (void)
586 {
587         DeleteCriticalSection (&mini_arch_mutex);
588 }
589
590 /*
591  * This function returns the optimizations supported on this cpu.
592  */
593 guint32
594 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
595 {
596         guint32 opts = 0;
597
598         /* no mips-specific optimizations yet */
599         *exclude_mask = 0;
600         return opts;
601 }
602
603 static gboolean
604 is_regsize_var (MonoType *t) {
605         if (t->byref)
606                 return TRUE;
607         t = mono_type_get_underlying_type (t);
608         switch (t->type) {
609         case MONO_TYPE_I4:
610         case MONO_TYPE_U4:
611 #if (SIZEOF_REGISTER == 8)
612         case MONO_TYPE_I8:
613         case MONO_TYPE_U8:
614 #endif
615         case MONO_TYPE_I:
616         case MONO_TYPE_U:
617         case MONO_TYPE_PTR:
618         case MONO_TYPE_FNPTR:
619                 return TRUE;
620         case MONO_TYPE_OBJECT:
621         case MONO_TYPE_STRING:
622         case MONO_TYPE_CLASS:
623         case MONO_TYPE_SZARRAY:
624         case MONO_TYPE_ARRAY:
625                 return TRUE;
626         case MONO_TYPE_GENERICINST:
627                 if (!mono_type_generic_inst_is_valuetype (t))
628                         return TRUE;
629                 return FALSE;
630         case MONO_TYPE_VALUETYPE:
631                 return FALSE;
632         }
633         return FALSE;
634 }
635
636 GList *
637 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
638 {
639         GList *vars = NULL;
640         int i;
641
642         for (i = 0; i < cfg->num_varinfo; i++) {
643                 MonoInst *ins = cfg->varinfo [i];
644                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
645
646                 /* unused vars */
647                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
648                         continue;
649
650                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
651                         continue;
652
653                 /* we can only allocate 32 bit values */
654                 if (is_regsize_var (ins->inst_vtype)) {
655                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
656                         g_assert (i == vmv->idx);
657                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
658                 }
659         }
660
661         return vars;
662 }
663
664 GList *
665 mono_arch_get_global_int_regs (MonoCompile *cfg)
666 {
667         GList *regs = NULL;
668
669         regs = g_list_prepend (regs, (gpointer)mips_s0);
670         regs = g_list_prepend (regs, (gpointer)mips_s1);
671         regs = g_list_prepend (regs, (gpointer)mips_s2);
672         regs = g_list_prepend (regs, (gpointer)mips_s3);
673         regs = g_list_prepend (regs, (gpointer)mips_s4);
674         //regs = g_list_prepend (regs, (gpointer)mips_s5);
675         regs = g_list_prepend (regs, (gpointer)mips_s6);
676         regs = g_list_prepend (regs, (gpointer)mips_s7);
677
678         return regs;
679 }
680
681 /*
682  * mono_arch_regalloc_cost:
683  *
684  * Return the cost, in number of memory references, of the action of 
685  * allocating the variable VMV into a register during global register
686  * allocation.
687  */
688 guint32
689 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
690 {
691         /* FIXME: */
692         return 2;
693 }
694
695 static void
696 args_onto_stack (CallInfo *info)
697 {
698         g_assert (!info->on_stack);
699         g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
700         info->on_stack = TRUE;
701         info->stack_size = MIPS_STACK_PARAM_OFFSET;
702 }
703
704 #if _MIPS_SIM == _ABIO32
705 /*
706  * O32 calling convention version
707  */
708
709 static void
710 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
711         /* First, see if we need to drop onto the stack */
712         if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
713                 args_onto_stack (info);
714
715         /* Now, place the argument */
716         if (info->on_stack) {
717                 ainfo->storage = ArgOnStack;
718                 ainfo->reg = mips_sp; /* in the caller */
719                 ainfo->offset = info->stack_size;
720         }
721         else {
722                 ainfo->storage = ArgInIReg;
723                 ainfo->reg = info->gr;
724                 info->gr += 1;
725                 info->gr_passed = TRUE;
726         }
727         info->stack_size += 4;
728 }
729
730 static void
731 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
732         /* First, see if we need to drop onto the stack */
733         if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
734                 args_onto_stack (info);
735
736         /* Now, place the argument */
737         if (info->on_stack) {
738                 g_assert (info->stack_size % 4 == 0);
739                 info->stack_size += (info->stack_size % 8);
740
741                 ainfo->storage = ArgOnStack;
742                 ainfo->reg = mips_sp; /* in the caller */
743                 ainfo->offset = info->stack_size;
744         }
745         else {
746                 // info->gr must be a0 or a2
747                 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
748                 g_assert(info->gr <= MIPS_LAST_ARG_REG);
749
750                 ainfo->storage = ArgInIReg;
751                 ainfo->reg = info->gr;
752                 info->gr += 2;
753                 info->gr_passed = TRUE;
754         }
755         info->stack_size += 8;
756 }
757
758 static void
759 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
760         /* First, see if we need to drop onto the stack */
761         if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
762                 args_onto_stack (info);
763
764         /* Now, place the argument */
765         if (info->on_stack) {
766                 ainfo->storage = ArgOnStack;
767                 ainfo->reg = mips_sp; /* in the caller */
768                 ainfo->offset = info->stack_size;
769         }
770         else {
771                 /* Only use FP regs for args if no int args passed yet */
772                 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
773                         ainfo->storage = ArgInFReg;
774                         ainfo->reg = info->fr;
775                         /* Even though it's a single-precision float, it takes up two FP regs */
776                         info->fr += 2;
777                         /* FP and GP slots do not overlap */
778                         info->gr += 1;
779                 }
780                 else {
781                         /* Passing single-precision float arg in a GP register
782                          * such as: func (0, 1.0, 2, 3);
783                          * In this case, only one 'gr' register is consumed.
784                          */
785                         ainfo->storage = ArgInIReg;
786                         ainfo->reg = info->gr;
787
788                         info->gr += 1;
789                         info->gr_passed = TRUE;
790                 }
791         }
792         info->stack_size += 4;
793 }
794
795 static void
796 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
797         /* First, see if we need to drop onto the stack */
798         if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
799                 args_onto_stack (info);
800
801         /* Now, place the argument */
802         if (info->on_stack) {
803                 g_assert(info->stack_size % 4 == 0);
804                 info->stack_size += (info->stack_size % 8);
805
806                 ainfo->storage = ArgOnStack;
807                 ainfo->reg = mips_sp; /* in the caller */
808                 ainfo->offset = info->stack_size;
809         }
810         else {
811                 /* Only use FP regs for args if no int args passed yet */
812                 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
813                         ainfo->storage = ArgInFReg;
814                         ainfo->reg = info->fr;
815                         info->fr += 2;
816                         /* FP and GP slots do not overlap */
817                         info->gr += 2;
818                 }
819                 else {
820                         // info->gr must be a0 or a2
821                         info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
822                         g_assert(info->gr <= MIPS_LAST_ARG_REG);
823
824                         ainfo->storage = ArgInIReg;
825                         ainfo->reg = info->gr;
826                         info->gr += 2;
827                         info->gr_passed = TRUE;
828                 }
829         }
830         info->stack_size += 8;
831 }
832 #elif _MIPS_SIM == _ABIN32
833 /*
834  * N32 calling convention version
835  */
836
837 static void
838 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
839         /* First, see if we need to drop onto the stack */
840         if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
841                 args_onto_stack (info);
842
843         /* Now, place the argument */
844         if (info->on_stack) {
845                 ainfo->storage = ArgOnStack;
846                 ainfo->reg = mips_sp; /* in the caller */
847                 ainfo->offset = info->stack_size;
848                 info->stack_size += SIZEOF_REGISTER;
849         }
850         else {
851                 ainfo->storage = ArgInIReg;
852                 ainfo->reg = info->gr;
853                 info->gr += 1;
854                 info->gr_passed = TRUE;
855         }
856 }
857
858 static void
859 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
860         /* First, see if we need to drop onto the stack */
861         if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
862                 args_onto_stack (info);
863
864         /* Now, place the argument */
865         if (info->on_stack) {
866                 g_assert (info->stack_size % 4 == 0);
867                 info->stack_size += (info->stack_size % 8);
868
869                 ainfo->storage = ArgOnStack;
870                 ainfo->reg = mips_sp; /* in the caller */
871                 ainfo->offset = info->stack_size;
872                 info->stack_size += SIZEOF_REGISTER;
873         }
874         else {
875                 g_assert (info->gr <= MIPS_LAST_ARG_REG);
876
877                 ainfo->storage = ArgInIReg;
878                 ainfo->reg = info->gr;
879                 info->gr += 1;
880                 info->gr_passed = TRUE;
881         }
882 }
883
884 static void
885 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
886         /* First, see if we need to drop onto the stack */
887         if (!info->on_stack) {
888                 if (info->gr > MIPS_LAST_ARG_REG)
889                         args_onto_stack (info);
890                 else if (info->fr > MIPS_LAST_FPARG_REG)
891                         args_onto_stack (info);
892         }
893
894         /* Now, place the argument */
895         if (info->on_stack) {
896                 ainfo->storage = ArgOnStack;
897                 ainfo->reg = mips_sp; /* in the caller */
898                 ainfo->offset = info->stack_size;
899                 info->stack_size += FREG_SIZE;
900         }
901         else {
902                 ainfo->storage = ArgInFReg;
903                 ainfo->reg = info->fr;
904                 info->fr += 1;
905                 /* FP and GP slots do not overlap */
906                 info->gr += 1;
907         }
908 }
909
910 static void
911 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
912         /* First, see if we need to drop onto the stack */
913         if (!info->on_stack) {
914                 if (info->gr > MIPS_LAST_ARG_REG)
915                         args_onto_stack (info);
916                 else if (info->fr > MIPS_LAST_FPARG_REG)
917                         args_onto_stack (info);
918         }
919
920         /* Now, place the argument */
921         if (info->on_stack) {
922                 g_assert(info->stack_size % 4 == 0);
923                 info->stack_size += (info->stack_size % 8);
924
925                 ainfo->storage = ArgOnStack;
926                 ainfo->reg = mips_sp; /* in the caller */
927                 ainfo->offset = info->stack_size;
928                 info->stack_size += FREG_SIZE;
929         }
930         else {
931                 ainfo->storage = ArgInFReg;
932                 ainfo->reg = info->fr;
933                 info->fr += 1;
934                 /* FP and GP slots do not overlap */
935                 info->gr += 1;
936         }
937 }
938 #endif
939
940 static CallInfo*
941 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
942 {
943         guint i;
944         int n = sig->hasthis + sig->param_count;
945         int pstart;
946         MonoType* simpletype;
947         CallInfo *cinfo;
948         gboolean is_pinvoke = sig->pinvoke;
949
950         if (mp)
951                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
952         else
953                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
954
955         cinfo->fr = MIPS_FIRST_FPARG_REG;
956         cinfo->gr = MIPS_FIRST_ARG_REG;
957         cinfo->stack_size = 0;
958
959         DEBUG(printf("calculate_sizes\n"));
960
961         cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
962         pstart = 0;
963         n = 0;
964 #if 0
965         /* handle returning a struct */
966         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
967                 cinfo->struct_ret = cinfo->gr;
968                 add_int32_arg (cinfo, &cinfo->ret);
969         }
970
971         if (sig->hasthis) {
972                 add_int32_arg (cinfo, cinfo->args + n);
973                 n++;
974         }
975 #else
976         /*
977          * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
978          * the first argument, allowing 'this' to be always passed in the first arg reg.
979          * Also do this if the first argument is a reference type, since virtual calls
980          * are sometimes made using calli without sig->hasthis set, like in the delegate
981          * invoke wrappers.
982          */
983         if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, sig->params [0]))))) {
984                 if (sig->hasthis) {
985                         add_int32_arg (cinfo, cinfo->args + n);
986                         n ++;
987                 } else {
988                         add_int32_arg (cinfo, cinfo->args + sig->hasthis);
989                         pstart = 1;
990                         n ++;
991                 }
992                 add_int32_arg (cinfo, &cinfo->ret);
993                 cinfo->struct_ret = cinfo->ret.reg;
994         } else {
995                 /* this */
996                 if (sig->hasthis) {
997                         add_int32_arg (cinfo, cinfo->args + n);
998                         n ++;
999                 }
1000
1001                 if (cinfo->vtype_retaddr) {
1002                         add_int32_arg (cinfo, &cinfo->ret);
1003                         cinfo->struct_ret = cinfo->ret.reg;
1004                 }
1005         }
1006 #endif
1007
1008         DEBUG(printf("params: %d\n", sig->param_count));
1009         for (i = pstart; i < sig->param_count; ++i) {
1010                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1011                         /* Prevent implicit arguments and sig_cookie from
1012                            being passed in registers */
1013                         args_onto_stack (cinfo);
1014                         /* Emit the signature cookie just before the implicit arguments */
1015                         add_int32_arg (cinfo, &cinfo->sig_cookie);
1016                 }
1017                 DEBUG(printf("param %d: ", i));
1018                 if (sig->params [i]->byref) {
1019                         DEBUG(printf("byref\n"));
1020                         add_int32_arg (cinfo, &cinfo->args[n]);
1021                         n++;
1022                         continue;
1023                 }
1024                 simpletype = mono_type_get_underlying_type (sig->params [i]);
1025                 switch (simpletype->type) {
1026                 case MONO_TYPE_BOOLEAN:
1027                 case MONO_TYPE_I1:
1028                 case MONO_TYPE_U1:
1029                         DEBUG(printf("1 byte\n"));
1030                         cinfo->args [n].size = 1;
1031                         add_int32_arg (cinfo, &cinfo->args[n]);
1032                         n++;
1033                         break;
1034                 case MONO_TYPE_CHAR:
1035                 case MONO_TYPE_I2:
1036                 case MONO_TYPE_U2:
1037                         DEBUG(printf("2 bytes\n"));
1038                         cinfo->args [n].size = 2;
1039                         add_int32_arg (cinfo, &cinfo->args[n]);
1040                         n++;
1041                         break;
1042                 case MONO_TYPE_I4:
1043                 case MONO_TYPE_U4:
1044                         DEBUG(printf("4 bytes\n"));
1045                         cinfo->args [n].size = 4;
1046                         add_int32_arg (cinfo, &cinfo->args[n]);
1047                         n++;
1048                         break;
1049                 case MONO_TYPE_I:
1050                 case MONO_TYPE_U:
1051                 case MONO_TYPE_PTR:
1052                 case MONO_TYPE_FNPTR:
1053                 case MONO_TYPE_CLASS:
1054                 case MONO_TYPE_OBJECT:
1055                 case MONO_TYPE_STRING:
1056                 case MONO_TYPE_SZARRAY:
1057                 case MONO_TYPE_ARRAY:
1058                         cinfo->args [n].size = sizeof (gpointer);
1059                         add_int32_arg (cinfo, &cinfo->args[n]);
1060                         n++;
1061                         break;
1062                 case MONO_TYPE_GENERICINST:
1063                         if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1064                                 cinfo->args [n].size = sizeof (gpointer);
1065                                 add_int32_arg (cinfo, &cinfo->args[n]);
1066                                 n++;
1067                                 break;
1068                         }
1069                         /* Fall through */
1070                 case MONO_TYPE_VALUETYPE: {
1071                         int j;
1072                         int nwords = 0;
1073                         int has_offset = FALSE;
1074                         ArgInfo dummy_arg;
1075                         gint size, alignment;
1076                         MonoClass *klass;
1077
1078                         klass = mono_class_from_mono_type (sig->params [i]);
1079                         if (is_pinvoke)
1080                             size = mono_class_native_size (klass, NULL);
1081                         else
1082                             size = mono_class_value_size (klass, NULL);
1083                         alignment = mono_class_min_align (klass);
1084 #if MIPS_PASS_STRUCTS_BY_VALUE
1085                         /* Need to do alignment if struct contains long or double */
1086                         if (alignment > 4) {
1087                                 /* Drop onto stack *before* looking at
1088                                    stack_size, if required. */
1089                                 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1090                                         args_onto_stack (cinfo);
1091                                 if (cinfo->stack_size & (alignment - 1)) {
1092                                         add_int32_arg (cinfo, &dummy_arg);
1093                                 }
1094                                 g_assert (!(cinfo->stack_size & (alignment - 1)));
1095                         }
1096
1097 #if 0
1098                         g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1099                                   mono_class_native_size (sig->params [i]->data.klass, NULL),
1100                                   cinfo->stack_size, alignment);
1101 #endif
1102                         nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1103                         g_assert (cinfo->args [n].size == 0);
1104                         g_assert (cinfo->args [n].vtsize == 0);
1105                         for (j = 0; j < nwords; ++j) {
1106                                 if (j == 0) {
1107                                         add_int32_arg (cinfo, &cinfo->args [n]);
1108                                         if (cinfo->on_stack)
1109                                                 has_offset = TRUE;
1110                                 } else {
1111                                         add_int32_arg (cinfo, &dummy_arg);
1112                                         if (!has_offset && cinfo->on_stack) {
1113                                                 cinfo->args [n].offset = dummy_arg.offset;
1114                                                 has_offset = TRUE;
1115                                         }
1116                                 }
1117                                 if (cinfo->on_stack)
1118                                         cinfo->args [n].vtsize += 1;
1119                                 else
1120                                         cinfo->args [n].size += 1;
1121                         }
1122                         //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1123                         cinfo->args [n].storage = ArgStructByVal;
1124 #else
1125                         add_int32_arg (cinfo, &cinfo->args[n]);
1126                         cinfo->args [n].storage = ArgStructByAddr;
1127 #endif
1128                         n++;
1129                         break;
1130                 }
1131                 case MONO_TYPE_TYPEDBYREF: {
1132                         /* keep in sync or merge with the valuetype case */
1133 #if MIPS_PASS_STRUCTS_BY_VALUE
1134                         {
1135                                 int size = sizeof (MonoTypedRef);
1136                                 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1137                                 cinfo->args [n].storage = ArgStructByVal;
1138                                 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
1139                                         int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
1140                                         int n_in_regs = rest >= nwords? nwords: rest;
1141                                         cinfo->args [n].size = n_in_regs;
1142                                         cinfo->args [n].vtsize = nwords - n_in_regs;
1143                                         cinfo->args [n].reg = cinfo->gr;
1144                                         cinfo->gr += n_in_regs;
1145                                         cinfo->gr_passed = TRUE;
1146                                 } else {
1147                                         cinfo->args [n].size = 0;
1148                                         cinfo->args [n].vtsize = nwords;
1149                                 }
1150                                 if (cinfo->args [n].vtsize > 0) {
1151                                         if (!cinfo->on_stack)
1152                                                 args_onto_stack (cinfo);
1153                                         g_assert(cinfo->on_stack);
1154                                         cinfo->args [n].offset = cinfo->stack_size;
1155                                         g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
1156                                         cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
1157                                 }
1158                         }
1159 #else
1160                         add_int32_arg (cinfo, &cinfo->args[n]);
1161                         cinfo->args [n].storage = ArgStructByAddr;
1162 #endif
1163                         n++;
1164                         break;
1165                 }
1166                 case MONO_TYPE_U8:
1167                 case MONO_TYPE_I8:
1168                         DEBUG(printf("8 bytes\n"));
1169                         cinfo->args [n].size = 8;
1170                         add_int64_arg (cinfo, &cinfo->args[n]);
1171                         n++;
1172                         break;
1173                 case MONO_TYPE_R4:
1174                         DEBUG(printf("R4\n"));
1175                         cinfo->args [n].size = 4;
1176                         add_float32_arg (cinfo, &cinfo->args[n]);
1177                         n++;
1178                         break;
1179                 case MONO_TYPE_R8:
1180                         DEBUG(printf("R8\n"));
1181                         cinfo->args [n].size = 8;
1182                         add_float64_arg (cinfo, &cinfo->args[n]);
1183                         n++;
1184                         break;
1185                 default:
1186                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1187                 }
1188         }
1189
1190         {
1191                 simpletype = mono_type_get_underlying_type (sig->ret);
1192                 switch (simpletype->type) {
1193                 case MONO_TYPE_BOOLEAN:
1194                 case MONO_TYPE_I1:
1195                 case MONO_TYPE_U1:
1196                 case MONO_TYPE_I2:
1197                 case MONO_TYPE_U2:
1198                 case MONO_TYPE_CHAR:
1199                 case MONO_TYPE_I4:
1200                 case MONO_TYPE_U4:
1201                 case MONO_TYPE_I:
1202                 case MONO_TYPE_U:
1203                 case MONO_TYPE_PTR:
1204                 case MONO_TYPE_FNPTR:
1205                 case MONO_TYPE_CLASS:
1206                 case MONO_TYPE_OBJECT:
1207                 case MONO_TYPE_SZARRAY:
1208                 case MONO_TYPE_ARRAY:
1209                 case MONO_TYPE_STRING:
1210                         cinfo->ret.reg = mips_v0;
1211                         break;
1212                 case MONO_TYPE_U8:
1213                 case MONO_TYPE_I8:
1214                         cinfo->ret.reg = mips_v0;
1215                         break;
1216                 case MONO_TYPE_R4:
1217                 case MONO_TYPE_R8:
1218                         cinfo->ret.reg = mips_f0;
1219                         cinfo->ret.storage = ArgInFReg;
1220                         break;
1221                 case MONO_TYPE_GENERICINST:
1222                         if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1223                                 cinfo->ret.reg = mips_v0;
1224                                 break;
1225                         }
1226                         break;
1227                 case MONO_TYPE_VALUETYPE:
1228                         break;
1229                 case MONO_TYPE_TYPEDBYREF:
1230                 case MONO_TYPE_VOID:
1231                         break;
1232                 default:
1233                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
1234                 }
1235         }
1236
1237         /* align stack size to 16 */
1238         cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1239
1240         cinfo->stack_usage = cinfo->stack_size;
1241         return cinfo;
1242 }
1243
1244
1245 /*
1246  * Set var information according to the calling convention. mips version.
1247  * The locals var stuff should most likely be split in another method.
1248  */
1249 void
1250 mono_arch_allocate_vars (MonoCompile *cfg)
1251 {
1252         MonoMethodSignature *sig;
1253         MonoMethodHeader *header;
1254         MonoInst *inst;
1255         int i, offset, size, align, curinst;
1256         int frame_reg = mips_sp;
1257         guint32 iregs_to_save = 0;
1258 #if SAVE_FP_REGS
1259         guint32 fregs_to_restore;
1260 #endif
1261         CallInfo *cinfo;
1262
1263         sig = mono_method_signature (cfg->method);
1264
1265         if (!cfg->arch.cinfo)
1266                 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1267         cinfo = cfg->arch.cinfo;
1268
1269         /* spill down, we'll fix it in a separate pass */
1270         // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1271
1272         /* allow room for the vararg method args: void* and long/double */
1273         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1274                 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1275
1276         /* this is bug #60332: remove when #59509 is fixed, so no weird vararg 
1277          * call convs needs to be handled this way.
1278          */
1279         if (cfg->flags & MONO_CFG_HAS_VARARGS)
1280                 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1281
1282         /* gtk-sharp and other broken code will dllimport vararg functions even with
1283          * non-varargs signatures. Since there is little hope people will get this right
1284          * we assume they won't.
1285          */
1286         if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1287                 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1288
1289         /* a0-a3 always present */
1290         cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1291
1292         header = cfg->header;
1293
1294         /* 
1295          * We use the frame register also for any method that has
1296          * exception clauses. This way, when the handlers are called,
1297          * the code will reference local variables using the frame reg instead of
1298          * the stack pointer: if we had to restore the stack pointer, we'd
1299          * corrupt the method frames that are already on the stack (since
1300          * filters get called before stack unwinding happens) when the filter
1301          * code would call any method (this also applies to finally etc.).
1302          */ 
1303
1304         if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1305                 frame_reg = mips_fp;
1306         cfg->frame_reg = frame_reg;
1307         if (frame_reg != mips_sp) {
1308                 cfg->used_int_regs |= 1 << frame_reg;
1309         }
1310
1311         offset = 0;
1312         curinst = 0;
1313         if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1314                 /* FIXME: handle long and FP values */
1315                 switch (mono_type_get_underlying_type (sig->ret)->type) {
1316                 case MONO_TYPE_VOID:
1317                         break;
1318                 case MONO_TYPE_R4:
1319                 case MONO_TYPE_R8:
1320                         cfg->ret->opcode = OP_REGVAR;
1321                         cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1322                         break;
1323                 default:
1324                         cfg->ret->opcode = OP_REGVAR;
1325                         cfg->ret->inst_c0 = mips_v0;
1326                         break;
1327                 }
1328         }
1329         /* Space for outgoing parameters, including a0-a3 */
1330         offset += cfg->param_area;
1331
1332         /* allow room to save the return value (if it's a struct) */
1333         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1334                 offset += 8;
1335
1336         if (sig->call_convention == MONO_CALL_VARARG) {
1337                 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1338         }
1339
1340         /* Now handle the local variables */
1341
1342         curinst = cfg->locals_start;
1343         for (i = curinst; i < cfg->num_varinfo; ++i) {
1344                 inst = cfg->varinfo [i];
1345                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1346                         continue;
1347
1348                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1349                  * pinvoke wrappers when they call functions returning structure
1350                  */
1351                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1352                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1353                 else
1354                         size = mono_type_size (inst->inst_vtype, &align);
1355
1356                 offset += align - 1;
1357                 offset &= ~(align - 1);
1358                 inst->inst_offset = offset;
1359                 inst->opcode = OP_REGOFFSET;
1360                 inst->inst_basereg = frame_reg;
1361                 offset += size;
1362                 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1363         }
1364
1365         /* Space for LMF (if needed) */
1366 #if SAVE_LMF
1367         if (cfg->method->save_lmf) {
1368                 /* align the offset to 16 bytes */
1369                 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1370                 cfg->arch.lmf_offset = offset;
1371                 offset += sizeof (MonoLMF);
1372         }
1373 #endif
1374
1375         /* Space for saved registers */
1376         cfg->arch.iregs_offset = offset;
1377 #if SAVE_ALL_REGS
1378         iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1379 #else
1380         iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1381 #endif
1382         if (iregs_to_save) {
1383                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1384                         if (iregs_to_save & (1 << i)) {
1385                                 offset += SIZEOF_REGISTER;
1386                         }
1387                 }
1388         }
1389
1390         /* saved float registers */
1391 #if SAVE_FP_REGS
1392         fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1393         if (fregs_to_restore) {
1394                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1395                         if (fregs_to_restore & (1 << i)) {
1396                                 offset += sizeof(double);
1397                         }
1398                 }
1399         }
1400 #endif
1401
1402 #if _MIPS_SIM == _ABIO32
1403         /* Now add space for saving the ra */
1404         offset += SIZEOF_VOID_P;
1405
1406         /* change sign? */
1407         offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1408         cfg->stack_offset = offset;
1409         cfg->arch.local_alloc_offset = cfg->stack_offset;
1410 #endif
1411
1412         /*
1413          * Now allocate stack slots for the int arg regs (a0 - a3)
1414          * On MIPS o32, these are just above the incoming stack pointer
1415          * Even if the arg has been assigned to a regvar, it gets a stack slot
1416          */
1417
1418         /* Return struct-by-value results in a hidden first argument */
1419         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1420                 cfg->vret_addr->opcode = OP_REGOFFSET;
1421                 cfg->vret_addr->inst_c0 = mips_a0;
1422                 cfg->vret_addr->inst_offset = offset;
1423                 cfg->vret_addr->inst_basereg = frame_reg;
1424                 offset += SIZEOF_REGISTER;
1425         }
1426
1427         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1428                 inst = cfg->args [i];
1429                 if (inst->opcode != OP_REGVAR) {
1430                         MonoType *arg_type;
1431                         ArgInfo *ainfo = &cinfo->args [i];
1432                  
1433                         if (sig->hasthis && (i == 0))
1434                                 arg_type = &mono_defaults.object_class->byval_arg;
1435                         else
1436                                 arg_type = sig->params [i - sig->hasthis];
1437
1438                         inst->opcode = OP_REGOFFSET;
1439                         size = mono_type_size (arg_type, &align);
1440
1441                         if (size < SIZEOF_REGISTER) {
1442                                 size = SIZEOF_REGISTER;
1443                                 align = SIZEOF_REGISTER;
1444                         }
1445                         inst->inst_basereg = frame_reg;
1446                         offset = (offset + align - 1) & ~(align - 1);
1447                         inst->inst_offset = offset;
1448                         offset += size;
1449                         if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) 
1450                                 cfg->sig_cookie += size;
1451                         // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1452                 }
1453                 else {
1454 #if _MIPS_SIM == _ABIO32
1455                         /* o32: Even a0-a3 get stack slots */
1456                         size = SIZEOF_REGISTER;
1457                         align = SIZEOF_REGISTER;
1458                         inst->inst_basereg = frame_reg;
1459                         offset = (offset + align - 1) & ~(align - 1);
1460                         inst->inst_offset = offset;
1461                         offset += size;
1462                         if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) 
1463                                 cfg->sig_cookie += size;
1464                         // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1465 #endif
1466                 }
1467         }
1468 #if _MIPS_SIM == _ABIN32
1469         /* Now add space for saving the ra */
1470         offset += SIZEOF_VOID_P;
1471
1472         /* change sign? */
1473         offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1474         cfg->stack_offset = offset;
1475         cfg->arch.local_alloc_offset = cfg->stack_offset;
1476 #endif
1477 }
1478
1479 void
1480 mono_arch_create_vars (MonoCompile *cfg)
1481 {
1482         MonoMethodSignature *sig;
1483
1484         sig = mono_method_signature (cfg->method);
1485
1486         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1487                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1488                 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1489                         printf ("vret_addr = ");
1490                         mono_print_ins (cfg->vret_addr);
1491                 }
1492         }
1493 }
1494
1495 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1496  * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
1497  */
1498
1499 /* 
1500  * take the arguments and generate the arch-specific
1501  * instructions to properly call the function in call.
1502  * This includes pushing, moving arguments to the right register
1503  * etc.
1504  * Issue: who does the spilling if needed, and when?
1505  */
1506 static void
1507 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1508 {
1509         int sig_reg = mono_alloc_ireg (cfg);
1510
1511         MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1512         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1513                         mips_sp, cinfo->sig_cookie.offset, sig_reg);
1514 }
1515
1516 void
1517 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1518 {
1519         MonoInst *in, *ins;
1520         MonoMethodSignature *sig;
1521         int i, n;
1522         CallInfo *cinfo;
1523         int is_virtual = 0;
1524
1525         sig = call->signature;
1526         n = sig->param_count + sig->hasthis;
1527         
1528         cinfo = get_call_info (NULL, cfg->mempool, sig);
1529         if (cinfo->struct_ret)
1530                 call->used_iregs |= 1 << cinfo->struct_ret;
1531
1532         for (i = 0; i < n; ++i) {
1533                 ArgInfo *ainfo = cinfo->args + i;
1534                 MonoType *t;
1535
1536                 if (i >= sig->hasthis)
1537                         t = sig->params [i - sig->hasthis];
1538                 else
1539                         t = &mono_defaults.int_class->byval_arg;
1540                 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1541
1542                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1543                         emit_sig_cookie (cfg, call, cinfo);
1544                 if (is_virtual && i == 0) {
1545                         /* the argument will be attached to the call instrucion */
1546                         in = call->args [i];
1547                         call->used_iregs |= 1 << ainfo->reg;
1548                         continue;
1549                 }
1550                 in = call->args [i];
1551                 if (ainfo->storage == ArgInIReg) {
1552 #if SIZEOF_REGISTER == 4
1553                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1554                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1555                                 ins->dreg = mono_alloc_ireg (cfg);
1556                                 ins->sreg1 = in->dreg + 1;
1557                                 MONO_ADD_INS (cfg->cbb, ins);
1558                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1559
1560                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1561                                 ins->dreg = mono_alloc_ireg (cfg);
1562                                 ins->sreg1 = in->dreg + 2;
1563                                 MONO_ADD_INS (cfg->cbb, ins);
1564                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1565                         } else
1566 #endif
1567                         if (!t->byref && (t->type == MONO_TYPE_R4)) {
1568                                 int freg;
1569
1570 #if PROMOTE_R4_TO_R8
1571                                 /* ??? - convert to single first? */
1572                                 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1573                                 ins->dreg = mono_alloc_freg (cfg);
1574                                 ins->sreg1 = in->dreg;
1575                                 MONO_ADD_INS (cfg->cbb, ins);
1576                                 freg = ins->dreg;
1577 #else
1578                                 freg = in->dreg;
1579 #endif
1580                                 /* trying to load float value into int registers */
1581                                 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1582                                 ins->dreg = mono_alloc_ireg (cfg);
1583                                 ins->sreg1 = freg;
1584                                 MONO_ADD_INS (cfg->cbb, ins);
1585                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1586                         } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1587                                 /* trying to load float value into int registers */
1588                                 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1589                                 ins->dreg = mono_alloc_ireg (cfg);
1590                                 ins->sreg1 = in->dreg;
1591                                 MONO_ADD_INS (cfg->cbb, ins);
1592                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1593                         } else {
1594                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1595                                 ins->dreg = mono_alloc_ireg (cfg);
1596                                 ins->sreg1 = in->dreg;
1597                                 MONO_ADD_INS (cfg->cbb, ins);
1598                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1599                         }
1600                 } else if (ainfo->storage == ArgStructByAddr) {
1601                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1602                         ins->opcode = OP_OUTARG_VT;
1603                         ins->sreg1 = in->dreg;
1604                         ins->klass = in->klass;
1605                         ins->inst_p0 = call;
1606                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1607                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1608                         MONO_ADD_INS (cfg->cbb, ins);
1609                 } else if (ainfo->storage == ArgStructByVal) {
1610                         /* this is further handled in mono_arch_emit_outarg_vt () */
1611                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1612                         ins->opcode = OP_OUTARG_VT;
1613                         ins->sreg1 = in->dreg;
1614                         ins->klass = in->klass;
1615                         ins->inst_p0 = call;
1616                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1617                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1618                         MONO_ADD_INS (cfg->cbb, ins);
1619                 } else if (ainfo->storage == ArgOnStack) {
1620                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1621                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1622                         } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1623                                 if (t->type == MONO_TYPE_R8)
1624                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1625                                 else
1626                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1627                         } else {
1628                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1629                         }
1630                 } else if (ainfo->storage == ArgInFReg) {
1631                         if (t->type == MONO_TYPE_VALUETYPE) {
1632                                 /* this is further handled in mono_arch_emit_outarg_vt () */
1633                                 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1634                                 ins->opcode = OP_OUTARG_VT;
1635                                 ins->sreg1 = in->dreg;
1636                                 ins->klass = in->klass;
1637                                 ins->inst_p0 = call;
1638                                 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1639                                 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1640                                 MONO_ADD_INS (cfg->cbb, ins);
1641
1642                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1643                         } else {
1644                                 int dreg = mono_alloc_freg (cfg);
1645
1646                                 if (ainfo->size == 4) {
1647                                         MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1648                                 } else {
1649                                         MONO_INST_NEW (cfg, ins, OP_FMOVE);
1650                                         ins->dreg = dreg;
1651                                         ins->sreg1 = in->dreg;
1652                                         MONO_ADD_INS (cfg->cbb, ins);
1653                                 }
1654
1655                                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1656                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1657                         }
1658                 } else {
1659                         g_assert_not_reached ();
1660                 }
1661         }
1662
1663         /* Emit the signature cookie in the case that there is no
1664            additional argument */
1665         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1666                 emit_sig_cookie (cfg, call, cinfo);
1667
1668         if (cinfo->struct_ret) {
1669                 MonoInst *vtarg;
1670
1671                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1672                 vtarg->sreg1 = call->vret_var->dreg;
1673                 vtarg->dreg = mono_alloc_preg (cfg);
1674                 MONO_ADD_INS (cfg->cbb, vtarg);
1675
1676                 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1677         }
1678 #if 0
1679         /*
1680          * Reverse the call->out_args list.
1681          */
1682         {
1683                 MonoInst *prev = NULL, *list = call->out_args, *next;
1684                 while (list) {
1685                         next = list->next;
1686                         list->next = prev;
1687                         prev = list;
1688                         list = next;
1689                 }
1690                 call->out_args = prev;
1691         }
1692 #endif
1693         call->stack_usage = cinfo->stack_usage;
1694         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1695 #if _MIPS_SIM == _ABIO32
1696         /* a0-a3 always present */
1697         cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1698 #endif
1699         cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1700         cfg->flags |= MONO_CFG_HAS_CALLS;
1701         /* 
1702          * should set more info in call, such as the stack space
1703          * used by the args that needs to be added back to esp
1704          */
1705 }
1706
1707 void
1708 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1709 {
1710         MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1711         ArgInfo *ainfo = ins->inst_p1;
1712         int ovf_size = ainfo->vtsize;
1713         int doffset = ainfo->offset;
1714         int i, soffset, dreg;
1715
1716         if (ainfo->storage == ArgStructByVal) {
1717 #if 1
1718                 if (cfg->verbose_level > 0) {
1719                         char* nm = mono_method_full_name (cfg->method, TRUE);
1720                         g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n", 
1721                                  nm, doffset, ainfo->size, ovf_size);
1722                         g_free (nm);
1723                 }
1724 #endif
1725
1726                 soffset = 0;
1727                 for (i = 0; i < ainfo->size; ++i) {
1728                         dreg = mono_alloc_ireg (cfg);
1729                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1730                         mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1731                         soffset += SIZEOF_REGISTER;
1732                 }
1733                 if (ovf_size != 0) {
1734                         mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1735                 }
1736         } else if (ainfo->storage == ArgInFReg) {
1737                 int tmpr = mono_alloc_freg (cfg);
1738
1739                 if (ainfo->size == 4)
1740                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1741                 else
1742                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1743                 dreg = mono_alloc_freg (cfg);
1744                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1745                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1746         } else {
1747                 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1748                 MonoInst *load;
1749                 guint32 size;
1750
1751                 /* FIXME: alignment? */
1752                 if (call->signature->pinvoke) {
1753                         size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1754                         vtcopy->backend.is_pinvoke = 1;
1755                 } else {
1756                         size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1757                 }
1758                 if (size > 0)
1759                         g_assert (ovf_size > 0);
1760
1761                 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1762                 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1763
1764                 if (ainfo->offset)
1765                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1766                 else
1767                         mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1768         }
1769 }
1770
1771 void
1772 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1773 {
1774         MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1775                         mono_method_signature (method)->ret);
1776
1777         if (!ret->byref) {
1778 #if (SIZEOF_REGISTER == 4)
1779                 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1780                         MonoInst *ins;
1781
1782                         MONO_INST_NEW (cfg, ins, OP_SETLRET);
1783                         ins->sreg1 = val->dreg + 1;
1784                         ins->sreg2 = val->dreg + 2;
1785                         MONO_ADD_INS (cfg->cbb, ins);
1786                         return;
1787                 }
1788 #endif
1789                 if (ret->type == MONO_TYPE_R8) {
1790                         MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1791                         return;
1792                 }
1793                 if (ret->type == MONO_TYPE_R4) {
1794                         MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1795                         return;
1796                 }
1797         }
1798         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1799 }
1800
1801 void
1802 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1803 {
1804         MonoInst *ins, *n, *last_ins = NULL;
1805
1806         if (cfg->verbose_level > 2)
1807                 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1808
1809         ins = bb->code;
1810         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1811                 if (cfg->verbose_level > 2)
1812                         mono_print_ins_index (0, ins);
1813
1814                 switch (ins->opcode) {
1815 #if 0
1816                 case OP_LOAD_MEMBASE:
1817                 case OP_LOADI4_MEMBASE:
1818                         /*
1819                          * OP_IADD              reg2, reg1, const1
1820                          * OP_LOAD_MEMBASE      const2(reg2), reg3
1821                          * ->
1822                          * OP_LOAD_MEMBASE      (const1+const2)(reg1), reg3
1823                          */
1824                         if (last_ins && (last_ins->opcode == OP_IADD_IMM || last_ins->opcode == OP_ADD_IMM) && (last_ins->dreg == ins->inst_basereg) && (last_ins->sreg1 != last_ins->dreg)){
1825                                 int const1 = last_ins->inst_imm;
1826                                 int const2 = ins->inst_offset;
1827
1828                                 if (mips_is_imm16 (const1 + const2)) {
1829                                         ins->inst_basereg = last_ins->sreg1;
1830                                         ins->inst_offset = const1 + const2;
1831                                 }
1832                         }
1833                         break;
1834 #endif
1835
1836                 }
1837                 last_ins = ins;
1838                 ins = ins->next;
1839         }
1840         bb->last_ins = last_ins;
1841 }
1842
1843 void
1844 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1845 {
1846         MonoInst *ins, *n, *last_ins = NULL;
1847         ins = bb->code;
1848
1849         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1850                 MonoInst *last_ins = ins->prev;
1851
1852                 switch (ins->opcode) {
1853                 case OP_MUL_IMM: 
1854                         /* remove unnecessary multiplication with 1 */
1855                         if (ins->inst_imm == 1) {
1856                                 if (ins->dreg != ins->sreg1) {
1857                                         ins->opcode = OP_MOVE;
1858                                 } else {
1859                                         MONO_DELETE_INS (bb, ins);
1860                                         continue;
1861                                 }
1862                         } else {
1863                                 int power2 = mono_is_power_of_two (ins->inst_imm);
1864                                 if (power2 > 0) {
1865                                         ins->opcode = OP_SHL_IMM;
1866                                         ins->inst_imm = power2;
1867                                 }
1868                         }
1869                         break;
1870                 case OP_LOAD_MEMBASE:
1871                 case OP_LOADI4_MEMBASE:
1872                         /* 
1873                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1874                          * OP_LOAD_MEMBASE offset(basereg), reg
1875                          */
1876                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1877                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1878                             ins->inst_basereg == last_ins->inst_destbasereg &&
1879                             ins->inst_offset == last_ins->inst_offset) {
1880                                 if (ins->dreg == last_ins->sreg1) {
1881                                         MONO_DELETE_INS (bb, ins);
1882                                         continue;
1883                                 } else {
1884                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1885                                         ins->opcode = OP_MOVE;
1886                                         ins->sreg1 = last_ins->sreg1;
1887                                 }
1888                                 break;
1889                         }
1890                         /* 
1891                          * Note: reg1 must be different from the basereg in the second load
1892                          * OP_LOAD_MEMBASE offset(basereg), reg1
1893                          * OP_LOAD_MEMBASE offset(basereg), reg2
1894                          * -->
1895                          * OP_LOAD_MEMBASE offset(basereg), reg1
1896                          * OP_MOVE reg1, reg2
1897                          */
1898                         if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1899                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1900                               ins->inst_basereg != last_ins->dreg &&
1901                               ins->inst_basereg == last_ins->inst_basereg &&
1902                               ins->inst_offset == last_ins->inst_offset) {
1903
1904                                 if (ins->dreg == last_ins->dreg) {
1905                                         MONO_DELETE_INS (bb, ins);
1906                                         continue;
1907                                 } else {
1908                                         ins->opcode = OP_MOVE;
1909                                         ins->sreg1 = last_ins->dreg;
1910                                 }
1911
1912                                 //g_assert_not_reached ();
1913                                 break;
1914                         }
1915 #if 0
1916                         /* 
1917                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1918                          * OP_LOAD_MEMBASE offset(basereg), reg
1919                          * -->
1920                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1921                          * OP_ICONST reg, imm
1922                          */
1923                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1924                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1925                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1926                                    ins->inst_offset == last_ins->inst_offset) {
1927                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1928                                 ins->opcode = OP_ICONST;
1929                                 ins->inst_c0 = last_ins->inst_imm;
1930                                 g_assert_not_reached (); // check this rule
1931                                 break;
1932                         }
1933 #endif
1934                         break;
1935                 case OP_LOADU1_MEMBASE:
1936                 case OP_LOADI1_MEMBASE:
1937                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1938                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1939                                         ins->inst_offset == last_ins->inst_offset) {
1940                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1941                                 ins->sreg1 = last_ins->sreg1;                           
1942                         }
1943                         break;
1944                 case OP_LOADU2_MEMBASE:
1945                 case OP_LOADI2_MEMBASE:
1946                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1947                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1948                                         ins->inst_offset == last_ins->inst_offset) {
1949                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1950                                 ins->sreg1 = last_ins->sreg1;                           
1951                         }
1952                         break;
1953                 case OP_ICONV_TO_I4:
1954                 case OP_ICONV_TO_U4:
1955                 case OP_MOVE:
1956                         ins->opcode = OP_MOVE;
1957                         /* 
1958                          * OP_MOVE reg, reg 
1959                          */
1960                         if (ins->dreg == ins->sreg1) {
1961                                 MONO_DELETE_INS (bb, ins);
1962                                 continue;
1963                         }
1964                         /* 
1965                          * OP_MOVE sreg, dreg 
1966                          * OP_MOVE dreg, sreg
1967                          */
1968                         if (last_ins && last_ins->opcode == OP_MOVE &&
1969                             ins->sreg1 == last_ins->dreg &&
1970                             ins->dreg == last_ins->sreg1) {
1971                                 MONO_DELETE_INS (bb, ins);
1972                                 continue;
1973                         }
1974                         break;
1975                 }
1976                 last_ins = ins;
1977                 ins = ins->next;
1978         }
1979         bb->last_ins = last_ins;
1980 }
1981
1982 void
1983 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
1984 {
1985         int tmp1 = -1;
1986         int tmp2 = -1;
1987         int tmp3 = -1;
1988         int tmp4 = -1;
1989         int tmp5 = -1;
1990
1991         switch (ins->opcode) {
1992 #if 0
1993         case OP_LCOMPARE:
1994         case OP_LCOMPARE_IMM:
1995                 mono_print_ins (ins);
1996                 g_assert_not_reached ();
1997 #endif
1998         case OP_LADD:
1999                 tmp1 = mono_alloc_ireg (cfg);
2000                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2001                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2002                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2003                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2004                 NULLIFY_INS(ins);
2005                 break;
2006
2007         case OP_LADD_IMM:
2008                 tmp1 = mono_alloc_ireg (cfg);
2009                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2010                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2011                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2012                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2013                 NULLIFY_INS(ins);
2014                 break;
2015
2016         case OP_LSUB:
2017                 tmp1 = mono_alloc_ireg (cfg);
2018                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2019                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2020                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2021                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2022                 NULLIFY_INS(ins);
2023                 break;
2024
2025         case OP_LSUB_IMM:
2026                 tmp1 = mono_alloc_ireg (cfg);
2027                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2028                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2029                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2030                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2031                 NULLIFY_INS(ins);
2032                 break;
2033
2034         case OP_LMUL:
2035         case OP_LDIV:
2036         case OP_LDIV_UN:
2037         case OP_LREM:
2038         case OP_LREM_UN:
2039         case OP_LSHL:
2040         case OP_LSHR:
2041         case OP_LSHR_UN:
2042                 mono_print_ins (ins);
2043                 g_assert_not_reached ();
2044
2045         case OP_LNEG:
2046                 tmp1 = mono_alloc_ireg (cfg);
2047                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2048                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2049                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2050                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2051                 NULLIFY_INS(ins);
2052                 break;
2053
2054 #if 0
2055         case OP_LNOT:
2056 #endif
2057 #if 0
2058         case OP_LCONV_TO_I1:
2059         case OP_LCONV_TO_I2:
2060         case OP_LCONV_TO_I4:
2061         case OP_LCONV_TO_I8:
2062         case OP_LCONV_TO_R4:
2063         case OP_LCONV_TO_R8:
2064         case OP_LCONV_TO_U4:
2065         case OP_LCONV_TO_U8:
2066         case OP_LCONV_TO_U2:
2067         case OP_LCONV_TO_U1:
2068         case OP_LCONV_TO_I:
2069         case OP_LCONV_TO_OVF_I:
2070         case OP_LCONV_TO_OVF_U:
2071 #endif
2072                 mono_print_ins (ins);
2073                 g_assert_not_reached ();
2074
2075         case OP_LADD_OVF:
2076                 tmp1 = mono_alloc_ireg (cfg);
2077                 tmp2 = mono_alloc_ireg (cfg);
2078                 tmp3 = mono_alloc_ireg (cfg);
2079                 tmp4 = mono_alloc_ireg (cfg);
2080                 tmp5 = mono_alloc_ireg (cfg);
2081
2082                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2083
2084                 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2085                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2086
2087                 /* add the high 32-bits, and add in the carry from the low 32-bits */
2088                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2089                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2090
2091                 /* Overflow happens if
2092                  *      neg + neg = pos    or
2093                  *      pos + pos = neg
2094                  * XOR of the high bits returns 0 if the signs match
2095                  * XOR of that with the high bit of the result return 1 if overflow.
2096                  */
2097
2098                 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2099                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2100
2101                 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2102                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2103                 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2104
2105                 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2106                 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2107                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2108
2109                 /* Now, if (tmp4 == 0) then overflow */
2110                 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2111                 NULLIFY_INS(ins);
2112                 break;
2113
2114         case OP_LADD_OVF_UN:
2115                 tmp1 = mono_alloc_ireg (cfg);
2116                 tmp2 = mono_alloc_ireg (cfg);
2117
2118                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2119                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2120                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2121                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2122                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2123                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2124                 NULLIFY_INS(ins);
2125                 break;
2126
2127         case OP_LMUL_OVF:
2128         case OP_LMUL_OVF_UN:
2129                 mono_print_ins (ins);
2130                 g_assert_not_reached ();
2131
2132         case OP_LSUB_OVF:
2133                 tmp1 = mono_alloc_ireg (cfg);
2134                 tmp2 = mono_alloc_ireg (cfg);
2135                 tmp3 = mono_alloc_ireg (cfg);
2136                 tmp4 = mono_alloc_ireg (cfg);
2137                 tmp5 = mono_alloc_ireg (cfg);
2138
2139                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2140
2141                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2142                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2143                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2144
2145                 /* Overflow happens if
2146                  *      neg - pos = pos    or
2147                  *      pos - neg = neg
2148                  * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2149                  *
2150                  * tmp1 = (lhs ^ rhs)
2151                  * tmp2 = (lhs ^ result)
2152                  * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2153                  */
2154
2155                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2156                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2157                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2158                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2159
2160                 /* Now, if (tmp4 == 1) then overflow */
2161                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2162                 NULLIFY_INS(ins);
2163                 break;
2164
2165         case OP_LSUB_OVF_UN:
2166                 tmp1 = mono_alloc_ireg (cfg);
2167                 tmp2 = mono_alloc_ireg (cfg);
2168
2169                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2170                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2171                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2172                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2173
2174                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2175                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2176                 NULLIFY_INS(ins);
2177                 break;
2178 #if 0
2179         case OP_LCONV_TO_OVF_I1_UN:
2180         case OP_LCONV_TO_OVF_I2_UN:
2181         case OP_LCONV_TO_OVF_I4_UN:
2182         case OP_LCONV_TO_OVF_I8_UN:
2183         case OP_LCONV_TO_OVF_U1_UN:
2184         case OP_LCONV_TO_OVF_U2_UN:
2185         case OP_LCONV_TO_OVF_U4_UN:
2186         case OP_LCONV_TO_OVF_U8_UN:
2187         case OP_LCONV_TO_OVF_I_UN:
2188         case OP_LCONV_TO_OVF_U_UN:
2189         case OP_LCONV_TO_OVF_I1:
2190         case OP_LCONV_TO_OVF_U1:
2191         case OP_LCONV_TO_OVF_I2:
2192         case OP_LCONV_TO_OVF_U2:
2193         case OP_LCONV_TO_OVF_I4:
2194         case OP_LCONV_TO_OVF_U4:
2195         case OP_LCONV_TO_OVF_I8:
2196         case OP_LCONV_TO_OVF_U8:
2197 #endif
2198         case OP_LCEQ:
2199         case OP_LCGT:
2200         case OP_LCGT_UN:
2201         case OP_LCLT:
2202         case OP_LCLT_UN:
2203 #if 0
2204         case OP_LCONV_TO_R_UN:
2205         case OP_LCONV_TO_U:
2206 #endif
2207         case OP_LMUL_IMM:
2208         case OP_LSHL_IMM:
2209         case OP_LSHR_IMM:
2210         case OP_LSHR_UN_IMM:
2211         case OP_LDIV_IMM:
2212         case OP_LDIV_UN_IMM:
2213         case OP_LREM_IMM:
2214         case OP_LREM_UN_IMM:
2215         case OP_LBEQ:
2216         case OP_LBGE:
2217         case OP_LBGT:
2218         case OP_LBLE:
2219         case OP_LBLT:
2220         case OP_LBNE_UN:
2221         case OP_LBGE_UN:
2222         case OP_LBGT_UN:
2223         case OP_LBLE_UN:
2224         case OP_LBLT_UN:
2225                 mono_print_ins (ins);
2226                 g_assert_not_reached ();
2227 #if 0
2228         case OP_LCONV_TO_R8_2:
2229         case OP_LCONV_TO_R4_2:
2230         case OP_LCONV_TO_R_UN_2:
2231 #endif
2232         case OP_LCONV_TO_OVF_I4_2:
2233                 tmp1 = mono_alloc_ireg (cfg);
2234
2235                 /* Overflows if reg2 != sign extension of reg1 */
2236                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2237                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2238                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2239                 NULLIFY_INS(ins);
2240                 break;
2241
2242         case OP_LMIN_UN:
2243         case OP_LMAX_UN:
2244         case OP_LMIN:
2245         case OP_LMAX:
2246                 mono_print_ins (ins);
2247                 g_assert_not_reached ();
2248
2249         default:
2250                 break;
2251         }
2252 }
2253
2254 void
2255 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2256 {
2257         int tmp1 = -1;
2258         int tmp2 = -1;
2259         int tmp3 = -1;
2260         int tmp4 = -1;
2261         int tmp5 = -1;
2262
2263         switch (ins->opcode) {
2264         case OP_IADD_OVF:
2265                 tmp1 = mono_alloc_ireg (cfg);
2266                 tmp2 = mono_alloc_ireg (cfg);
2267                 tmp3 = mono_alloc_ireg (cfg);
2268                 tmp4 = mono_alloc_ireg (cfg);
2269                 tmp5 = mono_alloc_ireg (cfg);
2270
2271                 /* add the operands */
2272
2273                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2274
2275                 /* Overflow happens if
2276                  *      neg + neg = pos    or
2277                  *      pos + pos = neg
2278                  *
2279                  * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2280                  * XOR of the high bit returns 0 if the signs match
2281                  * XOR of that with the high bit of the result return 1 if overflow.
2282                  */
2283
2284                 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2285                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2286
2287                 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2288                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2289                 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2290
2291                 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2292                 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2293
2294                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2295
2296                 /* Now, if (tmp5 == 0) then overflow */
2297                 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2298                 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2299                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2300                 NULLIFY_INS(ins);
2301                 break;
2302
2303         case OP_IADD_OVF_UN:
2304                 tmp1 = mono_alloc_ireg (cfg);
2305
2306                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2307                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2308                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2309                 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2310                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2311                 NULLIFY_INS(ins);
2312                 break;
2313
2314         case OP_ISUB_OVF:
2315                 tmp1 = mono_alloc_ireg (cfg);
2316                 tmp2 = mono_alloc_ireg (cfg);
2317                 tmp3 = mono_alloc_ireg (cfg);
2318                 tmp4 = mono_alloc_ireg (cfg);
2319                 tmp5 = mono_alloc_ireg (cfg);
2320
2321                 /* add the operands */
2322
2323                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2324
2325                 /* Overflow happens if
2326                  *      neg - pos = pos    or
2327                  *      pos - neg = neg
2328                  * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2329                  *
2330                  * tmp1 = (lhs ^ rhs)
2331                  * tmp2 = (lhs ^ result)
2332                  * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2333                  */
2334
2335                 /* tmp3 = 1 if the signs of the two inputs differ */
2336                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2337                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2338                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2339                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2340                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2341
2342                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2343                 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2344                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2345                 NULLIFY_INS(ins);
2346                 break;
2347
2348         case OP_ISUB_OVF_UN:
2349                 tmp1 = mono_alloc_ireg (cfg);
2350
2351                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2352                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2353                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2354                 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2355                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2356                 NULLIFY_INS(ins);
2357                 break;
2358         }
2359 }
2360
2361 static int
2362 map_to_reg_reg_op (int op)
2363 {
2364         switch (op) {
2365         case OP_ADD_IMM:
2366                 return OP_IADD;
2367         case OP_SUB_IMM:
2368                 return OP_ISUB;
2369         case OP_AND_IMM:
2370                 return OP_IAND;
2371         case OP_COMPARE_IMM:
2372                 return OP_COMPARE;
2373         case OP_ICOMPARE_IMM:
2374                 return OP_ICOMPARE;
2375         case OP_LCOMPARE_IMM:
2376                 return OP_LCOMPARE;
2377         case OP_ADDCC_IMM:
2378                 return OP_IADDCC;
2379         case OP_ADC_IMM:
2380                 return OP_IADC;
2381         case OP_SUBCC_IMM:
2382                 return OP_ISUBCC;
2383         case OP_SBB_IMM:
2384                 return OP_ISBB;
2385         case OP_OR_IMM:
2386                 return OP_IOR;
2387         case OP_XOR_IMM:
2388                 return OP_IXOR;
2389         case OP_MUL_IMM:
2390                 return OP_IMUL;
2391         case OP_LOAD_MEMBASE:
2392                 return OP_LOAD_MEMINDEX;
2393         case OP_LOADI4_MEMBASE:
2394                 return OP_LOADI4_MEMINDEX;
2395         case OP_LOADU4_MEMBASE:
2396                 return OP_LOADU4_MEMINDEX;
2397         case OP_LOADU1_MEMBASE:
2398                 return OP_LOADU1_MEMINDEX;
2399         case OP_LOADI2_MEMBASE:
2400                 return OP_LOADI2_MEMINDEX;
2401         case OP_LOADU2_MEMBASE:
2402                 return OP_LOADU2_MEMINDEX;
2403         case OP_LOADI1_MEMBASE:
2404                 return OP_LOADI1_MEMINDEX;
2405         case OP_LOADR4_MEMBASE:
2406                 return OP_LOADR4_MEMINDEX;
2407         case OP_LOADR8_MEMBASE:
2408                 return OP_LOADR8_MEMINDEX;
2409         case OP_STOREI1_MEMBASE_REG:
2410                 return OP_STOREI1_MEMINDEX;
2411         case OP_STOREI2_MEMBASE_REG:
2412                 return OP_STOREI2_MEMINDEX;
2413         case OP_STOREI4_MEMBASE_REG:
2414                 return OP_STOREI4_MEMINDEX;
2415         case OP_STORE_MEMBASE_REG:
2416                 return OP_STORE_MEMINDEX;
2417         case OP_STORER4_MEMBASE_REG:
2418                 return OP_STORER4_MEMINDEX;
2419         case OP_STORER8_MEMBASE_REG:
2420                 return OP_STORER8_MEMINDEX;
2421         case OP_STORE_MEMBASE_IMM:
2422                 return OP_STORE_MEMBASE_REG;
2423         case OP_STOREI1_MEMBASE_IMM:
2424                 return OP_STOREI1_MEMBASE_REG;
2425         case OP_STOREI2_MEMBASE_IMM:
2426                 return OP_STOREI2_MEMBASE_REG;
2427         case OP_STOREI4_MEMBASE_IMM:
2428                 return OP_STOREI4_MEMBASE_REG;
2429         case OP_STOREI8_MEMBASE_IMM:
2430                 return OP_STOREI8_MEMBASE_REG;
2431         }
2432         return mono_op_imm_to_op (op);
2433 }
2434
2435 static int
2436 map_to_mips_op (int op)
2437 {
2438         switch (op) {
2439         case OP_FBEQ:
2440                 return OP_MIPS_FBEQ;
2441         case OP_FBGE:
2442                 return OP_MIPS_FBGE;
2443         case OP_FBGT:
2444                 return OP_MIPS_FBGT;
2445         case OP_FBLE:
2446                 return OP_MIPS_FBLE;
2447         case OP_FBLT:
2448                 return OP_MIPS_FBLT;
2449         case OP_FBNE_UN:
2450                 return OP_MIPS_FBNE;
2451         case OP_FBGE_UN:
2452                 return OP_MIPS_FBGE_UN;
2453         case OP_FBGT_UN:
2454                 return OP_MIPS_FBGT_UN;
2455         case OP_FBLE_UN:
2456                 return OP_MIPS_FBLE_UN;
2457         case OP_FBLT_UN:
2458                 return OP_MIPS_FBLT_UN;
2459
2460         case OP_FCEQ:
2461         case OP_FCGT:
2462         case OP_FCGT_UN:
2463         case OP_FCLT:
2464         case OP_FCLT_UN:
2465         default:
2466                 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2467                 g_assert_not_reached ();
2468         }
2469 }
2470
2471 #define NEW_INS(cfg,after,dest,op) do {                                 \
2472                 MONO_INST_NEW((cfg), (dest), (op));                     \
2473                 mono_bblock_insert_after_ins (bb, (after), (dest));     \
2474         } while (0)
2475
2476 #define INS(pos,op,_dreg,_sreg1,_sreg2) do {            \
2477                 MonoInst *temp;                                         \
2478                 MONO_INST_NEW(cfg, temp, (op));                         \
2479                 mono_bblock_insert_after_ins (bb, (pos), temp);         \
2480                 temp->dreg = (_dreg);                                   \
2481                 temp->sreg1 = (_sreg1);                                 \
2482                 temp->sreg2 = (_sreg2);                                 \
2483                 pos = temp;                                             \
2484         } while (0)
2485
2486 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do {          \
2487                 MonoInst *temp;                                         \
2488                 MONO_INST_NEW(cfg, temp, (op));                         \
2489                 mono_bblock_insert_after_ins (bb, (pos), temp);         \
2490                 temp->dreg = (_dreg);                                   \
2491                 temp->sreg1 = (_sreg1);                                 \
2492                 temp->inst_c0 = (_imm);                                 \
2493                 pos = temp;                                             \
2494         } while (0)
2495
2496 /*
2497  * Remove from the instruction list the instructions that can't be
2498  * represented with very simple instructions with no register
2499  * requirements.
2500  */
2501 void
2502 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2503 {
2504         MonoInst *ins, *next, *temp, *last_ins = NULL;
2505         int imm;
2506
2507 #if 1
2508         if (cfg->verbose_level > 2) {
2509                 int idx = 0;
2510
2511                 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2512                 MONO_BB_FOR_EACH_INS (bb, ins) {
2513                         mono_print_ins_index (idx++, ins);
2514                 }
2515                 
2516         }
2517 #endif
2518
2519         MONO_BB_FOR_EACH_INS (bb, ins) {
2520 loop_start:
2521                 switch (ins->opcode) {
2522                 case OP_COMPARE:
2523                 case OP_ICOMPARE:
2524                 case OP_LCOMPARE:
2525                         next = ins->next;
2526                         /* Branch opts can eliminate the branch */
2527                         if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2528                                 NULLIFY_INS(ins);
2529                                 break;
2530                         }
2531                         break;
2532
2533                 case OP_COMPARE_IMM:
2534                 case OP_ICOMPARE_IMM:
2535                 case OP_LCOMPARE_IMM:
2536                         next = ins->next;
2537                         /* Branch opts can eliminate the branch */
2538                         if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2539                                 NULLIFY_INS(ins);
2540                                 break;
2541                         }
2542                         if (ins->inst_imm) {
2543                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2544                                 temp->inst_c0 = ins->inst_imm;
2545                                 temp->dreg = mono_alloc_ireg (cfg);
2546                                 ins->sreg2 = temp->dreg;
2547                                 last_ins = temp;
2548                         }
2549                         else {
2550                                 ins->sreg2 = mips_zero;
2551                         }
2552                         if (ins->opcode == OP_COMPARE_IMM)
2553                                 ins->opcode = OP_COMPARE;
2554                         else if (ins->opcode == OP_ICOMPARE_IMM)
2555                                 ins->opcode = OP_ICOMPARE;
2556                         else if (ins->opcode == OP_LCOMPARE_IMM)
2557                                 ins->opcode = OP_LCOMPARE;
2558                         goto loop_start;
2559
2560                 case OP_IDIV_UN_IMM:
2561                 case OP_IDIV_IMM:
2562                 case OP_IREM_IMM:
2563                 case OP_IREM_UN_IMM:
2564                         NEW_INS (cfg, last_ins, temp, OP_ICONST);
2565                         temp->inst_c0 = ins->inst_imm;
2566                         temp->dreg = mono_alloc_ireg (cfg);
2567                         ins->sreg2 = temp->dreg;
2568                         if (ins->opcode == OP_IDIV_IMM)
2569                                 ins->opcode = OP_IDIV;
2570                         else if (ins->opcode == OP_IREM_IMM)
2571                                 ins->opcode = OP_IREM;
2572                         else if (ins->opcode == OP_IDIV_UN_IMM)
2573                                 ins->opcode = OP_IDIV_UN;
2574                         else if (ins->opcode == OP_IREM_UN_IMM)
2575                                 ins->opcode = OP_IREM_UN;
2576                         last_ins = temp;
2577                         /* handle rem separately */
2578                         goto loop_start;
2579
2580 #if 0
2581                 case OP_AND_IMM:
2582                 case OP_OR_IMM:
2583                 case OP_XOR_IMM:
2584                         if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2585                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2586                                 temp->inst_c0 = ins->inst_imm;
2587                                 temp->dreg = mono_alloc_ireg (cfg);
2588                                 ins->sreg2 = temp->dreg;
2589                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2590                         }
2591                         break;
2592 #endif
2593                 case OP_AND_IMM:
2594                 case OP_IAND_IMM:
2595                 case OP_OR_IMM:
2596                 case OP_IOR_IMM:
2597                 case OP_XOR_IMM:
2598                 case OP_IXOR_IMM:
2599                         /* unsigned 16 bit immediate */
2600                         if (ins->inst_imm & 0xffff0000) {
2601                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2602                                 temp->inst_c0 = ins->inst_imm;
2603                                 temp->dreg = mono_alloc_ireg (cfg);
2604                                 ins->sreg2 = temp->dreg;
2605                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2606                         }
2607                         break;
2608
2609                 case OP_IADD_IMM:
2610                 case OP_ADD_IMM:
2611                 case OP_ADDCC_IMM:
2612                         /* signed 16 bit immediate */
2613                         if (!mips_is_imm16 (ins->inst_imm)) {
2614                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2615                                 temp->inst_c0 = ins->inst_imm;
2616                                 temp->dreg = mono_alloc_ireg (cfg);
2617                                 ins->sreg2 = temp->dreg;
2618                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2619                         }
2620                         break;
2621
2622                 case OP_SUB_IMM:
2623                 case OP_ISUB_IMM:
2624                         if (!mips_is_imm16 (-ins->inst_imm)) {
2625                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2626                                 temp->inst_c0 = ins->inst_imm;
2627                                 temp->dreg = mono_alloc_ireg (cfg);
2628                                 ins->sreg2 = temp->dreg;
2629                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2630                         }
2631                         break;
2632
2633                 case OP_MUL_IMM:
2634                 case OP_IMUL_IMM:
2635                         if (ins->inst_imm == 1) {
2636                                 ins->opcode = OP_MOVE;
2637                                 break;
2638                         }
2639                         if (ins->inst_imm == 0) {
2640                                 ins->opcode = OP_ICONST;
2641                                 ins->inst_c0 = 0;
2642                                 break;
2643                         }
2644                         imm = mono_is_power_of_two (ins->inst_imm);
2645                         if (imm > 0) {
2646                                 ins->opcode = OP_SHL_IMM;
2647                                 ins->inst_imm = imm;
2648                                 break;
2649                         }
2650                         NEW_INS (cfg, last_ins, temp, OP_ICONST);
2651                         temp->inst_c0 = ins->inst_imm;
2652                         temp->dreg = mono_alloc_ireg (cfg);
2653                         ins->sreg2 = temp->dreg;
2654                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2655                         break;
2656
2657                 case OP_LOCALLOC_IMM:
2658                         NEW_INS (cfg, last_ins, temp, OP_ICONST);
2659                         temp->inst_c0 = ins->inst_imm;
2660                         temp->dreg = mono_alloc_ireg (cfg);
2661                         ins->sreg1 = temp->dreg;
2662                         ins->opcode = OP_LOCALLOC;
2663                         break;
2664
2665                 case OP_LOADR4_MEMBASE:
2666                 case OP_STORER4_MEMBASE_REG:
2667                         /* we can do two things: load the immed in a register
2668                          * and use an indexed load, or see if the immed can be
2669                          * represented as an ad_imm + a load with a smaller offset
2670                          * that fits. We just do the first for now, optimize later.
2671                          */
2672                         if (mips_is_imm16 (ins->inst_offset))
2673                                 break;
2674                         NEW_INS (cfg, last_ins, temp, OP_ICONST);
2675                         temp->inst_c0 = ins->inst_offset;
2676                         temp->dreg = mono_alloc_ireg (cfg);
2677                         ins->sreg2 = temp->dreg;
2678                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2679                         break;
2680
2681                 case OP_STORE_MEMBASE_IMM:
2682                 case OP_STOREI1_MEMBASE_IMM:
2683                 case OP_STOREI2_MEMBASE_IMM:
2684                 case OP_STOREI4_MEMBASE_IMM:
2685                 case OP_STOREI8_MEMBASE_IMM:
2686                         if (!ins->inst_imm) {
2687                                 ins->sreg1 = mips_zero;
2688                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2689                         }
2690                         else {
2691                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2692                                 temp->inst_c0 = ins->inst_imm;
2693                                 temp->dreg = mono_alloc_ireg (cfg);
2694                                 ins->sreg1 = temp->dreg;
2695                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2696                                 last_ins = temp;
2697                                 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2698                         }
2699                         break;
2700
2701                 case OP_FCOMPARE:
2702                         next = ins->next;
2703                         /* Branch opts can eliminate the branch */
2704                         if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2705                                 NULLIFY_INS(ins);
2706                                 break;
2707                         }
2708                         g_assert(next);
2709
2710                         /*
2711                          * remap compare/branch and compare/set
2712                          * to MIPS specific opcodes.
2713                          */
2714                         next->opcode = map_to_mips_op (next->opcode);
2715                         next->sreg1 = ins->sreg1;
2716                         next->sreg2 = ins->sreg2;
2717                         NULLIFY_INS(ins);
2718                         break;
2719
2720 #if 0
2721                 case OP_R8CONST:
2722                 case OP_R4CONST:
2723                         NEW_INS (cfg, last_ins, temp, OP_ICONST);
2724                         temp->inst_c0 = (guint32)ins->inst_p0;
2725                         temp->dreg = mono_alloc_ireg (cfg);
2726                         ins->inst_basereg = temp->dreg;
2727                         ins->inst_offset = 0;
2728                         ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2729                         last_ins = temp;
2730                         /* make it handle the possibly big ins->inst_offset
2731                          * later optimize to use lis + load_membase
2732                          */
2733                         goto loop_start;
2734 #endif
2735                 case OP_IBEQ:
2736                         g_assert (ins_is_compare(last_ins));
2737                         INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2738                         NULLIFY_INS(last_ins);
2739                         break;
2740
2741                 case OP_IBNE_UN:
2742                         g_assert (ins_is_compare(last_ins));
2743                         INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2744                         NULLIFY_INS(last_ins);
2745                         break;
2746
2747                 case OP_IBGE:
2748                         g_assert (ins_is_compare(last_ins));
2749                         INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2750                         last_ins->dreg = mono_alloc_ireg (cfg);
2751                         INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2752                         break;
2753
2754                 case OP_IBGE_UN:
2755                         g_assert (ins_is_compare(last_ins));
2756                         INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2757                         last_ins->dreg = mono_alloc_ireg (cfg);
2758                         INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2759                         break;
2760
2761                 case OP_IBLT:
2762                         g_assert (ins_is_compare(last_ins));
2763                         INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2764                         last_ins->dreg = mono_alloc_ireg (cfg);
2765                         INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2766                         break;
2767
2768                 case OP_IBLT_UN:
2769                         g_assert (ins_is_compare(last_ins));
2770                         INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2771                         last_ins->dreg = mono_alloc_ireg (cfg);
2772                         INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2773                         break;
2774
2775                 case OP_IBLE:
2776                         g_assert (ins_is_compare(last_ins));
2777                         INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2778                         last_ins->dreg = mono_alloc_ireg (cfg);
2779                         INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2780                         break;
2781
2782                 case OP_IBLE_UN:
2783                         g_assert (ins_is_compare(last_ins));
2784                         INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2785                         last_ins->dreg = mono_alloc_ireg (cfg);
2786                         INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2787                         break;
2788
2789                 case OP_IBGT:
2790                         g_assert (ins_is_compare(last_ins));
2791                         INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2792                         last_ins->dreg = mono_alloc_ireg (cfg);
2793                         INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2794                         break;
2795
2796                 case OP_IBGT_UN:
2797                         g_assert (ins_is_compare(last_ins));
2798                         INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2799                         last_ins->dreg = mono_alloc_ireg (cfg);
2800                         INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2801                         break;
2802
2803                 case OP_CEQ:
2804                 case OP_ICEQ:
2805                         g_assert (ins_is_compare(last_ins));
2806                         last_ins->opcode = OP_IXOR;
2807                         last_ins->dreg = mono_alloc_ireg(cfg);
2808                         INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2809                         break;
2810
2811                 case OP_CLT:
2812                 case OP_ICLT:
2813                         INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2814                         NULLIFY_INS(last_ins);
2815                         break;
2816
2817
2818                 case OP_CLT_UN:
2819                 case OP_ICLT_UN:
2820                         INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2821                         NULLIFY_INS(last_ins);
2822                         break;
2823
2824                 case OP_CGT:
2825                 case OP_ICGT:
2826                         g_assert (ins_is_compare(last_ins));
2827                         INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2828                         MONO_DELETE_INS(bb, last_ins);
2829                         break;
2830
2831                 case OP_CGT_UN:
2832                 case OP_ICGT_UN:
2833                         g_assert (ins_is_compare(last_ins));
2834                         INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2835                         MONO_DELETE_INS(bb, last_ins);
2836                         break;
2837
2838                 case OP_COND_EXC_EQ:
2839                 case OP_COND_EXC_IEQ:
2840                         g_assert (ins_is_compare(last_ins));
2841                         INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2842                         MONO_DELETE_INS(bb, last_ins);
2843                         break;
2844
2845                 case OP_COND_EXC_GE:
2846                 case OP_COND_EXC_IGE:
2847                         g_assert (ins_is_compare(last_ins));
2848                         INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2849                         MONO_DELETE_INS(bb, last_ins);
2850                         break;
2851
2852                 case OP_COND_EXC_GT:
2853                 case OP_COND_EXC_IGT:
2854                         g_assert (ins_is_compare(last_ins));
2855                         INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2856                         MONO_DELETE_INS(bb, last_ins);
2857                         break;
2858
2859                 case OP_COND_EXC_LE:
2860                 case OP_COND_EXC_ILE:
2861                         g_assert (ins_is_compare(last_ins));
2862                         INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2863                         MONO_DELETE_INS(bb, last_ins);
2864                         break;
2865
2866                 case OP_COND_EXC_LT:
2867                 case OP_COND_EXC_ILT:
2868                         g_assert (ins_is_compare(last_ins));
2869                         INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2870                         MONO_DELETE_INS(bb, last_ins);
2871                         break;
2872
2873                 case OP_COND_EXC_NE_UN:
2874                 case OP_COND_EXC_INE_UN:
2875                         g_assert (ins_is_compare(last_ins));
2876                         INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2877                         MONO_DELETE_INS(bb, last_ins);
2878                         break;
2879
2880                 case OP_COND_EXC_GE_UN:
2881                 case OP_COND_EXC_IGE_UN:
2882                         g_assert (ins_is_compare(last_ins));
2883                         INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2884                         MONO_DELETE_INS(bb, last_ins);
2885                         break;
2886
2887                 case OP_COND_EXC_GT_UN:
2888                 case OP_COND_EXC_IGT_UN:
2889                         g_assert (ins_is_compare(last_ins));
2890                         INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2891                         MONO_DELETE_INS(bb, last_ins);
2892                         break;
2893
2894                 case OP_COND_EXC_LE_UN:
2895                 case OP_COND_EXC_ILE_UN:
2896                         g_assert (ins_is_compare(last_ins));
2897                         INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2898                         MONO_DELETE_INS(bb, last_ins);
2899                         break;
2900
2901                 case OP_COND_EXC_LT_UN:
2902                 case OP_COND_EXC_ILT_UN:
2903                         g_assert (ins_is_compare(last_ins));
2904                         INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2905                         MONO_DELETE_INS(bb, last_ins);
2906                         break;
2907
2908                 case OP_COND_EXC_OV:
2909                 case OP_COND_EXC_IOV: {
2910                         int tmp1, tmp2, tmp3, tmp4, tmp5;
2911                         MonoInst *pos = last_ins;
2912
2913                         /* Overflow happens if
2914                          *      neg + neg = pos    or
2915                          *      pos + pos = neg
2916                          *
2917                          * (bit31s of operands match) AND (bit31 of operand
2918                          * != bit31 of result)
2919                          * XOR of the high bit returns 0 if the signs match
2920                          * XOR of that with the high bit of the result return 1
2921                          * if overflow.
2922                          */
2923                         g_assert (last_ins->opcode == OP_IADC);
2924
2925                         tmp1 = mono_alloc_ireg (cfg);
2926                         tmp2 = mono_alloc_ireg (cfg);
2927                         tmp3 = mono_alloc_ireg (cfg);
2928                         tmp4 = mono_alloc_ireg (cfg);
2929                         tmp5 = mono_alloc_ireg (cfg);
2930
2931                         /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2932                         INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2933
2934                         /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2935                         INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2936                         INS (pos, OP_INOT, tmp3, tmp2, -1);
2937
2938                         /* OR(tmp1, tmp2) = 0 if both conditions are true */
2939                         INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2940                         INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2941
2942                         /* Now, if (tmp5 == 0) then overflow */
2943                         INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2944                         ins->dreg = -1;
2945                         break;
2946                         }
2947
2948                 case OP_COND_EXC_NO:
2949                 case OP_COND_EXC_INO:
2950                         g_assert_not_reached ();
2951                         break;
2952
2953                 case OP_COND_EXC_C:
2954                 case OP_COND_EXC_IC:
2955                         g_assert_not_reached ();
2956                         break;
2957
2958                 case OP_COND_EXC_NC:
2959                 case OP_COND_EXC_INC:
2960                         g_assert_not_reached ();
2961                         break;
2962
2963                 }
2964                 last_ins = ins;
2965         }
2966         bb->last_ins = last_ins;
2967         bb->max_vreg = cfg->next_vreg;
2968
2969 #if 1
2970         if (cfg->verbose_level > 2) {
2971                 int idx = 0;
2972
2973                 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
2974                 MONO_BB_FOR_EACH_INS (bb, ins) {
2975                         mono_print_ins_index (idx++, ins);
2976                 }
2977                 
2978         }
2979 #endif
2980
2981 }
2982
2983 static guchar*
2984 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2985 {
2986         /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2987 #if 1
2988         mips_truncwd (code, mips_ftemp, sreg);
2989 #else
2990         mips_cvtwd (code, mips_ftemp, sreg);
2991 #endif
2992         mips_mfc1 (code, dreg, mips_ftemp);
2993         if (!is_signed) {
2994                 if (size == 1)
2995                         mips_andi (code, dreg, dreg, 0xff);
2996                 else if (size == 2) {
2997                         mips_sll (code, dreg, dreg, 16);
2998                         mips_srl (code, dreg, dreg, 16);
2999                 }
3000         } else {
3001                 if (size == 1) {
3002                         mips_sll (code, dreg, dreg, 24);
3003                         mips_sra (code, dreg, dreg, 24);
3004                 }
3005                 else if (size == 2) {
3006                         mips_sll (code, dreg, dreg, 16);
3007                         mips_sra (code, dreg, dreg, 16);
3008                 }
3009         }
3010         return code;
3011 }
3012
3013 /*
3014  * emit_load_volatile_arguments:
3015  *
3016  * Load volatile arguments from the stack to the original input registers.
3017  * Required before a tail call.
3018  */
3019 static guint8 *
3020 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3021 {
3022         MonoMethod *method = cfg->method;
3023         MonoMethodSignature *sig;
3024         MonoInst *inst;
3025         CallInfo *cinfo;
3026         int i;
3027
3028         sig = mono_method_signature (method);
3029
3030         if (!cfg->arch.cinfo)
3031                 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
3032         cinfo = cfg->arch.cinfo;
3033
3034         if (cinfo->struct_ret) {
3035                 ArgInfo *ainfo = &cinfo->ret;
3036                 inst = cfg->vret_addr;
3037                 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3038         }
3039
3040         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3041                 ArgInfo *ainfo = cinfo->args + i;
3042                 inst = cfg->args [i];
3043                 if (inst->opcode == OP_REGVAR) {
3044                         if (ainfo->storage == ArgInIReg)
3045                                 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3046                         else if (ainfo->storage == ArgInFReg)
3047                                 g_assert_not_reached();
3048                         else if (ainfo->storage == ArgOnStack) {
3049                                 /* do nothing */
3050                         } else
3051                                 g_assert_not_reached ();
3052                 } else {
3053                         if (ainfo->storage == ArgInIReg) {
3054                                 g_assert (mips_is_imm16 (inst->inst_offset));
3055                                 switch (ainfo->size) {
3056                                 case 1:
3057                                         mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3058                                         break;
3059                                 case 2:
3060                                         mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3061                                         break;
3062                                 case 0: /* XXX */
3063                                 case 4:
3064                                         mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3065                                         break;
3066                                 case 8:
3067                                         mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3068                                         mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3069                                         break;
3070                                 default:
3071                                         g_assert_not_reached ();
3072                                         break;
3073                                 }
3074                         } else if (ainfo->storage == ArgOnStack) {
3075                                 /* do nothing */
3076                         } else if (ainfo->storage == ArgInFReg) {
3077                                 g_assert (mips_is_imm16 (inst->inst_offset));
3078                                 if (ainfo->size == 8) {
3079 #if _MIPS_SIM == _ABIO32
3080                                         mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3081                                         mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3082 #elif _MIPS_SIM == _ABIN32
3083                                         mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3084 #endif
3085                                 }
3086                                 else if (ainfo->size == 4)
3087                                         mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3088                                 else
3089                                         g_assert_not_reached ();
3090                         } else if (ainfo->storage == ArgStructByVal) {
3091                                 int i;
3092                                 int doffset = inst->inst_offset;
3093
3094                                 g_assert (mips_is_imm16 (inst->inst_offset));
3095                                 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3096                                 for (i = 0; i < ainfo->size; ++i) {
3097                                         mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3098                                         doffset += SIZEOF_REGISTER;
3099                                 }
3100                         } else if (ainfo->storage == ArgStructByAddr) {
3101                                 g_assert (mips_is_imm16 (inst->inst_offset));
3102                                 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3103                         } else
3104                                 g_assert_not_reached ();
3105                 }
3106         }
3107
3108         return code;
3109 }
3110
3111 static guint8*
3112 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3113 {
3114         int size = cfg->param_area;
3115
3116         size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3117         size &= -MONO_ARCH_FRAME_ALIGNMENT;
3118
3119         if (!size)
3120                 return code;
3121 #if 0
3122         ppc_lwz (code, ppc_r0, 0, ppc_sp);
3123         if (ppc_is_imm16 (-size)) {
3124                 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3125         } else {
3126                 ppc_load (code, ppc_r11, -size);
3127                 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3128         }
3129 #endif
3130         return code;
3131 }
3132
3133 static guint8*
3134 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3135 {
3136         int size = cfg->param_area;
3137
3138         size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3139         size &= -MONO_ARCH_FRAME_ALIGNMENT;
3140
3141         if (!size)
3142                 return code;
3143 #if 0
3144         ppc_lwz (code, ppc_r0, 0, ppc_sp);
3145         if (ppc_is_imm16 (size)) {
3146                 ppc_stwu (code, ppc_r0, size, ppc_sp);
3147         } else {
3148                 ppc_load (code, ppc_r11, size);
3149                 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3150         }
3151 #endif
3152         return code;
3153 }
3154
3155 void
3156 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3157 {
3158         MonoInst *ins;
3159         MonoCallInst *call;
3160         guint offset;
3161         guint8 *code = cfg->native_code + cfg->code_len;
3162         MonoInst *last_ins = NULL;
3163         guint last_offset = 0;
3164         int max_len, cpos;
3165         int ins_cnt = 0;
3166
3167         /* we don't align basic blocks of loops on mips */
3168
3169         if (cfg->verbose_level > 2)
3170                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3171
3172         cpos = bb->max_offset;
3173
3174 #if 0
3175         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3176                 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3177                 g_assert (!mono_compile_aot);
3178                 cpos += 20;
3179                 if (bb->cil_code)
3180                         cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3181                 /* this is not thread save, but good enough */
3182                 /* fixme: howto handle overflows? */
3183                 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3184                 mips_lw (code, mips_temp, mips_at, 0);
3185                 mips_addiu (code, mips_temp, mips_temp, 1);
3186                 mips_sw (code, mips_temp, mips_at, 0);
3187         }
3188 #endif
3189         MONO_BB_FOR_EACH_INS (bb, ins) {
3190                 offset = code - cfg->native_code;
3191
3192                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3193
3194                 if (offset > (cfg->code_size - max_len - 16)) {
3195                         cfg->code_size *= 2;
3196                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3197                         code = cfg->native_code + offset;
3198                 }
3199                 mono_debug_record_line_number (cfg, ins, offset);
3200                 if (cfg->verbose_level > 2) {
3201                         g_print ("    @ 0x%x\t", offset);
3202                         mono_print_ins_index (ins_cnt++, ins);
3203                 }
3204                 /* Check for virtual regs that snuck by */
3205                 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3206
3207                 switch (ins->opcode) {
3208                 case OP_RELAXED_NOP:
3209                 case OP_NOP:
3210                 case OP_DUMMY_USE:
3211                 case OP_DUMMY_STORE:
3212                 case OP_NOT_REACHED:
3213                 case OP_NOT_NULL:
3214                         break;
3215                 case OP_SEQ_POINT: {
3216                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3217                                 guint32 addr = (guint32)ss_trigger_page;
3218
3219                                 mips_load_const (code, mips_t9, addr);
3220                                 mips_lw (code, mips_t9, mips_t9, 0);
3221                         }
3222
3223                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3224
3225                         /*
3226                          * A placeholder for a possible breakpoint inserted by
3227                          * mono_arch_set_breakpoint ().
3228                          */
3229                         /* mips_load_const () + mips_lw */
3230                         mips_nop (code);
3231                         mips_nop (code);
3232                         mips_nop (code);
3233                         break;
3234                 }
3235                 case OP_TLS_GET:
3236                         g_assert_not_reached();
3237 #if 0
3238                         emit_tls_access (code, ins->dreg, ins->inst_offset);
3239 #endif
3240                         break;
3241                 case OP_BIGMUL:
3242                         mips_mult (code, ins->sreg1, ins->sreg2);
3243                         mips_mflo (code, ins->dreg);
3244                         mips_mfhi (code, ins->dreg+1);
3245                         break;
3246                 case OP_BIGMUL_UN:
3247                         mips_multu (code, ins->sreg1, ins->sreg2);
3248                         mips_mflo (code, ins->dreg);
3249                         mips_mfhi (code, ins->dreg+1);
3250                         break;
3251                 case OP_MEMORY_BARRIER:
3252 #if 0
3253                         ppc_sync (code);
3254 #endif
3255                         break;
3256                 case OP_STOREI1_MEMBASE_IMM:
3257                         mips_load_const (code, mips_temp, ins->inst_imm);
3258                         if (mips_is_imm16 (ins->inst_offset)) {
3259                                 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3260                         } else {
3261                                 mips_load_const (code, mips_at, ins->inst_offset);
3262                                 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3263                         }
3264                         break;
3265                 case OP_STOREI2_MEMBASE_IMM:
3266                         mips_load_const (code, mips_temp, ins->inst_imm);
3267                         if (mips_is_imm16 (ins->inst_offset)) {
3268                                 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3269                         } else {
3270                                 mips_load_const (code, mips_at, ins->inst_offset);
3271                                 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3272                         }
3273                         break;
3274                 case OP_STOREI8_MEMBASE_IMM:
3275                         mips_load_const (code, mips_temp, ins->inst_imm);
3276                         if (mips_is_imm16 (ins->inst_offset)) {
3277                                 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3278                         } else {
3279                                 mips_load_const (code, mips_at, ins->inst_offset);
3280                                 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3281                         }
3282                         break;
3283                 case OP_STORE_MEMBASE_IMM:
3284                 case OP_STOREI4_MEMBASE_IMM:
3285                         mips_load_const (code, mips_temp, ins->inst_imm);
3286                         if (mips_is_imm16 (ins->inst_offset)) {
3287                                 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3288                         } else {
3289                                 mips_load_const (code, mips_at, ins->inst_offset);
3290                                 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3291                         }
3292                         break;
3293                 case OP_STOREI1_MEMBASE_REG:
3294                         if (mips_is_imm16 (ins->inst_offset)) {
3295                                 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3296                         } else {
3297                                 mips_load_const (code, mips_at, ins->inst_offset);
3298                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3299                                 mips_sb (code, ins->sreg1, mips_at, 0);
3300                         }
3301                         break;
3302                 case OP_STOREI2_MEMBASE_REG:
3303                         if (mips_is_imm16 (ins->inst_offset)) {
3304                                 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3305                         } else {
3306                                 mips_load_const (code, mips_at, ins->inst_offset);
3307                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3308                                 mips_sh (code, ins->sreg1, mips_at, 0);
3309                         }
3310                         break;
3311                 case OP_STORE_MEMBASE_REG:
3312                 case OP_STOREI4_MEMBASE_REG:
3313                         if (mips_is_imm16 (ins->inst_offset)) {
3314                                 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3315                         } else {
3316                                 mips_load_const (code, mips_at, ins->inst_offset);
3317                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3318                                 mips_sw (code, ins->sreg1, mips_at, 0);
3319                         }
3320                         break;
3321                 case OP_STOREI8_MEMBASE_REG:
3322                         if (mips_is_imm16 (ins->inst_offset)) {
3323                                 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3324                         } else {
3325                                 mips_load_const (code, mips_at, ins->inst_offset);
3326                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3327                                 mips_sd (code, ins->sreg1, mips_at, 0);
3328                         }
3329                         break;
3330                 case OP_LOADU4_MEM:
3331                         g_assert_not_reached ();
3332                         //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3333                         //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3334                         break;
3335                 case OP_LOADI8_MEMBASE:
3336                         if (mips_is_imm16 (ins->inst_offset)) {
3337                                 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3338                         } else {
3339                                 mips_load_const (code, mips_at, ins->inst_offset);
3340                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3341                                 mips_ld (code, ins->dreg, mips_at, 0);
3342                         }
3343                         break;
3344                 case OP_LOAD_MEMBASE:
3345                 case OP_LOADI4_MEMBASE:
3346                 case OP_LOADU4_MEMBASE:
3347                         g_assert (ins->dreg != -1);
3348                         if (mips_is_imm16 (ins->inst_offset)) {
3349                                 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3350                         } else {
3351                                 mips_load_const (code, mips_at, ins->inst_offset);
3352                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3353                                 mips_lw (code, ins->dreg, mips_at, 0);
3354                         }
3355                         break;
3356                 case OP_LOADI1_MEMBASE:
3357                         if (mips_is_imm16 (ins->inst_offset)) {
3358                                 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3359                         } else {
3360                                 mips_load_const (code, mips_at, ins->inst_offset);
3361                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3362                                 mips_lb (code, ins->dreg, mips_at, 0);
3363                         }
3364                         break;
3365                 case OP_LOADU1_MEMBASE:
3366                         if (mips_is_imm16 (ins->inst_offset)) {
3367                                 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3368                         } else {
3369                                 mips_load_const (code, mips_at, ins->inst_offset);
3370                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3371                                 mips_lbu (code, ins->dreg, mips_at, 0);
3372                         }
3373                         break;
3374                 case OP_LOADI2_MEMBASE:
3375                         if (mips_is_imm16 (ins->inst_offset)) {
3376                                 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3377                         } else {
3378                                 mips_load_const (code, mips_at, ins->inst_offset);
3379                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3380                                 mips_lh (code, ins->dreg, mips_at, 0);
3381                         }
3382                         break;
3383                 case OP_LOADU2_MEMBASE:
3384                         if (mips_is_imm16 (ins->inst_offset)) {
3385                                 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3386                         } else {
3387                                 mips_load_const (code, mips_at, ins->inst_offset);
3388                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3389                                 mips_lhu (code, ins->dreg, mips_at, 0);
3390                         }
3391                         break;
3392                 case OP_ICONV_TO_I1:
3393                         mips_sll (code, mips_at, ins->sreg1, 24);
3394                         mips_sra (code, ins->dreg, mips_at, 24);
3395                         break;
3396                 case OP_ICONV_TO_I2:
3397                         mips_sll (code, mips_at, ins->sreg1, 16);
3398                         mips_sra (code, ins->dreg, mips_at, 16);
3399                         break;
3400                 case OP_ICONV_TO_U1:
3401                         mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3402                         break;
3403                 case OP_ICONV_TO_U2:
3404                         mips_sll (code, mips_at, ins->sreg1, 16);
3405                         mips_srl (code, ins->dreg, mips_at, 16);
3406                         break;
3407                 case OP_MIPS_SLT:
3408                         mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3409                         break;
3410                 case OP_MIPS_SLTI:
3411                         g_assert (mips_is_imm16 (ins->inst_imm));
3412                         mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3413                         break;
3414                 case OP_MIPS_SLTU:
3415                         mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3416                         break;
3417                 case OP_MIPS_SLTIU:
3418                         g_assert (mips_is_imm16 (ins->inst_imm));
3419                         mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3420                         break;
3421                 case OP_BREAK:
3422                         /*
3423                          * gdb does not like encountering the hw breakpoint ins in the debugged code. 
3424                          * So instead of emitting a trap, we emit a call a C function and place a 
3425                          * breakpoint there.
3426                          */
3427                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3428                                                                  (gpointer)"mono_break");
3429                         mips_load (code, mips_t9, 0x1f1f1f1f);
3430                         mips_jalr (code, mips_t9, mips_ra);
3431                         mips_nop (code);
3432                         break;
3433                 case OP_IADD:
3434                         mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3435                         break;
3436                 case OP_LADD:
3437                         mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3438                         break;
3439
3440                 case OP_ADD_IMM:
3441                 case OP_IADD_IMM:
3442                         g_assert (mips_is_imm16 (ins->inst_imm));
3443                         mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3444                         break;
3445                 case OP_LADD_IMM:
3446                         g_assert (mips_is_imm16 (ins->inst_imm));
3447                         mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3448                         break;
3449
3450                 case OP_ISUB:
3451                         mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3452                         break;
3453                 case OP_LSUB:
3454                         mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3455                         break;
3456
3457                 case OP_ISUB_IMM:
3458                 case OP_SUB_IMM:
3459                         // we add the negated value
3460                         g_assert (mips_is_imm16 (-ins->inst_imm));
3461                         mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3462                         break;
3463
3464                 case OP_LSUB_IMM:
3465                         // we add the negated value
3466                         g_assert (mips_is_imm16 (-ins->inst_imm));
3467                         mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3468                         break;
3469
3470                 case OP_IAND:
3471                 case OP_LAND:
3472                         mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3473                         break;
3474
3475                 case OP_AND_IMM:
3476                 case OP_IAND_IMM:
3477                 case OP_LAND_IMM:
3478                         g_assert (!(ins->inst_imm & 0xffff0000));
3479                         mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3480                         break;
3481
3482                 case OP_IDIV:
3483                 case OP_IREM: {
3484                         guint32 *divisor_is_m1;
3485                         guint32 *dividend_is_minvalue;
3486                         guint32 *divisor_is_zero;
3487
3488                         mips_load_const (code, mips_at, -1);
3489                         divisor_is_m1 = (guint32 *)(void *)code;
3490                         mips_bne (code, ins->sreg2, mips_at, 0);
3491                         mips_lui (code, mips_at, mips_zero, 0x8000);
3492                         dividend_is_minvalue = (guint32 *)(void *)code;
3493                         mips_bne (code, ins->sreg1, mips_at, 0);
3494                         mips_nop (code);
3495
3496                         /* Divide Int32.MinValue by -1 -- throw exception */
3497                         EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3498
3499                         mips_patch (divisor_is_m1, (guint32)code);
3500                         mips_patch (dividend_is_minvalue, (guint32)code);
3501
3502                         /* Put divide in branch delay slot (NOT YET) */
3503                         divisor_is_zero = (guint32 *)(void *)code;
3504                         mips_bne (code, ins->sreg2, mips_zero, 0);
3505                         mips_nop (code);
3506
3507                         /* Divide by zero -- throw exception */
3508                         EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3509
3510                         mips_patch (divisor_is_zero, (guint32)code);
3511                         mips_div (code, ins->sreg1, ins->sreg2);
3512                         if (ins->opcode == OP_IDIV)
3513                                 mips_mflo (code, ins->dreg);
3514                         else
3515                                 mips_mfhi (code, ins->dreg);
3516                         break;
3517                 }
3518                 case OP_IDIV_UN: 
3519                 case OP_IREM_UN: {
3520                         guint32 *divisor_is_zero = (guint32 *)(void *)code;
3521
3522                         /* Put divide in branch delay slot (NOT YET) */
3523                         mips_bne (code, ins->sreg2, mips_zero, 0);
3524                         mips_nop (code);
3525
3526                         /* Divide by zero -- throw exception */
3527                         EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3528
3529                         mips_patch (divisor_is_zero, (guint32)code);
3530                         mips_divu (code, ins->sreg1, ins->sreg2);
3531                         if (ins->opcode == OP_IDIV_UN)
3532                                 mips_mflo (code, ins->dreg);
3533                         else
3534                                 mips_mfhi (code, ins->dreg);
3535                         break;
3536                 }
3537                 case OP_DIV_IMM:
3538                         g_assert_not_reached ();
3539 #if 0
3540                         ppc_load (code, ppc_r11, ins->inst_imm);
3541                         ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3542                         ppc_mfspr (code, ppc_r0, ppc_xer);
3543                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3544                         /* FIXME: use OverflowException for 0x80000000/-1 */
3545                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3546 #endif
3547                         g_assert_not_reached();
3548                         break;
3549                 case OP_REM_IMM:
3550                         g_assert_not_reached ();
3551                 case OP_IOR:
3552                         mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3553                         break;
3554                 case OP_OR_IMM:
3555                 case OP_IOR_IMM:
3556                         g_assert (!(ins->inst_imm & 0xffff0000));
3557                         mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3558                         break;
3559                 case OP_IXOR:
3560                         mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3561                         break;
3562                 case OP_XOR_IMM:
3563                 case OP_IXOR_IMM:
3564                         /* unsigned 16-bit immediate */
3565                         g_assert (!(ins->inst_imm & 0xffff0000));
3566                         mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3567                         break;
3568                 case OP_ISHL:
3569                         mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3570                         break;
3571                 case OP_SHL_IMM:
3572                 case OP_ISHL_IMM:
3573                         mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3574                         break;
3575                 case OP_ISHR:
3576                         mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3577                         break;
3578                 case OP_LSHR:
3579                         mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3580                         break;
3581                 case OP_SHR_IMM:
3582                 case OP_ISHR_IMM:
3583                         mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3584                         break;
3585                 case OP_LSHR_IMM:
3586                         mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3587                         break;
3588                 case OP_SHR_UN_IMM:
3589                 case OP_ISHR_UN_IMM:
3590                         mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3591                         break;
3592                 case OP_LSHR_UN_IMM:
3593                         mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3594                         break;
3595                 case OP_ISHR_UN:
3596                         mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3597                         break;
3598                 case OP_LSHR_UN:
3599                         mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3600                         break;
3601                 case OP_INOT:
3602                 case OP_LNOT:
3603                         mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3604                         break;
3605                 case OP_INEG:
3606                         mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3607                         break;
3608                 case OP_LNEG:
3609                         mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3610                         break;
3611                 case OP_IMUL:
3612 #if USE_MUL
3613                         mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3614 #else
3615                         mips_mult (code, ins->sreg1, ins->sreg2);
3616                         mips_mflo (code, ins->dreg);
3617                         mips_nop (code);
3618                         mips_nop (code);
3619 #endif
3620                         break;
3621 #if SIZEOF_REGISTER == 8
3622                 case OP_LMUL:
3623                         mips_dmult (code, ins->sreg1, ins->sreg2);
3624                         mips_mflo (code, ins->dreg);
3625                         break;
3626 #endif
3627                 case OP_IMUL_OVF: {
3628                         guint32 *patch;
3629                         mips_mult (code, ins->sreg1, ins->sreg2);
3630                         mips_mflo (code, ins->dreg);
3631                         mips_mfhi (code, mips_at);
3632                         mips_nop (code);
3633                         mips_nop (code);
3634                         mips_sra (code, mips_temp, ins->dreg, 31);
3635                         patch = (guint32 *)(void *)code;
3636                         mips_beq (code, mips_temp, mips_at, 0);
3637                         mips_nop (code);
3638                         EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3639                         mips_patch (patch, (guint32)code);
3640                         break;
3641                 }
3642                 case OP_IMUL_OVF_UN: {
3643                         guint32 *patch;
3644                         mips_mult (code, ins->sreg1, ins->sreg2);
3645                         mips_mflo (code, ins->dreg);
3646                         mips_mfhi (code, mips_at);
3647                         mips_nop (code);
3648                         mips_nop (code);
3649                         patch = (guint32 *)(void *)code;
3650                         mips_beq (code, mips_at, mips_zero, 0);
3651                         mips_nop (code);
3652                         EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3653                         mips_patch (patch, (guint32)code);
3654                         break;
3655                 }
3656                 case OP_ICONST:
3657                         mips_load_const (code, ins->dreg, ins->inst_c0);
3658                         break;
3659 #if SIZEOF_REGISTER == 8
3660                 case OP_I8CONST:
3661                         mips_load_const (code, ins->dreg, ins->inst_c0);
3662                         break;
3663 #endif
3664                 case OP_AOTCONST:
3665                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3666                         mips_load (code, ins->dreg, 0);
3667                         break;
3668
3669                 case OP_MIPS_MTC1S:
3670                         mips_mtc1 (code, ins->dreg, ins->sreg1);
3671                         break;
3672                 case OP_MIPS_MTC1S_2:
3673                         mips_mtc1 (code, ins->dreg, ins->sreg1);
3674                         mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3675                         break;
3676                 case OP_MIPS_MFC1S:
3677                         mips_mfc1 (code, ins->dreg, ins->sreg1);
3678                         break;
3679                 case OP_MIPS_MTC1D:
3680                         mips_dmtc1 (code, ins->dreg, ins->sreg1);
3681                         break;
3682                 case OP_MIPS_MFC1D:
3683 #if 0
3684                         mips_dmfc1 (code, ins->dreg, ins->sreg1);
3685 #else
3686                         mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3687                         mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3688 #endif
3689                         break;
3690
3691                 case OP_ICONV_TO_I4:
3692                 case OP_ICONV_TO_U4:
3693                 case OP_MOVE:
3694                         if (ins->dreg != ins->sreg1)
3695                                 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3696                         break;
3697 #if SIZEOF_REGISTER == 8
3698                 case OP_ZEXT_I4:
3699                         mips_dsll (code, ins->dreg, ins->sreg1, 32);
3700                         mips_dsrl (code, ins->dreg, ins->dreg, 32);
3701                         break;
3702                 case OP_SEXT_I4:
3703                         mips_dsll (code, ins->dreg, ins->sreg1, 32);
3704                         mips_dsra (code, ins->dreg, ins->dreg, 32);
3705                         break;
3706 #endif
3707                 case OP_SETLRET: {
3708                         int lsreg = mips_v0 + ls_word_idx;
3709                         int msreg = mips_v0 + ms_word_idx;
3710
3711                         /* Get sreg1 into lsreg, sreg2 into msreg */
3712
3713                         if (ins->sreg1 == msreg) {
3714                                 if (ins->sreg1 != mips_at)
3715                                         MIPS_MOVE (code, mips_at, ins->sreg1);
3716                                 if (ins->sreg2 != msreg)
3717                                         MIPS_MOVE (code, msreg, ins->sreg2);
3718                                 MIPS_MOVE (code, lsreg, mips_at);
3719                         }
3720                         else {
3721                                 if (ins->sreg2 != msreg)
3722                                         MIPS_MOVE (code, msreg, ins->sreg2);
3723                                 if (ins->sreg1 != lsreg)
3724                                         MIPS_MOVE (code, lsreg, ins->sreg1);
3725                         }
3726                         break;
3727                 }
3728                 case OP_FMOVE:
3729                         if (ins->dreg != ins->sreg1) {
3730                                 mips_fmovd (code, ins->dreg, ins->sreg1);
3731                         }
3732                         break;
3733                 case OP_MIPS_CVTSD:
3734                         /* Convert from double to float and leave it there */
3735                         mips_cvtsd (code, ins->dreg, ins->sreg1);
3736                         break;
3737                 case OP_FCONV_TO_R4:
3738 #if 0
3739                         mips_cvtsd (code, ins->dreg, ins->sreg1);
3740 #else
3741                         /* Just a move, no precision change */
3742                         if (ins->dreg != ins->sreg1) {
3743                                 mips_fmovd (code, ins->dreg, ins->sreg1);
3744                         }
3745 #endif
3746                         break;
3747                 case OP_JMP:
3748                         code = emit_load_volatile_arguments(cfg, code);
3749
3750                         /*
3751                          * Pop our stack, then jump to specified method (tail-call)
3752                          * Keep in sync with mono_arch_emit_epilog
3753                          */
3754                         code = mono_arch_emit_epilog_sub (cfg, code);
3755
3756                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3757                                              MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3758                         if (cfg->arch.long_branch) {
3759                                 mips_lui (code, mips_t9, mips_zero, 0);
3760                                 mips_addiu (code, mips_t9, mips_t9, 0);
3761                                 mips_jr (code, mips_t9);
3762                                 mips_nop (code);
3763                         }
3764                         else {
3765                                 mips_beq (code, mips_zero, mips_zero, 0);
3766                                 mips_nop (code);
3767                         }
3768                         break;
3769                 case OP_CHECK_THIS:
3770                         /* ensure ins->sreg1 is not NULL */
3771                         mips_lw (code, mips_zero, ins->sreg1, 0);
3772                         break;
3773                 case OP_ARGLIST: {
3774                         if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3775                                 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3776                         } else {
3777                                 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3778                                 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3779                         }
3780                         mips_sw (code, mips_at, ins->sreg1, 0);
3781                         break;
3782                 }
3783                 case OP_FCALL:
3784                 case OP_LCALL:
3785                 case OP_VCALL:
3786                 case OP_VCALL2:
3787                 case OP_VOIDCALL:
3788                 case OP_CALL:
3789                 case OP_FCALL_REG:
3790                 case OP_LCALL_REG:
3791                 case OP_VCALL_REG:
3792                 case OP_VCALL2_REG:
3793                 case OP_VOIDCALL_REG:
3794                 case OP_CALL_REG:
3795                 case OP_FCALL_MEMBASE:
3796                 case OP_LCALL_MEMBASE:
3797                 case OP_VCALL_MEMBASE:
3798                 case OP_VCALL2_MEMBASE:
3799                 case OP_VOIDCALL_MEMBASE:
3800                 case OP_CALL_MEMBASE:
3801                         call = (MonoCallInst*)ins;
3802                         switch (ins->opcode) {
3803                         case OP_FCALL:
3804                         case OP_LCALL:
3805                         case OP_VCALL:
3806                         case OP_VCALL2:
3807                         case OP_VOIDCALL:
3808                         case OP_CALL:
3809                                 if (ins->flags & MONO_INST_HAS_METHOD) {
3810                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3811                                         mips_load (code, mips_t9, call->method);
3812                                 }
3813                                 else {
3814                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3815                                         mips_load (code, mips_t9, call->fptr);
3816                                 }
3817                                 mips_jalr (code, mips_t9, mips_ra);
3818                                 mips_nop (code);
3819                                 break;
3820                         case OP_FCALL_REG:
3821                         case OP_LCALL_REG:
3822                         case OP_VCALL_REG:
3823                         case OP_VCALL2_REG:
3824                         case OP_VOIDCALL_REG:
3825                         case OP_CALL_REG:
3826                                 MIPS_MOVE (code, mips_t9, ins->sreg1);
3827                                 mips_jalr (code, mips_t9, mips_ra);
3828                                 mips_nop (code);
3829                                 break;
3830                         case OP_FCALL_MEMBASE:
3831                         case OP_LCALL_MEMBASE:
3832                         case OP_VCALL_MEMBASE:
3833                         case OP_VCALL2_MEMBASE:
3834                         case OP_VOIDCALL_MEMBASE:
3835                         case OP_CALL_MEMBASE:
3836                                 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3837                                 mips_jalr (code, mips_t9, mips_ra);
3838                                 mips_nop (code);
3839                                 break;
3840                         }
3841 #if PROMOTE_R4_TO_R8
3842                         /* returned an FP R4 (single), promote to R8 (double) in place */
3843                         if ((ins->opcode == OP_FCALL ||
3844                              ins->opcode == OP_FCALL_REG) &&
3845                             call->signature->ret->type == MONO_TYPE_R4) {
3846                                 mips_cvtds (code, mips_f0, mips_f0);
3847                         }
3848 #endif
3849                         break;
3850                 case OP_LOCALLOC: {
3851                         int area_offset = cfg->param_area;
3852
3853                         /* Round up ins->sreg1, mips_at ends up holding size */
3854                         mips_addiu (code, mips_at, ins->sreg1, 31);
3855                         mips_addiu (code, mips_temp, mips_zero, ~31);
3856                         mips_and (code, mips_at, mips_at, mips_temp);
3857
3858                         mips_subu (code, mips_sp, mips_sp, mips_at);
3859                         g_assert (mips_is_imm16 (area_offset));
3860                         mips_addiu (code, ins->dreg, mips_sp, area_offset);
3861
3862                         if (ins->flags & MONO_INST_INIT) {
3863                                 mips_move (code, mips_temp, ins->dreg);
3864                                 mips_sb (code, mips_zero, mips_temp, 0);
3865                                 mips_addiu (code, mips_at, mips_at, -1);
3866                                 mips_bne (code, mips_at, mips_zero, -3);
3867                                 mips_addiu (code, mips_temp, mips_temp, 1);
3868                         }
3869                         break;
3870                 }
3871                 case OP_THROW: {
3872                         gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3873                         mips_move (code, mips_a0, ins->sreg1);
3874                         mips_call (code, mips_t9, addr);
3875                         mips_break (code, 0xfc);
3876                         break;
3877                 }
3878                 case OP_RETHROW: {
3879                         gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3880                         mips_move (code, mips_a0, ins->sreg1);
3881                         mips_call (code, mips_t9, addr);
3882                         mips_break (code, 0xfb);
3883                         break;
3884                 }
3885                 case OP_START_HANDLER: {
3886                         /*
3887                          * The START_HANDLER instruction marks the beginning of
3888                          * a handler block. It is called using a call
3889                          * instruction, so mips_ra contains the return address.
3890                          * Since the handler executes in the same stack frame
3891                          * as the method itself, we can't use save/restore to
3892                          * save the return address. Instead, we save it into
3893                          * a dedicated variable.
3894                          */
3895                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3896                         g_assert (spvar->inst_basereg != mips_sp);
3897                         code = emit_reserve_param_area (cfg, code);
3898
3899                         if (mips_is_imm16 (spvar->inst_offset)) {
3900                                 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3901                         } else {
3902                                 mips_load_const (code, mips_at, spvar->inst_offset);
3903                                 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3904                                 mips_sw (code, mips_ra, mips_at, 0);
3905                         }
3906                         break;
3907                 }
3908                 case OP_ENDFILTER: {
3909                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3910                         g_assert (spvar->inst_basereg != mips_sp);
3911                         code = emit_unreserve_param_area (cfg, code);
3912
3913                         if (ins->sreg1 != mips_v0)
3914                                 MIPS_MOVE (code, mips_v0, ins->sreg1);
3915                         if (mips_is_imm16 (spvar->inst_offset)) {
3916                                 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3917                         } else {
3918                                 mips_load_const (code, mips_at, spvar->inst_offset);
3919                                 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3920                                 mips_lw (code, mips_ra, mips_at, 0);
3921                         }
3922                         mips_jr (code, mips_ra);
3923                         mips_nop (code);
3924                         break;
3925                 }
3926                 case OP_ENDFINALLY: {
3927                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3928                         g_assert (spvar->inst_basereg != mips_sp);
3929                         code = emit_unreserve_param_area (cfg, code);
3930                         mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3931                         mips_jalr (code, mips_t9, mips_ra);
3932                         mips_nop (code);
3933                         break;
3934                 }
3935                 case OP_CALL_HANDLER: 
3936                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3937                         mips_lui (code, mips_t9, mips_zero, 0);
3938                         mips_addiu (code, mips_t9, mips_t9, 0);
3939                         mips_jalr (code, mips_t9, mips_ra);
3940                         mips_nop (code);
3941                         /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3942                         mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3943                         break;
3944                 case OP_LABEL:
3945                         ins->inst_c0 = code - cfg->native_code;
3946                         break;
3947                 case OP_BR:
3948                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3949                         if (cfg->arch.long_branch) {
3950                                 mips_lui (code, mips_at, mips_zero, 0);
3951                                 mips_addiu (code, mips_at, mips_at, 0);
3952                                 mips_jr (code, mips_at);
3953                                 mips_nop (code);
3954                         }
3955                         else {
3956                                 mips_beq (code, mips_zero, mips_zero, 0);
3957                                 mips_nop (code);
3958                         }
3959                         break;
3960                 case OP_BR_REG:
3961                         mips_jr (code, ins->sreg1);
3962                         mips_nop (code);
3963                         break;
3964                 case OP_SWITCH: {
3965                         int i;
3966
3967                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
3968                         if (offset > (cfg->code_size - max_len - 16)) {
3969                                 cfg->code_size += max_len;
3970                                 cfg->code_size *= 2;
3971                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3972                                 code = cfg->native_code + offset;
3973                         }
3974                         g_assert (ins->sreg1 != -1);
3975                         mips_sll (code, mips_at, ins->sreg1, 2);
3976                         if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3977                                 MIPS_MOVE (code, mips_t8, mips_ra);
3978                         mips_bgezal (code, mips_zero, 1);       /* bal */
3979                         mips_nop (code);
3980                         mips_addu (code, mips_t9, mips_ra, mips_at);
3981                         /* Table is 16 or 20 bytes from target of bal above */
3982                         if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3983                                 MIPS_MOVE (code, mips_ra, mips_t8);
3984                                 mips_lw (code, mips_t9, mips_t9, 20);
3985                         }
3986                         else
3987                                 mips_lw (code, mips_t9, mips_t9, 16);
3988                         mips_jalr (code, mips_t9, mips_t8);
3989                         mips_nop (code);
3990                         for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3991                                 mips_emit32 (code, 0xfefefefe);
3992                         break;
3993                 }
3994                 case OP_CEQ:
3995                 case OP_ICEQ:
3996                         mips_addiu (code, ins->dreg, mips_zero, 1);
3997                         mips_beq (code, mips_at, mips_zero, 2);
3998                         mips_nop (code);
3999                         MIPS_MOVE (code, ins->dreg, mips_zero);
4000                         break;
4001                 case OP_CLT:
4002                 case OP_CLT_UN:
4003                 case OP_ICLT:
4004                 case OP_ICLT_UN:
4005                         mips_addiu (code, ins->dreg, mips_zero, 1);
4006                         mips_bltz (code, mips_at, 2);
4007                         mips_nop (code);
4008                         MIPS_MOVE (code, ins->dreg, mips_zero);
4009                         break;
4010                 case OP_CGT:
4011                 case OP_CGT_UN:
4012                 case OP_ICGT:
4013                 case OP_ICGT_UN:
4014                         mips_addiu (code, ins->dreg, mips_zero, 1);
4015                         mips_bgtz (code, mips_at, 2);
4016                         mips_nop (code);
4017                         MIPS_MOVE (code, ins->dreg, mips_zero);
4018                         break;
4019
4020                 case OP_MIPS_COND_EXC_EQ:
4021                 case OP_MIPS_COND_EXC_GE:
4022                 case OP_MIPS_COND_EXC_GT:
4023                 case OP_MIPS_COND_EXC_LE:
4024                 case OP_MIPS_COND_EXC_LT:
4025                 case OP_MIPS_COND_EXC_NE_UN:
4026                 case OP_MIPS_COND_EXC_GE_UN:
4027                 case OP_MIPS_COND_EXC_GT_UN:
4028                 case OP_MIPS_COND_EXC_LE_UN:
4029                 case OP_MIPS_COND_EXC_LT_UN:
4030
4031                 case OP_MIPS_COND_EXC_OV:
4032                 case OP_MIPS_COND_EXC_NO:
4033                 case OP_MIPS_COND_EXC_C:
4034                 case OP_MIPS_COND_EXC_NC:
4035
4036                 case OP_MIPS_COND_EXC_IEQ:
4037                 case OP_MIPS_COND_EXC_IGE:
4038                 case OP_MIPS_COND_EXC_IGT:
4039                 case OP_MIPS_COND_EXC_ILE:
4040                 case OP_MIPS_COND_EXC_ILT:
4041                 case OP_MIPS_COND_EXC_INE_UN:
4042                 case OP_MIPS_COND_EXC_IGE_UN:
4043                 case OP_MIPS_COND_EXC_IGT_UN:
4044                 case OP_MIPS_COND_EXC_ILE_UN:
4045                 case OP_MIPS_COND_EXC_ILT_UN:
4046
4047                 case OP_MIPS_COND_EXC_IOV:
4048                 case OP_MIPS_COND_EXC_INO:
4049                 case OP_MIPS_COND_EXC_IC:
4050                 case OP_MIPS_COND_EXC_INC: {
4051                         guint32 *skip;
4052                         guint32 *throw;
4053
4054                         /* If the condition is true, raise the exception */
4055
4056                         /* need to reverse test to skip around exception raising */
4057
4058                         /* For the moment, branch around a branch to avoid reversing
4059                            the tests. */
4060
4061                         /* Remember, an unpatched branch to 0 branches to the delay slot */
4062                         switch (ins->opcode) {
4063                         case OP_MIPS_COND_EXC_EQ:
4064                                 throw = (guint32 *)(void *)code;
4065                                 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4066                                 mips_nop (code);
4067                                 break;
4068
4069                         case OP_MIPS_COND_EXC_NE_UN:
4070                                 throw = (guint32 *)(void *)code;
4071                                 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4072                                 mips_nop (code);
4073                                 break;
4074
4075                         case OP_MIPS_COND_EXC_LE_UN:
4076                                 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4077                                 throw = (guint32 *)(void *)code;
4078                                 mips_beq (code, mips_at, mips_zero, 0);
4079                                 mips_nop (code);
4080                                 break;
4081
4082                         case OP_MIPS_COND_EXC_GT:
4083                                 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4084                                 throw = (guint32 *)(void *)code;
4085                                 mips_bne (code, mips_at, mips_zero, 0);
4086                                 mips_nop (code);
4087                                 break;
4088
4089                         case OP_MIPS_COND_EXC_GT_UN:
4090                                 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4091                                 throw = (guint32 *)(void *)code;
4092                                 mips_bne (code, mips_at, mips_zero, 0);
4093                                 mips_nop (code);
4094                                 break;
4095
4096                         case OP_MIPS_COND_EXC_LT:
4097                                 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4098                                 throw = (guint32 *)(void *)code;
4099                                 mips_bne (code, mips_at, mips_zero, 0);
4100                                 mips_nop (code);
4101                                 break;
4102
4103                         case OP_MIPS_COND_EXC_LT_UN:
4104                                 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4105                                 throw = (guint32 *)(void *)code;
4106                                 mips_bne (code, mips_at, mips_zero, 0);
4107                                 mips_nop (code);
4108                                 break;
4109
4110                         default:
4111                                 /* Not yet implemented */
4112                                 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4113                                 g_assert_not_reached ();
4114                         }
4115                         skip = (guint32 *)(void *)code;
4116                         mips_beq (code, mips_zero, mips_zero, 0);
4117                         mips_nop (code);
4118                         mips_patch (throw, (guint32)code);
4119                         code = mips_emit_exc_by_name (code, ins->inst_p1);
4120                         mips_patch (skip, (guint32)code);
4121                         cfg->bb_exit->max_offset += 24;
4122                         break;
4123                 }
4124                 case OP_MIPS_BEQ:
4125                 case OP_MIPS_BNE:
4126                 case OP_MIPS_BGEZ:
4127                 case OP_MIPS_BGTZ:
4128                 case OP_MIPS_BLEZ:
4129                 case OP_MIPS_BLTZ:
4130                         code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4131                         break;
4132
4133                 /* floating point opcodes */
4134                 case OP_R8CONST:
4135 #if 0
4136                         if (((guint32)ins->inst_p0) & (1 << 15))
4137                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4138                         else
4139                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4140                         mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4141 #else
4142                         mips_load_const (code, mips_at, ins->inst_p0);
4143                         mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4144                         mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4145 #endif
4146                         break;
4147                 case OP_R4CONST:
4148                         if (((guint32)ins->inst_p0) & (1 << 15))
4149                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4150                         else
4151                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4152                         mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4153 #if PROMOTE_R4_TO_R8
4154                         mips_cvtds (code, ins->dreg, ins->dreg);
4155 #endif
4156                         break;
4157                 case OP_STORER8_MEMBASE_REG:
4158                         if (mips_is_imm16 (ins->inst_offset)) {
4159 #if _MIPS_SIM == _ABIO32
4160                                 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4161                                 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4162 #elif _MIPS_SIM == _ABIN32
4163                                 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4164 #endif
4165                         } else {
4166                                 mips_load_const (code, mips_at, ins->inst_offset);
4167                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4168                                 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4169                                 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4170                         }
4171                         break;
4172                 case OP_LOADR8_MEMBASE:
4173                         if (mips_is_imm16 (ins->inst_offset)) {
4174 #if _MIPS_SIM == _ABIO32
4175                                 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4176                                 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4177 #elif _MIPS_SIM == _ABIN32
4178                                 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4179 #endif
4180                         } else {
4181                                 mips_load_const (code, mips_at, ins->inst_offset);
4182                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4183                                 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4184                                 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4185                         }
4186                         break;
4187                 case OP_STORER4_MEMBASE_REG:
4188                         g_assert (mips_is_imm16 (ins->inst_offset));
4189 #if PROMOTE_R4_TO_R8
4190                         /* Need to convert ins->sreg1 to single-precision first */
4191                         mips_cvtsd (code, mips_ftemp, ins->sreg1);
4192                         mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4193 #else
4194                         mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4195 #endif
4196                         break;
4197                 case OP_MIPS_LWC1:
4198                         g_assert (mips_is_imm16 (ins->inst_offset));
4199                         mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4200                         break;
4201                 case OP_LOADR4_MEMBASE:
4202                         g_assert (mips_is_imm16 (ins->inst_offset));
4203                         mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4204 #if PROMOTE_R4_TO_R8
4205                         /* Convert to double precision in place */
4206                         mips_cvtds (code, ins->dreg, ins->dreg);
4207 #endif
4208                         break;
4209                 case OP_LOADR4_MEMINDEX:
4210                         mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4211                         mips_lwc1 (code, ins->dreg, mips_at, 0);
4212                         break;
4213                 case OP_LOADR8_MEMINDEX:
4214                         mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4215 #if _MIPS_SIM == _ABIO32
4216                         mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4217                         mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4218 #elif _MIPS_SIM == _ABIN32
4219                         mips_ldc1 (code, ins->dreg, mips_at, 0);
4220 #endif
4221                         break;
4222                 case OP_STORER4_MEMINDEX:
4223                         mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4224 #if PROMOTE_R4_TO_R8
4225                         /* Need to convert ins->sreg1 to single-precision first */
4226                         mips_cvtsd (code, mips_ftemp, ins->sreg1);
4227                         mips_swc1 (code, mips_ftemp, mips_at, 0);
4228 #else
4229                         mips_swc1 (code, ins->sreg1, mips_at, 0);
4230 #endif
4231                         break;
4232                 case OP_STORER8_MEMINDEX:
4233                         mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4234 #if _MIPS_SIM == _ABIO32
4235                         mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4236                         mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4237 #elif _MIPS_SIM == _ABIN32
4238                         mips_sdc1 (code, ins->sreg1, mips_at, 0);
4239 #endif
4240                         break;
4241                 case OP_ICONV_TO_R_UN: {
4242                         static const guint64 adjust_val = 0x41F0000000000000ULL;
4243
4244                         /* convert unsigned int to double */
4245                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4246                         mips_bgez (code, ins->sreg1, 5);
4247                         mips_cvtdw (code, ins->dreg, mips_ftemp);
4248
4249                         mips_load (code, mips_at, (guint32) &adjust_val);
4250                         mips_ldc1  (code, mips_ftemp, mips_at, 0);
4251                         mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4252                         /* target is here */
4253                         break;
4254                 }
4255                 case OP_ICONV_TO_R4:
4256                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4257                         mips_cvtsw (code, ins->dreg, mips_ftemp);
4258                         mips_cvtds (code, ins->dreg, ins->dreg);
4259                         break;
4260                 case OP_ICONV_TO_R8:
4261                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4262                         mips_cvtdw (code, ins->dreg, mips_ftemp);
4263                         break;
4264                 case OP_FCONV_TO_I1:
4265                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4266                         break;
4267                 case OP_FCONV_TO_U1:
4268                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4269                         break;
4270                 case OP_FCONV_TO_I2:
4271                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4272                         break;
4273                 case OP_FCONV_TO_U2:
4274                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4275                         break;
4276                 case OP_FCONV_TO_I4:
4277                 case OP_FCONV_TO_I:
4278                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4279                         break;
4280                 case OP_FCONV_TO_U4:
4281                 case OP_FCONV_TO_U:
4282                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4283                         break;
4284                 case OP_SQRT:
4285                         mips_fsqrtd (code, ins->dreg, ins->sreg1);
4286                         break;
4287                 case OP_FADD:
4288                         mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4289                         break;
4290                 case OP_FSUB:
4291                         mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4292                         break;          
4293                 case OP_FMUL:
4294                         mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4295                         break;          
4296                 case OP_FDIV:
4297                         mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4298                         break;          
4299                 case OP_FNEG:
4300                         mips_fnegd (code, ins->dreg, ins->sreg1);
4301                         break;          
4302                 case OP_FCEQ:
4303                         mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4304                         mips_addiu (code, ins->dreg, mips_zero, 1);
4305                         mips_fbtrue (code, 2);
4306                         mips_nop (code);
4307                         MIPS_MOVE (code, ins->dreg, mips_zero);
4308                         break;
4309                 case OP_FCLT:
4310                         mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4311                         mips_addiu (code, ins->dreg, mips_zero, 1);
4312                         mips_fbtrue (code, 2);
4313                         mips_nop (code);
4314                         MIPS_MOVE (code, ins->dreg, mips_zero);
4315                         break;
4316                 case OP_FCLT_UN:
4317                         /* Less than, or Unordered */
4318                         mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4319                         mips_addiu (code, ins->dreg, mips_zero, 1);
4320                         mips_fbtrue (code, 2);
4321                         mips_nop (code);
4322                         MIPS_MOVE (code, ins->dreg, mips_zero);
4323                         break;
4324                 case OP_FCGT:
4325                         mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4326                         MIPS_MOVE (code, ins->dreg, mips_zero);
4327                         mips_fbtrue (code, 2);
4328                         mips_nop (code);
4329                         mips_addiu (code, ins->dreg, mips_zero, 1);
4330                         break;
4331                 case OP_FCGT_UN:
4332                         /* Greater than, or Unordered */
4333                         mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4334                         MIPS_MOVE (code, ins->dreg, mips_zero);
4335                         mips_fbtrue (code, 2);
4336                         mips_nop (code);
4337                         mips_addiu (code, ins->dreg, mips_zero, 1);
4338                         break;
4339                 case OP_MIPS_FBEQ:
4340                 case OP_MIPS_FBNE:
4341                 case OP_MIPS_FBLT:
4342                 case OP_MIPS_FBLT_UN:
4343                 case OP_MIPS_FBGT:
4344                 case OP_MIPS_FBGT_UN:
4345                 case OP_MIPS_FBGE:
4346                 case OP_MIPS_FBGE_UN:
4347                 case OP_MIPS_FBLE:
4348                 case OP_MIPS_FBLE_UN: {
4349                         int cond = 0;
4350                         gboolean is_true = TRUE, is_ordered = FALSE;
4351                         guint32 *buf = NULL;
4352
4353                         switch (ins->opcode) {
4354                         case OP_MIPS_FBEQ:
4355                                 cond = MIPS_FPU_EQ;
4356                                 is_true = TRUE;
4357                                 break;
4358                         case OP_MIPS_FBNE:
4359                                 cond = MIPS_FPU_EQ;
4360                                 is_true = FALSE;
4361                                 break;
4362                         case OP_MIPS_FBLT:
4363                                 cond = MIPS_FPU_LT;
4364                                 is_true = TRUE;
4365                                 is_ordered = TRUE;
4366                                 break;
4367                         case OP_MIPS_FBLT_UN:
4368                                 cond = MIPS_FPU_ULT;
4369                                 is_true = TRUE;
4370                                 break;
4371                         case OP_MIPS_FBGT:
4372                                 cond = MIPS_FPU_LE;
4373                                 is_true = FALSE;
4374                                 is_ordered = TRUE;
4375                                 break;
4376                         case OP_MIPS_FBGT_UN:
4377                                 cond = MIPS_FPU_OLE;
4378                                 is_true = FALSE;
4379                                 break;
4380                         case OP_MIPS_FBGE:
4381                                 cond = MIPS_FPU_LT;
4382                                 is_true = FALSE;
4383                                 is_ordered = TRUE;
4384                                 break;
4385                         case OP_MIPS_FBGE_UN:
4386                                 cond = MIPS_FPU_OLT;
4387                                 is_true = FALSE;
4388                                 break;
4389                         case OP_MIPS_FBLE:
4390                                 cond = MIPS_FPU_OLE;
4391                                 is_true = TRUE;
4392                                 is_ordered = TRUE;
4393                                 break;
4394                         case OP_MIPS_FBLE_UN:
4395                                 cond = MIPS_FPU_ULE;
4396                                 is_true = TRUE;
4397                                 break;
4398                         default:
4399                                 g_assert_not_reached ();
4400                         }
4401
4402                         if (is_ordered) {
4403                                 /* Skip the check if unordered */
4404                                 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4405                                 mips_nop (code);
4406                                 buf = (guint32*)code;
4407                                 mips_fbtrue (code, 0);
4408                                 mips_nop (code);
4409                         }
4410                         
4411                         mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4412                         mips_nop (code);
4413                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4414                         if (is_true)
4415                                 mips_fbtrue (code, 0);
4416                         else
4417                                 mips_fbfalse (code, 0);
4418                         mips_nop (code);
4419
4420                         if (is_ordered)
4421                                 mips_patch (buf, (guint32)code);
4422                         break;
4423                 }
4424                 case OP_CKFINITE: {
4425                         guint32 *branch_patch;
4426
4427                         mips_mfc1 (code, mips_at, ins->sreg1+1);
4428                         mips_srl (code, mips_at, mips_at, 16+4);
4429                         mips_andi (code, mips_at, mips_at, 2047);
4430                         mips_addiu (code, mips_at, mips_at, -2047);
4431
4432                         branch_patch = (guint32 *)(void *)code;
4433                         mips_bne (code, mips_at, mips_zero, 0);
4434                         mips_nop (code);
4435
4436                         EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4437                         mips_patch (branch_patch, (guint32)code);
4438                         mips_fmovd (code, ins->dreg, ins->sreg1);
4439                         break;
4440                 }
4441                 case OP_JUMP_TABLE:
4442                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4443                         mips_load (code, ins->dreg, 0x0f0f0f0f);
4444                         break;
4445
4446
4447                 default:
4448                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4449                         g_assert_not_reached ();
4450                 }
4451
4452                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4453                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4454                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4455                         g_assert_not_reached ();
4456                 }
4457                
4458                 cpos += max_len;
4459
4460                 last_ins = ins;
4461                 last_offset = offset;
4462         }
4463
4464         cfg->code_len = code - cfg->native_code;
4465 }
4466
4467 void
4468 mono_arch_register_lowlevel_calls (void)
4469 {
4470 }
4471
4472 void
4473 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4474 {
4475         MonoJumpInfo *patch_info;
4476
4477         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4478                 unsigned char *ip = patch_info->ip.i + code;
4479                 const unsigned char *target = NULL;
4480
4481                 switch (patch_info->type) {
4482                 case MONO_PATCH_INFO_IP:
4483                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4484                         continue;
4485                 case MONO_PATCH_INFO_SWITCH: {
4486                         gpointer *table = (gpointer *)patch_info->data.table->table;
4487                         int i;
4488
4489                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4490
4491                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
4492                                 table [i] = (int)patch_info->data.table->table [i] + code;
4493                         }
4494                         continue;
4495                 }
4496                 case MONO_PATCH_INFO_METHODCONST:
4497                 case MONO_PATCH_INFO_CLASS:
4498                 case MONO_PATCH_INFO_IMAGE:
4499                 case MONO_PATCH_INFO_FIELD:
4500                 case MONO_PATCH_INFO_VTABLE:
4501                 case MONO_PATCH_INFO_IID:
4502                 case MONO_PATCH_INFO_SFLDA:
4503                 case MONO_PATCH_INFO_LDSTR:
4504                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4505                 case MONO_PATCH_INFO_LDTOKEN:
4506                 case MONO_PATCH_INFO_R4:
4507                 case MONO_PATCH_INFO_R8:
4508                         /* from OP_AOTCONST : lui + addiu */
4509                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4510                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4511                         continue;
4512 #if 0
4513                 case MONO_PATCH_INFO_EXC_NAME:
4514                         g_assert_not_reached ();
4515                         *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4516                         continue;
4517 #endif
4518                 case MONO_PATCH_INFO_NONE:
4519                         /* everything is dealt with at epilog output time */
4520                         continue;
4521                 default:
4522                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4523                         mips_patch ((guint32 *)(void *)ip, (guint32)target);
4524                         break;
4525                 }
4526         }
4527 }
4528
4529 #if 0
4530 static
4531 void
4532 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4533 {
4534 }
4535
4536 static
4537 void
4538 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4539 {
4540 }
4541 #endif
4542
4543 /*
4544  * Allow tracing to work with this interface (with an optional argument)
4545  *
4546  * This code is expected to be inserted just after the 'real' prolog code,
4547  * and before the first basic block.  We need to allocate a 2nd, temporary
4548  * stack frame so that we can preserve f12-f15 as well as a0-a3.
4549  */
4550
4551 void*
4552 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4553 {
4554         guchar *code = p;
4555         int offset = cfg->arch.tracing_offset;
4556
4557         mips_nop (code);
4558         mips_nop (code);
4559         mips_nop (code);
4560
4561         /* For N32, need to know for each stack slot if it's an integer
4562          * or float argument, and save/restore the appropriate register
4563          */
4564         MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4565         MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4566         MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4567         MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4568 #if _MIPS_SIM == _ABIN32
4569         MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4570         MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4571         MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4572         MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4573 #endif
4574
4575         mips_load_const (code, mips_a0, cfg->method);
4576         mips_addiu (code, mips_a1, mips_sp, offset);
4577         mips_call (code, mips_t9, func);
4578
4579         MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4580         MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4581         MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4582         MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4583 #if _MIPS_SIM == _ABIN32
4584         MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4585         MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4586         MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4587         MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4588 #endif
4589
4590         mips_nop (code);
4591         mips_nop (code);
4592         mips_nop (code);
4593         return code;
4594 }
4595
4596 void
4597 mips_adjust_stackframe(MonoCompile *cfg)
4598 {
4599         MonoBasicBlock *bb;
4600         int delta, threshold, i;
4601         MonoMethodSignature *sig;
4602         int ra_offset;
4603
4604         if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4605                 return;
4606
4607         /* adjust cfg->stack_offset for account for down-spilling */
4608         cfg->stack_offset += SIZEOF_REGISTER;
4609
4610         /* re-align cfg->stack_offset if needed (due to var spilling) */
4611         cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4612         delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4613         if (cfg->verbose_level > 2) {
4614                 g_print ("mips_adjust_stackframe:\n");
4615                 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4616         }
4617         threshold = cfg->arch.local_alloc_offset;
4618         ra_offset = cfg->stack_offset - sizeof(gpointer);
4619         if (cfg->verbose_level > 2) {
4620                 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4621         }
4622
4623         sig = mono_method_signature (cfg->method);
4624         if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4625                 cfg->vret_addr->inst_offset += delta;
4626         }
4627         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4628                 MonoInst *inst = cfg->args [i];
4629
4630                 inst->inst_offset += delta;
4631         }
4632
4633         /*
4634          * loads and stores based off the frame reg that (used to) lie
4635          * above the spill var area need to be increased by 'delta'
4636          * to make room for the spill vars.
4637          */
4638         /* Need to find loads and stores to adjust that
4639          * are above where the spillvars were inserted, but
4640          * which are not the spillvar references themselves.
4641          *
4642          * Idea - since all offsets from fp are positive, make
4643          * spillvar offsets negative to begin with so we can spot
4644          * them here.
4645          */
4646
4647 #if 1
4648         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4649                 int ins_cnt = 0;
4650                 MonoInst *ins;
4651
4652                 if (cfg->verbose_level > 2) {
4653                         g_print ("BASIC BLOCK %d:\n", bb->block_num);
4654                 }
4655                 MONO_BB_FOR_EACH_INS (bb, ins) {
4656                         int adj_c0 = 0;
4657                         int adj_imm = 0;
4658
4659                         if (cfg->verbose_level > 2) {
4660                                 mono_print_ins_index (ins_cnt, ins);
4661                         }
4662                         /* The == mips_sp tests catch FP spills */
4663                         if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4664                                                           (ins->inst_basereg == mips_sp))) {
4665                                 switch (ins->opcode) {
4666                                 case OP_LOADI8_MEMBASE:
4667                                 case OP_LOADR8_MEMBASE:
4668                                         adj_c0 = 8;
4669                                         break;
4670                                 default:
4671                                         adj_c0 = 4;
4672                                         break;
4673                                 }
4674                         } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4675                                                                   (ins->dreg == mips_sp))) {
4676                                 switch (ins->opcode) {
4677                                 case OP_STOREI8_MEMBASE_REG:
4678                                 case OP_STORER8_MEMBASE_REG:
4679                                 case OP_STOREI8_MEMBASE_IMM:
4680                                         adj_c0 = 8;
4681                                         break;
4682                                 default:
4683                                         adj_c0 = 4;
4684                                         break;
4685                                 }
4686                         }
4687                         if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4688                                 adj_imm = 1;
4689                         if (adj_c0) {
4690                                 if (ins->inst_c0 >= threshold) {
4691                                         ins->inst_c0 += delta;
4692                                         if (cfg->verbose_level > 2) {
4693                                                 g_print ("adj");
4694                                                 mono_print_ins_index (ins_cnt, ins);
4695                                         }
4696                                 }
4697                                 else if (ins->inst_c0 < 0) {
4698                                         /* Adj_c0 holds the size of the datatype. */
4699                                         ins->inst_c0 = - ins->inst_c0 - adj_c0;
4700                                         if (cfg->verbose_level > 2) {
4701                                                 g_print ("spill");
4702                                                 mono_print_ins_index (ins_cnt, ins);
4703                                         }
4704                                 }
4705                                 g_assert (ins->inst_c0 != ra_offset);
4706                         }
4707                         if (adj_imm) {
4708                                 if (ins->inst_imm >= threshold) {
4709                                         ins->inst_imm += delta;
4710                                         if (cfg->verbose_level > 2) {
4711                                                 g_print ("adj");
4712                                                 mono_print_ins_index (ins_cnt, ins);
4713                                         }
4714                                 }
4715                                 g_assert (ins->inst_c0 != ra_offset);
4716                         }
4717
4718                         ++ins_cnt;
4719                 }
4720         }
4721 #endif
4722 }
4723
4724 /*
4725  * Stack frame layout:
4726  * 
4727  *   ------------------- sp + cfg->stack_usage + cfg->param_area
4728  *      param area              incoming
4729  *   ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4730  *      a0-a3                   incoming
4731  *   ------------------- sp + cfg->stack_usage
4732  *      ra
4733  *   ------------------- sp + cfg->stack_usage-4
4734  *      spilled regs
4735  *   ------------------- sp + 
4736  *      MonoLMF structure       optional
4737  *   ------------------- sp + cfg->arch.lmf_offset
4738  *      saved registers         s0-s8
4739  *   ------------------- sp + cfg->arch.iregs_offset
4740  *      locals
4741  *   ------------------- sp + cfg->param_area
4742  *      param area              outgoing
4743  *   ------------------- sp + MIPS_STACK_PARAM_OFFSET
4744  *      a0-a3                   outgoing
4745  *   ------------------- sp
4746  *      red zone
4747  */
4748 guint8 *
4749 mono_arch_emit_prolog (MonoCompile *cfg)
4750 {
4751         MonoMethod *method = cfg->method;
4752         MonoMethodSignature *sig;
4753         MonoInst *inst;
4754         int alloc_size, pos, i;
4755         int alloc2_size = 0;
4756         guint8 *code;
4757         CallInfo *cinfo;
4758         int tracing = 0;
4759         guint32 iregs_to_save = 0;
4760 #if SAVE_FP_REGS
4761         guint32 fregs_to_save = 0;
4762 #endif
4763 #if SAVE_LMF
4764         /* lmf_offset is the offset of the LMF from our stack pointer. */
4765         guint32 lmf_offset = cfg->arch.lmf_offset;
4766 #endif
4767         int cfa_offset = 0;
4768
4769         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4770                 tracing = 1;
4771
4772         if (tracing)
4773                 cfg->flags |= MONO_CFG_HAS_CALLS;
4774         
4775         sig = mono_method_signature (method);
4776         cfg->code_size = 768 + sig->param_count * 20;
4777         code = cfg->native_code = g_malloc (cfg->code_size);
4778
4779         if (tracing) {
4780 #if _MIPS_SIM == _ABIO32
4781                 cfg->arch.tracing_offset = cfg->stack_offset;
4782 #elif _MIPS_SIM == _ABIN32
4783                 /* no stack slots by default for argument regs, reserve a special block */
4784                 cfg->arch.tracing_offset = cfg->stack_offset;
4785                 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4786 #endif
4787         }
4788
4789         /* adjust stackframe assignments for spillvars if needed */
4790         mips_adjust_stackframe (cfg);
4791
4792         /* Offset between current sp and the CFA */
4793         cfa_offset = 0;
4794         mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4795
4796         /* stack_offset should not be changed here. */
4797         alloc_size = cfg->stack_offset;
4798         cfg->stack_usage = alloc_size;
4799
4800 #if SAVE_ALL_REGS
4801         iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4802 #else
4803         iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4804 #endif
4805 #if SAVE_FP_REGS
4806 #if 0
4807         fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4808 #else
4809         fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4810         fregs_to_save |= (fregs_to_save << 1);
4811 #endif
4812 #endif
4813         /* If the stack size is too big, save 1024 bytes to start with
4814          * so the prologue can use imm16(reg) addressing, then allocate
4815          * the rest of the frame.
4816          */
4817         if (alloc_size > ((1 << 15) - 1024)) {
4818                 alloc2_size = alloc_size - 1024;
4819                 alloc_size = 1024;
4820         }
4821         if (alloc_size) {
4822                 g_assert (mips_is_imm16 (-alloc_size));
4823                 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4824                 cfa_offset = alloc_size;
4825                 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4826         }
4827
4828         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4829                 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4830                 if (mips_is_imm16(offset))
4831                         mips_sw (code, mips_ra, mips_sp, offset);
4832                 else {
4833                         g_assert_not_reached ();
4834                 }
4835                 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4836                 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4837         }
4838
4839         /* XXX - optimize this later to not save all regs if LMF constructed */
4840         pos = cfg->arch.iregs_offset - alloc2_size;
4841
4842         if (iregs_to_save) {
4843                 /* save used registers in own stack frame (at pos) */
4844                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4845                         if (iregs_to_save & (1 << i)) {
4846                                 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4847                                 g_assert (mips_is_imm16(pos));
4848                                 MIPS_SW (code, i, mips_sp, pos);
4849                                 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4850                                 pos += SIZEOF_REGISTER;
4851                         }
4852                 }
4853         }
4854 #if SAVE_LMF
4855         if (method->save_lmf) {
4856                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4857                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4858                         g_assert (mips_is_imm16(offset));
4859                         MIPS_SW (code, i, mips_sp, offset);
4860                 }
4861         }
4862 #endif
4863
4864 #if SAVE_FP_REGS
4865         /* Save float registers */
4866         if (fregs_to_save) {
4867                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4868                         if (fregs_to_save & (1 << i)) {
4869                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4870                                 g_assert (mips_is_imm16(pos));
4871                                 mips_swc1 (code, i, mips_sp, pos);
4872                                 pos += sizeof (gulong);
4873                         }
4874                 }
4875         }
4876 #if SAVE_LMF
4877         if (method->save_lmf) {
4878                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4879                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4880                         g_assert (mips_is_imm16(offset));
4881                         mips_swc1 (code, i, mips_sp, offset);
4882                 }
4883         }
4884 #endif
4885 #endif
4886         if (cfg->frame_reg != mips_sp) {
4887                 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4888                 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4889 #if SAVE_LMF
4890                 if (method->save_lmf) {
4891                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4892                         g_assert (mips_is_imm16(offset));
4893                         MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4894                 }
4895 #endif
4896         }
4897
4898         /* Do instrumentation before assigning regvars to registers.  Because they may be assigned
4899          * to the t* registers, which would be clobbered by the instrumentation calls.
4900          */
4901         if (tracing) {
4902                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4903         }
4904
4905
4906         /* load arguments allocated to register from the stack */
4907         pos = 0;
4908
4909         if (!cfg->arch.cinfo)
4910                 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
4911         cinfo = cfg->arch.cinfo;
4912
4913         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4914                 ArgInfo *ainfo = &cinfo->ret;
4915                 inst = cfg->vret_addr;
4916                 if (inst->opcode == OP_REGVAR)
4917                         MIPS_MOVE (code, inst->dreg, ainfo->reg);
4918                 else if (mips_is_imm16 (inst->inst_offset)) {
4919                         mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4920                 } else {
4921                         mips_load_const (code, mips_at, inst->inst_offset);
4922                         mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4923                         mips_sw (code, ainfo->reg, mips_at, 0);
4924                 }
4925         }
4926         /* Keep this in sync with emit_load_volatile_arguments */
4927         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4928                 ArgInfo *ainfo = cinfo->args + i;
4929                 inst = cfg->args [pos];
4930                 
4931                 if (cfg->verbose_level > 2)
4932                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
4933                 if (inst->opcode == OP_REGVAR) {
4934                         /* Argument ends up in a register */
4935                         if (ainfo->storage == ArgInIReg)
4936                                 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4937                         else if (ainfo->storage == ArgInFReg) {
4938                                 g_assert_not_reached();
4939 #if 0
4940                                 ppc_fmr (code, inst->dreg, ainfo->reg);
4941 #endif
4942                         }
4943                         else if (ainfo->storage == ArgOnStack) {
4944                                 int offset = cfg->stack_usage + ainfo->offset;
4945                                 g_assert (mips_is_imm16(offset));
4946                                 mips_lw (code, inst->dreg, mips_sp, offset);
4947                         } else
4948                                 g_assert_not_reached ();
4949
4950                         if (cfg->verbose_level > 2)
4951                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4952                 } else {
4953                         /* Argument ends up on the stack */
4954                         if (ainfo->storage == ArgInIReg) {
4955                                 int basereg_offset;
4956                                 /* Incoming parameters should be above this frame */
4957                                 if (cfg->verbose_level > 2)
4958                                         g_print ("stack slot at %d of %d+%d\n",
4959                                                  inst->inst_offset, alloc_size, alloc2_size);
4960                                 /* g_assert (inst->inst_offset >= alloc_size); */
4961                                 g_assert (inst->inst_basereg == mips_fp);
4962                                 basereg_offset = inst->inst_offset - alloc2_size;
4963                                 g_assert (mips_is_imm16 (basereg_offset));
4964                                 switch (ainfo->size) {
4965                                 case 1:
4966                                         mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4967                                         break;
4968                                 case 2:
4969                                         mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4970                                         break;
4971                                 case 0: /* XXX */
4972                                 case 4:
4973                                         mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4974                                         break;
4975                                 case 8:
4976 #if (SIZEOF_REGISTER == 4)
4977                                         mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
4978                                         mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
4979 #elif (SIZEOF_REGISTER == 8)
4980                                         mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4981 #endif
4982                                         break;
4983                                 default:
4984                                         g_assert_not_reached ();
4985                                         break;
4986                                 }
4987                         } else if (ainfo->storage == ArgOnStack) {
4988                                 /*
4989                                  * Argument comes in on the stack, and ends up on the stack
4990                                  * 1 and 2 byte args are passed as 32-bit quantities, but used as
4991                                  * 8 and 16 bit quantities.  Shorten them in place.
4992                                  */
4993                                 g_assert (mips_is_imm16 (inst->inst_offset));
4994                                 switch (ainfo->size) {
4995                                 case 1:
4996                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4997                                         mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4998                                         break;
4999                                 case 2:
5000                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5001                                         mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5002                                         break;
5003                                 case 0: /* XXX */
5004                                 case 4:
5005                                 case 8:
5006                                         break;
5007                                 default:
5008                                         g_assert_not_reached ();
5009                                 }
5010                         } else if (ainfo->storage == ArgInFReg) {
5011                                 g_assert (mips_is_imm16 (inst->inst_offset));
5012                                 g_assert (mips_is_imm16 (inst->inst_offset+4));
5013                                 if (ainfo->size == 8) {
5014 #if _MIPS_SIM == _ABIO32
5015                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5016                                         mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5017 #elif _MIPS_SIM == _ABIN32
5018                                         mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5019 #endif
5020                                 }
5021                                 else if (ainfo->size == 4)
5022                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5023                                 else
5024                                         g_assert_not_reached ();
5025                         } else if (ainfo->storage == ArgStructByVal) {
5026                                 int i;
5027                                 int doffset = inst->inst_offset;
5028
5029                                 g_assert (mips_is_imm16 (inst->inst_offset));
5030                                 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5031                                 /* Push the argument registers into their stack slots */
5032                                 for (i = 0; i < ainfo->size; ++i) {
5033                                         g_assert (mips_is_imm16(doffset));
5034                                         MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5035                                         doffset += SIZEOF_REGISTER;
5036                                 }
5037                         } else if (ainfo->storage == ArgStructByAddr) {
5038                                 g_assert (mips_is_imm16 (inst->inst_offset));
5039                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5040                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5041                         } else
5042                                 g_assert_not_reached ();
5043                 }
5044                 pos++;
5045         }
5046
5047         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
5048                 mips_load_const (code, mips_a0, cfg->domain);
5049                 mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
5050         }
5051
5052 #if SAVE_LMF
5053         if (method->save_lmf) {
5054                 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5055                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5056
5057                 if (lmf_pthread_key != -1) {
5058                         g_assert_not_reached();
5059 #if 0
5060                         emit_tls_access (code, mips_temp, lmf_pthread_key);
5061 #endif
5062                         if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5063                                 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5064                                 g_assert (mips_is_imm16(offset));
5065                                 mips_addiu (code, mips_a0, mips_temp, offset);
5066                         }
5067                 } else {
5068                         /* This can/will clobber the a0-a3 registers */
5069                         mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5070                 }
5071
5072                 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5073                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5074                 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5075                 /* new_lmf->previous_lmf = *lmf_addr */
5076                 mips_lw (code, mips_at, mips_v0, 0);
5077                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5078                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5079                 /* *(lmf_addr) = sp + lmf_offset */
5080                 g_assert (mips_is_imm16(lmf_offset));
5081                 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5082                 mips_sw (code, mips_at, mips_v0, 0);
5083
5084                 /* save method info */
5085                 mips_load_const (code, mips_at, method);
5086                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5087                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5088                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
5089                 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
5090
5091                 /* save the current IP */
5092                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5093                 mips_load_const (code, mips_at, 0x01010101);
5094                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5095         }
5096 #endif
5097         if (alloc2_size) {
5098                 /* The CFA is fp now, so this doesn't need unwind info */
5099                 if (mips_is_imm16 (-alloc2_size)) {
5100                         mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5101                 }
5102                 else {
5103                         mips_load_const (code, mips_at, -alloc2_size);
5104                         mips_addu (code, mips_sp, mips_sp, mips_at);
5105                 }
5106                 if (cfg->frame_reg != mips_sp)
5107                         MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5108                 alloc_size += alloc2_size;
5109         }
5110
5111         cfg->code_len = code - cfg->native_code;
5112         g_assert (cfg->code_len < cfg->code_size);
5113
5114         return code;
5115 }
5116
5117 enum {
5118         SAVE_NONE,
5119         SAVE_STRUCT,
5120         SAVE_ONE,
5121         SAVE_TWO,
5122         SAVE_FP
5123 };
5124
5125 void*
5126 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5127 {
5128         guchar *code = p;
5129         int save_mode = SAVE_NONE;
5130         int offset;
5131         MonoMethod *method = cfg->method;
5132         int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5133         int save_offset = MIPS_STACK_PARAM_OFFSET;
5134
5135         g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5136         
5137         offset = code - cfg->native_code;
5138         /* we need about 16 instructions */
5139         if (offset > (cfg->code_size - 16 * 4)) {
5140                 cfg->code_size *= 2;
5141                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5142                 code = cfg->native_code + offset;
5143         }
5144         mips_nop (code);
5145         mips_nop (code);
5146         switch (rtype) {
5147         case MONO_TYPE_VOID:
5148                 /* special case string .ctor icall */
5149                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5150                         save_mode = SAVE_ONE;
5151                 else
5152                         save_mode = SAVE_NONE;
5153                 break;
5154         case MONO_TYPE_R4:
5155         case MONO_TYPE_R8:
5156                 save_mode = SAVE_FP;
5157                 break;
5158         case MONO_TYPE_VALUETYPE:
5159                 save_mode = SAVE_STRUCT;
5160                 break;
5161         case MONO_TYPE_I8:
5162         case MONO_TYPE_U8:
5163 #if SIZEOF_REGISTER == 4
5164                 save_mode = SAVE_TWO;
5165 #elif SIZEOF_REGISTER == 8
5166                 save_mode = SAVE_ONE;
5167 #endif
5168                 break;
5169         default:
5170                 save_mode = SAVE_ONE;
5171                 break;
5172         }
5173
5174         mips_addiu (code, mips_sp, mips_sp, -32);
5175         g_assert (mips_is_imm16(save_offset));
5176         switch (save_mode) {
5177         case SAVE_TWO:
5178                 mips_sw (code, mips_v0, mips_sp, save_offset);
5179                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5180                 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5181                 if (enable_arguments) {
5182                         MIPS_MOVE (code, mips_a1, mips_v0);
5183                         MIPS_MOVE (code, mips_a2, mips_v1);
5184                 }
5185                 break;
5186         case SAVE_ONE:
5187                 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5188                 if (enable_arguments) {
5189                         MIPS_MOVE (code, mips_a1, mips_v0);
5190                 }
5191                 break;
5192         case SAVE_FP:
5193                 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5194                 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5195                 mips_lw (code, mips_a0, mips_sp, save_offset);
5196                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5197                 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5198                 break;
5199         case SAVE_STRUCT:
5200         case SAVE_NONE:
5201         default:
5202                 break;
5203         }
5204         mips_load_const (code, mips_a0, cfg->method);
5205         mips_call (code, mips_t9, func);
5206
5207         switch (save_mode) {
5208         case SAVE_TWO:
5209                 mips_lw (code, mips_v0, mips_sp, save_offset);
5210                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5211                 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5212                 break;
5213         case SAVE_ONE:
5214                 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5215                 break;
5216         case SAVE_FP:
5217                 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5218                 break;
5219         case SAVE_STRUCT:
5220         case SAVE_NONE:
5221         default:
5222                 break;
5223         }
5224         mips_addiu (code, mips_sp, mips_sp, 32);
5225         mips_nop (code);
5226         mips_nop (code);
5227         return code;
5228 }
5229
5230 guint8 *
5231 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5232 {
5233         MonoMethod *method = cfg->method;
5234         int pos = 0, i;
5235         int max_epilog_size = 16 + 20*4;
5236         int alloc2_size = 0;
5237         guint32 iregs_to_restore;
5238 #if SAVE_FP_REGS
5239         guint32 fregs_to_restore;
5240 #endif
5241
5242 #if SAVE_LMF
5243         if (cfg->method->save_lmf)
5244                 max_epilog_size += 128;
5245 #endif
5246         
5247         if (mono_jit_trace_calls != NULL)
5248                 max_epilog_size += 50;
5249
5250         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5251                 max_epilog_size += 50;
5252
5253         if (code)
5254                 pos = code - cfg->native_code;
5255         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5256                 cfg->code_size *= 2;
5257                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5258                 cfg->stat_code_reallocs++;
5259         }
5260
5261         /*
5262          * Keep in sync with OP_JMP
5263          */
5264         if (code)
5265                 code = cfg->native_code + pos;
5266         else
5267                 code = cfg->native_code + cfg->code_len;
5268
5269         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5270                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5271         }
5272         if (cfg->frame_reg != mips_sp) {
5273                 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5274         }
5275         /* If the stack frame is really large, deconstruct it in two steps */
5276         if (cfg->stack_usage > ((1 << 15) - 1024)) {
5277                 alloc2_size = cfg->stack_usage - 1024;
5278                 /* partially deconstruct the stack */
5279                 mips_load_const (code, mips_at, alloc2_size);
5280                 mips_addu (code, mips_sp, mips_sp, mips_at);
5281         }
5282         pos = cfg->arch.iregs_offset - alloc2_size;
5283 #if SAVE_ALL_REGS
5284         iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5285 #else
5286         iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5287 #endif
5288         if (iregs_to_restore) {
5289                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5290                         if (iregs_to_restore & (1 << i)) {
5291                                 g_assert (mips_is_imm16(pos));
5292                                 MIPS_LW (code, i, mips_sp, pos);
5293                                 pos += SIZEOF_REGISTER;
5294                         }
5295                 }
5296         }
5297
5298 #if SAVE_FP_REGS
5299 #if 0
5300         fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5301 #else
5302         fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5303         fregs_to_restore |= (fregs_to_restore << 1);
5304 #endif
5305         if (fregs_to_restore) {
5306                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5307                         if (fregs_to_restore & (1 << i)) {
5308                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5309                                 g_assert (mips_is_imm16(pos));
5310                                 mips_lwc1 (code, i, mips_sp, pos);
5311                                 pos += FREG_SIZE
5312                         }
5313                 }
5314         }
5315 #endif
5316 #if SAVE_LMF
5317         /* Unlink the LMF if necessary */
5318         if (method->save_lmf) {
5319                 int lmf_offset = cfg->arch.lmf_offset;
5320
5321                 /* t0 = current_lmf->previous_lmf */
5322                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5323                 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5324                 /* t1 = lmf_addr */
5325                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5326                 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5327                 /* (*lmf_addr) = previous_lmf */
5328                 mips_sw (code, mips_temp, mips_t1, 0);
5329         }
5330 #endif
5331 #if 0
5332         /* Restore the fp */
5333         mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5334 #endif
5335         /* Restore ra */
5336         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5337                 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5338                 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5339         }
5340         /* Restore the stack pointer */
5341         g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5342         mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5343
5344         /* Caller will emit either return or tail-call sequence */
5345
5346         cfg->code_len = code - cfg->native_code;
5347
5348         g_assert (cfg->code_len < cfg->code_size);
5349         return (code);
5350 }
5351
5352 void
5353 mono_arch_emit_epilog (MonoCompile *cfg)
5354 {
5355         guint8 *code;
5356
5357         code = mono_arch_emit_epilog_sub (cfg, NULL);
5358
5359         mips_jr (code, mips_ra);
5360         mips_nop (code);
5361
5362         cfg->code_len = code - cfg->native_code;
5363
5364         g_assert (cfg->code_len < cfg->code_size);
5365 }
5366
5367 /* remove once throw_exception_by_name is eliminated */
5368 #if 0
5369 static int
5370 exception_id_by_name (const char *name)
5371 {
5372         if (strcmp (name, "IndexOutOfRangeException") == 0)
5373                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5374         if (strcmp (name, "OverflowException") == 0)
5375                 return MONO_EXC_OVERFLOW;
5376         if (strcmp (name, "ArithmeticException") == 0)
5377                 return MONO_EXC_ARITHMETIC;
5378         if (strcmp (name, "DivideByZeroException") == 0)
5379                 return MONO_EXC_DIVIDE_BY_ZERO;
5380         if (strcmp (name, "InvalidCastException") == 0)
5381                 return MONO_EXC_INVALID_CAST;
5382         if (strcmp (name, "NullReferenceException") == 0)
5383                 return MONO_EXC_NULL_REF;
5384         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5385                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5386         if (strcmp (name, "ArgumentException") == 0)
5387                 return MONO_EXC_ARGUMENT;
5388         g_error ("Unknown intrinsic exception %s\n", name);
5389         return 0;
5390 }
5391 #endif
5392
5393 void
5394 mono_arch_emit_exceptions (MonoCompile *cfg)
5395 {
5396 #if 0
5397         MonoJumpInfo *patch_info;
5398         int i;
5399         guint8 *code;
5400         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5401         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5402         int max_epilog_size = 50;
5403
5404         /* count the number of exception infos */
5405      
5406         /* 
5407          * make sure we have enough space for exceptions
5408          * 24 is the simulated call to throw_exception_by_name
5409          */
5410         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5411 #if 0
5412                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5413                         i = exception_id_by_name (patch_info->data.target);
5414                         g_assert (i < MONO_EXC_INTRINS_NUM);
5415                         if (!exc_throw_found [i]) {
5416                                 max_epilog_size += 12;
5417                                 exc_throw_found [i] = TRUE;
5418                         }
5419                 }
5420 #endif
5421         }
5422
5423         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5424                 cfg->code_size *= 2;
5425                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5426                 cfg->stat_code_reallocs++;
5427         }
5428
5429         code = cfg->native_code + cfg->code_len;
5430
5431         /* add code to raise exceptions */
5432         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5433                 switch (patch_info->type) {
5434                 case MONO_PATCH_INFO_EXC: {
5435 #if 0
5436                         //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5437
5438                         i = exception_id_by_name (patch_info->data.target);
5439                         g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5440                         if (!exc_throw_pos [i]) {
5441                                 guint32 addr;
5442
5443                                 exc_throw_pos [i] = code;
5444                                 //g_print ("exc: writing stub at %p\n", code);
5445                                 mips_load_const (code, mips_a0, patch_info->data.target);
5446                                 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5447                                 mips_load_const (code, mips_t9, addr);
5448                                 mips_jr (code, mips_t9);
5449                                 mips_nop (code);
5450                         }
5451                         //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5452
5453                         /* Turn into a Relative patch, pointing at code stub */
5454                         patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5455                         patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5456 #else
5457                         g_assert_not_reached();
5458 #endif
5459                         break;
5460                 }
5461                 default:
5462                         /* do nothing */
5463                         break;
5464                 }
5465         }
5466
5467         cfg->code_len = code - cfg->native_code;
5468
5469         g_assert (cfg->code_len < cfg->code_size);
5470 #endif
5471 }
5472
5473 /*
5474  * Thread local storage support
5475  */
5476 static void
5477 setup_tls_access (void)
5478 {
5479         guint32 ptk;
5480         //guint32 *ins, *code;
5481
5482         if (tls_mode == TLS_MODE_FAILED)
5483                 return;
5484
5485         if (g_getenv ("MONO_NO_TLS")) {
5486                 tls_mode = TLS_MODE_FAILED;
5487                 return;
5488         }
5489
5490         if (tls_mode == TLS_MODE_DETECT) {
5491                 /* XXX */
5492                 tls_mode = TLS_MODE_FAILED;
5493                 return;
5494 #if 0
5495
5496                 ins = (guint32*)pthread_getspecific;
5497                 /* uncond branch to the real method */
5498                 if ((*ins >> 26) == 18) {
5499                         gint32 val;
5500                         val = (*ins & ~3) << 6;
5501                         val >>= 6;
5502                         if (*ins & 2) {
5503                                 /* absolute */
5504                                 ins = (guint32*)val;
5505                         } else {
5506                                 ins = (guint32*) ((char*)ins + val);
5507                         }
5508                 }
5509                 code = &cmplwi_1023;
5510                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5511                 code = &li_0x48;
5512                 ppc_li (code, ppc_r4, 0x48);
5513                 code = &blr_ins;
5514                 ppc_blr (code);
5515                 if (*ins == cmplwi_1023) {
5516                         int found_lwz_284 = 0;
5517                         for (ptk = 0; ptk < 20; ++ptk) {
5518                                 ++ins;
5519                                 if (!*ins || *ins == blr_ins)
5520                                         break;
5521                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5522                                         found_lwz_284 = 1;
5523                                         break;
5524                                 }
5525                         }
5526                         if (!found_lwz_284) {
5527                                 tls_mode = TLS_MODE_FAILED;
5528                                 return;
5529                         }
5530                         tls_mode = TLS_MODE_LTHREADS;
5531                 } else if (*ins == li_0x48) {
5532                         ++ins;
5533                         /* uncond branch to the real method */
5534                         if ((*ins >> 26) == 18) {
5535                                 gint32 val;
5536                                 val = (*ins & ~3) << 6;
5537                                 val >>= 6;
5538                                 if (*ins & 2) {
5539                                         /* absolute */
5540                                         ins = (guint32*)val;
5541                                 } else {
5542                                         ins = (guint32*) ((char*)ins + val);
5543                                 }
5544                                 code = &val;
5545                                 ppc_li (code, ppc_r0, 0x7FF2);
5546                                 if (ins [1] == val) {
5547                                         /* Darwin on G4, implement */
5548                                         tls_mode = TLS_MODE_FAILED;
5549                                         return;
5550                                 } else {
5551                                         code = &val;
5552                                         ppc_mfspr (code, ppc_r3, 104);
5553                                         if (ins [1] != val) {
5554                                                 tls_mode = TLS_MODE_FAILED;
5555                                                 return;
5556                                         }
5557                                         tls_mode = TLS_MODE_DARWIN_G5;
5558                                 }
5559                         } else {
5560                                 tls_mode = TLS_MODE_FAILED;
5561                                 return;
5562                         }
5563                 } else {
5564                         tls_mode = TLS_MODE_FAILED;
5565                         return;
5566                 }
5567 #endif
5568         }
5569         if (monodomain_key == -1) {
5570                 ptk = mono_domain_get_tls_key ();
5571                 if (ptk < 1024)
5572                         monodomain_key = ptk;
5573         }
5574         if (lmf_pthread_key == -1) {
5575                 ptk = mono_jit_tls_id;
5576                 if (ptk < 1024) {
5577                         /*g_print ("MonoLMF at: %d\n", ptk);*/
5578                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5579                                 init_tls_failed = 1;
5580                                 return;
5581                         }*/
5582                         lmf_pthread_key = ptk;
5583                 }
5584         }
5585         if (monothread_key == -1) {
5586                 ptk = mono_thread_get_tls_key ();
5587                 if (ptk < 1024) {
5588                         monothread_key = ptk;
5589                         /*g_print ("thread inited: %d\n", ptk);*/
5590                 } else {
5591                         /*g_print ("thread not inited yet %d\n", ptk);*/
5592                 }
5593         }
5594 }
5595
5596 void
5597 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5598 {
5599         setup_tls_access ();
5600 }
5601
5602 void
5603 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5604 {
5605 }
5606
5607 void
5608 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5609 {
5610         int this_dreg = mips_a0;
5611         
5612         if (vt_reg != -1)
5613                 this_dreg = mips_a1;
5614
5615         /* add the this argument */
5616         if (this_reg != -1) {
5617                 MonoInst *this;
5618                 MONO_INST_NEW (cfg, this, OP_MOVE);
5619                 this->type = this_type;
5620                 this->sreg1 = this_reg;
5621                 this->dreg = mono_alloc_ireg (cfg);
5622                 mono_bblock_add_inst (cfg->cbb, this);
5623                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5624         }
5625
5626         if (vt_reg != -1) {
5627                 MonoInst *vtarg;
5628                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5629                 vtarg->type = STACK_MP;
5630                 vtarg->sreg1 = vt_reg;
5631                 vtarg->dreg = mono_alloc_ireg (cfg);
5632                 mono_bblock_add_inst (cfg->cbb, vtarg);
5633                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5634         }
5635 }
5636
5637 MonoInst*
5638 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5639 {
5640         MonoInst *ins = NULL;
5641
5642         return ins;
5643 }
5644
5645 MonoInst*
5646 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5647 {
5648         return NULL;
5649 }
5650
5651 gboolean
5652 mono_arch_print_tree (MonoInst *tree, int arity)
5653 {
5654         return 0;
5655 }
5656
5657 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5658 {
5659         MonoInst* ins;
5660
5661         setup_tls_access ();
5662         if (monodomain_key == -1)
5663                 return NULL;
5664         
5665         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5666         ins->inst_offset = monodomain_key;
5667         return ins;
5668 }
5669
5670 mgreg_t
5671 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5672 {
5673         return ctx->sc_regs [reg];
5674 }
5675
5676 #ifdef MONO_ARCH_HAVE_IMT
5677
5678 #define ENABLE_WRONG_METHOD_CHECK 0
5679
5680 #define MIPS_LOAD_SEQUENCE_LENGTH       8
5681 #define CMP_SIZE                        (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5682 #define BR_SIZE                         8
5683 #define LOADSTORE_SIZE                  4
5684 #define JUMP_IMM_SIZE                   16
5685 #define JUMP_IMM32_SIZE                 (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5686 #define LOAD_CONST_SIZE                 8
5687 #define JUMP_JR_SIZE                    8
5688
5689 /*
5690  * LOCKING: called with the domain lock held
5691  */
5692 gpointer
5693 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5694         gpointer fail_tramp)
5695 {
5696         int i;
5697         int size = 0;
5698         guint8 *code, *start, *patch;
5699
5700         for (i = 0; i < count; ++i) {
5701                 MonoIMTCheckItem *item = imt_entries [i];
5702
5703                 if (item->is_equals) {
5704                         if (item->check_target_idx) {
5705                                 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5706                                 if (item->has_target_code)
5707                                         item->chunk_size += LOAD_CONST_SIZE;
5708                                 else
5709                                         item->chunk_size += LOADSTORE_SIZE;
5710                         } else {
5711                                 if (fail_tramp) {
5712                                         item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5713                                                 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5714                                         if (!item->has_target_code)
5715                                                 item->chunk_size += LOADSTORE_SIZE;
5716                                 } else {
5717                                         item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5718 #if ENABLE_WRONG_METHOD_CHECK
5719                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5720 #endif
5721                                 }
5722                         }
5723                 } else {
5724                         item->chunk_size += CMP_SIZE + BR_SIZE;
5725                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5726                 }
5727                 size += item->chunk_size;
5728         }
5729         /* the initial load of the vtable address */
5730         size += MIPS_LOAD_SEQUENCE_LENGTH;
5731         if (fail_tramp) {
5732                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5733         } else {
5734                 code = mono_domain_code_reserve (domain, size);
5735         }
5736         start = code;
5737
5738 #if 0
5739         /*
5740          * We need to save and restore r11 because it might be
5741          * used by the caller as the vtable register, so
5742          * clobbering it will trip up the magic trampoline.
5743          *
5744          * FIXME: Get rid of this by making sure that r11 is
5745          * not used as the vtable register in interface calls.
5746          */
5747         ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5748         ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5749 #endif
5750         /* t7 points to the vtable */
5751         mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5752
5753         for (i = 0; i < count; ++i) {
5754                 MonoIMTCheckItem *item = imt_entries [i];
5755
5756                 item->code_target = code;
5757                 if (item->is_equals) {
5758                         if (item->check_target_idx) {
5759                                 mips_load_const (code, mips_temp, (gsize)item->key);
5760                                 item->jmp_code = code;
5761                                 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5762                                 mips_nop (code);
5763                                 if (item->has_target_code) {
5764                                         mips_load_const (code, mips_t9,
5765                                                          item->value.target_code);
5766                                 }
5767                                 else {
5768                                         mips_lw (code, mips_t9, mips_t7,
5769                                                 (sizeof (gpointer) * item->value.vtable_slot));
5770                                 }
5771                                 mips_jr (code, mips_t9);
5772                                 mips_nop (code);
5773                         } else {
5774                                 if (fail_tramp) {
5775                                         mips_load_const (code, mips_temp, (gsize)item->key);
5776                                         patch = code;
5777                                         mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5778                                         mips_nop (code);
5779                                         if (item->has_target_code) {
5780                                                 mips_load_const (code, mips_t9,
5781                                                                  item->value.target_code);
5782                                         } else {
5783                                                 g_assert (vtable);
5784                                                 mips_load_const (code, mips_at,
5785                                                                  & (vtable->vtable [item->value.vtable_slot]));
5786                                                 mips_lw (code, mips_t9, mips_at, 0);
5787                                         }
5788                                         mips_jr (code, mips_t9);
5789                                         mips_nop (code);
5790                                         mips_patch ((guint32 *)(void *)patch, (guint32)code);
5791                                         mips_load_const (code, mips_at, fail_tramp);
5792                                         mips_lw (code, mips_t9, mips_at, 0);
5793                                         mips_jr (code, mips_t9);
5794                                         mips_nop (code);
5795                                 } else {
5796                                         /* enable the commented code to assert on wrong method */
5797 #if ENABLE_WRONG_METHOD_CHECK
5798                                         ppc_load (code, ppc_r0, (guint32)item->key);
5799                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5800                                         patch = code;
5801                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5802 #endif
5803                                         mips_lw (code, mips_t9, mips_t7,
5804                                                  (sizeof (gpointer) * item->value.vtable_slot));
5805                                         mips_jr (code, mips_t9);
5806                                         mips_nop (code);
5807
5808 #if ENABLE_WRONG_METHOD_CHECK
5809                                         ppc_patch (patch, code);
5810                                         ppc_break (code);
5811 #endif
5812                                 }
5813                         }
5814                 } else {
5815                         mips_load_const (code, mips_temp, (gulong)item->key);
5816                         mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5817
5818                         item->jmp_code = code;
5819                         mips_beq (code, mips_temp, mips_zero, 0);
5820                         mips_nop (code);
5821                 }
5822         }
5823         /* patch the branches to get to the target items */
5824         for (i = 0; i < count; ++i) {
5825                 MonoIMTCheckItem *item = imt_entries [i];
5826                 if (item->jmp_code && item->check_target_idx) {
5827                         mips_patch ((guint32 *)item->jmp_code,
5828                                    (guint32)imt_entries [item->check_target_idx]->code_target);
5829                 }
5830         }
5831
5832         if (!fail_tramp)
5833                 mono_stats.imt_thunks_size += code - start;
5834         g_assert (code - start <= size);
5835         mono_arch_flush_icache (start, size);
5836         return start;
5837 }
5838
5839 MonoMethod*
5840 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5841 {
5842         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5843 }
5844 #endif
5845
5846 MonoVTable*
5847 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5848 {
5849         NOT_IMPLEMENTED;
5850         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5851 }
5852
5853 /* Soft Debug support */
5854 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5855
5856 /*
5857  * mono_arch_set_breakpoint:
5858  *
5859  *   See mini-amd64.c for docs.
5860  */
5861 void
5862 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5863 {
5864         guint8 *code = ip;
5865         guint32 addr = (guint32)bp_trigger_page;
5866
5867         mips_load_const (code, mips_t9, addr);
5868         mips_lw (code, mips_t9, mips_t9, 0);
5869
5870         mono_arch_flush_icache (ip, code - ip);
5871 }
5872
5873 /*
5874  * mono_arch_clear_breakpoint:
5875  *
5876  *   See mini-amd64.c for docs.
5877  */
5878 void
5879 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5880 {
5881         guint8 *code = ip;
5882
5883         mips_nop (code);
5884         mips_nop (code);
5885         mips_nop (code);
5886
5887         mono_arch_flush_icache (ip, code - ip);
5888 }
5889         
5890 /*
5891  * mono_arch_start_single_stepping:
5892  *
5893  *   See mini-amd64.c for docs.
5894  */
5895 void
5896 mono_arch_start_single_stepping (void)
5897 {
5898         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5899 }
5900         
5901 /*
5902  * mono_arch_stop_single_stepping:
5903  *
5904  *   See mini-amd64.c for docs.
5905  */
5906 void
5907 mono_arch_stop_single_stepping (void)
5908 {
5909         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5910 }
5911
5912 /*
5913  * mono_arch_is_single_step_event:
5914  *
5915  *   See mini-amd64.c for docs.
5916  */
5917 gboolean
5918 mono_arch_is_single_step_event (void *info, void *sigctx)
5919 {
5920         siginfo_t* sinfo = (siginfo_t*) info;
5921         /* Sometimes the address is off by 4 */
5922         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5923                 return TRUE;
5924         else
5925                 return FALSE;
5926 }
5927
5928 /*
5929  * mono_arch_is_breakpoint_event:
5930  *
5931  *   See mini-amd64.c for docs.
5932  */
5933 gboolean
5934 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5935 {
5936         siginfo_t* sinfo = (siginfo_t*) info;
5937         /* Sometimes the address is off by 4 */
5938         if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5939                 return TRUE;
5940         else
5941                 return FALSE;
5942 }
5943
5944 /*
5945  * mono_arch_skip_breakpoint:
5946  *
5947  *   See mini-amd64.c for docs.
5948  */
5949 void
5950 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5951 {
5952         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5953 }
5954
5955 /*
5956  * mono_arch_skip_single_step:
5957  *
5958  *   See mini-amd64.c for docs.
5959  */
5960 void
5961 mono_arch_skip_single_step (MonoContext *ctx)
5962 {
5963         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5964 }
5965
5966 /*
5967  * mono_arch_get_seq_point_info:
5968  *
5969  *   See mini-amd64.c for docs.
5970  */
5971 gpointer
5972 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5973 {
5974         NOT_IMPLEMENTED;
5975         return NULL;
5976 }
5977
5978 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */