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