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