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