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