70e1a2ccb300853c6b82d6686a4330f361234bbf
[mono.git] / mono / mini / mini-mips.c
1 /**
2  * \file
3  * MIPS backend for the Mono code generator
4  *
5  * Authors:
6  *   Mark Mason (mason@broadcom.com)
7  *
8  * Based on mini-ppc.c by
9  *   Paolo Molaro (lupus@ximian.com)
10  *   Dietmar Maurer (dietmar@ximian.com)
11  *
12  * (C) 2006 Broadcom
13  * (C) 2003 Ximian, Inc.
14  */
15 #include "mini.h"
16 #include <string.h>
17 #include <asm/cachectl.h>
18
19 #include <mono/metadata/abi-details.h>
20 #include <mono/metadata/appdomain.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/utils/mono-mmap.h>
23 #include <mono/utils/mono-hwcap.h>
24
25 #include <mono/arch/mips/mips-codegen.h>
26
27 #include "mini-mips.h"
28 #include "cpu-mips.h"
29 #include "trace.h"
30 #include "ir-emit.h"
31
32 #define SAVE_FP_REGS            0
33
34 #define ALWAYS_SAVE_RA          1       /* call-handler & switch currently clobber ra */
35
36 #define PROMOTE_R4_TO_R8        1       /* promote single values in registers to doubles */
37 #define USE_MUL                 0       /* use mul instead of mult/mflo for multiply
38                                                            remember to update cpu-mips.md if you change this */
39
40 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
41 #define mips_call(c,D,v) do {   \
42                 guint32 _target = (guint32)(v); \
43                 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
44                         mips_load_const (c, D, _target); \
45                         mips_jalr (c, D, mips_ra); \
46                 } \
47                 else { \
48                         mips_jumpl (c, _target >> 2); \
49                 } \
50                 mips_nop (c); \
51         } while (0)
52
53 enum {
54         TLS_MODE_DETECT,
55         TLS_MODE_FAILED,
56         TLS_MODE_LTHREADS,
57         TLS_MODE_NPTL
58 };
59
60 /* This mutex protects architecture specific caches */
61 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
62 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
63 static mono_mutex_t mini_arch_mutex;
64
65 int mono_exc_esp_offset = 0;
66
67 /* Whenever the host is little-endian */
68 static int little_endian;
69 /* Index of ms word/register */
70 static int ls_word_idx;
71 /* Index of ls word/register */
72 static int ms_word_idx;
73 /* Same for offsets */
74 static int ls_word_offset;
75 static int ms_word_offset;
76
77 /*
78  * The code generated for sequence points reads from this location, which is
79  * made read-only when single stepping is enabled.
80  */
81 static gpointer ss_trigger_page;
82
83 /* Enabled breakpoints read from this trigger page */
84 static gpointer bp_trigger_page;
85
86 #undef DEBUG
87 #define DEBUG(a) if (cfg->verbose_level > 1) a
88 #undef DEBUG
89 #define DEBUG(a) a
90 #undef DEBUG
91 #define DEBUG(a)
92
93 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name)            \
94         do {                                                        \
95                 code = mips_emit_exc_by_name (code, exc_name);  \
96                 cfg->bb_exit->max_offset += 16;                         \
97         } while (0) 
98
99 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
100                 MonoInst *inst;                            \
101                 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
102                 inst->type = STACK_R8;                     \
103                 inst->dreg = (dr);                     \
104                 inst->inst_p0 = (void*)(addr);         \
105                 mono_bblock_add_inst (cfg->cbb, inst); \
106         } while (0)
107
108 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
109                                        || ((ins)->opcode == OP_ICOMPARE) \
110                                        || ((ins)->opcode == OP_LCOMPARE)))
111 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
112                                            || ((ins)->opcode == OP_ICOMPARE_IMM) \
113                                            || ((ins)->opcode == OP_LCOMPARE_IMM)))
114
115 #define INS_REWRITE(ins, op, _s1, _s2)  do { \
116                         int s1 = _s1;                   \
117                         int s2 = _s2;                   \
118                         ins->opcode = (op);             \
119                         ins->sreg1 = (s1);              \
120                         ins->sreg2 = (s2);              \
121         } while (0);
122
123 #define INS_REWRITE_IMM(ins, op, _s1, _imm)     do { \
124                         int s1 = _s1;                   \
125                         ins->opcode = (op);             \
126                         ins->sreg1 = (s1);              \
127                         ins->inst_imm = (_imm);         \
128         } while (0);
129
130
131 typedef struct InstList InstList;
132
133 struct InstList {
134         InstList *prev;
135         InstList *next;
136         MonoInst *data;
137 };
138
139 typedef enum {
140         ArgInIReg,
141         ArgOnStack,
142         ArgInFReg,
143         ArgStructByVal,
144         ArgStructByAddr
145 } ArgStorage;
146
147 typedef struct {
148         gint32  offset;
149         guint16 vtsize; /* in param area */
150         guint8  reg;
151         ArgStorage storage;
152         guint8  size    : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
153 } ArgInfo;
154
155 typedef struct {
156         int nargs;
157         int gr;
158         int fr;
159         gboolean gr_passed;
160         gboolean on_stack;
161         gboolean vtype_retaddr;
162         int stack_size;
163         guint32 stack_usage;
164         guint32 struct_ret;
165         ArgInfo ret;
166         ArgInfo sig_cookie;
167         ArgInfo args [1];
168 } CallInfo;
169
170 void patch_lui_addiu(guint32 *ip, guint32 val);
171 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
172 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
173 void mips_adjust_stackframe(MonoCompile *cfg);
174 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
175 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
176
177
178 /* Not defined in asm/cachectl.h */
179 int cacheflush(char *addr, int nbytes, int cache);
180
181 void
182 mono_arch_flush_icache (guint8 *code, gint size)
183 {
184         /* Linux/MIPS specific */
185         cacheflush ((char*)code, size, BCACHE);
186 }
187
188 void
189 mono_arch_flush_register_windows (void)
190 {
191 }
192
193 gboolean 
194 mono_arch_is_inst_imm (gint64 imm)
195 {
196         return TRUE;
197 }
198
199 static guint8 *
200 mips_emit_exc_by_name(guint8 *code, const char *name)
201 {
202         gpointer addr;
203         MonoClass *exc_class;
204
205         exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", name);
206
207         mips_load_const (code, mips_a0, exc_class->type_token);
208         addr = mono_get_throw_corlib_exception ();
209         mips_call (code, mips_t9, addr);
210         return code;
211 }
212
213
214 guint8 *
215 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
216 {
217         if (mips_is_imm16 (v))
218                 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
219         else {
220 #if SIZEOF_REGISTER == 8
221                 if (v != (long) v) {
222                         /* v is not a sign-extended 32-bit value */
223                         mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
224                         mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
225                         mips_dsll (code, dreg, dreg, 16);
226                         mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
227                         mips_dsll (code, dreg, dreg, 16);
228                         mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
229                         return code;
230                 }
231 #endif
232                 if (((guint32)v) & (1 << 15)) {
233                         mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
234                 }
235                 else {
236                         mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
237                 }
238                 if (((guint32)v) & 0xffff)
239                         mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
240         }
241         return code;
242 }
243
244 guint8 *
245 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
246 {
247         g_assert (ins);
248         if (cfg->arch.long_branch) {
249                 int br_offset = 5;
250
251                 /* Invert test and emit branch around jump */
252                 switch (op) {
253                 case OP_MIPS_BEQ:
254                         mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
255                         mips_nop (code);
256                         break;
257                 case OP_MIPS_BNE:
258                         mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
259                         mips_nop (code);
260                         break;
261                 case OP_MIPS_BGEZ:
262                         mips_bltz (code, ins->sreg1, br_offset);
263                         mips_nop (code);
264                         break;
265                 case OP_MIPS_BGTZ:
266                         mips_blez (code, ins->sreg1, br_offset);
267                         mips_nop (code);
268                         break;
269                 case OP_MIPS_BLEZ:
270                         mips_bgtz (code, ins->sreg1, br_offset);
271                         mips_nop (code);
272                         break;
273                 case OP_MIPS_BLTZ:
274                         mips_bgez (code, ins->sreg1, br_offset);
275                         mips_nop (code);
276                         break;
277                 default:
278                         g_assert_not_reached ();
279                 }
280                 mono_add_patch_info (cfg, code - cfg->native_code,
281                                      MONO_PATCH_INFO_BB, ins->inst_true_bb);
282                 mips_lui (code, mips_at, mips_zero, 0);
283                 mips_addiu (code, mips_at, mips_at, 0);
284                 mips_jr (code, mips_at);
285                 mips_nop (code);
286         }
287         else {
288                 mono_add_patch_info (cfg, code - cfg->native_code,
289                                      MONO_PATCH_INFO_BB, ins->inst_true_bb);
290                 switch (op) {
291                 case OP_MIPS_BEQ:
292                         mips_beq (code, ins->sreg1, ins->sreg2, 0);
293                         mips_nop (code);
294                         break;
295                 case OP_MIPS_BNE:
296                         mips_bne (code, ins->sreg1, ins->sreg2, 0);
297                         mips_nop (code);
298                         break;
299                 case OP_MIPS_BGEZ:
300                         mips_bgez (code, ins->sreg1, 0);
301                         mips_nop (code);
302                         break;
303                 case OP_MIPS_BGTZ:
304                         mips_bgtz (code, ins->sreg1, 0);
305                         mips_nop (code);
306                         break;
307                 case OP_MIPS_BLEZ:
308                         mips_blez (code, ins->sreg1, 0);
309                         mips_nop (code);
310                         break;
311                 case OP_MIPS_BLTZ:
312                         mips_bltz (code, ins->sreg1, 0);
313                         mips_nop (code);
314                         break;
315                 default:
316                         g_assert_not_reached ();
317                 }
318         }
319         return (code);
320 }
321
322 /* XXX - big-endian dependent? */
323 void
324 patch_lui_addiu(guint32 *ip, guint32 val)
325 {
326         guint16 *__lui_addiu = (guint16*)(void *)(ip);
327
328 #if 0
329         printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
330                 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
331         fflush (stdout);
332 #endif
333         if (((guint32)(val)) & (1 << 15))
334                 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
335         else
336                 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
337         __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
338         mono_arch_flush_icache ((guint8 *)ip, 8);
339 }
340
341 guint32 trap_target;
342 void
343 mips_patch (guint32 *code, guint32 target)
344 {
345         guint32 ins = *code;
346         guint32 op = ins >> 26;
347         guint32 diff, offset;
348
349         g_assert (trap_target != target);
350         //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
351         switch (op) {
352         case 0x00: /* jr ra */
353                 if (ins == 0x3e00008)
354                         break;
355                 g_assert_not_reached ();
356                 break;
357         case 0x02: /* j */
358         case 0x03: /* jal */
359                 g_assert (!(target & 0x03));
360                 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
361                 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
362                 *code = ins;
363                 mono_arch_flush_icache ((guint8 *)code, 4);
364                 break;
365         case 0x01: /* BLTZ */
366         case 0x04: /* BEQ */
367         case 0x05: /* BNE */
368         case 0x06: /* BLEZ */
369         case 0x07: /* BGTZ */
370         case 0x11: /* bc1t */
371                 diff = target - (guint32)(code + 1);
372                 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
373                 g_assert (!(diff & 0x03));
374                 offset = ((gint32)diff) >> 2;
375                 if (((int)offset) != ((int)(short)offset))
376                         g_assert (((int)offset) == ((int)(short)offset));
377                 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
378                 *code = ins;
379                 mono_arch_flush_icache ((guint8 *)code, 4);
380                 break;
381         case 0x0f: /* LUI / ADDIU pair */
382                 g_assert ((code[1] >> 26) == 0x9);
383                 patch_lui_addiu (code, target);
384                 mono_arch_flush_icache ((guint8 *)code, 8);
385                 break;
386
387         default:
388                 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
389                 g_assert_not_reached ();
390         }
391 }
392
393 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
394
395 const char*
396 mono_arch_regname (int reg) {
397 #if _MIPS_SIM == _ABIO32
398         static const char * rnames[] = {
399                 "zero", "at", "v0", "v1",
400                 "a0", "a1", "a2", "a3",
401                 "t0", "t1", "t2", "t3",
402                 "t4", "t5", "t6", "t7",
403                 "s0", "s1", "s2", "s3",
404                 "s4", "s5", "s6", "s7",
405                 "t8", "t9", "k0", "k1",
406                 "gp", "sp", "fp", "ra"
407         };
408 #elif _MIPS_SIM == _ABIN32
409         static const char * rnames[] = {
410                 "zero", "at", "v0", "v1",
411                 "a0", "a1", "a2", "a3",
412                 "a4", "a5", "a6", "a7",
413                 "t0", "t1", "t2", "t3",
414                 "s0", "s1", "s2", "s3",
415                 "s4", "s5", "s6", "s7",
416                 "t8", "t9", "k0", "k1",
417                 "gp", "sp", "fp", "ra"
418         };
419 #endif
420         if (reg >= 0 && reg < 32)
421                 return rnames [reg];
422         return "unknown";
423 }
424
425 const char*
426 mono_arch_fregname (int reg) {
427         static const char * rnames[] = {
428                 "f0", "f1", "f2", "f3",
429                 "f4", "f5", "f6", "f7",
430                 "f8", "f9", "f10", "f11",
431                 "f12", "f13", "f14", "f15",
432                 "f16", "f17", "f18", "f19",
433                 "f20", "f21", "f22", "f23",
434                 "f24", "f25", "f26", "f27",
435                 "f28", "f29", "f30", "f31"
436         };
437         if (reg >= 0 && reg < 32)
438                 return rnames [reg];
439         return "unknown";
440 }
441
442 /* this function overwrites at */
443 static guint8*
444 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
445 {
446         /* XXX write a loop, not an unrolled loop */
447         while (size > 0) {
448                 mips_lw (code, mips_at, sreg, soffset);
449                 mips_sw (code, mips_at, dreg, doffset);
450                 size -= 4;
451                 soffset += 4;
452                 doffset += 4;
453         }
454         return code;
455 }
456
457 /*
458  * mono_arch_get_argument_info:
459  * @csig:  a method signature
460  * @param_count: the number of parameters to consider
461  * @arg_info: an array to store the result infos
462  *
463  * Gathers information on parameters such as size, alignment and
464  * padding. arg_info should be large enought to hold param_count + 1 entries. 
465  *
466  * Returns the size of the activation frame.
467  */
468 int
469 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
470 {
471         int k, frame_size = 0;
472         guint32 size, align, pad;
473         int offset = 0;
474
475         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
476                 frame_size += sizeof (gpointer);
477                 offset += 4;
478         }
479
480         arg_info [0].offset = offset;
481
482         if (csig->hasthis) {
483                 frame_size += sizeof (gpointer);
484                 offset += 4;
485         }
486
487         arg_info [0].size = frame_size;
488
489         for (k = 0; k < param_count; k++) {
490                 size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
491
492                 /* ignore alignment for now */
493                 align = 1;
494
495                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
496                 arg_info [k].pad = pad;
497                 frame_size += size;
498                 arg_info [k + 1].pad = 0;
499                 arg_info [k + 1].size = size;
500                 offset += pad;
501                 arg_info [k + 1].offset = offset;
502                 offset += size;
503         }
504
505         align = MONO_ARCH_FRAME_ALIGNMENT;
506         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
507         arg_info [k].pad = pad;
508
509         return frame_size;
510 }
511
512 /* The delegate object plus 3 params */
513 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
514
515 static gpointer
516 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
517 {
518         guint8 *code, *start;
519
520         if (has_target) {
521                 start = code = mono_global_codeman_reserve (16);
522
523                 /* Replace the this argument with the target */
524                 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
525                 mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
526                 mips_jr (code, mips_temp);
527                 mips_nop (code);
528
529                 g_assert ((code - start) <= 16);
530
531                 mono_arch_flush_icache (start, 16);
532         } else {
533                 int size, i;
534
535                 size = 16 + param_count * 4;
536                 start = code = mono_global_codeman_reserve (size);
537
538                 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
539                 /* slide down the arguments */
540                 for (i = 0; i < param_count; ++i) {
541                         mips_move (code, mips_a0 + i, mips_a0 + i + 1);
542                 }
543                 mips_jr (code, mips_temp);
544                 mips_nop (code);
545
546                 g_assert ((code - start) <= size);
547
548                 mono_arch_flush_icache (start, size);
549         }
550
551         if (has_target) {
552                 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
553         } else {
554                 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
555                 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
556                 g_free (name);
557         }
558
559         return start;
560 }
561
562 /*
563  * mono_arch_get_delegate_invoke_impls:
564  *
565  *   Return a list of MonoAotTrampInfo structures for the delegate invoke impl
566  * trampolines.
567  */
568 GSList*
569 mono_arch_get_delegate_invoke_impls (void)
570 {
571         GSList *res = NULL;
572         MonoTrampInfo *info;
573         int i;
574
575         get_delegate_invoke_impl (&info, TRUE, 0);
576         res = g_slist_prepend (res, info);
577
578         for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
579                 get_delegate_invoke_impl (&info, FALSE, i);
580                 res = g_slist_prepend (res, info);
581         }
582
583         return res;
584 }
585
586 gpointer
587 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
588 {
589         guint8 *code, *start;
590
591         /* FIXME: Support more cases */
592         if (MONO_TYPE_ISSTRUCT (sig->ret))
593                 return NULL;
594
595         if (has_target) {
596                 static guint8* cached = NULL;
597                 mono_mini_arch_lock ();
598                 if (cached) {
599                         mono_mini_arch_unlock ();
600                         return cached;
601                 }
602
603                 if (mono_aot_only) {
604                         start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
605                 } else {
606                         MonoTrampInfo *info;
607                         start = get_delegate_invoke_impl (&info, TRUE, 0);
608                         mono_tramp_info_register (info, NULL);
609                 }
610                 cached = start;
611                 mono_mini_arch_unlock ();
612                 return cached;
613         } else {
614                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
615                 int i;
616
617                 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
618                         return NULL;
619                 for (i = 0; i < sig->param_count; ++i)
620                         if (!mono_is_regsize_var (sig->params [i]))
621                                 return NULL;
622
623                 mono_mini_arch_lock ();
624                 code = cache [sig->param_count];
625                 if (code) {
626                         mono_mini_arch_unlock ();
627                         return code;
628                 }
629
630                 if (mono_aot_only) {
631                         char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
632                         start = mono_aot_get_trampoline (name);
633                         g_free (name);
634                 } else {
635                         MonoTrampInfo *info;
636                         start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
637                         mono_tramp_info_register (info, NULL);
638                 }
639                 cache [sig->param_count] = start;
640                 mono_mini_arch_unlock ();
641                 return start;
642         }
643
644         return NULL;
645 }
646
647 gpointer
648 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
649 {
650         return NULL;
651 }
652
653 gpointer
654 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
655 {
656         g_assert(regs);
657         return (gpointer)regs [mips_a0];
658 }
659
660 /*
661  * Initialize the cpu to execute managed code.
662  */
663 void
664 mono_arch_cpu_init (void)
665 {
666 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
667         little_endian = 1;
668         ls_word_idx = 0;
669         ms_word_idx = 1;
670 #else
671         ls_word_idx = 1;
672         ms_word_idx = 0;
673 #endif
674
675         ls_word_offset = ls_word_idx * 4;
676         ms_word_offset = ms_word_idx * 4;
677 }
678
679 /*
680  * Initialize architecture specific code.
681  */
682 void
683 mono_arch_init (void)
684 {
685         mono_os_mutex_init_recursive (&mini_arch_mutex);
686
687         ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
688         bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
689         mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
690 }
691
692 /*
693  * Cleanup architecture specific code.
694  */
695 void
696 mono_arch_cleanup (void)
697 {
698         mono_os_mutex_destroy (&mini_arch_mutex);
699 }
700
701 gboolean
702 mono_arch_have_fast_tls (void)
703 {
704         return FALSE;
705 }
706
707 /*
708  * This function returns the optimizations supported on this cpu.
709  */
710 guint32
711 mono_arch_cpu_optimizations (guint32 *exclude_mask)
712 {
713         guint32 opts = 0;
714
715         /* no mips-specific optimizations yet */
716         *exclude_mask = 0;
717         return opts;
718 }
719
720 /*
721  * This function test for all SIMD functions supported.
722  *
723  * Returns a bitmask corresponding to all supported versions.
724  *
725  */
726 guint32
727 mono_arch_cpu_enumerate_simd_versions (void)
728 {
729         /* SIMD is currently unimplemented */
730         return 0;
731 }
732
733 GList *
734 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
735 {
736         GList *vars = NULL;
737         int i;
738
739         for (i = 0; i < cfg->num_varinfo; i++) {
740                 MonoInst *ins = cfg->varinfo [i];
741                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
742
743                 /* unused vars */
744                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
745                         continue;
746
747                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
748                         continue;
749
750                 /* we can only allocate 32 bit values */
751                 if (mono_is_regsize_var (ins->inst_vtype)) {
752                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
753                         g_assert (i == vmv->idx);
754                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
755                 }
756         }
757
758         return vars;
759 }
760
761 GList *
762 mono_arch_get_global_int_regs (MonoCompile *cfg)
763 {
764         GList *regs = NULL;
765
766         regs = g_list_prepend (regs, (gpointer)mips_s0);
767         regs = g_list_prepend (regs, (gpointer)mips_s1);
768         regs = g_list_prepend (regs, (gpointer)mips_s2);
769         regs = g_list_prepend (regs, (gpointer)mips_s3);
770         regs = g_list_prepend (regs, (gpointer)mips_s4);
771         //regs = g_list_prepend (regs, (gpointer)mips_s5);
772         regs = g_list_prepend (regs, (gpointer)mips_s6);
773         regs = g_list_prepend (regs, (gpointer)mips_s7);
774
775         return regs;
776 }
777
778 /*
779  * mono_arch_regalloc_cost:
780  *
781  * Return the cost, in number of memory references, of the action of 
782  * allocating the variable VMV into a register during global register
783  * allocation.
784  */
785 guint32
786 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
787 {
788         /* FIXME: */
789         return 2;
790 }
791
792 static void
793 args_onto_stack (CallInfo *info)
794 {
795         g_assert (!info->on_stack);
796         g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
797         info->on_stack = TRUE;
798         info->stack_size = MIPS_STACK_PARAM_OFFSET;
799 }
800
801 #if _MIPS_SIM == _ABIO32
802 /*
803  * O32 calling convention version
804  */
805
806 static void
807 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
808         /* First, see if we need to drop onto the stack */
809         if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
810                 args_onto_stack (info);
811
812         /* Now, place the argument */
813         if (info->on_stack) {
814                 ainfo->storage = ArgOnStack;
815                 ainfo->reg = mips_sp; /* in the caller */
816                 ainfo->offset = info->stack_size;
817         }
818         else {
819                 ainfo->storage = ArgInIReg;
820                 ainfo->reg = info->gr;
821                 info->gr += 1;
822                 info->gr_passed = TRUE;
823         }
824         info->stack_size += 4;
825 }
826
827 static void
828 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
829         /* First, see if we need to drop onto the stack */
830         if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
831                 args_onto_stack (info);
832
833         /* Now, place the argument */
834         if (info->on_stack) {
835                 g_assert (info->stack_size % 4 == 0);
836                 info->stack_size += (info->stack_size % 8);
837
838                 ainfo->storage = ArgOnStack;
839                 ainfo->reg = mips_sp; /* in the caller */
840                 ainfo->offset = info->stack_size;
841         }
842         else {
843                 // info->gr must be a0 or a2
844                 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
845                 g_assert(info->gr <= MIPS_LAST_ARG_REG);
846
847                 ainfo->storage = ArgInIReg;
848                 ainfo->reg = info->gr;
849                 info->gr += 2;
850                 info->gr_passed = TRUE;
851         }
852         info->stack_size += 8;
853 }
854
855 static void
856 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
857         /* First, see if we need to drop onto the stack */
858         if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
859                 args_onto_stack (info);
860
861         /* Now, place the argument */
862         if (info->on_stack) {
863                 ainfo->storage = ArgOnStack;
864                 ainfo->reg = mips_sp; /* in the caller */
865                 ainfo->offset = info->stack_size;
866         }
867         else {
868                 /* Only use FP regs for args if no int args passed yet */
869                 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
870                         ainfo->storage = ArgInFReg;
871                         ainfo->reg = info->fr;
872                         /* Even though it's a single-precision float, it takes up two FP regs */
873                         info->fr += 2;
874                         /* FP and GP slots do not overlap */
875                         info->gr += 1;
876                 }
877                 else {
878                         /* Passing single-precision float arg in a GP register
879                          * such as: func (0, 1.0, 2, 3);
880                          * In this case, only one 'gr' register is consumed.
881                          */
882                         ainfo->storage = ArgInIReg;
883                         ainfo->reg = info->gr;
884
885                         info->gr += 1;
886                         info->gr_passed = TRUE;
887                 }
888         }
889         info->stack_size += 4;
890 }
891
892 static void
893 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
894         /* First, see if we need to drop onto the stack */
895         if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
896                 args_onto_stack (info);
897
898         /* Now, place the argument */
899         if (info->on_stack) {
900                 g_assert(info->stack_size % 4 == 0);
901                 info->stack_size += (info->stack_size % 8);
902
903                 ainfo->storage = ArgOnStack;
904                 ainfo->reg = mips_sp; /* in the caller */
905                 ainfo->offset = info->stack_size;
906         }
907         else {
908                 /* Only use FP regs for args if no int args passed yet */
909                 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
910                         ainfo->storage = ArgInFReg;
911                         ainfo->reg = info->fr;
912                         info->fr += 2;
913                         /* FP and GP slots do not overlap */
914                         info->gr += 2;
915                 }
916                 else {
917                         // info->gr must be a0 or a2
918                         info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
919                         g_assert(info->gr <= MIPS_LAST_ARG_REG);
920
921                         ainfo->storage = ArgInIReg;
922                         ainfo->reg = info->gr;
923                         info->gr += 2;
924                         info->gr_passed = TRUE;
925                 }
926         }
927         info->stack_size += 8;
928 }
929 #elif _MIPS_SIM == _ABIN32
930 /*
931  * N32 calling convention version
932  */
933
934 static void
935 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
936         /* First, see if we need to drop onto the stack */
937         if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
938                 args_onto_stack (info);
939
940         /* Now, place the argument */
941         if (info->on_stack) {
942                 ainfo->storage = ArgOnStack;
943                 ainfo->reg = mips_sp; /* in the caller */
944                 ainfo->offset = info->stack_size;
945                 info->stack_size += SIZEOF_REGISTER;
946         }
947         else {
948                 ainfo->storage = ArgInIReg;
949                 ainfo->reg = info->gr;
950                 info->gr += 1;
951                 info->gr_passed = TRUE;
952         }
953 }
954
955 static void
956 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
957         /* First, see if we need to drop onto the stack */
958         if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
959                 args_onto_stack (info);
960
961         /* Now, place the argument */
962         if (info->on_stack) {
963                 g_assert (info->stack_size % 4 == 0);
964                 info->stack_size += (info->stack_size % 8);
965
966                 ainfo->storage = ArgOnStack;
967                 ainfo->reg = mips_sp; /* in the caller */
968                 ainfo->offset = info->stack_size;
969                 info->stack_size += SIZEOF_REGISTER;
970         }
971         else {
972                 g_assert (info->gr <= MIPS_LAST_ARG_REG);
973
974                 ainfo->storage = ArgInIReg;
975                 ainfo->reg = info->gr;
976                 info->gr += 1;
977                 info->gr_passed = TRUE;
978         }
979 }
980
981 static void
982 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
983         /* First, see if we need to drop onto the stack */
984         if (!info->on_stack) {
985                 if (info->gr > MIPS_LAST_ARG_REG)
986                         args_onto_stack (info);
987                 else if (info->fr > MIPS_LAST_FPARG_REG)
988                         args_onto_stack (info);
989         }
990
991         /* Now, place the argument */
992         if (info->on_stack) {
993                 ainfo->storage = ArgOnStack;
994                 ainfo->reg = mips_sp; /* in the caller */
995                 ainfo->offset = info->stack_size;
996                 info->stack_size += FREG_SIZE;
997         }
998         else {
999                 ainfo->storage = ArgInFReg;
1000                 ainfo->reg = info->fr;
1001                 info->fr += 1;
1002                 /* FP and GP slots do not overlap */
1003                 info->gr += 1;
1004         }
1005 }
1006
1007 static void
1008 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1009         /* First, see if we need to drop onto the stack */
1010         if (!info->on_stack) {
1011                 if (info->gr > MIPS_LAST_ARG_REG)
1012                         args_onto_stack (info);
1013                 else if (info->fr > MIPS_LAST_FPARG_REG)
1014                         args_onto_stack (info);
1015         }
1016
1017         /* Now, place the argument */
1018         if (info->on_stack) {
1019                 g_assert(info->stack_size % 4 == 0);
1020                 info->stack_size += (info->stack_size % 8);
1021
1022                 ainfo->storage = ArgOnStack;
1023                 ainfo->reg = mips_sp; /* in the caller */
1024                 ainfo->offset = info->stack_size;
1025                 info->stack_size += FREG_SIZE;
1026         }
1027         else {
1028                 ainfo->storage = ArgInFReg;
1029                 ainfo->reg = info->fr;
1030                 info->fr += 1;
1031                 /* FP and GP slots do not overlap */
1032                 info->gr += 1;
1033         }
1034 }
1035 #endif
1036
1037 static CallInfo*
1038 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1039 {
1040         guint i;
1041         int n = sig->hasthis + sig->param_count;
1042         int pstart;
1043         MonoType* simpletype;
1044         CallInfo *cinfo;
1045         gboolean is_pinvoke = sig->pinvoke;
1046
1047         if (mp)
1048                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1049         else
1050                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1051
1052         cinfo->fr = MIPS_FIRST_FPARG_REG;
1053         cinfo->gr = MIPS_FIRST_ARG_REG;
1054         cinfo->stack_size = 0;
1055
1056         DEBUG(printf("calculate_sizes\n"));
1057
1058         cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1059         pstart = 0;
1060         n = 0;
1061 #if 0
1062         /* handle returning a struct */
1063         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1064                 cinfo->struct_ret = cinfo->gr;
1065                 add_int32_arg (cinfo, &cinfo->ret);
1066         }
1067
1068         if (sig->hasthis) {
1069                 add_int32_arg (cinfo, cinfo->args + n);
1070                 n++;
1071         }
1072 #else
1073         /*
1074          * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1075          * the first argument, allowing 'this' to be always passed in the first arg reg.
1076          * Also do this if the first argument is a reference type, since virtual calls
1077          * are sometimes made using calli without sig->hasthis set, like in the delegate
1078          * invoke wrappers.
1079          */
1080         if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1081                 if (sig->hasthis) {
1082                         add_int32_arg (cinfo, cinfo->args + n);
1083                         n ++;
1084                 } else {
1085                         add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1086                         pstart = 1;
1087                         n ++;
1088                 }
1089                 add_int32_arg (cinfo, &cinfo->ret);
1090                 cinfo->struct_ret = cinfo->ret.reg;
1091         } else {
1092                 /* this */
1093                 if (sig->hasthis) {
1094                         add_int32_arg (cinfo, cinfo->args + n);
1095                         n ++;
1096                 }
1097
1098                 if (cinfo->vtype_retaddr) {
1099                         add_int32_arg (cinfo, &cinfo->ret);
1100                         cinfo->struct_ret = cinfo->ret.reg;
1101                 }
1102         }
1103 #endif
1104
1105         DEBUG(printf("params: %d\n", sig->param_count));
1106         for (i = pstart; i < sig->param_count; ++i) {
1107                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1108                         /* Prevent implicit arguments and sig_cookie from
1109                            being passed in registers */
1110                         args_onto_stack (cinfo);
1111                         /* Emit the signature cookie just before the implicit arguments */
1112                         add_int32_arg (cinfo, &cinfo->sig_cookie);
1113                 }
1114                 DEBUG(printf("param %d: ", i));
1115                 simpletype = mini_get_underlying_type (sig->params [i]);
1116                 switch (simpletype->type) {
1117                 case MONO_TYPE_BOOLEAN:
1118                 case MONO_TYPE_I1:
1119                 case MONO_TYPE_U1:
1120                         DEBUG(printf("1 byte\n"));
1121                         cinfo->args [n].size = 1;
1122                         add_int32_arg (cinfo, &cinfo->args[n]);
1123                         n++;
1124                         break;
1125                 case MONO_TYPE_CHAR:
1126                 case MONO_TYPE_I2:
1127                 case MONO_TYPE_U2:
1128                         DEBUG(printf("2 bytes\n"));
1129                         cinfo->args [n].size = 2;
1130                         add_int32_arg (cinfo, &cinfo->args[n]);
1131                         n++;
1132                         break;
1133                 case MONO_TYPE_I4:
1134                 case MONO_TYPE_U4:
1135                         DEBUG(printf("4 bytes\n"));
1136                         cinfo->args [n].size = 4;
1137                         add_int32_arg (cinfo, &cinfo->args[n]);
1138                         n++;
1139                         break;
1140                 case MONO_TYPE_I:
1141                 case MONO_TYPE_U:
1142                 case MONO_TYPE_PTR:
1143                 case MONO_TYPE_FNPTR:
1144                 case MONO_TYPE_CLASS:
1145                 case MONO_TYPE_OBJECT:
1146                 case MONO_TYPE_STRING:
1147                 case MONO_TYPE_SZARRAY:
1148                 case MONO_TYPE_ARRAY:
1149                         cinfo->args [n].size = sizeof (gpointer);
1150                         add_int32_arg (cinfo, &cinfo->args[n]);
1151                         n++;
1152                         break;
1153                 case MONO_TYPE_GENERICINST:
1154                         if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1155                                 cinfo->args [n].size = sizeof (gpointer);
1156                                 add_int32_arg (cinfo, &cinfo->args[n]);
1157                                 n++;
1158                                 break;
1159                         }
1160                         /* Fall through */
1161                 case MONO_TYPE_TYPEDBYREF:
1162                 case MONO_TYPE_VALUETYPE: {
1163                         int j;
1164                         int nwords = 0;
1165                         int has_offset = FALSE;
1166                         ArgInfo dummy_arg;
1167                         gint size, alignment;
1168                         MonoClass *klass;
1169
1170                         if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1171                                 size = sizeof (MonoTypedRef);
1172                                 alignment = sizeof (gpointer);
1173                         } else {
1174                                 klass = mono_class_from_mono_type (sig->params [i]);
1175                                 if (is_pinvoke)
1176                                         size = mono_class_native_size (klass, NULL);
1177                                 else
1178                                         size = mono_class_value_size (klass, NULL);
1179                                 alignment = mono_class_min_align (klass);
1180                         }
1181 #if MIPS_PASS_STRUCTS_BY_VALUE
1182                         /* Need to do alignment if struct contains long or double */
1183                         if (alignment > 4) {
1184                                 /* Drop onto stack *before* looking at
1185                                    stack_size, if required. */
1186                                 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1187                                         args_onto_stack (cinfo);
1188                                 if (cinfo->stack_size & (alignment - 1)) {
1189                                         add_int32_arg (cinfo, &dummy_arg);
1190                                 }
1191                                 g_assert (!(cinfo->stack_size & (alignment - 1)));
1192                         }
1193
1194 #if 0
1195                         g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1196                                   mono_class_native_size (sig->params [i]->data.klass, NULL),
1197                                   cinfo->stack_size, alignment);
1198 #endif
1199                         nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1200                         g_assert (cinfo->args [n].size == 0);
1201                         g_assert (cinfo->args [n].vtsize == 0);
1202                         for (j = 0; j < nwords; ++j) {
1203                                 if (j == 0) {
1204                                         add_int32_arg (cinfo, &cinfo->args [n]);
1205                                         if (cinfo->on_stack)
1206                                                 has_offset = TRUE;
1207                                 } else {
1208                                         add_int32_arg (cinfo, &dummy_arg);
1209                                         if (!has_offset && cinfo->on_stack) {
1210                                                 cinfo->args [n].offset = dummy_arg.offset;
1211                                                 has_offset = TRUE;
1212                                         }
1213                                 }
1214                                 if (cinfo->on_stack)
1215                                         cinfo->args [n].vtsize += 1;
1216                                 else
1217                                         cinfo->args [n].size += 1;
1218                         }
1219                         //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1220                         cinfo->args [n].storage = ArgStructByVal;
1221 #else
1222                         add_int32_arg (cinfo, &cinfo->args[n]);
1223                         cinfo->args [n].storage = ArgStructByAddr;
1224 #endif
1225                         n++;
1226                         break;
1227                 }
1228                 case MONO_TYPE_U8:
1229                 case MONO_TYPE_I8:
1230                         DEBUG(printf("8 bytes\n"));
1231                         cinfo->args [n].size = 8;
1232                         add_int64_arg (cinfo, &cinfo->args[n]);
1233                         n++;
1234                         break;
1235                 case MONO_TYPE_R4:
1236                         DEBUG(printf("R4\n"));
1237                         cinfo->args [n].size = 4;
1238                         add_float32_arg (cinfo, &cinfo->args[n]);
1239                         n++;
1240                         break;
1241                 case MONO_TYPE_R8:
1242                         DEBUG(printf("R8\n"));
1243                         cinfo->args [n].size = 8;
1244                         add_float64_arg (cinfo, &cinfo->args[n]);
1245                         n++;
1246                         break;
1247                 default:
1248                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1249                 }
1250         }
1251
1252         /* Handle the case where there are no implicit arguments */
1253         if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1254                 /* Prevent implicit arguments and sig_cookie from
1255                    being passed in registers */
1256                 args_onto_stack (cinfo);
1257                 /* Emit the signature cookie just before the implicit arguments */
1258                 add_int32_arg (cinfo, &cinfo->sig_cookie);
1259         }
1260
1261         {
1262                 simpletype = mini_get_underlying_type (sig->ret);
1263                 switch (simpletype->type) {
1264                 case MONO_TYPE_BOOLEAN:
1265                 case MONO_TYPE_I1:
1266                 case MONO_TYPE_U1:
1267                 case MONO_TYPE_I2:
1268                 case MONO_TYPE_U2:
1269                 case MONO_TYPE_CHAR:
1270                 case MONO_TYPE_I4:
1271                 case MONO_TYPE_U4:
1272                 case MONO_TYPE_I:
1273                 case MONO_TYPE_U:
1274                 case MONO_TYPE_PTR:
1275                 case MONO_TYPE_FNPTR:
1276                 case MONO_TYPE_CLASS:
1277                 case MONO_TYPE_OBJECT:
1278                 case MONO_TYPE_SZARRAY:
1279                 case MONO_TYPE_ARRAY:
1280                 case MONO_TYPE_STRING:
1281                         cinfo->ret.reg = mips_v0;
1282                         break;
1283                 case MONO_TYPE_U8:
1284                 case MONO_TYPE_I8:
1285                         cinfo->ret.reg = mips_v0;
1286                         break;
1287                 case MONO_TYPE_R4:
1288                 case MONO_TYPE_R8:
1289                         cinfo->ret.reg = mips_f0;
1290                         cinfo->ret.storage = ArgInFReg;
1291                         break;
1292                 case MONO_TYPE_GENERICINST:
1293                         if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1294                                 cinfo->ret.reg = mips_v0;
1295                                 break;
1296                         }
1297                         break;
1298                 case MONO_TYPE_VALUETYPE:
1299                 case MONO_TYPE_TYPEDBYREF:
1300                         break;
1301                 case MONO_TYPE_VOID:
1302                         break;
1303                 default:
1304                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
1305                 }
1306         }
1307
1308         /* align stack size to 16 */
1309         cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1310
1311         cinfo->stack_usage = cinfo->stack_size;
1312         return cinfo;
1313 }
1314
1315 static gboolean
1316 debug_omit_fp (void)
1317 {
1318 #if 0
1319         return mono_debug_count ();
1320 #else
1321         return TRUE;
1322 #endif
1323 }
1324
1325 /**
1326  * mono_arch_compute_omit_fp:
1327  * Determine whether 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         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 }