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