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