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