e18c2bdef1de8b074d31965a7dbe6dc1eca352ed
[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->arch.omit_fp = FALSE;
1356         /*
1357          * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1358          * there are stack arguments.
1359          */
1360         /*
1361         if (cinfo->stack_usage)
1362                 cfg->arch.omit_fp = FALSE;
1363         */
1364
1365         locals_size = 0;
1366         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1367                 MonoInst *ins = cfg->varinfo [i];
1368                 int ialign;
1369
1370                 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1371         }
1372
1373         //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1374 }
1375
1376 /*
1377  * Set var information according to the calling convention. mips version.
1378  * The locals var stuff should most likely be split in another method.
1379  */
1380 void
1381 mono_arch_allocate_vars (MonoCompile *cfg)
1382 {
1383         MonoMethodSignature *sig;
1384         MonoMethodHeader *header;
1385         MonoInst *inst;
1386         int i, offset, size, align, curinst;
1387         int frame_reg = mips_sp;
1388         guint32 iregs_to_save = 0;
1389 #if SAVE_FP_REGS
1390         guint32 fregs_to_restore;
1391 #endif
1392         CallInfo *cinfo;
1393
1394         sig = mono_method_signature (cfg->method);
1395
1396         if (!cfg->arch.cinfo)
1397                 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1398         cinfo = cfg->arch.cinfo;
1399
1400         mono_arch_compute_omit_fp (cfg);
1401
1402         /* spill down, we'll fix it in a separate pass */
1403         // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1404
1405         /* allow room for the vararg method args: void* and long/double */
1406         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1407                 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1408
1409         /* this is bug #60332: remove when #59509 is fixed, so no weird vararg 
1410          * call convs needs to be handled this way.
1411          */
1412         if (cfg->flags & MONO_CFG_HAS_VARARGS)
1413                 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1414
1415         /* gtk-sharp and other broken code will dllimport vararg functions even with
1416          * non-varargs signatures. Since there is little hope people will get this right
1417          * we assume they won't.
1418          */
1419         if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1420                 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1421
1422         /* a0-a3 always present */
1423         cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1424
1425         header = cfg->header;
1426
1427         if (cfg->arch.omit_fp)
1428                 frame_reg = mips_sp;
1429         else
1430                 frame_reg = mips_fp;
1431         cfg->frame_reg = frame_reg;
1432         if (frame_reg != mips_sp) {
1433                 cfg->used_int_regs |= 1 << frame_reg;
1434         }
1435
1436         offset = 0;
1437         curinst = 0;
1438         if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1439                 /* FIXME: handle long and FP values */
1440                 switch (mini_get_underlying_type (sig->ret)->type) {
1441                 case MONO_TYPE_VOID:
1442                         break;
1443                 case MONO_TYPE_R4:
1444                 case MONO_TYPE_R8:
1445                         cfg->ret->opcode = OP_REGVAR;
1446                         cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1447                         break;
1448                 default:
1449                         cfg->ret->opcode = OP_REGVAR;
1450                         cfg->ret->inst_c0 = mips_v0;
1451                         break;
1452                 }
1453         }
1454         /* Space for outgoing parameters, including a0-a3 */
1455         offset += cfg->param_area;
1456
1457         /* allow room to save the return value (if it's a struct) */
1458         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1459                 offset += 8;
1460
1461         /* Now handle the local variables */
1462
1463         curinst = cfg->locals_start;
1464         for (i = curinst; i < cfg->num_varinfo; ++i) {
1465                 inst = cfg->varinfo [i];
1466                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1467                         continue;
1468
1469                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1470                  * pinvoke wrappers when they call functions returning structure
1471                  */
1472                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1473                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1474                 else
1475                         size = mono_type_size (inst->inst_vtype, &align);
1476
1477                 offset += align - 1;
1478                 offset &= ~(align - 1);
1479                 inst->inst_offset = offset;
1480                 inst->opcode = OP_REGOFFSET;
1481                 inst->inst_basereg = frame_reg;
1482                 offset += size;
1483                 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1484         }
1485
1486         /* Space for LMF (if needed) */
1487         if (cfg->method->save_lmf) {
1488                 /* align the offset to 16 bytes */
1489                 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1490                 cfg->arch.lmf_offset = offset;
1491                 offset += sizeof (MonoLMF);
1492         }
1493
1494         if (sig->call_convention == MONO_CALL_VARARG) {
1495                 size = 4;
1496                 align = 4;
1497
1498                 /* Allocate a local slot to hold the sig cookie address */
1499                 offset += align - 1;
1500                 offset &= ~(align - 1);
1501                 cfg->sig_cookie = offset;
1502                 offset += size;
1503         }                       
1504
1505         offset += SIZEOF_REGISTER - 1;
1506         offset &= ~(SIZEOF_REGISTER - 1);
1507
1508         /* Space for saved registers */
1509         cfg->arch.iregs_offset = offset;
1510         iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1511         if (iregs_to_save) {
1512                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1513                         if (iregs_to_save & (1 << i)) {
1514                                 offset += SIZEOF_REGISTER;
1515                         }
1516                 }
1517         }
1518
1519         /* saved float registers */
1520 #if SAVE_FP_REGS
1521         fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1522         if (fregs_to_restore) {
1523                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1524                         if (fregs_to_restore & (1 << i)) {
1525                                 offset += sizeof(double);
1526                         }
1527                 }
1528         }
1529 #endif
1530
1531 #if _MIPS_SIM == _ABIO32
1532         /* Now add space for saving the ra */
1533         offset += SIZEOF_VOID_P;
1534
1535         /* change sign? */
1536         offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1537         cfg->stack_offset = offset;
1538         cfg->arch.local_alloc_offset = cfg->stack_offset;
1539 #endif
1540
1541         /*
1542          * Now allocate stack slots for the int arg regs (a0 - a3)
1543          * On MIPS o32, these are just above the incoming stack pointer
1544          * Even if the arg has been assigned to a regvar, it gets a stack slot
1545          */
1546
1547         /* Return struct-by-value results in a hidden first argument */
1548         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1549                 cfg->vret_addr->opcode = OP_REGOFFSET;
1550                 cfg->vret_addr->inst_c0 = mips_a0;
1551                 cfg->vret_addr->inst_offset = offset;
1552                 cfg->vret_addr->inst_basereg = frame_reg;
1553                 offset += SIZEOF_REGISTER;
1554         }
1555
1556         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1557                 inst = cfg->args [i];
1558                 if (inst->opcode != OP_REGVAR) {
1559                         MonoType *arg_type;
1560                  
1561                         if (sig->hasthis && (i == 0))
1562                                 arg_type = &mono_defaults.object_class->byval_arg;
1563                         else
1564                                 arg_type = sig->params [i - sig->hasthis];
1565
1566                         inst->opcode = OP_REGOFFSET;
1567                         size = mono_type_size (arg_type, &align);
1568
1569                         if (size < SIZEOF_REGISTER) {
1570                                 size = SIZEOF_REGISTER;
1571                                 align = SIZEOF_REGISTER;
1572                         }
1573                         inst->inst_basereg = frame_reg;
1574                         offset = (offset + align - 1) & ~(align - 1);
1575                         inst->inst_offset = offset;
1576                         offset += size;
1577                         if (cfg->verbose_level > 1)
1578                                 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1579                 }
1580                 else {
1581 #if _MIPS_SIM == _ABIO32
1582                         /* o32: Even a0-a3 get stack slots */
1583                         size = SIZEOF_REGISTER;
1584                         align = SIZEOF_REGISTER;
1585                         inst->inst_basereg = frame_reg;
1586                         offset = (offset + align - 1) & ~(align - 1);
1587                         inst->inst_offset = offset;
1588                         offset += size;
1589                         if (cfg->verbose_level > 1)
1590                                 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1591 #endif
1592                 }
1593         }
1594 #if _MIPS_SIM == _ABIN32
1595         /* Now add space for saving the ra */
1596         offset += SIZEOF_VOID_P;
1597
1598         /* change sign? */
1599         offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1600         cfg->stack_offset = offset;
1601         cfg->arch.local_alloc_offset = cfg->stack_offset;
1602 #endif
1603 }
1604
1605 void
1606 mono_arch_create_vars (MonoCompile *cfg)
1607 {
1608         MonoMethodSignature *sig;
1609
1610         sig = mono_method_signature (cfg->method);
1611
1612         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1613                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1614                 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1615                         printf ("vret_addr = ");
1616                         mono_print_ins (cfg->vret_addr);
1617                 }
1618         }
1619 }
1620
1621 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1622  * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
1623  */
1624
1625 /* 
1626  * take the arguments and generate the arch-specific
1627  * instructions to properly call the function in call.
1628  * This includes pushing, moving arguments to the right register
1629  * etc.
1630  * Issue: who does the spilling if needed, and when?
1631  */
1632 static void
1633 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1634 {
1635         MonoMethodSignature *tmp_sig;
1636         MonoInst *sig_arg;
1637
1638         if (call->tail_call)
1639                 NOT_IMPLEMENTED;
1640
1641         /* FIXME: Add support for signature tokens to AOT */
1642         cfg->disable_aot = TRUE;
1643
1644         /*
1645          * mono_ArgIterator_Setup assumes the signature cookie is 
1646          * passed first and all the arguments which were before it are
1647          * passed on the stack after the signature. So compensate by 
1648          * passing a different signature.
1649          */
1650         tmp_sig = mono_metadata_signature_dup (call->signature);
1651         tmp_sig->param_count -= call->signature->sentinelpos;
1652         tmp_sig->sentinelpos = 0;
1653         memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1654
1655         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1656         sig_arg->dreg = mono_alloc_ireg (cfg);
1657         sig_arg->inst_p0 = tmp_sig;
1658         MONO_ADD_INS (cfg->cbb, sig_arg);
1659
1660         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1661 }
1662
1663 void
1664 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1665 {
1666         MonoInst *in, *ins;
1667         MonoMethodSignature *sig;
1668         int i, n;
1669         CallInfo *cinfo;
1670         int is_virtual = 0;
1671
1672         sig = call->signature;
1673         n = sig->param_count + sig->hasthis;
1674         
1675         cinfo = get_call_info (cfg->mempool, sig);
1676         if (cinfo->struct_ret)
1677                 call->used_iregs |= 1 << cinfo->struct_ret;
1678
1679         for (i = 0; i < n; ++i) {
1680                 ArgInfo *ainfo = cinfo->args + i;
1681                 MonoType *t;
1682
1683                 if (i >= sig->hasthis)
1684                         t = sig->params [i - sig->hasthis];
1685                 else
1686                         t = &mono_defaults.int_class->byval_arg;
1687                 t = mini_get_underlying_type (t);
1688
1689                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1690                         /* Emit the signature cookie just before the implicit arguments */
1691                         emit_sig_cookie (cfg, call, cinfo);
1692                 }
1693
1694                 if (is_virtual && i == 0) {
1695                         /* the argument will be attached to the call instrucion */
1696                         in = call->args [i];
1697                         call->used_iregs |= 1 << ainfo->reg;
1698                         continue;
1699                 }
1700                 in = call->args [i];
1701                 if (ainfo->storage == ArgInIReg) {
1702 #if SIZEOF_REGISTER == 4
1703                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1704                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1705                                 ins->dreg = mono_alloc_ireg (cfg);
1706                                 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1707                                 MONO_ADD_INS (cfg->cbb, ins);
1708                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1709
1710                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1711                                 ins->dreg = mono_alloc_ireg (cfg);
1712                                 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1713                                 MONO_ADD_INS (cfg->cbb, ins);
1714                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1715                         } else
1716 #endif
1717                         if (!t->byref && (t->type == MONO_TYPE_R4)) {
1718                                 int freg;
1719
1720 #if PROMOTE_R4_TO_R8
1721                                 /* ??? - convert to single first? */
1722                                 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1723                                 ins->dreg = mono_alloc_freg (cfg);
1724                                 ins->sreg1 = in->dreg;
1725                                 MONO_ADD_INS (cfg->cbb, ins);
1726                                 freg = ins->dreg;
1727 #else
1728                                 freg = in->dreg;
1729 #endif
1730                                 /* trying to load float value into int registers */
1731                                 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1732                                 ins->dreg = mono_alloc_ireg (cfg);
1733                                 ins->sreg1 = freg;
1734                                 MONO_ADD_INS (cfg->cbb, ins);
1735                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1736                         } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1737                                 /* trying to load float value into int registers */
1738                                 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1739                                 ins->dreg = mono_alloc_ireg (cfg);
1740                                 ins->sreg1 = in->dreg;
1741                                 MONO_ADD_INS (cfg->cbb, ins);
1742                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1743                         } else {
1744                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1745                                 ins->dreg = mono_alloc_ireg (cfg);
1746                                 ins->sreg1 = in->dreg;
1747                                 MONO_ADD_INS (cfg->cbb, ins);
1748                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1749                         }
1750                 } else if (ainfo->storage == ArgStructByAddr) {
1751                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1752                         ins->opcode = OP_OUTARG_VT;
1753                         ins->sreg1 = in->dreg;
1754                         ins->klass = in->klass;
1755                         ins->inst_p0 = call;
1756                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1757                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1758                         MONO_ADD_INS (cfg->cbb, ins);
1759                 } else if (ainfo->storage == ArgStructByVal) {
1760                         /* this is further handled in mono_arch_emit_outarg_vt () */
1761                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1762                         ins->opcode = OP_OUTARG_VT;
1763                         ins->sreg1 = in->dreg;
1764                         ins->klass = in->klass;
1765                         ins->inst_p0 = call;
1766                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1767                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1768                         MONO_ADD_INS (cfg->cbb, ins);
1769                 } else if (ainfo->storage == ArgOnStack) {
1770                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1771                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1772                         } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1773                                 if (t->type == MONO_TYPE_R8)
1774                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1775                                 else
1776                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1777                         } else {
1778                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1779                         }
1780                 } else if (ainfo->storage == ArgInFReg) {
1781                         if (t->type == MONO_TYPE_VALUETYPE) {
1782                                 /* this is further handled in mono_arch_emit_outarg_vt () */
1783                                 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1784                                 ins->opcode = OP_OUTARG_VT;
1785                                 ins->sreg1 = in->dreg;
1786                                 ins->klass = in->klass;
1787                                 ins->inst_p0 = call;
1788                                 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1789                                 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1790                                 MONO_ADD_INS (cfg->cbb, ins);
1791
1792                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1793                         } else {
1794                                 int dreg = mono_alloc_freg (cfg);
1795
1796                                 if (ainfo->size == 4) {
1797                                         MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1798                                 } else {
1799                                         MONO_INST_NEW (cfg, ins, OP_FMOVE);
1800                                         ins->dreg = dreg;
1801                                         ins->sreg1 = in->dreg;
1802                                         MONO_ADD_INS (cfg->cbb, ins);
1803                                 }
1804
1805                                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1806                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1807                         }
1808                 } else {
1809                         g_assert_not_reached ();
1810                 }
1811         }
1812
1813         /* Handle the case where there are no implicit arguments */
1814         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1815                 emit_sig_cookie (cfg, call, cinfo);
1816
1817         if (cinfo->struct_ret) {
1818                 MonoInst *vtarg;
1819
1820                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1821                 vtarg->sreg1 = call->vret_var->dreg;
1822                 vtarg->dreg = mono_alloc_preg (cfg);
1823                 MONO_ADD_INS (cfg->cbb, vtarg);
1824
1825                 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1826         }
1827 #if 0
1828         /*
1829          * Reverse the call->out_args list.
1830          */
1831         {
1832                 MonoInst *prev = NULL, *list = call->out_args, *next;
1833                 while (list) {
1834                         next = list->next;
1835                         list->next = prev;
1836                         prev = list;
1837                         list = next;
1838                 }
1839                 call->out_args = prev;
1840         }
1841 #endif
1842         call->stack_usage = cinfo->stack_usage;
1843         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1844 #if _MIPS_SIM == _ABIO32
1845         /* a0-a3 always present */
1846         cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1847 #endif
1848         cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1849         cfg->flags |= MONO_CFG_HAS_CALLS;
1850         /* 
1851          * should set more info in call, such as the stack space
1852          * used by the args that needs to be added back to esp
1853          */
1854 }
1855
1856 void
1857 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1858 {
1859         MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1860         ArgInfo *ainfo = ins->inst_p1;
1861         int ovf_size = ainfo->vtsize;
1862         int doffset = ainfo->offset;
1863         int i, soffset, dreg;
1864
1865         if (ainfo->storage == ArgStructByVal) {
1866 #if 0
1867                 if (cfg->verbose_level > 0) {
1868                         char* nm = mono_method_full_name (cfg->method, TRUE);
1869                         g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n", 
1870                                  nm, doffset, ainfo->size, ovf_size);
1871                         g_free (nm);
1872                 }
1873 #endif
1874
1875                 soffset = 0;
1876                 for (i = 0; i < ainfo->size; ++i) {
1877                         dreg = mono_alloc_ireg (cfg);
1878                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1879                         mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1880                         soffset += SIZEOF_REGISTER;
1881                 }
1882                 if (ovf_size != 0) {
1883                         mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), SIZEOF_VOID_P);
1884                 }
1885         } else if (ainfo->storage == ArgInFReg) {
1886                 int tmpr = mono_alloc_freg (cfg);
1887
1888                 if (ainfo->size == 4)
1889                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1890                 else
1891                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1892                 dreg = mono_alloc_freg (cfg);
1893                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1894                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1895         } else {
1896                 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1897                 MonoInst *load;
1898                 guint32 size;
1899
1900                 /* FIXME: alignment? */
1901                 if (call->signature->pinvoke) {
1902                         size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1903                         vtcopy->backend.is_pinvoke = 1;
1904                 } else {
1905                         size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1906                 }
1907                 if (size > 0)
1908                         g_assert (ovf_size > 0);
1909
1910                 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1911                 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, SIZEOF_VOID_P);
1912
1913                 if (ainfo->offset)
1914                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1915                 else
1916                         mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1917         }
1918 }
1919
1920 void
1921 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1922 {
1923         MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1924
1925         if (!ret->byref) {
1926 #if (SIZEOF_REGISTER == 4)
1927                 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1928                         MonoInst *ins;
1929
1930                         MONO_INST_NEW (cfg, ins, OP_SETLRET);
1931                         ins->sreg1 = MONO_LVREG_LS (val->dreg);
1932                         ins->sreg2 = MONO_LVREG_MS (val->dreg);
1933                         MONO_ADD_INS (cfg->cbb, ins);
1934                         return;
1935                 }
1936 #endif
1937                 if (ret->type == MONO_TYPE_R8) {
1938                         MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1939                         return;
1940                 }
1941                 if (ret->type == MONO_TYPE_R4) {
1942                         MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1943                         return;
1944                 }
1945         }
1946         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1947 }
1948
1949 void
1950 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1951 {
1952         MonoInst *ins, *n, *last_ins = NULL;
1953
1954         if (cfg->verbose_level > 2)
1955                 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1956
1957         ins = bb->code;
1958         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1959                 if (cfg->verbose_level > 2)
1960                         mono_print_ins_index (0, ins);
1961
1962                 switch (ins->opcode) {
1963 #if 0
1964                 case OP_LOAD_MEMBASE:
1965                 case OP_LOADI4_MEMBASE:
1966                         /*
1967                          * OP_IADD              reg2, reg1, const1
1968                          * OP_LOAD_MEMBASE      const2(reg2), reg3
1969                          * ->
1970                          * OP_LOAD_MEMBASE      (const1+const2)(reg1), reg3
1971                          */
1972                         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)){
1973                                 int const1 = last_ins->inst_imm;
1974                                 int const2 = ins->inst_offset;
1975
1976                                 if (mips_is_imm16 (const1 + const2)) {
1977                                         ins->inst_basereg = last_ins->sreg1;
1978                                         ins->inst_offset = const1 + const2;
1979                                 }
1980                         }
1981                         break;
1982 #endif
1983
1984                 }
1985                 last_ins = ins;
1986                 ins = ins->next;
1987         }
1988         bb->last_ins = last_ins;
1989 }
1990
1991 void
1992 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1993 {
1994         MonoInst *ins, *n, *last_ins = NULL;
1995         ins = bb->code;
1996
1997         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1998                 MonoInst *last_ins = ins->prev;
1999
2000                 switch (ins->opcode) {
2001                 case OP_MUL_IMM: 
2002                         /* remove unnecessary multiplication with 1 */
2003                         if (ins->inst_imm == 1) {
2004                                 if (ins->dreg != ins->sreg1) {
2005                                         ins->opcode = OP_MOVE;
2006                                 } else {
2007                                         MONO_DELETE_INS (bb, ins);
2008                                         continue;
2009                                 }
2010                         } else {
2011                                 int power2 = mono_is_power_of_two (ins->inst_imm);
2012                                 if (power2 > 0) {
2013                                         ins->opcode = OP_SHL_IMM;
2014                                         ins->inst_imm = power2;
2015                                 }
2016                         }
2017                         break;
2018                 case OP_LOAD_MEMBASE:
2019                 case OP_LOADI4_MEMBASE:
2020                         /* 
2021                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
2022                          * OP_LOAD_MEMBASE offset(basereg), reg
2023                          */
2024                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
2025                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2026                             ins->inst_basereg == last_ins->inst_destbasereg &&
2027                             ins->inst_offset == last_ins->inst_offset) {
2028                                 if (ins->dreg == last_ins->sreg1) {
2029                                         MONO_DELETE_INS (bb, ins);
2030                                         continue;
2031                                 } else {
2032                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2033                                         ins->opcode = OP_MOVE;
2034                                         ins->sreg1 = last_ins->sreg1;
2035                                 }
2036                                 break;
2037                         }
2038                         /* 
2039                          * Note: reg1 must be different from the basereg in the second load
2040                          * OP_LOAD_MEMBASE offset(basereg), reg1
2041                          * OP_LOAD_MEMBASE offset(basereg), reg2
2042                          * -->
2043                          * OP_LOAD_MEMBASE offset(basereg), reg1
2044                          * OP_MOVE reg1, reg2
2045                          */
2046                         if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2047                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
2048                               ins->inst_basereg != last_ins->dreg &&
2049                               ins->inst_basereg == last_ins->inst_basereg &&
2050                               ins->inst_offset == last_ins->inst_offset) {
2051
2052                                 if (ins->dreg == last_ins->dreg) {
2053                                         MONO_DELETE_INS (bb, ins);
2054                                         continue;
2055                                 } else {
2056                                         ins->opcode = OP_MOVE;
2057                                         ins->sreg1 = last_ins->dreg;
2058                                 }
2059
2060                                 //g_assert_not_reached ();
2061                                 break;
2062                         }
2063 #if 0
2064                         /* 
2065                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
2066                          * OP_LOAD_MEMBASE offset(basereg), reg
2067                          * -->
2068                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
2069                          * OP_ICONST reg, imm
2070                          */
2071                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2072                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2073                                    ins->inst_basereg == last_ins->inst_destbasereg &&
2074                                    ins->inst_offset == last_ins->inst_offset) {
2075                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2076                                 ins->opcode = OP_ICONST;
2077                                 ins->inst_c0 = last_ins->inst_imm;
2078                                 g_assert_not_reached (); // check this rule
2079                                 break;
2080                         }
2081 #endif
2082                         break;
2083                 case OP_LOADU1_MEMBASE:
2084                 case OP_LOADI1_MEMBASE:
2085                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2086                                         ins->inst_basereg == last_ins->inst_destbasereg &&
2087                                         ins->inst_offset == last_ins->inst_offset) {
2088                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2089                                 ins->sreg1 = last_ins->sreg1;                           
2090                         }
2091                         break;
2092                 case OP_LOADU2_MEMBASE:
2093                 case OP_LOADI2_MEMBASE:
2094                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2095                                         ins->inst_basereg == last_ins->inst_destbasereg &&
2096                                         ins->inst_offset == last_ins->inst_offset) {
2097                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2098                                 ins->sreg1 = last_ins->sreg1;                           
2099                         }
2100                         break;
2101                 case OP_ICONV_TO_I4:
2102                 case OP_ICONV_TO_U4:
2103                 case OP_MOVE:
2104                         ins->opcode = OP_MOVE;
2105                         /* 
2106                          * OP_MOVE reg, reg 
2107                          */
2108                         if (ins->dreg == ins->sreg1) {
2109                                 MONO_DELETE_INS (bb, ins);
2110                                 continue;
2111                         }
2112                         /* 
2113                          * OP_MOVE sreg, dreg 
2114                          * OP_MOVE dreg, sreg
2115                          */
2116                         if (last_ins && last_ins->opcode == OP_MOVE &&
2117                             ins->sreg1 == last_ins->dreg &&
2118                             ins->dreg == last_ins->sreg1) {
2119                                 MONO_DELETE_INS (bb, ins);
2120                                 continue;
2121                         }
2122                         break;
2123                 }
2124                 last_ins = ins;
2125                 ins = ins->next;
2126         }
2127         bb->last_ins = last_ins;
2128 }
2129
2130 void
2131 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2132 {
2133         int tmp1 = -1;
2134         int tmp2 = -1;
2135         int tmp3 = -1;
2136         int tmp4 = -1;
2137         int tmp5 = -1;
2138
2139         switch (ins->opcode) {
2140         case OP_LADD:
2141                 tmp1 = mono_alloc_ireg (cfg);
2142                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2143                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2144                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2145                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2146                 NULLIFY_INS(ins);
2147                 break;
2148
2149         case OP_LADD_IMM:
2150                 tmp1 = mono_alloc_ireg (cfg);
2151                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2152                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2153                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2154                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2155                 NULLIFY_INS(ins);
2156                 break;
2157
2158         case OP_LSUB:
2159                 tmp1 = mono_alloc_ireg (cfg);
2160                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2161                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2162                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2163                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2164                 NULLIFY_INS(ins);
2165                 break;
2166
2167         case OP_LSUB_IMM:
2168                 tmp1 = mono_alloc_ireg (cfg);
2169                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2170                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2171                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2172                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2173                 NULLIFY_INS(ins);
2174                 break;
2175
2176         case OP_LNEG:
2177                 tmp1 = mono_alloc_ireg (cfg);
2178                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2179                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2180                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2181                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2182                 NULLIFY_INS(ins);
2183                 break;
2184
2185         case OP_LADD_OVF:
2186                 tmp1 = mono_alloc_ireg (cfg);
2187                 tmp2 = mono_alloc_ireg (cfg);
2188                 tmp3 = mono_alloc_ireg (cfg);
2189                 tmp4 = mono_alloc_ireg (cfg);
2190                 tmp5 = mono_alloc_ireg (cfg);
2191
2192                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2193
2194                 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2195                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2196
2197                 /* add the high 32-bits, and add in the carry from the low 32-bits */
2198                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2199                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2200
2201                 /* Overflow happens if
2202                  *      neg + neg = pos    or
2203                  *      pos + pos = neg
2204                  * XOR of the high bits returns 0 if the signs match
2205                  * XOR of that with the high bit of the result return 1 if overflow.
2206                  */
2207
2208                 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2209                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2210
2211                 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2212                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2213                 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2214
2215                 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2216                 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2217                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2218
2219                 /* Now, if (tmp4 == 0) then overflow */
2220                 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2221                 NULLIFY_INS(ins);
2222                 break;
2223
2224         case OP_LADD_OVF_UN:
2225                 tmp1 = mono_alloc_ireg (cfg);
2226                 tmp2 = mono_alloc_ireg (cfg);
2227
2228                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2229                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2230                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2231                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2232                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2233                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2234                 NULLIFY_INS(ins);
2235                 break;
2236
2237         case OP_LSUB_OVF:
2238                 tmp1 = mono_alloc_ireg (cfg);
2239                 tmp2 = mono_alloc_ireg (cfg);
2240                 tmp3 = mono_alloc_ireg (cfg);
2241                 tmp4 = mono_alloc_ireg (cfg);
2242                 tmp5 = mono_alloc_ireg (cfg);
2243
2244                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2245
2246                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2247                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2248                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2249
2250                 /* Overflow happens if
2251                  *      neg - pos = pos    or
2252                  *      pos - neg = neg
2253                  * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2254                  *
2255                  * tmp1 = (lhs ^ rhs)
2256                  * tmp2 = (lhs ^ result)
2257                  * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2258                  */
2259
2260                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2261                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2262                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2263                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2264
2265                 /* Now, if (tmp4 == 1) then overflow */
2266                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2267                 NULLIFY_INS(ins);
2268                 break;
2269
2270         case OP_LSUB_OVF_UN:
2271                 tmp1 = mono_alloc_ireg (cfg);
2272                 tmp2 = mono_alloc_ireg (cfg);
2273
2274                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2275                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2276                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2277                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2278
2279                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2280                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2281                 NULLIFY_INS(ins);
2282                 break;
2283         case OP_LCONV_TO_OVF_I4_2:
2284                 tmp1 = mono_alloc_ireg (cfg);
2285
2286                 /* Overflows if reg2 != sign extension of reg1 */
2287                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2288                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2289                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2290                 NULLIFY_INS(ins);
2291                 break;
2292         default:
2293                 break;
2294         }
2295 }
2296
2297 void
2298 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2299 {
2300         int tmp1 = -1;
2301         int tmp2 = -1;
2302         int tmp3 = -1;
2303         int tmp4 = -1;
2304         int tmp5 = -1;
2305
2306         switch (ins->opcode) {
2307         case OP_IADD_OVF:
2308                 tmp1 = mono_alloc_ireg (cfg);
2309                 tmp2 = mono_alloc_ireg (cfg);
2310                 tmp3 = mono_alloc_ireg (cfg);
2311                 tmp4 = mono_alloc_ireg (cfg);
2312                 tmp5 = mono_alloc_ireg (cfg);
2313
2314                 /* add the operands */
2315
2316                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2317
2318                 /* Overflow happens if
2319                  *      neg + neg = pos    or
2320                  *      pos + pos = neg
2321                  *
2322                  * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2323                  * XOR of the high bit returns 0 if the signs match
2324                  * XOR of that with the high bit of the result return 1 if overflow.
2325                  */
2326
2327                 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2328                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2329
2330                 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2331                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2332                 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2333
2334                 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2335                 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2336
2337                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2338
2339                 /* Now, if (tmp5 == 0) then overflow */
2340                 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2341                 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2342                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2343                 NULLIFY_INS(ins);
2344                 break;
2345
2346         case OP_IADD_OVF_UN:
2347                 tmp1 = mono_alloc_ireg (cfg);
2348
2349                 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2350                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2351                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2352                 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2353                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2354                 NULLIFY_INS(ins);
2355                 break;
2356
2357         case OP_ISUB_OVF:
2358                 tmp1 = mono_alloc_ireg (cfg);
2359                 tmp2 = mono_alloc_ireg (cfg);
2360                 tmp3 = mono_alloc_ireg (cfg);
2361                 tmp4 = mono_alloc_ireg (cfg);
2362                 tmp5 = mono_alloc_ireg (cfg);
2363
2364                 /* add the operands */
2365
2366                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2367
2368                 /* Overflow happens if
2369                  *      neg - pos = pos    or
2370                  *      pos - neg = neg
2371                  * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2372                  *
2373                  * tmp1 = (lhs ^ rhs)
2374                  * tmp2 = (lhs ^ result)
2375                  * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2376                  */
2377
2378                 /* tmp3 = 1 if the signs of the two inputs differ */
2379                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2380                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2381                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2382                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2383                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2384
2385                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2386                 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2387                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2388                 NULLIFY_INS(ins);
2389                 break;
2390
2391         case OP_ISUB_OVF_UN:
2392                 tmp1 = mono_alloc_ireg (cfg);
2393
2394                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2395                 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2396                 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2397                 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2398                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2399                 NULLIFY_INS(ins);
2400                 break;
2401         }
2402 }
2403
2404 static int
2405 map_to_reg_reg_op (int op)
2406 {
2407         switch (op) {
2408         case OP_ADD_IMM:
2409                 return OP_IADD;
2410         case OP_SUB_IMM:
2411                 return OP_ISUB;
2412         case OP_AND_IMM:
2413                 return OP_IAND;
2414         case OP_COMPARE_IMM:
2415                 return OP_COMPARE;
2416         case OP_ICOMPARE_IMM:
2417                 return OP_ICOMPARE;
2418         case OP_LCOMPARE_IMM:
2419                 return OP_LCOMPARE;
2420         case OP_ADDCC_IMM:
2421                 return OP_IADDCC;
2422         case OP_ADC_IMM:
2423                 return OP_IADC;
2424         case OP_SUBCC_IMM:
2425                 return OP_ISUBCC;
2426         case OP_SBB_IMM:
2427                 return OP_ISBB;
2428         case OP_OR_IMM:
2429                 return OP_IOR;
2430         case OP_XOR_IMM:
2431                 return OP_IXOR;
2432         case OP_MUL_IMM:
2433                 return OP_IMUL;
2434         case OP_LOAD_MEMBASE:
2435                 return OP_LOAD_MEMINDEX;
2436         case OP_LOADI4_MEMBASE:
2437                 return OP_LOADI4_MEMINDEX;
2438         case OP_LOADU4_MEMBASE:
2439                 return OP_LOADU4_MEMINDEX;
2440         case OP_LOADU1_MEMBASE:
2441                 return OP_LOADU1_MEMINDEX;
2442         case OP_LOADI2_MEMBASE:
2443                 return OP_LOADI2_MEMINDEX;
2444         case OP_LOADU2_MEMBASE:
2445                 return OP_LOADU2_MEMINDEX;
2446         case OP_LOADI1_MEMBASE:
2447                 return OP_LOADI1_MEMINDEX;
2448         case OP_LOADR4_MEMBASE:
2449                 return OP_LOADR4_MEMINDEX;
2450         case OP_LOADR8_MEMBASE:
2451                 return OP_LOADR8_MEMINDEX;
2452         case OP_STOREI1_MEMBASE_REG:
2453                 return OP_STOREI1_MEMINDEX;
2454         case OP_STOREI2_MEMBASE_REG:
2455                 return OP_STOREI2_MEMINDEX;
2456         case OP_STOREI4_MEMBASE_REG:
2457                 return OP_STOREI4_MEMINDEX;
2458         case OP_STORE_MEMBASE_REG:
2459                 return OP_STORE_MEMINDEX;
2460         case OP_STORER4_MEMBASE_REG:
2461                 return OP_STORER4_MEMINDEX;
2462         case OP_STORER8_MEMBASE_REG:
2463                 return OP_STORER8_MEMINDEX;
2464         case OP_STORE_MEMBASE_IMM:
2465                 return OP_STORE_MEMBASE_REG;
2466         case OP_STOREI1_MEMBASE_IMM:
2467                 return OP_STOREI1_MEMBASE_REG;
2468         case OP_STOREI2_MEMBASE_IMM:
2469                 return OP_STOREI2_MEMBASE_REG;
2470         case OP_STOREI4_MEMBASE_IMM:
2471                 return OP_STOREI4_MEMBASE_REG;
2472         case OP_STOREI8_MEMBASE_IMM:
2473                 return OP_STOREI8_MEMBASE_REG;
2474         }
2475         if (mono_op_imm_to_op (op) == -1)
2476                 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2477         return mono_op_imm_to_op (op);
2478 }
2479
2480 static int
2481 map_to_mips_op (int op)
2482 {
2483         switch (op) {
2484         case OP_FBEQ:
2485                 return OP_MIPS_FBEQ;
2486         case OP_FBGE:
2487                 return OP_MIPS_FBGE;
2488         case OP_FBGT:
2489                 return OP_MIPS_FBGT;
2490         case OP_FBLE:
2491                 return OP_MIPS_FBLE;
2492         case OP_FBLT:
2493                 return OP_MIPS_FBLT;
2494         case OP_FBNE_UN:
2495                 return OP_MIPS_FBNE;
2496         case OP_FBGE_UN:
2497                 return OP_MIPS_FBGE_UN;
2498         case OP_FBGT_UN:
2499                 return OP_MIPS_FBGT_UN;
2500         case OP_FBLE_UN:
2501                 return OP_MIPS_FBLE_UN;
2502         case OP_FBLT_UN:
2503                 return OP_MIPS_FBLT_UN;
2504
2505         case OP_FCEQ:
2506         case OP_FCGT:
2507         case OP_FCGT_UN:
2508         case OP_FCLT:
2509         case OP_FCLT_UN:
2510         default:
2511                 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2512                 g_assert_not_reached ();
2513         }
2514 }
2515
2516 #define NEW_INS(cfg,after,dest,op) do {                                 \
2517                 MONO_INST_NEW((cfg), (dest), (op));                     \
2518                 mono_bblock_insert_after_ins (bb, (after), (dest));     \
2519         } while (0)
2520
2521 #define INS(pos,op,_dreg,_sreg1,_sreg2) do {            \
2522                 MonoInst *temp;                                         \
2523                 MONO_INST_NEW(cfg, temp, (op));                         \
2524                 mono_bblock_insert_after_ins (bb, (pos), temp);         \
2525                 temp->dreg = (_dreg);                                   \
2526                 temp->sreg1 = (_sreg1);                                 \
2527                 temp->sreg2 = (_sreg2);                                 \
2528                 pos = temp;                                             \
2529         } while (0)
2530
2531 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do {          \
2532                 MonoInst *temp;                                         \
2533                 MONO_INST_NEW(cfg, temp, (op));                         \
2534                 mono_bblock_insert_after_ins (bb, (pos), temp);         \
2535                 temp->dreg = (_dreg);                                   \
2536                 temp->sreg1 = (_sreg1);                                 \
2537                 temp->inst_c0 = (_imm);                                 \
2538                 pos = temp;                                             \
2539         } while (0)
2540
2541 /*
2542  * Remove from the instruction list the instructions that can't be
2543  * represented with very simple instructions with no register
2544  * requirements.
2545  */
2546 void
2547 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2548 {
2549         MonoInst *ins, *next, *temp, *last_ins = NULL;
2550         int imm;
2551
2552 #if 1
2553         if (cfg->verbose_level > 2) {
2554                 int idx = 0;
2555
2556                 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2557                 MONO_BB_FOR_EACH_INS (bb, ins) {
2558                         mono_print_ins_index (idx++, ins);
2559                 }
2560                 
2561         }
2562 #endif
2563
2564         MONO_BB_FOR_EACH_INS (bb, ins) {
2565 loop_start:
2566                 switch (ins->opcode) {
2567                 case OP_COMPARE:
2568                 case OP_ICOMPARE:
2569                 case OP_LCOMPARE:
2570                         next = ins->next;
2571                         /* Branch opts can eliminate the branch */
2572                         if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2573                                 NULLIFY_INS(ins);
2574                                 break;
2575                         }
2576                         break;
2577
2578                 case OP_COMPARE_IMM:
2579                 case OP_ICOMPARE_IMM:
2580                 case OP_LCOMPARE_IMM:
2581                         next = ins->next;
2582                         /* Branch opts can eliminate the branch */
2583                         if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2584                                 NULLIFY_INS(ins);
2585                                 break;
2586                         }
2587                         if (ins->inst_imm) {
2588                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2589                                 temp->inst_c0 = ins->inst_imm;
2590                                 temp->dreg = mono_alloc_ireg (cfg);
2591                                 ins->sreg2 = temp->dreg;
2592                                 last_ins = temp;
2593                         }
2594                         else {
2595                                 ins->sreg2 = mips_zero;
2596                         }
2597                         if (ins->opcode == OP_COMPARE_IMM)
2598                                 ins->opcode = OP_COMPARE;
2599                         else if (ins->opcode == OP_ICOMPARE_IMM)
2600                                 ins->opcode = OP_ICOMPARE;
2601                         else if (ins->opcode == OP_LCOMPARE_IMM)
2602                                 ins->opcode = OP_LCOMPARE;
2603                         goto loop_start;
2604
2605                 case OP_IDIV_UN_IMM:
2606                 case OP_IDIV_IMM:
2607                 case OP_IREM_IMM:
2608                 case OP_IREM_UN_IMM:
2609                         NEW_INS (cfg, last_ins, temp, OP_ICONST);
2610                         temp->inst_c0 = ins->inst_imm;
2611                         temp->dreg = mono_alloc_ireg (cfg);
2612                         ins->sreg2 = temp->dreg;
2613                         if (ins->opcode == OP_IDIV_IMM)
2614                                 ins->opcode = OP_IDIV;
2615                         else if (ins->opcode == OP_IREM_IMM)
2616                                 ins->opcode = OP_IREM;
2617                         else if (ins->opcode == OP_IDIV_UN_IMM)
2618                                 ins->opcode = OP_IDIV_UN;
2619                         else if (ins->opcode == OP_IREM_UN_IMM)
2620                                 ins->opcode = OP_IREM_UN;
2621                         last_ins = temp;
2622                         /* handle rem separately */
2623                         goto loop_start;
2624
2625 #if 0
2626                 case OP_AND_IMM:
2627                 case OP_OR_IMM:
2628                 case OP_XOR_IMM:
2629                         if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2630                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2631                                 temp->inst_c0 = ins->inst_imm;
2632                                 temp->dreg = mono_alloc_ireg (cfg);
2633                                 ins->sreg2 = temp->dreg;
2634                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2635                         }
2636                         break;
2637 #endif
2638                 case OP_AND_IMM:
2639                 case OP_IAND_IMM:
2640                 case OP_OR_IMM:
2641                 case OP_IOR_IMM:
2642                 case OP_XOR_IMM:
2643                 case OP_IXOR_IMM:
2644                         /* unsigned 16 bit immediate */
2645                         if (ins->inst_imm & 0xffff0000) {
2646                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2647                                 temp->inst_c0 = ins->inst_imm;
2648                                 temp->dreg = mono_alloc_ireg (cfg);
2649                                 ins->sreg2 = temp->dreg;
2650                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2651                         }
2652                         break;
2653
2654                 case OP_IADD_IMM:
2655                 case OP_ADD_IMM:
2656                 case OP_ADDCC_IMM:
2657                         /* signed 16 bit immediate */
2658                         if (!mips_is_imm16 (ins->inst_imm)) {
2659                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2660                                 temp->inst_c0 = ins->inst_imm;
2661                                 temp->dreg = mono_alloc_ireg (cfg);
2662                                 ins->sreg2 = temp->dreg;
2663                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2664                         }
2665                         break;
2666
2667                 case OP_SUB_IMM:
2668                 case OP_ISUB_IMM:
2669                         if (!mips_is_imm16 (-ins->inst_imm)) {
2670                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2671                                 temp->inst_c0 = ins->inst_imm;
2672                                 temp->dreg = mono_alloc_ireg (cfg);
2673                                 ins->sreg2 = temp->dreg;
2674                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2675                         }
2676                         break;
2677
2678                 case OP_MUL_IMM:
2679                 case OP_IMUL_IMM:
2680                         if (ins->inst_imm == 1) {
2681                                 ins->opcode = OP_MOVE;
2682                                 break;
2683                         }
2684                         if (ins->inst_imm == 0) {
2685                                 ins->opcode = OP_ICONST;
2686                                 ins->inst_c0 = 0;
2687                                 break;
2688                         }
2689                         imm = mono_is_power_of_two (ins->inst_imm);
2690                         if (imm > 0) {
2691                                 ins->opcode = OP_SHL_IMM;
2692                                 ins->inst_imm = imm;
2693                                 break;
2694                         }
2695                         NEW_INS (cfg, last_ins, temp, OP_ICONST);
2696                         temp->inst_c0 = ins->inst_imm;
2697                         temp->dreg = mono_alloc_ireg (cfg);
2698                         ins->sreg2 = temp->dreg;
2699                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2700                         break;
2701
2702                 case OP_LOCALLOC_IMM:
2703                         NEW_INS (cfg, last_ins, temp, OP_ICONST);
2704                         temp->inst_c0 = ins->inst_imm;
2705                         temp->dreg = mono_alloc_ireg (cfg);
2706                         ins->sreg1 = temp->dreg;
2707                         ins->opcode = OP_LOCALLOC;
2708                         break;
2709
2710                 case OP_LOADR4_MEMBASE:
2711                 case OP_STORER4_MEMBASE_REG:
2712                         /* we can do two things: load the immed in a register
2713                          * and use an indexed load, or see if the immed can be
2714                          * represented as an ad_imm + a load with a smaller offset
2715                          * that fits. We just do the first for now, optimize later.
2716                          */
2717                         if (mips_is_imm16 (ins->inst_offset))
2718                                 break;
2719                         NEW_INS (cfg, last_ins, temp, OP_ICONST);
2720                         temp->inst_c0 = ins->inst_offset;
2721                         temp->dreg = mono_alloc_ireg (cfg);
2722                         ins->sreg2 = temp->dreg;
2723                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2724                         break;
2725
2726                 case OP_STORE_MEMBASE_IMM:
2727                 case OP_STOREI1_MEMBASE_IMM:
2728                 case OP_STOREI2_MEMBASE_IMM:
2729                 case OP_STOREI4_MEMBASE_IMM:
2730                 case OP_STOREI8_MEMBASE_IMM:
2731                         if (!ins->inst_imm) {
2732                                 ins->sreg1 = mips_zero;
2733                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2734                         }
2735                         else {
2736                                 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2737                                 temp->inst_c0 = ins->inst_imm;
2738                                 temp->dreg = mono_alloc_ireg (cfg);
2739                                 ins->sreg1 = temp->dreg;
2740                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
2741                                 last_ins = temp;
2742                                 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2743                         }
2744                         break;
2745
2746                 case OP_FCOMPARE:
2747                         next = ins->next;
2748                         /* Branch opts can eliminate the branch */
2749                         if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2750                                 NULLIFY_INS(ins);
2751                                 break;
2752                         }
2753                         g_assert(next);
2754
2755                         /*
2756                          * remap compare/branch and compare/set
2757                          * to MIPS specific opcodes.
2758                          */
2759                         next->opcode = map_to_mips_op (next->opcode);
2760                         next->sreg1 = ins->sreg1;
2761                         next->sreg2 = ins->sreg2;
2762                         NULLIFY_INS(ins);
2763                         break;
2764
2765 #if 0
2766                 case OP_R8CONST:
2767                 case OP_R4CONST:
2768                         NEW_INS (cfg, last_ins, temp, OP_ICONST);
2769                         temp->inst_c0 = (guint32)ins->inst_p0;
2770                         temp->dreg = mono_alloc_ireg (cfg);
2771                         ins->inst_basereg = temp->dreg;
2772                         ins->inst_offset = 0;
2773                         ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2774                         last_ins = temp;
2775                         /* make it handle the possibly big ins->inst_offset
2776                          * later optimize to use lis + load_membase
2777                          */
2778                         goto loop_start;
2779 #endif
2780                 case OP_IBEQ:
2781                         g_assert (ins_is_compare(last_ins));
2782                         INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2783                         NULLIFY_INS(last_ins);
2784                         break;
2785
2786                 case OP_IBNE_UN:
2787                         g_assert (ins_is_compare(last_ins));
2788                         INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2789                         NULLIFY_INS(last_ins);
2790                         break;
2791
2792                 case OP_IBGE:
2793                         g_assert (ins_is_compare(last_ins));
2794                         INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2795                         last_ins->dreg = mono_alloc_ireg (cfg);
2796                         INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2797                         break;
2798
2799                 case OP_IBGE_UN:
2800                         g_assert (ins_is_compare(last_ins));
2801                         INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2802                         last_ins->dreg = mono_alloc_ireg (cfg);
2803                         INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2804                         break;
2805
2806                 case OP_IBLT:
2807                         g_assert (ins_is_compare(last_ins));
2808                         INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2809                         last_ins->dreg = mono_alloc_ireg (cfg);
2810                         INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2811                         break;
2812
2813                 case OP_IBLT_UN:
2814                         g_assert (ins_is_compare(last_ins));
2815                         INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2816                         last_ins->dreg = mono_alloc_ireg (cfg);
2817                         INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2818                         break;
2819
2820                 case OP_IBLE:
2821                         g_assert (ins_is_compare(last_ins));
2822                         INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2823                         last_ins->dreg = mono_alloc_ireg (cfg);
2824                         INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2825                         break;
2826
2827                 case OP_IBLE_UN:
2828                         g_assert (ins_is_compare(last_ins));
2829                         INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2830                         last_ins->dreg = mono_alloc_ireg (cfg);
2831                         INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2832                         break;
2833
2834                 case OP_IBGT:
2835                         g_assert (ins_is_compare(last_ins));
2836                         INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2837                         last_ins->dreg = mono_alloc_ireg (cfg);
2838                         INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2839                         break;
2840
2841                 case OP_IBGT_UN:
2842                         g_assert (ins_is_compare(last_ins));
2843                         INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2844                         last_ins->dreg = mono_alloc_ireg (cfg);
2845                         INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2846                         break;
2847
2848                 case OP_CEQ:
2849                 case OP_ICEQ:
2850                         g_assert (ins_is_compare(last_ins));
2851                         last_ins->opcode = OP_IXOR;
2852                         last_ins->dreg = mono_alloc_ireg(cfg);
2853                         INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2854                         break;
2855
2856                 case OP_CLT:
2857                 case OP_ICLT:
2858                         INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2859                         NULLIFY_INS(last_ins);
2860                         break;
2861
2862
2863                 case OP_CLT_UN:
2864                 case OP_ICLT_UN:
2865                         INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2866                         NULLIFY_INS(last_ins);
2867                         break;
2868
2869                 case OP_CGT:
2870                 case OP_ICGT:
2871                         g_assert (ins_is_compare(last_ins));
2872                         INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2873                         MONO_DELETE_INS(bb, last_ins);
2874                         break;
2875
2876                 case OP_CGT_UN:
2877                 case OP_ICGT_UN:
2878                         g_assert (ins_is_compare(last_ins));
2879                         INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2880                         MONO_DELETE_INS(bb, last_ins);
2881                         break;
2882
2883                 case OP_COND_EXC_EQ:
2884                 case OP_COND_EXC_IEQ:
2885                         g_assert (ins_is_compare(last_ins));
2886                         INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2887                         MONO_DELETE_INS(bb, last_ins);
2888                         break;
2889
2890                 case OP_COND_EXC_GE:
2891                 case OP_COND_EXC_IGE:
2892                         g_assert (ins_is_compare(last_ins));
2893                         INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2894                         MONO_DELETE_INS(bb, last_ins);
2895                         break;
2896
2897                 case OP_COND_EXC_GT:
2898                 case OP_COND_EXC_IGT:
2899                         g_assert (ins_is_compare(last_ins));
2900                         INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2901                         MONO_DELETE_INS(bb, last_ins);
2902                         break;
2903
2904                 case OP_COND_EXC_LE:
2905                 case OP_COND_EXC_ILE:
2906                         g_assert (ins_is_compare(last_ins));
2907                         INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2908                         MONO_DELETE_INS(bb, last_ins);
2909                         break;
2910
2911                 case OP_COND_EXC_LT:
2912                 case OP_COND_EXC_ILT:
2913                         g_assert (ins_is_compare(last_ins));
2914                         INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2915                         MONO_DELETE_INS(bb, last_ins);
2916                         break;
2917
2918                 case OP_COND_EXC_NE_UN:
2919                 case OP_COND_EXC_INE_UN:
2920                         g_assert (ins_is_compare(last_ins));
2921                         INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2922                         MONO_DELETE_INS(bb, last_ins);
2923                         break;
2924
2925                 case OP_COND_EXC_GE_UN:
2926                 case OP_COND_EXC_IGE_UN:
2927                         g_assert (ins_is_compare(last_ins));
2928                         INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2929                         MONO_DELETE_INS(bb, last_ins);
2930                         break;
2931
2932                 case OP_COND_EXC_GT_UN:
2933                 case OP_COND_EXC_IGT_UN:
2934                         g_assert (ins_is_compare(last_ins));
2935                         INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2936                         MONO_DELETE_INS(bb, last_ins);
2937                         break;
2938
2939                 case OP_COND_EXC_LE_UN:
2940                 case OP_COND_EXC_ILE_UN:
2941                         g_assert (ins_is_compare(last_ins));
2942                         INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2943                         MONO_DELETE_INS(bb, last_ins);
2944                         break;
2945
2946                 case OP_COND_EXC_LT_UN:
2947                 case OP_COND_EXC_ILT_UN:
2948                         g_assert (ins_is_compare(last_ins));
2949                         INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2950                         MONO_DELETE_INS(bb, last_ins);
2951                         break;
2952
2953                 case OP_COND_EXC_OV:
2954                 case OP_COND_EXC_IOV: {
2955                         int tmp1, tmp2, tmp3, tmp4, tmp5;
2956                         MonoInst *pos = last_ins;
2957
2958                         /* Overflow happens if
2959                          *      neg + neg = pos    or
2960                          *      pos + pos = neg
2961                          *
2962                          * (bit31s of operands match) AND (bit31 of operand
2963                          * != bit31 of result)
2964                          * XOR of the high bit returns 0 if the signs match
2965                          * XOR of that with the high bit of the result return 1
2966                          * if overflow.
2967                          */
2968                         g_assert (last_ins->opcode == OP_IADC);
2969
2970                         tmp1 = mono_alloc_ireg (cfg);
2971                         tmp2 = mono_alloc_ireg (cfg);
2972                         tmp3 = mono_alloc_ireg (cfg);
2973                         tmp4 = mono_alloc_ireg (cfg);
2974                         tmp5 = mono_alloc_ireg (cfg);
2975
2976                         /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2977                         INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2978
2979                         /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2980                         INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2981                         INS (pos, OP_INOT, tmp3, tmp2, -1);
2982
2983                         /* OR(tmp1, tmp2) = 0 if both conditions are true */
2984                         INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2985                         INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2986
2987                         /* Now, if (tmp5 == 0) then overflow */
2988                         INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2989                         ins->dreg = -1;
2990                         break;
2991                         }
2992
2993                 case OP_COND_EXC_NO:
2994                 case OP_COND_EXC_INO:
2995                         g_assert_not_reached ();
2996                         break;
2997
2998                 case OP_COND_EXC_C:
2999                 case OP_COND_EXC_IC:
3000                         g_assert_not_reached ();
3001                         break;
3002
3003                 case OP_COND_EXC_NC:
3004                 case OP_COND_EXC_INC:
3005                         g_assert_not_reached ();
3006                         break;
3007
3008                 }
3009                 last_ins = ins;
3010         }
3011         bb->last_ins = last_ins;
3012         bb->max_vreg = cfg->next_vreg;
3013
3014 #if 1
3015         if (cfg->verbose_level > 2) {
3016                 int idx = 0;
3017
3018                 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3019                 MONO_BB_FOR_EACH_INS (bb, ins) {
3020                         mono_print_ins_index (idx++, ins);
3021                 }
3022                 
3023         }
3024 #endif
3025
3026 }
3027
3028 static guchar*
3029 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3030 {
3031         /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3032 #if 1
3033         mips_truncwd (code, mips_ftemp, sreg);
3034 #else
3035         mips_cvtwd (code, mips_ftemp, sreg);
3036 #endif
3037         mips_mfc1 (code, dreg, mips_ftemp);
3038         if (!is_signed) {
3039                 if (size == 1)
3040                         mips_andi (code, dreg, dreg, 0xff);
3041                 else if (size == 2) {
3042                         mips_sll (code, dreg, dreg, 16);
3043                         mips_srl (code, dreg, dreg, 16);
3044                 }
3045         } else {
3046                 if (size == 1) {
3047                         mips_sll (code, dreg, dreg, 24);
3048                         mips_sra (code, dreg, dreg, 24);
3049                 }
3050                 else if (size == 2) {
3051                         mips_sll (code, dreg, dreg, 16);
3052                         mips_sra (code, dreg, dreg, 16);
3053                 }
3054         }
3055         return code;
3056 }
3057
3058 /*
3059  * emit_load_volatile_arguments:
3060  *
3061  * Load volatile arguments from the stack to the original input registers.
3062  * Required before a tail call.
3063  */
3064 static guint8 *
3065 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3066 {
3067         MonoMethod *method = cfg->method;
3068         MonoMethodSignature *sig;
3069         MonoInst *inst;
3070         CallInfo *cinfo;
3071         int i;
3072
3073         sig = mono_method_signature (method);
3074
3075         if (!cfg->arch.cinfo)
3076                 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3077         cinfo = cfg->arch.cinfo;
3078
3079         if (cinfo->struct_ret) {
3080                 ArgInfo *ainfo = &cinfo->ret;
3081                 inst = cfg->vret_addr;
3082                 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3083         }
3084
3085         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3086                 ArgInfo *ainfo = cinfo->args + i;
3087                 inst = cfg->args [i];
3088                 if (inst->opcode == OP_REGVAR) {
3089                         if (ainfo->storage == ArgInIReg)
3090                                 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3091                         else if (ainfo->storage == ArgInFReg)
3092                                 g_assert_not_reached();
3093                         else if (ainfo->storage == ArgOnStack) {
3094                                 /* do nothing */
3095                         } else
3096                                 g_assert_not_reached ();
3097                 } else {
3098                         if (ainfo->storage == ArgInIReg) {
3099                                 g_assert (mips_is_imm16 (inst->inst_offset));
3100                                 switch (ainfo->size) {
3101                                 case 1:
3102                                         mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3103                                         break;
3104                                 case 2:
3105                                         mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3106                                         break;
3107                                 case 0: /* XXX */
3108                                 case 4:
3109                                         mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3110                                         break;
3111                                 case 8:
3112                                         mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3113                                         mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3114                                         break;
3115                                 default:
3116                                         g_assert_not_reached ();
3117                                         break;
3118                                 }
3119                         } else if (ainfo->storage == ArgOnStack) {
3120                                 /* do nothing */
3121                         } else if (ainfo->storage == ArgInFReg) {
3122                                 g_assert (mips_is_imm16 (inst->inst_offset));
3123                                 if (ainfo->size == 8) {
3124 #if _MIPS_SIM == _ABIO32
3125                                         mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3126                                         mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3127 #elif _MIPS_SIM == _ABIN32
3128                                         mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3129 #endif
3130                                 }
3131                                 else if (ainfo->size == 4)
3132                                         mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3133                                 else
3134                                         g_assert_not_reached ();
3135                         } else if (ainfo->storage == ArgStructByVal) {
3136                                 int i;
3137                                 int doffset = inst->inst_offset;
3138
3139                                 g_assert (mips_is_imm16 (inst->inst_offset));
3140                                 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3141                                 for (i = 0; i < ainfo->size; ++i) {
3142                                         mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3143                                         doffset += SIZEOF_REGISTER;
3144                                 }
3145                         } else if (ainfo->storage == ArgStructByAddr) {
3146                                 g_assert (mips_is_imm16 (inst->inst_offset));
3147                                 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3148                         } else
3149                                 g_assert_not_reached ();
3150                 }
3151         }
3152
3153         return code;
3154 }
3155
3156 static guint8*
3157 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3158 {
3159         int size = cfg->param_area;
3160
3161         size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3162         size &= -MONO_ARCH_FRAME_ALIGNMENT;
3163
3164         if (!size)
3165                 return code;
3166 #if 0
3167         ppc_lwz (code, ppc_r0, 0, ppc_sp);
3168         if (ppc_is_imm16 (-size)) {
3169                 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3170         } else {
3171                 ppc_load (code, ppc_r12, -size);
3172                 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3173         }
3174 #endif
3175         return code;
3176 }
3177
3178 static guint8*
3179 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3180 {
3181         int size = cfg->param_area;
3182
3183         size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3184         size &= -MONO_ARCH_FRAME_ALIGNMENT;
3185
3186         if (!size)
3187                 return code;
3188 #if 0
3189         ppc_lwz (code, ppc_r0, 0, ppc_sp);
3190         if (ppc_is_imm16 (size)) {
3191                 ppc_stwu (code, ppc_r0, size, ppc_sp);
3192         } else {
3193                 ppc_load (code, ppc_r12, size);
3194                 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3195         }
3196 #endif
3197         return code;
3198 }
3199
3200 void
3201 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3202 {
3203         MonoInst *ins;
3204         MonoCallInst *call;
3205         guint offset;
3206         guint8 *code = cfg->native_code + cfg->code_len;
3207         MonoInst *last_ins = NULL;
3208         guint last_offset = 0;
3209         int max_len, cpos;
3210         int ins_cnt = 0;
3211
3212         /* we don't align basic blocks of loops on mips */
3213
3214         if (cfg->verbose_level > 2)
3215                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3216
3217         cpos = bb->max_offset;
3218
3219 #if 0
3220         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3221                 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3222                 g_assert (!mono_compile_aot);
3223                 cpos += 20;
3224                 if (bb->cil_code)
3225                         cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3226                 /* this is not thread save, but good enough */
3227                 /* fixme: howto handle overflows? */
3228                 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3229                 mips_lw (code, mips_temp, mips_at, 0);
3230                 mips_addiu (code, mips_temp, mips_temp, 1);
3231                 mips_sw (code, mips_temp, mips_at, 0);
3232         }
3233 #endif
3234         MONO_BB_FOR_EACH_INS (bb, ins) {
3235                 offset = code - cfg->native_code;
3236
3237                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3238
3239                 if (offset > (cfg->code_size - max_len - 16)) {
3240                         cfg->code_size *= 2;
3241                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3242                         code = cfg->native_code + offset;
3243                 }
3244                 mono_debug_record_line_number (cfg, ins, offset);
3245                 if (cfg->verbose_level > 2) {
3246                         g_print ("    @ 0x%x\t", offset);
3247                         mono_print_ins_index (ins_cnt++, ins);
3248                 }
3249                 /* Check for virtual regs that snuck by */
3250                 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3251
3252                 switch (ins->opcode) {
3253                 case OP_RELAXED_NOP:
3254                 case OP_NOP:
3255                 case OP_DUMMY_USE:
3256                 case OP_DUMMY_STORE:
3257                 case OP_NOT_REACHED:
3258                 case OP_NOT_NULL:
3259                         break;
3260                 case OP_IL_SEQ_POINT:
3261                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3262                         break;
3263                 case OP_SEQ_POINT: {
3264                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3265                                 guint32 addr = (guint32)ss_trigger_page;
3266
3267                                 mips_load_const (code, mips_t9, addr);
3268                                 mips_lw (code, mips_t9, mips_t9, 0);
3269                         }
3270
3271                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3272
3273                         /*
3274                          * A placeholder for a possible breakpoint inserted by
3275                          * mono_arch_set_breakpoint ().
3276                          */
3277                         /* mips_load_const () + mips_lw */
3278                         mips_nop (code);
3279                         mips_nop (code);
3280                         mips_nop (code);
3281                         break;
3282                 }
3283                 case OP_BIGMUL:
3284                         mips_mult (code, ins->sreg1, ins->sreg2);
3285                         mips_mflo (code, ins->dreg);
3286                         mips_mfhi (code, ins->dreg+1);
3287                         break;
3288                 case OP_BIGMUL_UN:
3289                         mips_multu (code, ins->sreg1, ins->sreg2);
3290                         mips_mflo (code, ins->dreg);
3291                         mips_mfhi (code, ins->dreg+1);
3292                         break;
3293                 case OP_MEMORY_BARRIER:
3294                         mips_sync (code, 0);
3295                         break;
3296                 case OP_STOREI1_MEMBASE_IMM:
3297                         mips_load_const (code, mips_temp, ins->inst_imm);
3298                         if (mips_is_imm16 (ins->inst_offset)) {
3299                                 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3300                         } else {
3301                                 mips_load_const (code, mips_at, ins->inst_offset);
3302                                 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3303                         }
3304                         break;
3305                 case OP_STOREI2_MEMBASE_IMM:
3306                         mips_load_const (code, mips_temp, ins->inst_imm);
3307                         if (mips_is_imm16 (ins->inst_offset)) {
3308                                 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3309                         } else {
3310                                 mips_load_const (code, mips_at, ins->inst_offset);
3311                                 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3312                         }
3313                         break;
3314                 case OP_STOREI8_MEMBASE_IMM:
3315                         mips_load_const (code, mips_temp, ins->inst_imm);
3316                         if (mips_is_imm16 (ins->inst_offset)) {
3317                                 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3318                         } else {
3319                                 mips_load_const (code, mips_at, ins->inst_offset);
3320                                 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3321                         }
3322                         break;
3323                 case OP_STORE_MEMBASE_IMM:
3324                 case OP_STOREI4_MEMBASE_IMM:
3325                         mips_load_const (code, mips_temp, ins->inst_imm);
3326                         if (mips_is_imm16 (ins->inst_offset)) {
3327                                 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3328                         } else {
3329                                 mips_load_const (code, mips_at, ins->inst_offset);
3330                                 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3331                         }
3332                         break;
3333                 case OP_STOREI1_MEMBASE_REG:
3334                         if (mips_is_imm16 (ins->inst_offset)) {
3335                                 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3336                         } else {
3337                                 mips_load_const (code, mips_at, ins->inst_offset);
3338                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3339                                 mips_sb (code, ins->sreg1, mips_at, 0);
3340                         }
3341                         break;
3342                 case OP_STOREI2_MEMBASE_REG:
3343                         if (mips_is_imm16 (ins->inst_offset)) {
3344                                 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3345                         } else {
3346                                 mips_load_const (code, mips_at, ins->inst_offset);
3347                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3348                                 mips_sh (code, ins->sreg1, mips_at, 0);
3349                         }
3350                         break;
3351                 case OP_STORE_MEMBASE_REG:
3352                 case OP_STOREI4_MEMBASE_REG:
3353                         if (mips_is_imm16 (ins->inst_offset)) {
3354                                 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3355                         } else {
3356                                 mips_load_const (code, mips_at, ins->inst_offset);
3357                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3358                                 mips_sw (code, ins->sreg1, mips_at, 0);
3359                         }
3360                         break;
3361                 case OP_STOREI8_MEMBASE_REG:
3362                         if (mips_is_imm16 (ins->inst_offset)) {
3363                                 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3364                         } else {
3365                                 mips_load_const (code, mips_at, ins->inst_offset);
3366                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3367                                 mips_sd (code, ins->sreg1, mips_at, 0);
3368                         }
3369                         break;
3370                 case OP_LOADU4_MEM:
3371                         g_assert_not_reached ();
3372                         //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3373                         //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3374                         break;
3375                 case OP_LOADI8_MEMBASE:
3376                         if (mips_is_imm16 (ins->inst_offset)) {
3377                                 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3378                         } else {
3379                                 mips_load_const (code, mips_at, ins->inst_offset);
3380                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3381                                 mips_ld (code, ins->dreg, mips_at, 0);
3382                         }
3383                         break;
3384                 case OP_LOAD_MEMBASE:
3385                 case OP_LOADI4_MEMBASE:
3386                 case OP_LOADU4_MEMBASE:
3387                         g_assert (ins->dreg != -1);
3388                         if (mips_is_imm16 (ins->inst_offset)) {
3389                                 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3390                         } else {
3391                                 mips_load_const (code, mips_at, ins->inst_offset);
3392                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3393                                 mips_lw (code, ins->dreg, mips_at, 0);
3394                         }
3395                         break;
3396                 case OP_LOADI1_MEMBASE:
3397                         if (mips_is_imm16 (ins->inst_offset)) {
3398                                 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3399                         } else {
3400                                 mips_load_const (code, mips_at, ins->inst_offset);
3401                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3402                                 mips_lb (code, ins->dreg, mips_at, 0);
3403                         }
3404                         break;
3405                 case OP_LOADU1_MEMBASE:
3406                         if (mips_is_imm16 (ins->inst_offset)) {
3407                                 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3408                         } else {
3409                                 mips_load_const (code, mips_at, ins->inst_offset);
3410                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3411                                 mips_lbu (code, ins->dreg, mips_at, 0);
3412                         }
3413                         break;
3414                 case OP_LOADI2_MEMBASE:
3415                         if (mips_is_imm16 (ins->inst_offset)) {
3416                                 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3417                         } else {
3418                                 mips_load_const (code, mips_at, ins->inst_offset);
3419                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3420                                 mips_lh (code, ins->dreg, mips_at, 0);
3421                         }
3422                         break;
3423                 case OP_LOADU2_MEMBASE:
3424                         if (mips_is_imm16 (ins->inst_offset)) {
3425                                 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3426                         } else {
3427                                 mips_load_const (code, mips_at, ins->inst_offset);
3428                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3429                                 mips_lhu (code, ins->dreg, mips_at, 0);
3430                         }
3431                         break;
3432                 case OP_ICONV_TO_I1:
3433                         mips_sll (code, mips_at, ins->sreg1, 24);
3434                         mips_sra (code, ins->dreg, mips_at, 24);
3435                         break;
3436                 case OP_ICONV_TO_I2:
3437                         mips_sll (code, mips_at, ins->sreg1, 16);
3438                         mips_sra (code, ins->dreg, mips_at, 16);
3439                         break;
3440                 case OP_ICONV_TO_U1:
3441                         mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3442                         break;
3443                 case OP_ICONV_TO_U2:
3444                         mips_sll (code, mips_at, ins->sreg1, 16);
3445                         mips_srl (code, ins->dreg, mips_at, 16);
3446                         break;
3447                 case OP_MIPS_SLT:
3448                         mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3449                         break;
3450                 case OP_MIPS_SLTI:
3451                         g_assert (mips_is_imm16 (ins->inst_imm));
3452                         mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3453                         break;
3454                 case OP_MIPS_SLTU:
3455                         mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3456                         break;
3457                 case OP_MIPS_SLTIU:
3458                         g_assert (mips_is_imm16 (ins->inst_imm));
3459                         mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3460                         break;
3461                 case OP_BREAK:
3462                         /*
3463                          * gdb does not like encountering the hw breakpoint ins in the debugged code. 
3464                          * So instead of emitting a trap, we emit a call a C function and place a 
3465                          * breakpoint there.
3466                          */
3467                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3468                                                                  (gpointer)"mono_break");
3469                         mips_load (code, mips_t9, 0x1f1f1f1f);
3470                         mips_jalr (code, mips_t9, mips_ra);
3471                         mips_nop (code);
3472                         break;
3473                 case OP_IADD:
3474                         mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3475                         break;
3476                 case OP_LADD:
3477                         mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3478                         break;
3479
3480                 case OP_ADD_IMM:
3481                 case OP_IADD_IMM:
3482                         g_assert (mips_is_imm16 (ins->inst_imm));
3483                         mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3484                         break;
3485                 case OP_LADD_IMM:
3486                         g_assert (mips_is_imm16 (ins->inst_imm));
3487                         mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3488                         break;
3489
3490                 case OP_ISUB:
3491                         mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3492                         break;
3493                 case OP_LSUB:
3494                         mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3495                         break;
3496
3497                 case OP_ISUB_IMM:
3498                 case OP_SUB_IMM:
3499                         // we add the negated value
3500                         g_assert (mips_is_imm16 (-ins->inst_imm));
3501                         mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3502                         break;
3503
3504                 case OP_LSUB_IMM:
3505                         // we add the negated value
3506                         g_assert (mips_is_imm16 (-ins->inst_imm));
3507                         mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3508                         break;
3509
3510                 case OP_IAND:
3511                 case OP_LAND:
3512                         mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3513                         break;
3514
3515                 case OP_AND_IMM:
3516                 case OP_IAND_IMM:
3517                 case OP_LAND_IMM:
3518                         g_assert (!(ins->inst_imm & 0xffff0000));
3519                         mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3520                         break;
3521
3522                 case OP_IDIV:
3523                 case OP_IREM: {
3524                         guint32 *divisor_is_m1;
3525                         guint32 *dividend_is_minvalue;
3526                         guint32 *divisor_is_zero;
3527
3528                         mips_load_const (code, mips_at, -1);
3529                         divisor_is_m1 = (guint32 *)(void *)code;
3530                         mips_bne (code, ins->sreg2, mips_at, 0);
3531                         mips_lui (code, mips_at, mips_zero, 0x8000);
3532                         dividend_is_minvalue = (guint32 *)(void *)code;
3533                         mips_bne (code, ins->sreg1, mips_at, 0);
3534                         mips_nop (code);
3535
3536                         /* Divide Int32.MinValue by -1 -- throw exception */
3537                         EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3538
3539                         mips_patch (divisor_is_m1, (guint32)code);
3540                         mips_patch (dividend_is_minvalue, (guint32)code);
3541
3542                         /* Put divide in branch delay slot (NOT YET) */
3543                         divisor_is_zero = (guint32 *)(void *)code;
3544                         mips_bne (code, ins->sreg2, mips_zero, 0);
3545                         mips_nop (code);
3546
3547                         /* Divide by zero -- throw exception */
3548                         EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3549
3550                         mips_patch (divisor_is_zero, (guint32)code);
3551                         mips_div (code, ins->sreg1, ins->sreg2);
3552                         if (ins->opcode == OP_IDIV)
3553                                 mips_mflo (code, ins->dreg);
3554                         else
3555                                 mips_mfhi (code, ins->dreg);
3556                         break;
3557                 }
3558                 case OP_IDIV_UN: 
3559                 case OP_IREM_UN: {
3560                         guint32 *divisor_is_zero = (guint32 *)(void *)code;
3561
3562                         /* Put divide in branch delay slot (NOT YET) */
3563                         mips_bne (code, ins->sreg2, mips_zero, 0);
3564                         mips_nop (code);
3565
3566                         /* Divide by zero -- throw exception */
3567                         EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3568
3569                         mips_patch (divisor_is_zero, (guint32)code);
3570                         mips_divu (code, ins->sreg1, ins->sreg2);
3571                         if (ins->opcode == OP_IDIV_UN)
3572                                 mips_mflo (code, ins->dreg);
3573                         else
3574                                 mips_mfhi (code, ins->dreg);
3575                         break;
3576                 }
3577                 case OP_DIV_IMM:
3578                         g_assert_not_reached ();
3579 #if 0
3580                         ppc_load (code, ppc_r12, ins->inst_imm);
3581                         ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3582                         ppc_mfspr (code, ppc_r0, ppc_xer);
3583                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3584                         /* FIXME: use OverflowException for 0x80000000/-1 */
3585                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3586 #endif
3587                         g_assert_not_reached();
3588                         break;
3589                 case OP_REM_IMM:
3590                         g_assert_not_reached ();
3591                 case OP_IOR:
3592                         mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3593                         break;
3594                 case OP_OR_IMM:
3595                 case OP_IOR_IMM:
3596                         g_assert (!(ins->inst_imm & 0xffff0000));
3597                         mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3598                         break;
3599                 case OP_IXOR:
3600                         mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3601                         break;
3602                 case OP_XOR_IMM:
3603                 case OP_IXOR_IMM:
3604                         /* unsigned 16-bit immediate */
3605                         g_assert (!(ins->inst_imm & 0xffff0000));
3606                         mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3607                         break;
3608                 case OP_ISHL:
3609                         mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3610                         break;
3611                 case OP_SHL_IMM:
3612                 case OP_ISHL_IMM:
3613                         mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3614                         break;
3615                 case OP_ISHR:
3616                         mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3617                         break;
3618                 case OP_LSHR:
3619                         mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3620                         break;
3621                 case OP_SHR_IMM:
3622                 case OP_ISHR_IMM:
3623                         mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3624                         break;
3625                 case OP_LSHR_IMM:
3626                         mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3627                         break;
3628                 case OP_SHR_UN_IMM:
3629                 case OP_ISHR_UN_IMM:
3630                         mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3631                         break;
3632                 case OP_LSHR_UN_IMM:
3633                         mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3634                         break;
3635                 case OP_ISHR_UN:
3636                         mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3637                         break;
3638                 case OP_LSHR_UN:
3639                         mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3640                         break;
3641                 case OP_INOT:
3642                 case OP_LNOT:
3643                         mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3644                         break;
3645                 case OP_INEG:
3646                         mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3647                         break;
3648                 case OP_LNEG:
3649                         mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3650                         break;
3651                 case OP_IMUL:
3652 #if USE_MUL
3653                         mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3654 #else
3655                         mips_mult (code, ins->sreg1, ins->sreg2);
3656                         mips_mflo (code, ins->dreg);
3657                         mips_nop (code);
3658                         mips_nop (code);
3659 #endif
3660                         break;
3661 #if SIZEOF_REGISTER == 8
3662                 case OP_LMUL:
3663                         mips_dmult (code, ins->sreg1, ins->sreg2);
3664                         mips_mflo (code, ins->dreg);
3665                         break;
3666 #endif
3667                 case OP_IMUL_OVF: {
3668                         guint32 *patch;
3669                         mips_mult (code, ins->sreg1, ins->sreg2);
3670                         mips_mflo (code, ins->dreg);
3671                         mips_mfhi (code, mips_at);
3672                         mips_nop (code);
3673                         mips_nop (code);
3674                         mips_sra (code, mips_temp, ins->dreg, 31);
3675                         patch = (guint32 *)(void *)code;
3676                         mips_beq (code, mips_temp, mips_at, 0);
3677                         mips_nop (code);
3678                         EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3679                         mips_patch (patch, (guint32)code);
3680                         break;
3681                 }
3682                 case OP_IMUL_OVF_UN: {
3683                         guint32 *patch;
3684                         mips_mult (code, ins->sreg1, ins->sreg2);
3685                         mips_mflo (code, ins->dreg);
3686                         mips_mfhi (code, mips_at);
3687                         mips_nop (code);
3688                         mips_nop (code);
3689                         patch = (guint32 *)(void *)code;
3690                         mips_beq (code, mips_at, mips_zero, 0);
3691                         mips_nop (code);
3692                         EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3693                         mips_patch (patch, (guint32)code);
3694                         break;
3695                 }
3696                 case OP_ICONST:
3697                         mips_load_const (code, ins->dreg, ins->inst_c0);
3698                         break;
3699 #if SIZEOF_REGISTER == 8
3700                 case OP_I8CONST:
3701                         mips_load_const (code, ins->dreg, ins->inst_c0);
3702                         break;
3703 #endif
3704                 case OP_AOTCONST:
3705                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3706                         mips_load (code, ins->dreg, 0);
3707                         break;
3708
3709                 case OP_MIPS_MTC1S:
3710                         mips_mtc1 (code, ins->dreg, ins->sreg1);
3711                         break;
3712                 case OP_MIPS_MTC1S_2:
3713                         mips_mtc1 (code, ins->dreg, ins->sreg1);
3714                         mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3715                         break;
3716                 case OP_MIPS_MFC1S:
3717                         mips_mfc1 (code, ins->dreg, ins->sreg1);
3718                         break;
3719                 case OP_MIPS_MTC1D:
3720                         mips_dmtc1 (code, ins->dreg, ins->sreg1);
3721                         break;
3722                 case OP_MIPS_MFC1D:
3723 #if 0
3724                         mips_dmfc1 (code, ins->dreg, ins->sreg1);
3725 #else
3726                         mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3727                         mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3728 #endif
3729                         break;
3730
3731                 case OP_ICONV_TO_I4:
3732                 case OP_ICONV_TO_U4:
3733                 case OP_MOVE:
3734                         if (ins->dreg != ins->sreg1)
3735                                 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3736                         break;
3737 #if SIZEOF_REGISTER == 8
3738                 case OP_ZEXT_I4:
3739                         mips_dsll (code, ins->dreg, ins->sreg1, 32);
3740                         mips_dsrl (code, ins->dreg, ins->dreg, 32);
3741                         break;
3742                 case OP_SEXT_I4:
3743                         mips_dsll (code, ins->dreg, ins->sreg1, 32);
3744                         mips_dsra (code, ins->dreg, ins->dreg, 32);
3745                         break;
3746 #endif
3747                 case OP_SETLRET: {
3748                         int lsreg = mips_v0 + ls_word_idx;
3749                         int msreg = mips_v0 + ms_word_idx;
3750
3751                         /* Get sreg1 into lsreg, sreg2 into msreg */
3752
3753                         if (ins->sreg1 == msreg) {
3754                                 if (ins->sreg1 != mips_at)
3755                                         MIPS_MOVE (code, mips_at, ins->sreg1);
3756                                 if (ins->sreg2 != msreg)
3757                                         MIPS_MOVE (code, msreg, ins->sreg2);
3758                                 MIPS_MOVE (code, lsreg, mips_at);
3759                         }
3760                         else {
3761                                 if (ins->sreg2 != msreg)
3762                                         MIPS_MOVE (code, msreg, ins->sreg2);
3763                                 if (ins->sreg1 != lsreg)
3764                                         MIPS_MOVE (code, lsreg, ins->sreg1);
3765                         }
3766                         break;
3767                 }
3768                 case OP_FMOVE:
3769                         if (ins->dreg != ins->sreg1) {
3770                                 mips_fmovd (code, ins->dreg, ins->sreg1);
3771                         }
3772                         break;
3773                 case OP_MOVE_F_TO_I4:
3774                         mips_cvtsd (code, mips_ftemp, ins->sreg1);
3775                         mips_mfc1 (code, ins->dreg, mips_ftemp);
3776                         break;
3777                 case OP_MOVE_I4_TO_F:
3778                         mips_mtc1 (code, ins->dreg, ins->sreg1);
3779                         mips_cvtds (code, ins->dreg, ins->dreg);
3780                         break;
3781                 case OP_MIPS_CVTSD:
3782                         /* Convert from double to float and leave it there */
3783                         mips_cvtsd (code, ins->dreg, ins->sreg1);
3784                         break;
3785                 case OP_FCONV_TO_R4:
3786 #if 0
3787                         mips_cvtsd (code, ins->dreg, ins->sreg1);
3788 #else
3789                         /* Just a move, no precision change */
3790                         if (ins->dreg != ins->sreg1) {
3791                                 mips_fmovd (code, ins->dreg, ins->sreg1);
3792                         }
3793 #endif
3794                         break;
3795                 case OP_JMP:
3796                         code = emit_load_volatile_arguments(cfg, code);
3797
3798                         /*
3799                          * Pop our stack, then jump to specified method (tail-call)
3800                          * Keep in sync with mono_arch_emit_epilog
3801                          */
3802                         code = mono_arch_emit_epilog_sub (cfg, code);
3803
3804                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3805                                              MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3806                         mips_load (code, mips_t9, 0);
3807                         mips_jr (code, mips_t9);
3808                         mips_nop (code);
3809                         break;
3810                 case OP_CHECK_THIS:
3811                         /* ensure ins->sreg1 is not NULL */
3812                         mips_lw (code, mips_zero, ins->sreg1, 0);
3813                         break;
3814                 case OP_ARGLIST: {
3815                         g_assert (mips_is_imm16 (cfg->sig_cookie));
3816                         mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3817                         mips_sw (code, mips_at, ins->sreg1, 0);
3818                         break;
3819                 }
3820                 case OP_FCALL:
3821                 case OP_LCALL:
3822                 case OP_VCALL:
3823                 case OP_VCALL2:
3824                 case OP_VOIDCALL:
3825                 case OP_CALL:
3826                 case OP_FCALL_REG:
3827                 case OP_LCALL_REG:
3828                 case OP_VCALL_REG:
3829                 case OP_VCALL2_REG:
3830                 case OP_VOIDCALL_REG:
3831                 case OP_CALL_REG:
3832                 case OP_FCALL_MEMBASE:
3833                 case OP_LCALL_MEMBASE:
3834                 case OP_VCALL_MEMBASE:
3835                 case OP_VCALL2_MEMBASE:
3836                 case OP_VOIDCALL_MEMBASE:
3837                 case OP_CALL_MEMBASE:
3838                         call = (MonoCallInst*)ins;
3839                         switch (ins->opcode) {
3840                         case OP_FCALL:
3841                         case OP_LCALL:
3842                         case OP_VCALL:
3843                         case OP_VCALL2:
3844                         case OP_VOIDCALL:
3845                         case OP_CALL:
3846                                 if (ins->flags & MONO_INST_HAS_METHOD) {
3847                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3848                                         mips_load (code, mips_t9, call->method);
3849                                 }
3850                                 else {
3851                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3852                                         mips_load (code, mips_t9, call->fptr);
3853                                 }
3854                                 mips_jalr (code, mips_t9, mips_ra);
3855                                 mips_nop (code);
3856                                 break;
3857                         case OP_FCALL_REG:
3858                         case OP_LCALL_REG:
3859                         case OP_VCALL_REG:
3860                         case OP_VCALL2_REG:
3861                         case OP_VOIDCALL_REG:
3862                         case OP_CALL_REG:
3863                                 MIPS_MOVE (code, mips_t9, ins->sreg1);
3864                                 mips_jalr (code, mips_t9, mips_ra);
3865                                 mips_nop (code);
3866                                 break;
3867                         case OP_FCALL_MEMBASE:
3868                         case OP_LCALL_MEMBASE:
3869                         case OP_VCALL_MEMBASE:
3870                         case OP_VCALL2_MEMBASE:
3871                         case OP_VOIDCALL_MEMBASE:
3872                         case OP_CALL_MEMBASE:
3873                                 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3874                                 mips_jalr (code, mips_t9, mips_ra);
3875                                 mips_nop (code);
3876                                 break;
3877                         }
3878 #if PROMOTE_R4_TO_R8
3879                         /* returned an FP R4 (single), promote to R8 (double) in place */
3880                         switch (ins->opcode) {
3881                         case OP_FCALL:
3882                         case OP_FCALL_REG:
3883                         case OP_FCALL_MEMBASE:
3884                             if (call->signature->ret->type == MONO_TYPE_R4)
3885                                         mips_cvtds (code, mips_f0, mips_f0);
3886                                 break;
3887                         default:
3888                                 break;
3889                         }
3890 #endif
3891                         break;
3892                 case OP_LOCALLOC: {
3893                         int area_offset = cfg->param_area;
3894
3895                         /* Round up ins->sreg1, mips_at ends up holding size */
3896                         mips_addiu (code, mips_at, ins->sreg1, 31);
3897                         mips_addiu (code, mips_temp, mips_zero, ~31);
3898                         mips_and (code, mips_at, mips_at, mips_temp);
3899
3900                         mips_subu (code, mips_sp, mips_sp, mips_at);
3901                         g_assert (mips_is_imm16 (area_offset));
3902                         mips_addiu (code, ins->dreg, mips_sp, area_offset);
3903
3904                         if (ins->flags & MONO_INST_INIT) {
3905                                 guint32 *buf;
3906
3907                                 buf = (guint32*)(void*)code;
3908                                 mips_beq (code, mips_at, mips_zero, 0);
3909                                 mips_nop (code);
3910
3911                                 mips_move (code, mips_temp, ins->dreg);
3912                                 mips_sb (code, mips_zero, mips_temp, 0);
3913                                 mips_addiu (code, mips_at, mips_at, -1);
3914                                 mips_bne (code, mips_at, mips_zero, -3);
3915                                 mips_addiu (code, mips_temp, mips_temp, 1);
3916
3917                                 mips_patch (buf, (guint32)code);
3918                         }
3919                         break;
3920                 }
3921                 case OP_THROW: {
3922                         gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3923                         mips_move (code, mips_a0, ins->sreg1);
3924                         mips_call (code, mips_t9, addr);
3925                         mips_break (code, 0xfc);
3926                         break;
3927                 }
3928                 case OP_RETHROW: {
3929                         gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3930                         mips_move (code, mips_a0, ins->sreg1);
3931                         mips_call (code, mips_t9, addr);
3932                         mips_break (code, 0xfb);
3933                         break;
3934                 }
3935                 case OP_START_HANDLER: {
3936                         /*
3937                          * The START_HANDLER instruction marks the beginning of
3938                          * a handler block. It is called using a call
3939                          * instruction, so mips_ra contains the return address.
3940                          * Since the handler executes in the same stack frame
3941                          * as the method itself, we can't use save/restore to
3942                          * save the return address. Instead, we save it into
3943                          * a dedicated variable.
3944                          */
3945                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3946                         g_assert (spvar->inst_basereg != mips_sp);
3947                         code = emit_reserve_param_area (cfg, code);
3948
3949                         if (mips_is_imm16 (spvar->inst_offset)) {
3950                                 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3951                         } else {
3952                                 mips_load_const (code, mips_at, spvar->inst_offset);
3953                                 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3954                                 mips_sw (code, mips_ra, mips_at, 0);
3955                         }
3956                         break;
3957                 }
3958                 case OP_ENDFILTER: {
3959                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3960                         g_assert (spvar->inst_basereg != mips_sp);
3961                         code = emit_unreserve_param_area (cfg, code);
3962
3963                         if (ins->sreg1 != mips_v0)
3964                                 MIPS_MOVE (code, mips_v0, ins->sreg1);
3965                         if (mips_is_imm16 (spvar->inst_offset)) {
3966                                 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3967                         } else {
3968                                 mips_load_const (code, mips_at, spvar->inst_offset);
3969                                 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3970                                 mips_lw (code, mips_ra, mips_at, 0);
3971                         }
3972                         mips_jr (code, mips_ra);
3973                         mips_nop (code);
3974                         break;
3975                 }
3976                 case OP_ENDFINALLY: {
3977                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3978                         g_assert (spvar->inst_basereg != mips_sp);
3979                         code = emit_unreserve_param_area (cfg, code);
3980                         mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3981                         mips_jalr (code, mips_t9, mips_ra);
3982                         mips_nop (code);
3983                         break;
3984                 }
3985                 case OP_CALL_HANDLER: 
3986                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3987                         mips_lui (code, mips_t9, mips_zero, 0);
3988                         mips_addiu (code, mips_t9, mips_t9, 0);
3989                         mips_jalr (code, mips_t9, mips_ra);
3990                         mips_nop (code);
3991                         /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3992                         mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3993                         break;
3994                 case OP_LABEL:
3995                         ins->inst_c0 = code - cfg->native_code;
3996                         break;
3997                 case OP_BR:
3998                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3999                         if (cfg->arch.long_branch) {
4000                                 mips_lui (code, mips_at, mips_zero, 0);
4001                                 mips_addiu (code, mips_at, mips_at, 0);
4002                                 mips_jr (code, mips_at);
4003                                 mips_nop (code);
4004                         }
4005                         else {
4006                                 mips_beq (code, mips_zero, mips_zero, 0);
4007                                 mips_nop (code);
4008                         }
4009                         break;
4010                 case OP_BR_REG:
4011                         mips_jr (code, ins->sreg1);
4012                         mips_nop (code);
4013                         break;
4014                 case OP_SWITCH: {
4015                         int i;
4016
4017                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
4018                         if (offset > (cfg->code_size - max_len - 16)) {
4019                                 cfg->code_size += max_len;
4020                                 cfg->code_size *= 2;
4021                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4022                                 code = cfg->native_code + offset;
4023                         }
4024                         g_assert (ins->sreg1 != -1);
4025                         mips_sll (code, mips_at, ins->sreg1, 2);
4026                         if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4027                                 MIPS_MOVE (code, mips_t8, mips_ra);
4028                         mips_bgezal (code, mips_zero, 1);       /* bal */
4029                         mips_nop (code);
4030                         mips_addu (code, mips_t9, mips_ra, mips_at);
4031                         /* Table is 16 or 20 bytes from target of bal above */
4032                         if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4033                                 MIPS_MOVE (code, mips_ra, mips_t8);
4034                                 mips_lw (code, mips_t9, mips_t9, 20);
4035                         }
4036                         else
4037                                 mips_lw (code, mips_t9, mips_t9, 16);
4038                         mips_jalr (code, mips_t9, mips_t8);
4039                         mips_nop (code);
4040                         for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4041                                 mips_emit32 (code, 0xfefefefe);
4042                         break;
4043                 }
4044                 case OP_CEQ:
4045                 case OP_ICEQ:
4046                         mips_addiu (code, ins->dreg, mips_zero, 1);
4047                         mips_beq (code, mips_at, mips_zero, 2);
4048                         mips_nop (code);
4049                         MIPS_MOVE (code, ins->dreg, mips_zero);
4050                         break;
4051                 case OP_CLT:
4052                 case OP_CLT_UN:
4053                 case OP_ICLT:
4054                 case OP_ICLT_UN:
4055                         mips_addiu (code, ins->dreg, mips_zero, 1);
4056                         mips_bltz (code, mips_at, 2);
4057                         mips_nop (code);
4058                         MIPS_MOVE (code, ins->dreg, mips_zero);
4059                         break;
4060                 case OP_CGT:
4061                 case OP_CGT_UN:
4062                 case OP_ICGT:
4063                 case OP_ICGT_UN:
4064                         mips_addiu (code, ins->dreg, mips_zero, 1);
4065                         mips_bgtz (code, mips_at, 2);
4066                         mips_nop (code);
4067                         MIPS_MOVE (code, ins->dreg, mips_zero);
4068                         break;
4069
4070                 case OP_MIPS_COND_EXC_EQ:
4071                 case OP_MIPS_COND_EXC_GE:
4072                 case OP_MIPS_COND_EXC_GT:
4073                 case OP_MIPS_COND_EXC_LE:
4074                 case OP_MIPS_COND_EXC_LT:
4075                 case OP_MIPS_COND_EXC_NE_UN:
4076                 case OP_MIPS_COND_EXC_GE_UN:
4077                 case OP_MIPS_COND_EXC_GT_UN:
4078                 case OP_MIPS_COND_EXC_LE_UN:
4079                 case OP_MIPS_COND_EXC_LT_UN:
4080
4081                 case OP_MIPS_COND_EXC_OV:
4082                 case OP_MIPS_COND_EXC_NO:
4083                 case OP_MIPS_COND_EXC_C:
4084                 case OP_MIPS_COND_EXC_NC:
4085
4086                 case OP_MIPS_COND_EXC_IEQ:
4087                 case OP_MIPS_COND_EXC_IGE:
4088                 case OP_MIPS_COND_EXC_IGT:
4089                 case OP_MIPS_COND_EXC_ILE:
4090                 case OP_MIPS_COND_EXC_ILT:
4091                 case OP_MIPS_COND_EXC_INE_UN:
4092                 case OP_MIPS_COND_EXC_IGE_UN:
4093                 case OP_MIPS_COND_EXC_IGT_UN:
4094                 case OP_MIPS_COND_EXC_ILE_UN:
4095                 case OP_MIPS_COND_EXC_ILT_UN:
4096
4097                 case OP_MIPS_COND_EXC_IOV:
4098                 case OP_MIPS_COND_EXC_INO:
4099                 case OP_MIPS_COND_EXC_IC:
4100                 case OP_MIPS_COND_EXC_INC: {
4101                         guint32 *skip;
4102                         guint32 *throw;
4103
4104                         /* If the condition is true, raise the exception */
4105
4106                         /* need to reverse test to skip around exception raising */
4107
4108                         /* For the moment, branch around a branch to avoid reversing
4109                            the tests. */
4110
4111                         /* Remember, an unpatched branch to 0 branches to the delay slot */
4112                         switch (ins->opcode) {
4113                         case OP_MIPS_COND_EXC_EQ:
4114                                 throw = (guint32 *)(void *)code;
4115                                 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4116                                 mips_nop (code);
4117                                 break;
4118
4119                         case OP_MIPS_COND_EXC_NE_UN:
4120                                 throw = (guint32 *)(void *)code;
4121                                 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4122                                 mips_nop (code);
4123                                 break;
4124
4125                         case OP_MIPS_COND_EXC_LE_UN:
4126                                 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4127                                 throw = (guint32 *)(void *)code;
4128                                 mips_beq (code, mips_at, mips_zero, 0);
4129                                 mips_nop (code);
4130                                 break;
4131
4132                         case OP_MIPS_COND_EXC_GT:
4133                                 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4134                                 throw = (guint32 *)(void *)code;
4135                                 mips_bne (code, mips_at, mips_zero, 0);
4136                                 mips_nop (code);
4137                                 break;
4138
4139                         case OP_MIPS_COND_EXC_GT_UN:
4140                                 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4141                                 throw = (guint32 *)(void *)code;
4142                                 mips_bne (code, mips_at, mips_zero, 0);
4143                                 mips_nop (code);
4144                                 break;
4145
4146                         case OP_MIPS_COND_EXC_LT:
4147                                 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4148                                 throw = (guint32 *)(void *)code;
4149                                 mips_bne (code, mips_at, mips_zero, 0);
4150                                 mips_nop (code);
4151                                 break;
4152
4153                         case OP_MIPS_COND_EXC_LT_UN:
4154                                 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4155                                 throw = (guint32 *)(void *)code;
4156                                 mips_bne (code, mips_at, mips_zero, 0);
4157                                 mips_nop (code);
4158                                 break;
4159
4160                         default:
4161                                 /* Not yet implemented */
4162                                 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4163                                 g_assert_not_reached ();
4164                         }
4165                         skip = (guint32 *)(void *)code;
4166                         mips_beq (code, mips_zero, mips_zero, 0);
4167                         mips_nop (code);
4168                         mips_patch (throw, (guint32)code);
4169                         code = mips_emit_exc_by_name (code, ins->inst_p1);
4170                         mips_patch (skip, (guint32)code);
4171                         cfg->bb_exit->max_offset += 24;
4172                         break;
4173                 }
4174                 case OP_MIPS_BEQ:
4175                 case OP_MIPS_BNE:
4176                 case OP_MIPS_BGEZ:
4177                 case OP_MIPS_BGTZ:
4178                 case OP_MIPS_BLEZ:
4179                 case OP_MIPS_BLTZ:
4180                         code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4181                         break;
4182
4183                 /* floating point opcodes */
4184                 case OP_R8CONST:
4185 #if 0
4186                         if (((guint32)ins->inst_p0) & (1 << 15))
4187                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4188                         else
4189                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4190                         mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4191 #else
4192                         mips_load_const (code, mips_at, ins->inst_p0);
4193                         mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4194                         mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4195 #endif
4196                         break;
4197                 case OP_R4CONST:
4198                         if (((guint32)ins->inst_p0) & (1 << 15))
4199                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4200                         else
4201                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4202                         mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4203 #if PROMOTE_R4_TO_R8
4204                         mips_cvtds (code, ins->dreg, ins->dreg);
4205 #endif
4206                         break;
4207                 case OP_STORER8_MEMBASE_REG:
4208                         if (mips_is_imm16 (ins->inst_offset)) {
4209 #if _MIPS_SIM == _ABIO32
4210                                 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4211                                 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4212 #elif _MIPS_SIM == _ABIN32
4213                                 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4214 #endif
4215                         } else {
4216                                 mips_load_const (code, mips_at, ins->inst_offset);
4217                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4218                                 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4219                                 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4220                         }
4221                         break;
4222                 case OP_LOADR8_MEMBASE:
4223                         if (mips_is_imm16 (ins->inst_offset)) {
4224 #if _MIPS_SIM == _ABIO32
4225                                 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4226                                 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4227 #elif _MIPS_SIM == _ABIN32
4228                                 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4229 #endif
4230                         } else {
4231                                 mips_load_const (code, mips_at, ins->inst_offset);
4232                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4233                                 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4234                                 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4235                         }
4236                         break;
4237                 case OP_STORER4_MEMBASE_REG:
4238                         g_assert (mips_is_imm16 (ins->inst_offset));
4239 #if PROMOTE_R4_TO_R8
4240                         /* Need to convert ins->sreg1 to single-precision first */
4241                         mips_cvtsd (code, mips_ftemp, ins->sreg1);
4242                         mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4243 #else
4244                         mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4245 #endif
4246                         break;
4247                 case OP_MIPS_LWC1:
4248                         g_assert (mips_is_imm16 (ins->inst_offset));
4249                         mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4250                         break;
4251                 case OP_LOADR4_MEMBASE:
4252                         g_assert (mips_is_imm16 (ins->inst_offset));
4253                         mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4254 #if PROMOTE_R4_TO_R8
4255                         /* Convert to double precision in place */
4256                         mips_cvtds (code, ins->dreg, ins->dreg);
4257 #endif
4258                         break;
4259                 case OP_LOADR4_MEMINDEX:
4260                         mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4261                         mips_lwc1 (code, ins->dreg, mips_at, 0);
4262                         break;
4263                 case OP_LOADR8_MEMINDEX:
4264                         mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4265 #if _MIPS_SIM == _ABIO32
4266                         mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4267                         mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4268 #elif _MIPS_SIM == _ABIN32
4269                         mips_ldc1 (code, ins->dreg, mips_at, 0);
4270 #endif
4271                         break;
4272                 case OP_STORER4_MEMINDEX:
4273                         mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4274 #if PROMOTE_R4_TO_R8
4275                         /* Need to convert ins->sreg1 to single-precision first */
4276                         mips_cvtsd (code, mips_ftemp, ins->sreg1);
4277                         mips_swc1 (code, mips_ftemp, mips_at, 0);
4278 #else
4279                         mips_swc1 (code, ins->sreg1, mips_at, 0);
4280 #endif
4281                         break;
4282                 case OP_STORER8_MEMINDEX:
4283                         mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4284 #if _MIPS_SIM == _ABIO32
4285                         mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4286                         mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4287 #elif _MIPS_SIM == _ABIN32
4288                         mips_sdc1 (code, ins->sreg1, mips_at, 0);
4289 #endif
4290                         break;
4291                 case OP_ICONV_TO_R_UN: {
4292                         static const guint64 adjust_val = 0x41F0000000000000ULL;
4293
4294                         /* convert unsigned int to double */
4295                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4296                         mips_bgez (code, ins->sreg1, 5);
4297                         mips_cvtdw (code, ins->dreg, mips_ftemp);
4298
4299                         mips_load (code, mips_at, (guint32) &adjust_val);
4300                         mips_ldc1  (code, mips_ftemp, mips_at, 0);
4301                         mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4302                         /* target is here */
4303                         break;
4304                 }
4305                 case OP_ICONV_TO_R4:
4306                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4307                         mips_cvtsw (code, ins->dreg, mips_ftemp);
4308                         mips_cvtds (code, ins->dreg, ins->dreg);
4309                         break;
4310                 case OP_ICONV_TO_R8:
4311                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4312                         mips_cvtdw (code, ins->dreg, mips_ftemp);
4313                         break;
4314                 case OP_FCONV_TO_I1:
4315                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4316                         break;
4317                 case OP_FCONV_TO_U1:
4318                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4319                         break;
4320                 case OP_FCONV_TO_I2:
4321                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4322                         break;
4323                 case OP_FCONV_TO_U2:
4324                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4325                         break;
4326                 case OP_FCONV_TO_I4:
4327                 case OP_FCONV_TO_I:
4328                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4329                         break;
4330                 case OP_FCONV_TO_U4:
4331                 case OP_FCONV_TO_U:
4332                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4333                         break;
4334                 case OP_SQRT:
4335                         mips_fsqrtd (code, ins->dreg, ins->sreg1);
4336                         break;
4337                 case OP_FADD:
4338                         mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4339                         break;
4340                 case OP_FSUB:
4341                         mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4342                         break;          
4343                 case OP_FMUL:
4344                         mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4345                         break;          
4346                 case OP_FDIV:
4347                         mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4348                         break;          
4349                 case OP_FNEG:
4350                         mips_fnegd (code, ins->dreg, ins->sreg1);
4351                         break;          
4352                 case OP_FCEQ:
4353                         mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4354                         mips_addiu (code, ins->dreg, mips_zero, 1);
4355                         mips_fbtrue (code, 2);
4356                         mips_nop (code);
4357                         MIPS_MOVE (code, ins->dreg, mips_zero);
4358                         break;
4359                 case OP_FCLT:
4360                         mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4361                         mips_addiu (code, ins->dreg, mips_zero, 1);
4362                         mips_fbtrue (code, 2);
4363                         mips_nop (code);
4364                         MIPS_MOVE (code, ins->dreg, mips_zero);
4365                         break;
4366                 case OP_FCLT_UN:
4367                         /* Less than, or Unordered */
4368                         mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4369                         mips_addiu (code, ins->dreg, mips_zero, 1);
4370                         mips_fbtrue (code, 2);
4371                         mips_nop (code);
4372                         MIPS_MOVE (code, ins->dreg, mips_zero);
4373                         break;
4374                 case OP_FCGT:
4375                         mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4376                         MIPS_MOVE (code, ins->dreg, mips_zero);
4377                         mips_fbtrue (code, 2);
4378                         mips_nop (code);
4379                         mips_addiu (code, ins->dreg, mips_zero, 1);
4380                         break;
4381                 case OP_FCGT_UN:
4382                         /* Greater than, or Unordered */
4383                         mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4384                         MIPS_MOVE (code, ins->dreg, mips_zero);
4385                         mips_fbtrue (code, 2);
4386                         mips_nop (code);
4387                         mips_addiu (code, ins->dreg, mips_zero, 1);
4388                         break;
4389                 case OP_MIPS_FBEQ:
4390                 case OP_MIPS_FBNE:
4391                 case OP_MIPS_FBLT:
4392                 case OP_MIPS_FBLT_UN:
4393                 case OP_MIPS_FBGT:
4394                 case OP_MIPS_FBGT_UN:
4395                 case OP_MIPS_FBGE:
4396                 case OP_MIPS_FBGE_UN:
4397                 case OP_MIPS_FBLE:
4398                 case OP_MIPS_FBLE_UN: {
4399                         int cond = 0;
4400                         gboolean is_true = TRUE, is_ordered = FALSE;
4401                         guint32 *buf = NULL;
4402
4403                         switch (ins->opcode) {
4404                         case OP_MIPS_FBEQ:
4405                                 cond = MIPS_FPU_EQ;
4406                                 is_true = TRUE;
4407                                 break;
4408                         case OP_MIPS_FBNE:
4409                                 cond = MIPS_FPU_EQ;
4410                                 is_true = FALSE;
4411                                 break;
4412                         case OP_MIPS_FBLT:
4413                                 cond = MIPS_FPU_LT;
4414                                 is_true = TRUE;
4415                                 is_ordered = TRUE;
4416                                 break;
4417                         case OP_MIPS_FBLT_UN:
4418                                 cond = MIPS_FPU_ULT;
4419                                 is_true = TRUE;
4420                                 break;
4421                         case OP_MIPS_FBGT:
4422                                 cond = MIPS_FPU_LE;
4423                                 is_true = FALSE;
4424                                 is_ordered = TRUE;
4425                                 break;
4426                         case OP_MIPS_FBGT_UN:
4427                                 cond = MIPS_FPU_OLE;
4428                                 is_true = FALSE;
4429                                 break;
4430                         case OP_MIPS_FBGE:
4431                                 cond = MIPS_FPU_LT;
4432                                 is_true = FALSE;
4433                                 is_ordered = TRUE;
4434                                 break;
4435                         case OP_MIPS_FBGE_UN:
4436                                 cond = MIPS_FPU_OLT;
4437                                 is_true = FALSE;
4438                                 break;
4439                         case OP_MIPS_FBLE:
4440                                 cond = MIPS_FPU_OLE;
4441                                 is_true = TRUE;
4442                                 is_ordered = TRUE;
4443                                 break;
4444                         case OP_MIPS_FBLE_UN:
4445                                 cond = MIPS_FPU_ULE;
4446                                 is_true = TRUE;
4447                                 break;
4448                         default:
4449                                 g_assert_not_reached ();
4450                         }
4451
4452                         if (is_ordered) {
4453                                 /* Skip the check if unordered */
4454                                 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4455                                 mips_nop (code);
4456                                 buf = (guint32*)code;
4457                                 mips_fbtrue (code, 0);
4458                                 mips_nop (code);
4459                         }
4460                         
4461                         mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4462                         mips_nop (code);
4463                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4464                         if (is_true)
4465                                 mips_fbtrue (code, 0);
4466                         else
4467                                 mips_fbfalse (code, 0);
4468                         mips_nop (code);
4469
4470                         if (is_ordered)
4471                                 mips_patch (buf, (guint32)code);
4472                         break;
4473                 }
4474                 case OP_CKFINITE: {
4475                         guint32 *branch_patch;
4476
4477                         mips_mfc1 (code, mips_at, ins->sreg1+1);
4478                         mips_srl (code, mips_at, mips_at, 16+4);
4479                         mips_andi (code, mips_at, mips_at, 2047);
4480                         mips_addiu (code, mips_at, mips_at, -2047);
4481
4482                         branch_patch = (guint32 *)(void *)code;
4483                         mips_bne (code, mips_at, mips_zero, 0);
4484                         mips_nop (code);
4485
4486                         EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4487                         mips_patch (branch_patch, (guint32)code);
4488                         mips_fmovd (code, ins->dreg, ins->sreg1);
4489                         break;
4490                 }
4491                 case OP_JUMP_TABLE:
4492                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4493                         mips_load (code, ins->dreg, 0x0f0f0f0f);
4494                         break;
4495                 case OP_GC_SAFE_POINT:
4496                         break;
4497
4498
4499                 default:
4500                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4501                         g_assert_not_reached ();
4502                 }
4503
4504                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4505                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4506                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4507                         g_assert_not_reached ();
4508                 }
4509                
4510                 cpos += max_len;
4511
4512                 last_ins = ins;
4513                 last_offset = offset;
4514         }
4515
4516         cfg->code_len = code - cfg->native_code;
4517 }
4518
4519 void
4520 mono_arch_register_lowlevel_calls (void)
4521 {
4522 }
4523
4524 void
4525 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4526 {
4527         MonoJumpInfo *patch_info;
4528
4529         error_init (error);
4530
4531         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4532                 unsigned char *ip = patch_info->ip.i + code;
4533                 const unsigned char *target = NULL;
4534
4535                 switch (patch_info->type) {
4536                 case MONO_PATCH_INFO_IP:
4537                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4538                         continue;
4539                 case MONO_PATCH_INFO_SWITCH: {
4540                         gpointer *table = (gpointer *)patch_info->data.table->table;
4541                         int i;
4542
4543                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4544
4545                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
4546                                 table [i] = (int)patch_info->data.table->table [i] + code;
4547                         }
4548                         continue;
4549                 }
4550                 case MONO_PATCH_INFO_METHODCONST:
4551                 case MONO_PATCH_INFO_CLASS:
4552                 case MONO_PATCH_INFO_IMAGE:
4553                 case MONO_PATCH_INFO_FIELD:
4554                 case MONO_PATCH_INFO_VTABLE:
4555                 case MONO_PATCH_INFO_IID:
4556                 case MONO_PATCH_INFO_SFLDA:
4557                 case MONO_PATCH_INFO_LDSTR:
4558                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4559                 case MONO_PATCH_INFO_LDTOKEN:
4560                 case MONO_PATCH_INFO_R4:
4561                 case MONO_PATCH_INFO_R8:
4562                         /* from OP_AOTCONST : lui + addiu */
4563                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4564                         return_if_nok (error);
4565
4566                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4567                         continue;
4568 #if 0
4569                 case MONO_PATCH_INFO_EXC_NAME:
4570                         g_assert_not_reached ();
4571                         *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4572                         continue;
4573 #endif
4574                 case MONO_PATCH_INFO_NONE:
4575                         /* everything is dealt with at epilog output time */
4576                         continue;
4577                 default:
4578                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4579                         return_if_nok (error);
4580
4581                         mips_patch ((guint32 *)(void *)ip, (guint32)target);
4582                         break;
4583                 }
4584         }
4585 }
4586
4587 /*
4588  * Allow tracing to work with this interface (with an optional argument)
4589  *
4590  * This code is expected to be inserted just after the 'real' prolog code,
4591  * and before the first basic block.  We need to allocate a 2nd, temporary
4592  * stack frame so that we can preserve f12-f15 as well as a0-a3.
4593  */
4594
4595 void*
4596 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4597 {
4598         guchar *code = p;
4599         int offset = cfg->arch.tracing_offset;
4600
4601         mips_nop (code);
4602         mips_nop (code);
4603         mips_nop (code);
4604
4605         MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4606         MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4607         MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4608         MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4609 #if _MIPS_SIM == _ABIN32
4610         NOT_IMPLEMENTED;
4611         /* FIXME: Need a separate region for these */
4612         MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4613         MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4614         MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4615         MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4616         */
4617 #endif
4618
4619         mips_load_const (code, mips_a0, cfg->method);
4620         mips_addiu (code, mips_a1, mips_sp, offset);
4621         mips_call (code, mips_t9, func);
4622         mips_nop (code);
4623
4624         MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4625         MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4626         MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4627         MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4628 #if _MIPS_SIM == _ABIN32
4629         NOT_IMPLEMENTED;
4630         /*
4631         MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4632         MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4633         MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4634         MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4635         */
4636 #endif
4637
4638         mips_nop (code);
4639         mips_nop (code);
4640         mips_nop (code);
4641         return code;
4642 }
4643
4644 void
4645 mips_adjust_stackframe(MonoCompile *cfg)
4646 {
4647         MonoBasicBlock *bb;
4648         int delta, threshold, i;
4649         MonoMethodSignature *sig;
4650         int ra_offset;
4651
4652         if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4653                 return;
4654
4655         /* adjust cfg->stack_offset for account for down-spilling */
4656         cfg->stack_offset += SIZEOF_REGISTER;
4657
4658         /* re-align cfg->stack_offset if needed (due to var spilling) */
4659         cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4660         delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4661         if (cfg->verbose_level > 2) {
4662                 g_print ("mips_adjust_stackframe:\n");
4663                 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4664         }
4665         threshold = cfg->arch.local_alloc_offset;
4666         ra_offset = cfg->stack_offset - sizeof(gpointer);
4667         if (cfg->verbose_level > 2) {
4668                 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4669         }
4670
4671         sig = mono_method_signature (cfg->method);
4672         if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4673                 cfg->vret_addr->inst_offset += delta;
4674         }
4675         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4676                 MonoInst *inst = cfg->args [i];
4677
4678                 inst->inst_offset += delta;
4679         }
4680
4681         /*
4682          * loads and stores based off the frame reg that (used to) lie
4683          * above the spill var area need to be increased by 'delta'
4684          * to make room for the spill vars.
4685          */
4686         /* Need to find loads and stores to adjust that
4687          * are above where the spillvars were inserted, but
4688          * which are not the spillvar references themselves.
4689          *
4690          * Idea - since all offsets from fp are positive, make
4691          * spillvar offsets negative to begin with so we can spot
4692          * them here.
4693          */
4694
4695 #if 1
4696         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4697                 int ins_cnt = 0;
4698                 MonoInst *ins;
4699
4700                 if (cfg->verbose_level > 2) {
4701                         g_print ("BASIC BLOCK %d:\n", bb->block_num);
4702                 }
4703                 MONO_BB_FOR_EACH_INS (bb, ins) {
4704                         int adj_c0 = 0;
4705                         int adj_imm = 0;
4706
4707                         if (cfg->verbose_level > 2) {
4708                                 mono_print_ins_index (ins_cnt, ins);
4709                         }
4710                         /* The == mips_sp tests catch FP spills */
4711                         if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4712                                                           (ins->inst_basereg == mips_sp))) {
4713                                 switch (ins->opcode) {
4714                                 case OP_LOADI8_MEMBASE:
4715                                 case OP_LOADR8_MEMBASE:
4716                                         adj_c0 = 8;
4717                                         break;
4718                                 default:
4719                                         adj_c0 = 4;
4720                                         break;
4721                                 }
4722                         } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4723                                                                   (ins->dreg == mips_sp))) {
4724                                 switch (ins->opcode) {
4725                                 case OP_STOREI8_MEMBASE_REG:
4726                                 case OP_STORER8_MEMBASE_REG:
4727                                 case OP_STOREI8_MEMBASE_IMM:
4728                                         adj_c0 = 8;
4729                                         break;
4730                                 default:
4731                                         adj_c0 = 4;
4732                                         break;
4733                                 }
4734                         }
4735                         if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4736                                 adj_imm = 1;
4737                         if (adj_c0) {
4738                                 if (ins->inst_c0 >= threshold) {
4739                                         ins->inst_c0 += delta;
4740                                         if (cfg->verbose_level > 2) {
4741                                                 g_print ("adj");
4742                                                 mono_print_ins_index (ins_cnt, ins);
4743                                         }
4744                                 }
4745                                 else if (ins->inst_c0 < 0) {
4746                                         /* Adj_c0 holds the size of the datatype. */
4747                                         ins->inst_c0 = - ins->inst_c0 - adj_c0;
4748                                         if (cfg->verbose_level > 2) {
4749                                                 g_print ("spill");
4750                                                 mono_print_ins_index (ins_cnt, ins);
4751                                         }
4752                                 }
4753                                 g_assert (ins->inst_c0 != ra_offset);
4754                         }
4755                         if (adj_imm) {
4756                                 if (ins->inst_imm >= threshold) {
4757                                         ins->inst_imm += delta;
4758                                         if (cfg->verbose_level > 2) {
4759                                                 g_print ("adj");
4760                                                 mono_print_ins_index (ins_cnt, ins);
4761                                         }
4762                                 }
4763                                 g_assert (ins->inst_c0 != ra_offset);
4764                         }
4765
4766                         ++ins_cnt;
4767                 }
4768         }
4769 #endif
4770 }
4771
4772 /*
4773  * Stack frame layout:
4774  * 
4775  *   ------------------- sp + cfg->stack_usage + cfg->param_area
4776  *      param area              incoming
4777  *   ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4778  *      a0-a3                   incoming
4779  *   ------------------- sp + cfg->stack_usage
4780  *      ra
4781  *   ------------------- sp + cfg->stack_usage-4
4782  *      spilled regs
4783  *   ------------------- sp + 
4784  *      MonoLMF structure       optional
4785  *   ------------------- sp + cfg->arch.lmf_offset
4786  *      saved registers         s0-s8
4787  *   ------------------- sp + cfg->arch.iregs_offset
4788  *      locals
4789  *   ------------------- sp + cfg->param_area
4790  *      param area              outgoing
4791  *   ------------------- sp + MIPS_STACK_PARAM_OFFSET
4792  *      a0-a3                   outgoing
4793  *   ------------------- sp
4794  *      red zone
4795  */
4796 guint8 *
4797 mono_arch_emit_prolog (MonoCompile *cfg)
4798 {
4799         MonoMethod *method = cfg->method;
4800         MonoMethodSignature *sig;
4801         MonoInst *inst;
4802         int alloc_size, pos, i, max_offset;
4803         int alloc2_size = 0;
4804         guint8 *code;
4805         CallInfo *cinfo;
4806         int tracing = 0;
4807         guint32 iregs_to_save = 0;
4808 #if SAVE_FP_REGS
4809         guint32 fregs_to_save = 0;
4810 #endif
4811         /* lmf_offset is the offset of the LMF from our stack pointer. */
4812         guint32 lmf_offset = cfg->arch.lmf_offset;
4813         int cfa_offset = 0;
4814         MonoBasicBlock *bb;
4815
4816         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4817                 tracing = 1;
4818
4819         if (tracing)
4820                 cfg->flags |= MONO_CFG_HAS_CALLS;
4821         
4822         sig = mono_method_signature (method);
4823         cfg->code_size = 768 + sig->param_count * 20;
4824         code = cfg->native_code = g_malloc (cfg->code_size);
4825
4826         /* 
4827          * compute max_offset in order to use short forward jumps.
4828          */
4829         max_offset = 0;
4830         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4831                 MonoInst *ins = bb->code;
4832                 bb->max_offset = max_offset;
4833
4834                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4835                         max_offset += 6; 
4836
4837                 MONO_BB_FOR_EACH_INS (bb, ins)
4838                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4839         }
4840         if (max_offset > 0xffff)
4841                 cfg->arch.long_branch = TRUE;
4842
4843         /*
4844          * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4845          * This means that we have to adjust the offsets inside instructions which reference
4846          * arguments received on the stack, since the initial offset doesn't take into
4847          * account spill slots.
4848          */
4849         mips_adjust_stackframe (cfg);
4850
4851         /* Offset between current sp and the CFA */
4852         cfa_offset = 0;
4853         mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4854
4855         /* stack_offset should not be changed here. */
4856         alloc_size = cfg->stack_offset;
4857         cfg->stack_usage = alloc_size;
4858
4859         iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4860 #if SAVE_FP_REGS
4861 #if 0
4862         fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4863 #else
4864         fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4865         fregs_to_save |= (fregs_to_save << 1);
4866 #endif
4867 #endif
4868         /* If the stack size is too big, save 1024 bytes to start with
4869          * so the prologue can use imm16(reg) addressing, then allocate
4870          * the rest of the frame.
4871          */
4872         if (alloc_size > ((1 << 15) - 1024)) {
4873                 alloc2_size = alloc_size - 1024;
4874                 alloc_size = 1024;
4875         }
4876         if (alloc_size) {
4877                 g_assert (mips_is_imm16 (-alloc_size));
4878                 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4879                 cfa_offset = alloc_size;
4880                 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4881         }
4882
4883         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4884                 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4885                 if (mips_is_imm16(offset))
4886                         mips_sw (code, mips_ra, mips_sp, offset);
4887                 else {
4888                         g_assert_not_reached ();
4889                 }
4890                 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4891                 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4892         }
4893
4894         /* XXX - optimize this later to not save all regs if LMF constructed */
4895         pos = cfg->arch.iregs_offset - alloc2_size;
4896
4897         if (iregs_to_save) {
4898                 /* save used registers in own stack frame (at pos) */
4899                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4900                         if (iregs_to_save & (1 << i)) {
4901                                 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4902                                 g_assert (mips_is_imm16(pos));
4903                                 MIPS_SW (code, i, mips_sp, pos);
4904                                 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4905                                 pos += SIZEOF_REGISTER;
4906                         }
4907                 }
4908         }
4909
4910         // FIXME: Don't save registers twice if there is an LMF
4911         // s8 has to be special cased since it is overwritten with the updated value
4912         // below
4913         if (method->save_lmf) {
4914                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4915                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4916                         g_assert (mips_is_imm16(offset));
4917                         if (MIPS_LMF_IREGMASK & (1 << i))
4918                                 MIPS_SW (code, i, mips_sp, offset);
4919                 }
4920         }
4921
4922 #if SAVE_FP_REGS
4923         /* Save float registers */
4924         if (fregs_to_save) {
4925                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4926                         if (fregs_to_save & (1 << i)) {
4927                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4928                                 g_assert (mips_is_imm16(pos));
4929                                 mips_swc1 (code, i, mips_sp, pos);
4930                                 pos += sizeof (gulong);
4931                         }
4932                 }
4933         }
4934
4935         if (method->save_lmf) {
4936                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4937                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4938                         g_assert (mips_is_imm16(offset));
4939                         mips_swc1 (code, i, mips_sp, offset);
4940                 }
4941         }
4942
4943 #endif
4944         if (cfg->frame_reg != mips_sp) {
4945                 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4946                 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4947
4948                 if (method->save_lmf) {
4949                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4950                         g_assert (mips_is_imm16(offset));
4951                         MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4952                 }
4953         }
4954
4955         /* store runtime generic context */
4956         if (cfg->rgctx_var) {
4957                 MonoInst *ins = cfg->rgctx_var;
4958
4959                 g_assert (ins->opcode == OP_REGOFFSET);
4960
4961                 g_assert (mips_is_imm16 (ins->inst_offset));
4962                 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4963         }
4964
4965         /* load arguments allocated to register from the stack */
4966         pos = 0;
4967
4968         if (!cfg->arch.cinfo)
4969                 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
4970         cinfo = cfg->arch.cinfo;
4971
4972         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4973                 ArgInfo *ainfo = &cinfo->ret;
4974                 inst = cfg->vret_addr;
4975                 if (inst->opcode == OP_REGVAR)
4976                         MIPS_MOVE (code, inst->dreg, ainfo->reg);
4977                 else if (mips_is_imm16 (inst->inst_offset)) {
4978                         mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4979                 } else {
4980                         mips_load_const (code, mips_at, inst->inst_offset);
4981                         mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4982                         mips_sw (code, ainfo->reg, mips_at, 0);
4983                 }
4984         }
4985
4986         if (sig->call_convention == MONO_CALL_VARARG) {
4987                 ArgInfo *cookie = &cinfo->sig_cookie;
4988                 int offset = alloc_size + cookie->offset;
4989
4990                 /* Save the sig cookie address */
4991                 g_assert (cookie->storage == ArgOnStack);
4992
4993                 g_assert (mips_is_imm16(offset));
4994                 mips_addi (code, mips_at, cfg->frame_reg, offset);
4995                 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
4996         }
4997
4998         /* Keep this in sync with emit_load_volatile_arguments */
4999         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5000                 ArgInfo *ainfo = cinfo->args + i;
5001                 inst = cfg->args [pos];
5002                 
5003                 if (cfg->verbose_level > 2)
5004                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5005                 if (inst->opcode == OP_REGVAR) {
5006                         /* Argument ends up in a register */
5007                         if (ainfo->storage == ArgInIReg)
5008                                 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5009                         else if (ainfo->storage == ArgInFReg) {
5010                                 g_assert_not_reached();
5011 #if 0
5012                                 ppc_fmr (code, inst->dreg, ainfo->reg);
5013 #endif
5014                         }
5015                         else if (ainfo->storage == ArgOnStack) {
5016                                 int offset = cfg->stack_usage + ainfo->offset;
5017                                 g_assert (mips_is_imm16(offset));
5018                                 mips_lw (code, inst->dreg, mips_sp, offset);
5019                         } else
5020                                 g_assert_not_reached ();
5021
5022                         if (cfg->verbose_level > 2)
5023                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5024                 } else {
5025                         /* Argument ends up on the stack */
5026                         if (ainfo->storage == ArgInIReg) {
5027                                 int basereg_offset;
5028                                 /* Incoming parameters should be above this frame */
5029                                 if (cfg->verbose_level > 2)
5030                                         g_print ("stack slot at %d of %d+%d\n",
5031                                                  inst->inst_offset, alloc_size, alloc2_size);
5032                                 /* g_assert (inst->inst_offset >= alloc_size); */
5033                                 g_assert (inst->inst_basereg == cfg->frame_reg);
5034                                 basereg_offset = inst->inst_offset - alloc2_size;
5035                                 g_assert (mips_is_imm16 (basereg_offset));
5036                                 switch (ainfo->size) {
5037                                 case 1:
5038                                         mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5039                                         break;
5040                                 case 2:
5041                                         mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5042                                         break;
5043                                 case 0: /* XXX */
5044                                 case 4:
5045                                         mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5046                                         break;
5047                                 case 8:
5048 #if (SIZEOF_REGISTER == 4)
5049                                         mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5050                                         mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5051 #elif (SIZEOF_REGISTER == 8)
5052                                         mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5053 #endif
5054                                         break;
5055                                 default:
5056                                         g_assert_not_reached ();
5057                                         break;
5058                                 }
5059                         } else if (ainfo->storage == ArgOnStack) {
5060                                 /*
5061                                  * Argument comes in on the stack, and ends up on the stack
5062                                  * 1 and 2 byte args are passed as 32-bit quantities, but used as
5063                                  * 8 and 16 bit quantities.  Shorten them in place.
5064                                  */
5065                                 g_assert (mips_is_imm16 (inst->inst_offset));
5066                                 switch (ainfo->size) {
5067                                 case 1:
5068                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5069                                         mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5070                                         break;
5071                                 case 2:
5072                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5073                                         mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5074                                         break;
5075                                 case 0: /* XXX */
5076                                 case 4:
5077                                 case 8:
5078                                         break;
5079                                 default:
5080                                         g_assert_not_reached ();
5081                                 }
5082                         } else if (ainfo->storage == ArgInFReg) {
5083                                 g_assert (mips_is_imm16 (inst->inst_offset));
5084                                 g_assert (mips_is_imm16 (inst->inst_offset+4));
5085                                 if (ainfo->size == 8) {
5086 #if _MIPS_SIM == _ABIO32
5087                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5088                                         mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5089 #elif _MIPS_SIM == _ABIN32
5090                                         mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5091 #endif
5092                                 }
5093                                 else if (ainfo->size == 4)
5094                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5095                                 else
5096                                         g_assert_not_reached ();
5097                         } else if (ainfo->storage == ArgStructByVal) {
5098                                 int i;
5099                                 int doffset = inst->inst_offset;
5100
5101                                 g_assert (mips_is_imm16 (inst->inst_offset));
5102                                 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5103                                 /* Push the argument registers into their stack slots */
5104                                 for (i = 0; i < ainfo->size; ++i) {
5105                                         g_assert (mips_is_imm16(doffset));
5106                                         MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5107                                         doffset += SIZEOF_REGISTER;
5108                                 }
5109                         } else if (ainfo->storage == ArgStructByAddr) {
5110                                 g_assert (mips_is_imm16 (inst->inst_offset));
5111                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5112                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5113                         } else
5114                                 g_assert_not_reached ();
5115                 }
5116                 pos++;
5117         }
5118
5119         if (method->save_lmf) {
5120                 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5121                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5122
5123                 /* This can/will clobber the a0-a3 registers */
5124                 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5125
5126                 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5127                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5128                 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5129                 /* new_lmf->previous_lmf = *lmf_addr */
5130                 mips_lw (code, mips_at, mips_v0, 0);
5131                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5132                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5133                 /* *(lmf_addr) = sp + lmf_offset */
5134                 g_assert (mips_is_imm16(lmf_offset));
5135                 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5136                 mips_sw (code, mips_at, mips_v0, 0);
5137
5138                 /* save method info */
5139                 mips_load_const (code, mips_at, method);
5140                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5141                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5142
5143                 /* save the current IP */
5144                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5145                 mips_load_const (code, mips_at, 0x01010101);
5146                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5147         }
5148
5149         if (alloc2_size) {
5150                 if (mips_is_imm16 (-alloc2_size)) {
5151                         mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5152                 }
5153                 else {
5154                         mips_load_const (code, mips_at, -alloc2_size);
5155                         mips_addu (code, mips_sp, mips_sp, mips_at);
5156                 }
5157                 alloc_size += alloc2_size;
5158                 cfa_offset += alloc2_size;
5159                 if (cfg->frame_reg != mips_sp)
5160                         MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5161                 else
5162                         mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5163         }
5164
5165         if (tracing) {
5166 #if _MIPS_SIM == _ABIO32
5167                 cfg->arch.tracing_offset = cfg->stack_offset;
5168 #elif _MIPS_SIM == _ABIN32
5169                 /* no stack slots by default for argument regs, reserve a special block */
5170                 g_assert_not_reached ();
5171 #endif
5172                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5173         }
5174
5175         cfg->code_len = code - cfg->native_code;
5176         g_assert (cfg->code_len < cfg->code_size);
5177
5178         return code;
5179 }
5180
5181 enum {
5182         SAVE_NONE,
5183         SAVE_STRUCT,
5184         SAVE_ONE,
5185         SAVE_TWO,
5186         SAVE_FP
5187 };
5188
5189 void*
5190 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5191 {
5192         guchar *code = p;
5193         int save_mode = SAVE_NONE;
5194         int offset;
5195         MonoMethod *method = cfg->method;
5196         int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5197         int save_offset = MIPS_STACK_PARAM_OFFSET;
5198
5199         g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5200         
5201         offset = code - cfg->native_code;
5202         /* we need about 16 instructions */
5203         if (offset > (cfg->code_size - 16 * 4)) {
5204                 cfg->code_size *= 2;
5205                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5206                 code = cfg->native_code + offset;
5207         }
5208         mips_nop (code);
5209         mips_nop (code);
5210         switch (rtype) {
5211         case MONO_TYPE_VOID:
5212                 /* special case string .ctor icall */
5213                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5214                         save_mode = SAVE_ONE;
5215                 else
5216                         save_mode = SAVE_NONE;
5217                 break;
5218         case MONO_TYPE_R4:
5219         case MONO_TYPE_R8:
5220                 save_mode = SAVE_FP;
5221                 break;
5222         case MONO_TYPE_VALUETYPE:
5223                 save_mode = SAVE_STRUCT;
5224                 break;
5225         case MONO_TYPE_I8:
5226         case MONO_TYPE_U8:
5227 #if SIZEOF_REGISTER == 4
5228                 save_mode = SAVE_TWO;
5229 #elif SIZEOF_REGISTER == 8
5230                 save_mode = SAVE_ONE;
5231 #endif
5232                 break;
5233         default:
5234                 save_mode = SAVE_ONE;
5235                 break;
5236         }
5237
5238         mips_addiu (code, mips_sp, mips_sp, -32);
5239         g_assert (mips_is_imm16(save_offset));
5240         switch (save_mode) {
5241         case SAVE_TWO:
5242                 mips_sw (code, mips_v0, mips_sp, save_offset);
5243                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5244                 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5245                 if (enable_arguments) {
5246                         MIPS_MOVE (code, mips_a1, mips_v0);
5247                         MIPS_MOVE (code, mips_a2, mips_v1);
5248                 }
5249                 break;
5250         case SAVE_ONE:
5251                 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5252                 if (enable_arguments) {
5253                         MIPS_MOVE (code, mips_a1, mips_v0);
5254                 }
5255                 break;
5256         case SAVE_FP:
5257                 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5258                 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5259                 mips_lw (code, mips_a0, mips_sp, save_offset);
5260                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5261                 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5262                 break;
5263         case SAVE_STRUCT:
5264         case SAVE_NONE:
5265         default:
5266                 break;
5267         }
5268         mips_load_const (code, mips_a0, cfg->method);
5269         mips_call (code, mips_t9, func);
5270
5271         switch (save_mode) {
5272         case SAVE_TWO:
5273                 mips_lw (code, mips_v0, mips_sp, save_offset);
5274                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5275                 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5276                 break;
5277         case SAVE_ONE:
5278                 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5279                 break;
5280         case SAVE_FP:
5281                 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5282                 break;
5283         case SAVE_STRUCT:
5284         case SAVE_NONE:
5285         default:
5286                 break;
5287         }
5288         mips_addiu (code, mips_sp, mips_sp, 32);
5289         mips_nop (code);
5290         mips_nop (code);
5291         return code;
5292 }
5293
5294 guint8 *
5295 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5296 {
5297         MonoMethod *method = cfg->method;
5298         int pos = 0, i;
5299         int max_epilog_size = 16 + 20*4;
5300         int alloc2_size = 0;
5301         guint32 iregs_to_restore;
5302 #if SAVE_FP_REGS
5303         guint32 fregs_to_restore;
5304 #endif
5305
5306         if (cfg->method->save_lmf)
5307                 max_epilog_size += 128;
5308         
5309         if (mono_jit_trace_calls != NULL)
5310                 max_epilog_size += 50;
5311
5312         if (code)
5313                 pos = code - cfg->native_code;
5314         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5315                 cfg->code_size *= 2;
5316                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5317                 cfg->stat_code_reallocs++;
5318         }
5319
5320         /*
5321          * Keep in sync with OP_JMP
5322          */
5323         if (code)
5324                 code = cfg->native_code + pos;
5325         else
5326                 code = cfg->native_code + cfg->code_len;
5327
5328         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5329                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5330         }
5331         if (cfg->frame_reg != mips_sp) {
5332                 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5333         }
5334         /* If the stack frame is really large, deconstruct it in two steps */
5335         if (cfg->stack_usage > ((1 << 15) - 1024)) {
5336                 alloc2_size = cfg->stack_usage - 1024;
5337                 /* partially deconstruct the stack */
5338                 mips_load_const (code, mips_at, alloc2_size);
5339                 mips_addu (code, mips_sp, mips_sp, mips_at);
5340         }
5341         pos = cfg->arch.iregs_offset - alloc2_size;
5342         iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5343         if (iregs_to_restore) {
5344                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5345                         if (iregs_to_restore & (1 << i)) {
5346                                 g_assert (mips_is_imm16(pos));
5347                                 MIPS_LW (code, i, mips_sp, pos);
5348                                 pos += SIZEOF_REGISTER;
5349                         }
5350                 }
5351         }
5352
5353 #if SAVE_FP_REGS
5354 #if 0
5355         fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5356 #else
5357         fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5358         fregs_to_restore |= (fregs_to_restore << 1);
5359 #endif
5360         if (fregs_to_restore) {
5361                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5362                         if (fregs_to_restore & (1 << i)) {
5363                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5364                                 g_assert (mips_is_imm16(pos));
5365                                 mips_lwc1 (code, i, mips_sp, pos);
5366                                 pos += FREG_SIZE
5367                         }
5368                 }
5369         }
5370 #endif
5371
5372         /* Unlink the LMF if necessary */
5373         if (method->save_lmf) {
5374                 int lmf_offset = cfg->arch.lmf_offset;
5375
5376                 /* t0 = current_lmf->previous_lmf */
5377                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5378                 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5379                 /* t1 = lmf_addr */
5380                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5381                 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5382                 /* (*lmf_addr) = previous_lmf */
5383                 mips_sw (code, mips_temp, mips_t1, 0);
5384         }
5385
5386 #if 0
5387         /* Restore the fp */
5388         mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5389 #endif
5390         /* Restore ra */
5391         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5392                 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5393                 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5394         }
5395         /* Restore the stack pointer */
5396         g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5397         mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5398
5399         /* Caller will emit either return or tail-call sequence */
5400
5401         cfg->code_len = code - cfg->native_code;
5402
5403         g_assert (cfg->code_len < cfg->code_size);
5404         return (code);
5405 }
5406
5407 void
5408 mono_arch_emit_epilog (MonoCompile *cfg)
5409 {
5410         guint8 *code;
5411
5412         code = mono_arch_emit_epilog_sub (cfg, NULL);
5413
5414         mips_jr (code, mips_ra);
5415         mips_nop (code);
5416
5417         cfg->code_len = code - cfg->native_code;
5418
5419         g_assert (cfg->code_len < cfg->code_size);
5420 }
5421
5422 /* remove once throw_exception_by_name is eliminated */
5423 #if 0
5424 static int
5425 exception_id_by_name (const char *name)
5426 {
5427         if (strcmp (name, "IndexOutOfRangeException") == 0)
5428                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5429         if (strcmp (name, "OverflowException") == 0)
5430                 return MONO_EXC_OVERFLOW;
5431         if (strcmp (name, "ArithmeticException") == 0)
5432                 return MONO_EXC_ARITHMETIC;
5433         if (strcmp (name, "DivideByZeroException") == 0)
5434                 return MONO_EXC_DIVIDE_BY_ZERO;
5435         if (strcmp (name, "InvalidCastException") == 0)
5436                 return MONO_EXC_INVALID_CAST;
5437         if (strcmp (name, "NullReferenceException") == 0)
5438                 return MONO_EXC_NULL_REF;
5439         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5440                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5441         if (strcmp (name, "ArgumentException") == 0)
5442                 return MONO_EXC_ARGUMENT;
5443         g_error ("Unknown intrinsic exception %s\n", name);
5444         return 0;
5445 }
5446 #endif
5447
5448 void
5449 mono_arch_emit_exceptions (MonoCompile *cfg)
5450 {
5451 #if 0
5452         MonoJumpInfo *patch_info;
5453         int i;
5454         guint8 *code;
5455         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5456         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5457         int max_epilog_size = 50;
5458
5459         /* count the number of exception infos */
5460      
5461         /* 
5462          * make sure we have enough space for exceptions
5463          * 24 is the simulated call to throw_exception_by_name
5464          */
5465         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5466 #if 0
5467                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5468                         i = exception_id_by_name (patch_info->data.target);
5469                         g_assert (i < MONO_EXC_INTRINS_NUM);
5470                         if (!exc_throw_found [i]) {
5471                                 max_epilog_size += 12;
5472                                 exc_throw_found [i] = TRUE;
5473                         }
5474                 }
5475 #endif
5476         }
5477
5478         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5479                 cfg->code_size *= 2;
5480                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5481                 cfg->stat_code_reallocs++;
5482         }
5483
5484         code = cfg->native_code + cfg->code_len;
5485
5486         /* add code to raise exceptions */
5487         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5488                 switch (patch_info->type) {
5489                 case MONO_PATCH_INFO_EXC: {
5490 #if 0
5491                         //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5492
5493                         i = exception_id_by_name (patch_info->data.target);
5494                         g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5495                         if (!exc_throw_pos [i]) {
5496                                 guint32 addr;
5497
5498                                 exc_throw_pos [i] = code;
5499                                 //g_print ("exc: writing stub at %p\n", code);
5500                                 mips_load_const (code, mips_a0, patch_info->data.target);
5501                                 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5502                                 mips_load_const (code, mips_t9, addr);
5503                                 mips_jr (code, mips_t9);
5504                                 mips_nop (code);
5505                         }
5506                         //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5507
5508                         /* Turn into a Relative patch, pointing at code stub */
5509                         patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5510                         patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5511 #else
5512                         g_assert_not_reached();
5513 #endif
5514                         break;
5515                 }
5516                 default:
5517                         /* do nothing */
5518                         break;
5519                 }
5520         }
5521
5522         cfg->code_len = code - cfg->native_code;
5523
5524         g_assert (cfg->code_len < cfg->code_size);
5525 #endif
5526 }
5527
5528 void
5529 mono_arch_finish_init (void)
5530 {
5531 }
5532
5533 void
5534 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5535 {
5536 }
5537
5538 void
5539 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5540 {
5541         int this_dreg = mips_a0;
5542         
5543         if (vt_reg != -1)
5544                 this_dreg = mips_a1;
5545
5546         /* add the this argument */
5547         if (this_reg != -1) {
5548                 MonoInst *this_ins;
5549                 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5550                 this_ins->type = this_type;
5551                 this_ins->sreg1 = this_reg;
5552                 this_ins->dreg = mono_alloc_ireg (cfg);
5553                 mono_bblock_add_inst (cfg->cbb, this_ins);
5554                 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5555         }
5556
5557         if (vt_reg != -1) {
5558                 MonoInst *vtarg;
5559                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5560                 vtarg->type = STACK_MP;
5561                 vtarg->sreg1 = vt_reg;
5562                 vtarg->dreg = mono_alloc_ireg (cfg);
5563                 mono_bblock_add_inst (cfg->cbb, vtarg);
5564                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5565         }
5566 }
5567
5568 MonoInst*
5569 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5570 {
5571         MonoInst *ins = NULL;
5572
5573         return ins;
5574 }
5575
5576 MonoInst*
5577 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5578 {
5579         return NULL;
5580 }
5581
5582 gboolean
5583 mono_arch_print_tree (MonoInst *tree, int arity)
5584 {
5585         return 0;
5586 }
5587
5588 mgreg_t
5589 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5590 {
5591         return ctx->sc_regs [reg];
5592 }
5593
5594 #define ENABLE_WRONG_METHOD_CHECK 0
5595
5596 #define MIPS_LOAD_SEQUENCE_LENGTH       8
5597 #define CMP_SIZE                        (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5598 #define BR_SIZE                         8
5599 #define LOADSTORE_SIZE                  4
5600 #define JUMP_IMM_SIZE                   16
5601 #define JUMP_IMM32_SIZE                 (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5602 #define LOAD_CONST_SIZE                 8
5603 #define JUMP_JR_SIZE                    8
5604
5605 /*
5606  * LOCKING: called with the domain lock held
5607  */
5608 gpointer
5609 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5610                                                                 gpointer fail_tramp)
5611 {
5612         int i;
5613         int size = 0;
5614         guint8 *code, *start, *patch;
5615
5616         for (i = 0; i < count; ++i) {
5617                 MonoIMTCheckItem *item = imt_entries [i];
5618
5619                 if (item->is_equals) {
5620                         if (item->check_target_idx) {
5621                                 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5622                                 if (item->has_target_code)
5623                                         item->chunk_size += LOAD_CONST_SIZE;
5624                                 else
5625                                         item->chunk_size += LOADSTORE_SIZE;
5626                         } else {
5627                                 if (fail_tramp) {
5628                                         item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5629                                                 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5630                                         if (!item->has_target_code)
5631                                                 item->chunk_size += LOADSTORE_SIZE;
5632                                 } else {
5633                                         item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5634 #if ENABLE_WRONG_METHOD_CHECK
5635                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5636 #endif
5637                                 }
5638                         }
5639                 } else {
5640                         item->chunk_size += CMP_SIZE + BR_SIZE;
5641                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5642                 }
5643                 size += item->chunk_size;
5644         }
5645         /* the initial load of the vtable address */
5646         size += MIPS_LOAD_SEQUENCE_LENGTH;
5647         if (fail_tramp) {
5648                 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5649         } else {
5650                 code = mono_domain_code_reserve (domain, size);
5651         }
5652         start = code;
5653
5654         /* t7 points to the vtable */
5655         mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5656
5657         for (i = 0; i < count; ++i) {
5658                 MonoIMTCheckItem *item = imt_entries [i];
5659
5660                 item->code_target = code;
5661                 if (item->is_equals) {
5662                         if (item->check_target_idx) {
5663                                 mips_load_const (code, mips_temp, (gsize)item->key);
5664                                 item->jmp_code = code;
5665                                 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5666                                 mips_nop (code);
5667                                 if (item->has_target_code) {
5668                                         mips_load_const (code, mips_t9,
5669                                                          item->value.target_code);
5670                                 }
5671                                 else {
5672                                         mips_lw (code, mips_t9, mips_t7,
5673                                                 (sizeof (gpointer) * item->value.vtable_slot));
5674                                 }
5675                                 mips_jr (code, mips_t9);
5676                                 mips_nop (code);
5677                         } else {
5678                                 if (fail_tramp) {
5679                                         mips_load_const (code, mips_temp, (gsize)item->key);
5680                                         patch = code;
5681                                         mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5682                                         mips_nop (code);
5683                                         if (item->has_target_code) {
5684                                                 mips_load_const (code, mips_t9,
5685                                                                  item->value.target_code);
5686                                         } else {
5687                                                 g_assert (vtable);
5688                                                 mips_load_const (code, mips_at,
5689                                                                  & (vtable->vtable [item->value.vtable_slot]));
5690                                                 mips_lw (code, mips_t9, mips_at, 0);
5691                                         }
5692                                         mips_jr (code, mips_t9);
5693                                         mips_nop (code);
5694                                         mips_patch ((guint32 *)(void *)patch, (guint32)code);
5695                                         mips_load_const (code, mips_t9, fail_tramp);
5696                                         mips_jr (code, mips_t9);
5697                                         mips_nop (code);
5698                                 } else {
5699                                         /* enable the commented code to assert on wrong method */
5700 #if ENABLE_WRONG_METHOD_CHECK
5701                                         ppc_load (code, ppc_r0, (guint32)item->key);
5702                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5703                                         patch = code;
5704                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5705 #endif
5706                                         mips_lw (code, mips_t9, mips_t7,
5707                                                  (sizeof (gpointer) * item->value.vtable_slot));
5708                                         mips_jr (code, mips_t9);
5709                                         mips_nop (code);
5710
5711 #if ENABLE_WRONG_METHOD_CHECK
5712                                         ppc_patch (patch, code);
5713                                         ppc_break (code);
5714 #endif
5715                                 }
5716                         }
5717                 } else {
5718                         mips_load_const (code, mips_temp, (gulong)item->key);
5719                         mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5720
5721                         item->jmp_code = code;
5722                         mips_beq (code, mips_temp, mips_zero, 0);
5723                         mips_nop (code);
5724                 }
5725         }
5726         /* patch the branches to get to the target items */
5727         for (i = 0; i < count; ++i) {
5728                 MonoIMTCheckItem *item = imt_entries [i];
5729                 if (item->jmp_code && item->check_target_idx) {
5730                         mips_patch ((guint32 *)item->jmp_code,
5731                                    (guint32)imt_entries [item->check_target_idx]->code_target);
5732                 }
5733         }
5734
5735         if (!fail_tramp)
5736                 mono_stats.imt_trampolines_size += code - start;
5737         g_assert (code - start <= size);
5738         mono_arch_flush_icache (start, size);
5739
5740         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5741
5742         return start;
5743 }
5744
5745 MonoMethod*
5746 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5747 {
5748         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5749 }
5750
5751 MonoVTable*
5752 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5753 {
5754         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5755 }
5756
5757 /* Soft Debug support */
5758 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5759
5760 /*
5761  * mono_arch_set_breakpoint:
5762  *
5763  *   See mini-amd64.c for docs.
5764  */
5765 void
5766 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5767 {
5768         guint8 *code = ip;
5769         guint32 addr = (guint32)bp_trigger_page;
5770
5771         mips_load_const (code, mips_t9, addr);
5772         mips_lw (code, mips_t9, mips_t9, 0);
5773
5774         mono_arch_flush_icache (ip, code - ip);
5775 }
5776
5777 /*
5778  * mono_arch_clear_breakpoint:
5779  *
5780  *   See mini-amd64.c for docs.
5781  */
5782 void
5783 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5784 {
5785         guint8 *code = ip;
5786
5787         mips_nop (code);
5788         mips_nop (code);
5789         mips_nop (code);
5790
5791         mono_arch_flush_icache (ip, code - ip);
5792 }
5793         
5794 /*
5795  * mono_arch_start_single_stepping:
5796  *
5797  *   See mini-amd64.c for docs.
5798  */
5799 void
5800 mono_arch_start_single_stepping (void)
5801 {
5802         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5803 }
5804         
5805 /*
5806  * mono_arch_stop_single_stepping:
5807  *
5808  *   See mini-amd64.c for docs.
5809  */
5810 void
5811 mono_arch_stop_single_stepping (void)
5812 {
5813         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5814 }
5815
5816 /*
5817  * mono_arch_is_single_step_event:
5818  *
5819  *   See mini-amd64.c for docs.
5820  */
5821 gboolean
5822 mono_arch_is_single_step_event (void *info, void *sigctx)
5823 {
5824         siginfo_t* sinfo = (siginfo_t*) info;
5825         /* Sometimes the address is off by 4 */
5826         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5827                 return TRUE;
5828         else
5829                 return FALSE;
5830 }
5831
5832 /*
5833  * mono_arch_is_breakpoint_event:
5834  *
5835  *   See mini-amd64.c for docs.
5836  */
5837 gboolean
5838 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5839 {
5840         siginfo_t* sinfo = (siginfo_t*) info;
5841         /* Sometimes the address is off by 4 */
5842         if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5843                 return TRUE;
5844         else
5845                 return FALSE;
5846 }
5847
5848 /*
5849  * mono_arch_skip_breakpoint:
5850  *
5851  *   See mini-amd64.c for docs.
5852  */
5853 void
5854 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5855 {
5856         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5857 }
5858
5859 /*
5860  * mono_arch_skip_single_step:
5861  *
5862  *   See mini-amd64.c for docs.
5863  */
5864 void
5865 mono_arch_skip_single_step (MonoContext *ctx)
5866 {
5867         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5868 }
5869
5870 /*
5871  * mono_arch_get_seq_point_info:
5872  *
5873  *   See mini-amd64.c for docs.
5874  */
5875 gpointer
5876 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5877 {
5878         NOT_IMPLEMENTED;
5879         return NULL;
5880 }
5881
5882 void
5883 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5884 {
5885         ext->lmf.previous_lmf = prev_lmf;
5886         /* Mark that this is a MonoLMFExt */
5887         ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5888         ext->lmf.iregs [mips_sp] = (gssize)ext;
5889 }
5890
5891 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5892
5893 gboolean
5894 mono_arch_opcode_supported (int opcode)
5895 {
5896         return FALSE;
5897 }