Merge pull request #2429 from alexanderkyte/nunit_lite_integration
[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
4679         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4680                 unsigned char *ip = patch_info->ip.i + code;
4681                 const unsigned char *target = NULL;
4682
4683                 switch (patch_info->type) {
4684                 case MONO_PATCH_INFO_IP:
4685                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4686                         continue;
4687                 case MONO_PATCH_INFO_SWITCH: {
4688                         gpointer *table = (gpointer *)patch_info->data.table->table;
4689                         int i;
4690
4691                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4692
4693                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
4694                                 table [i] = (int)patch_info->data.table->table [i] + code;
4695                         }
4696                         continue;
4697                 }
4698                 case MONO_PATCH_INFO_METHODCONST:
4699                 case MONO_PATCH_INFO_CLASS:
4700                 case MONO_PATCH_INFO_IMAGE:
4701                 case MONO_PATCH_INFO_FIELD:
4702                 case MONO_PATCH_INFO_VTABLE:
4703                 case MONO_PATCH_INFO_IID:
4704                 case MONO_PATCH_INFO_SFLDA:
4705                 case MONO_PATCH_INFO_LDSTR:
4706                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4707                 case MONO_PATCH_INFO_LDTOKEN:
4708                 case MONO_PATCH_INFO_R4:
4709                 case MONO_PATCH_INFO_R8:
4710                         /* from OP_AOTCONST : lui + addiu */
4711                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4712                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4713                         continue;
4714 #if 0
4715                 case MONO_PATCH_INFO_EXC_NAME:
4716                         g_assert_not_reached ();
4717                         *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4718                         continue;
4719 #endif
4720                 case MONO_PATCH_INFO_NONE:
4721                         /* everything is dealt with at epilog output time */
4722                         continue;
4723                 default:
4724                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4725                         mips_patch ((guint32 *)(void *)ip, (guint32)target);
4726                         break;
4727                 }
4728         }
4729 }
4730
4731 /*
4732  * Allow tracing to work with this interface (with an optional argument)
4733  *
4734  * This code is expected to be inserted just after the 'real' prolog code,
4735  * and before the first basic block.  We need to allocate a 2nd, temporary
4736  * stack frame so that we can preserve f12-f15 as well as a0-a3.
4737  */
4738
4739 void*
4740 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4741 {
4742         guchar *code = p;
4743         int offset = cfg->arch.tracing_offset;
4744
4745         mips_nop (code);
4746         mips_nop (code);
4747         mips_nop (code);
4748
4749         MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4750         MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4751         MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4752         MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4753 #if _MIPS_SIM == _ABIN32
4754         NOT_IMPLEMENTED;
4755         /* FIXME: Need a separate region for these */
4756         MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4757         MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4758         MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4759         MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4760         */
4761 #endif
4762
4763         mips_load_const (code, mips_a0, cfg->method);
4764         mips_addiu (code, mips_a1, mips_sp, offset);
4765         mips_call (code, mips_t9, func);
4766         mips_nop (code);
4767
4768         MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4769         MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4770         MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4771         MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4772 #if _MIPS_SIM == _ABIN32
4773         NOT_IMPLEMENTED;
4774         /*
4775         MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4776         MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4777         MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4778         MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4779         */
4780 #endif
4781
4782         mips_nop (code);
4783         mips_nop (code);
4784         mips_nop (code);
4785         return code;
4786 }
4787
4788 void
4789 mips_adjust_stackframe(MonoCompile *cfg)
4790 {
4791         MonoBasicBlock *bb;
4792         int delta, threshold, i;
4793         MonoMethodSignature *sig;
4794         int ra_offset;
4795
4796         if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4797                 return;
4798
4799         /* adjust cfg->stack_offset for account for down-spilling */
4800         cfg->stack_offset += SIZEOF_REGISTER;
4801
4802         /* re-align cfg->stack_offset if needed (due to var spilling) */
4803         cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4804         delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4805         if (cfg->verbose_level > 2) {
4806                 g_print ("mips_adjust_stackframe:\n");
4807                 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4808         }
4809         threshold = cfg->arch.local_alloc_offset;
4810         ra_offset = cfg->stack_offset - sizeof(gpointer);
4811         if (cfg->verbose_level > 2) {
4812                 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4813         }
4814
4815         sig = mono_method_signature (cfg->method);
4816         if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4817                 cfg->vret_addr->inst_offset += delta;
4818         }
4819         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4820                 MonoInst *inst = cfg->args [i];
4821
4822                 inst->inst_offset += delta;
4823         }
4824
4825         /*
4826          * loads and stores based off the frame reg that (used to) lie
4827          * above the spill var area need to be increased by 'delta'
4828          * to make room for the spill vars.
4829          */
4830         /* Need to find loads and stores to adjust that
4831          * are above where the spillvars were inserted, but
4832          * which are not the spillvar references themselves.
4833          *
4834          * Idea - since all offsets from fp are positive, make
4835          * spillvar offsets negative to begin with so we can spot
4836          * them here.
4837          */
4838
4839 #if 1
4840         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4841                 int ins_cnt = 0;
4842                 MonoInst *ins;
4843
4844                 if (cfg->verbose_level > 2) {
4845                         g_print ("BASIC BLOCK %d:\n", bb->block_num);
4846                 }
4847                 MONO_BB_FOR_EACH_INS (bb, ins) {
4848                         int adj_c0 = 0;
4849                         int adj_imm = 0;
4850
4851                         if (cfg->verbose_level > 2) {
4852                                 mono_print_ins_index (ins_cnt, ins);
4853                         }
4854                         /* The == mips_sp tests catch FP spills */
4855                         if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4856                                                           (ins->inst_basereg == mips_sp))) {
4857                                 switch (ins->opcode) {
4858                                 case OP_LOADI8_MEMBASE:
4859                                 case OP_LOADR8_MEMBASE:
4860                                         adj_c0 = 8;
4861                                         break;
4862                                 default:
4863                                         adj_c0 = 4;
4864                                         break;
4865                                 }
4866                         } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4867                                                                   (ins->dreg == mips_sp))) {
4868                                 switch (ins->opcode) {
4869                                 case OP_STOREI8_MEMBASE_REG:
4870                                 case OP_STORER8_MEMBASE_REG:
4871                                 case OP_STOREI8_MEMBASE_IMM:
4872                                         adj_c0 = 8;
4873                                         break;
4874                                 default:
4875                                         adj_c0 = 4;
4876                                         break;
4877                                 }
4878                         }
4879                         if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4880                                 adj_imm = 1;
4881                         if (adj_c0) {
4882                                 if (ins->inst_c0 >= threshold) {
4883                                         ins->inst_c0 += delta;
4884                                         if (cfg->verbose_level > 2) {
4885                                                 g_print ("adj");
4886                                                 mono_print_ins_index (ins_cnt, ins);
4887                                         }
4888                                 }
4889                                 else if (ins->inst_c0 < 0) {
4890                                         /* Adj_c0 holds the size of the datatype. */
4891                                         ins->inst_c0 = - ins->inst_c0 - adj_c0;
4892                                         if (cfg->verbose_level > 2) {
4893                                                 g_print ("spill");
4894                                                 mono_print_ins_index (ins_cnt, ins);
4895                                         }
4896                                 }
4897                                 g_assert (ins->inst_c0 != ra_offset);
4898                         }
4899                         if (adj_imm) {
4900                                 if (ins->inst_imm >= threshold) {
4901                                         ins->inst_imm += delta;
4902                                         if (cfg->verbose_level > 2) {
4903                                                 g_print ("adj");
4904                                                 mono_print_ins_index (ins_cnt, ins);
4905                                         }
4906                                 }
4907                                 g_assert (ins->inst_c0 != ra_offset);
4908                         }
4909
4910                         ++ins_cnt;
4911                 }
4912         }
4913 #endif
4914 }
4915
4916 /*
4917  * Stack frame layout:
4918  * 
4919  *   ------------------- sp + cfg->stack_usage + cfg->param_area
4920  *      param area              incoming
4921  *   ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4922  *      a0-a3                   incoming
4923  *   ------------------- sp + cfg->stack_usage
4924  *      ra
4925  *   ------------------- sp + cfg->stack_usage-4
4926  *      spilled regs
4927  *   ------------------- sp + 
4928  *      MonoLMF structure       optional
4929  *   ------------------- sp + cfg->arch.lmf_offset
4930  *      saved registers         s0-s8
4931  *   ------------------- sp + cfg->arch.iregs_offset
4932  *      locals
4933  *   ------------------- sp + cfg->param_area
4934  *      param area              outgoing
4935  *   ------------------- sp + MIPS_STACK_PARAM_OFFSET
4936  *      a0-a3                   outgoing
4937  *   ------------------- sp
4938  *      red zone
4939  */
4940 guint8 *
4941 mono_arch_emit_prolog (MonoCompile *cfg)
4942 {
4943         MonoMethod *method = cfg->method;
4944         MonoMethodSignature *sig;
4945         MonoInst *inst;
4946         int alloc_size, pos, i, max_offset;
4947         int alloc2_size = 0;
4948         guint8 *code;
4949         CallInfo *cinfo;
4950         int tracing = 0;
4951         guint32 iregs_to_save = 0;
4952 #if SAVE_FP_REGS
4953         guint32 fregs_to_save = 0;
4954 #endif
4955         /* lmf_offset is the offset of the LMF from our stack pointer. */
4956         guint32 lmf_offset = cfg->arch.lmf_offset;
4957         int cfa_offset = 0;
4958         MonoBasicBlock *bb;
4959
4960         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4961                 tracing = 1;
4962
4963         if (tracing)
4964                 cfg->flags |= MONO_CFG_HAS_CALLS;
4965         
4966         sig = mono_method_signature (method);
4967         cfg->code_size = 768 + sig->param_count * 20;
4968         code = cfg->native_code = g_malloc (cfg->code_size);
4969
4970         /* 
4971          * compute max_offset in order to use short forward jumps.
4972          */
4973         max_offset = 0;
4974         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4975                 MonoInst *ins = bb->code;
4976                 bb->max_offset = max_offset;
4977
4978                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4979                         max_offset += 6; 
4980
4981                 MONO_BB_FOR_EACH_INS (bb, ins)
4982                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4983         }
4984         if (max_offset > 0xffff)
4985                 cfg->arch.long_branch = TRUE;
4986
4987         /*
4988          * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4989          * This means that we have to adjust the offsets inside instructions which reference
4990          * arguments received on the stack, since the initial offset doesn't take into
4991          * account spill slots.
4992          */
4993         mips_adjust_stackframe (cfg);
4994
4995         /* Offset between current sp and the CFA */
4996         cfa_offset = 0;
4997         mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4998
4999         /* stack_offset should not be changed here. */
5000         alloc_size = cfg->stack_offset;
5001         cfg->stack_usage = alloc_size;
5002
5003         iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5004 #if SAVE_FP_REGS
5005 #if 0
5006         fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5007 #else
5008         fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
5009         fregs_to_save |= (fregs_to_save << 1);
5010 #endif
5011 #endif
5012         /* If the stack size is too big, save 1024 bytes to start with
5013          * so the prologue can use imm16(reg) addressing, then allocate
5014          * the rest of the frame.
5015          */
5016         if (alloc_size > ((1 << 15) - 1024)) {
5017                 alloc2_size = alloc_size - 1024;
5018                 alloc_size = 1024;
5019         }
5020         if (alloc_size) {
5021                 g_assert (mips_is_imm16 (-alloc_size));
5022                 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
5023                 cfa_offset = alloc_size;
5024                 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5025         }
5026
5027         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5028                 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5029                 if (mips_is_imm16(offset))
5030                         mips_sw (code, mips_ra, mips_sp, offset);
5031                 else {
5032                         g_assert_not_reached ();
5033                 }
5034                 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5035                 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5036         }
5037
5038         /* XXX - optimize this later to not save all regs if LMF constructed */
5039         pos = cfg->arch.iregs_offset - alloc2_size;
5040
5041         if (iregs_to_save) {
5042                 /* save used registers in own stack frame (at pos) */
5043                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5044                         if (iregs_to_save & (1 << i)) {
5045                                 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5046                                 g_assert (mips_is_imm16(pos));
5047                                 MIPS_SW (code, i, mips_sp, pos);
5048                                 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5049                                 pos += SIZEOF_REGISTER;
5050                         }
5051                 }
5052         }
5053
5054         // FIXME: Don't save registers twice if there is an LMF
5055         // s8 has to be special cased since it is overwritten with the updated value
5056         // below
5057         if (method->save_lmf) {
5058                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5059                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5060                         g_assert (mips_is_imm16(offset));
5061                         if (MIPS_LMF_IREGMASK & (1 << i))
5062                                 MIPS_SW (code, i, mips_sp, offset);
5063                 }
5064         }
5065
5066 #if SAVE_FP_REGS
5067         /* Save float registers */
5068         if (fregs_to_save) {
5069                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5070                         if (fregs_to_save & (1 << i)) {
5071                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5072                                 g_assert (mips_is_imm16(pos));
5073                                 mips_swc1 (code, i, mips_sp, pos);
5074                                 pos += sizeof (gulong);
5075                         }
5076                 }
5077         }
5078
5079         if (method->save_lmf) {
5080                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5081                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5082                         g_assert (mips_is_imm16(offset));
5083                         mips_swc1 (code, i, mips_sp, offset);
5084                 }
5085         }
5086
5087 #endif
5088         if (cfg->frame_reg != mips_sp) {
5089                 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5090                 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5091
5092                 if (method->save_lmf) {
5093                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5094                         g_assert (mips_is_imm16(offset));
5095                         MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5096                 }
5097         }
5098
5099         /* store runtime generic context */
5100         if (cfg->rgctx_var) {
5101                 MonoInst *ins = cfg->rgctx_var;
5102
5103                 g_assert (ins->opcode == OP_REGOFFSET);
5104
5105                 g_assert (mips_is_imm16 (ins->inst_offset));
5106                 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5107         }
5108
5109         /* load arguments allocated to register from the stack */
5110         pos = 0;
5111
5112         if (!cfg->arch.cinfo)
5113                 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
5114         cinfo = cfg->arch.cinfo;
5115
5116         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5117                 ArgInfo *ainfo = &cinfo->ret;
5118                 inst = cfg->vret_addr;
5119                 if (inst->opcode == OP_REGVAR)
5120                         MIPS_MOVE (code, inst->dreg, ainfo->reg);
5121                 else if (mips_is_imm16 (inst->inst_offset)) {
5122                         mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5123                 } else {
5124                         mips_load_const (code, mips_at, inst->inst_offset);
5125                         mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5126                         mips_sw (code, ainfo->reg, mips_at, 0);
5127                 }
5128         }
5129
5130         if (sig->call_convention == MONO_CALL_VARARG) {
5131                 ArgInfo *cookie = &cinfo->sig_cookie;
5132                 int offset = alloc_size + cookie->offset;
5133
5134                 /* Save the sig cookie address */
5135                 g_assert (cookie->storage == ArgOnStack);
5136
5137                 g_assert (mips_is_imm16(offset));
5138                 mips_addi (code, mips_at, cfg->frame_reg, offset);
5139                 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5140         }
5141
5142         /* Keep this in sync with emit_load_volatile_arguments */
5143         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5144                 ArgInfo *ainfo = cinfo->args + i;
5145                 inst = cfg->args [pos];
5146                 
5147                 if (cfg->verbose_level > 2)
5148                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5149                 if (inst->opcode == OP_REGVAR) {
5150                         /* Argument ends up in a register */
5151                         if (ainfo->storage == ArgInIReg)
5152                                 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5153                         else if (ainfo->storage == ArgInFReg) {
5154                                 g_assert_not_reached();
5155 #if 0
5156                                 ppc_fmr (code, inst->dreg, ainfo->reg);
5157 #endif
5158                         }
5159                         else if (ainfo->storage == ArgOnStack) {
5160                                 int offset = cfg->stack_usage + ainfo->offset;
5161                                 g_assert (mips_is_imm16(offset));
5162                                 mips_lw (code, inst->dreg, mips_sp, offset);
5163                         } else
5164                                 g_assert_not_reached ();
5165
5166                         if (cfg->verbose_level > 2)
5167                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5168                 } else {
5169                         /* Argument ends up on the stack */
5170                         if (ainfo->storage == ArgInIReg) {
5171                                 int basereg_offset;
5172                                 /* Incoming parameters should be above this frame */
5173                                 if (cfg->verbose_level > 2)
5174                                         g_print ("stack slot at %d of %d+%d\n",
5175                                                  inst->inst_offset, alloc_size, alloc2_size);
5176                                 /* g_assert (inst->inst_offset >= alloc_size); */
5177                                 g_assert (inst->inst_basereg == cfg->frame_reg);
5178                                 basereg_offset = inst->inst_offset - alloc2_size;
5179                                 g_assert (mips_is_imm16 (basereg_offset));
5180                                 switch (ainfo->size) {
5181                                 case 1:
5182                                         mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5183                                         break;
5184                                 case 2:
5185                                         mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5186                                         break;
5187                                 case 0: /* XXX */
5188                                 case 4:
5189                                         mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5190                                         break;
5191                                 case 8:
5192 #if (SIZEOF_REGISTER == 4)
5193                                         mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5194                                         mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5195 #elif (SIZEOF_REGISTER == 8)
5196                                         mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5197 #endif
5198                                         break;
5199                                 default:
5200                                         g_assert_not_reached ();
5201                                         break;
5202                                 }
5203                         } else if (ainfo->storage == ArgOnStack) {
5204                                 /*
5205                                  * Argument comes in on the stack, and ends up on the stack
5206                                  * 1 and 2 byte args are passed as 32-bit quantities, but used as
5207                                  * 8 and 16 bit quantities.  Shorten them in place.
5208                                  */
5209                                 g_assert (mips_is_imm16 (inst->inst_offset));
5210                                 switch (ainfo->size) {
5211                                 case 1:
5212                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5213                                         mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5214                                         break;
5215                                 case 2:
5216                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5217                                         mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5218                                         break;
5219                                 case 0: /* XXX */
5220                                 case 4:
5221                                 case 8:
5222                                         break;
5223                                 default:
5224                                         g_assert_not_reached ();
5225                                 }
5226                         } else if (ainfo->storage == ArgInFReg) {
5227                                 g_assert (mips_is_imm16 (inst->inst_offset));
5228                                 g_assert (mips_is_imm16 (inst->inst_offset+4));
5229                                 if (ainfo->size == 8) {
5230 #if _MIPS_SIM == _ABIO32
5231                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5232                                         mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5233 #elif _MIPS_SIM == _ABIN32
5234                                         mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5235 #endif
5236                                 }
5237                                 else if (ainfo->size == 4)
5238                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5239                                 else
5240                                         g_assert_not_reached ();
5241                         } else if (ainfo->storage == ArgStructByVal) {
5242                                 int i;
5243                                 int doffset = inst->inst_offset;
5244
5245                                 g_assert (mips_is_imm16 (inst->inst_offset));
5246                                 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5247                                 /* Push the argument registers into their stack slots */
5248                                 for (i = 0; i < ainfo->size; ++i) {
5249                                         g_assert (mips_is_imm16(doffset));
5250                                         MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5251                                         doffset += SIZEOF_REGISTER;
5252                                 }
5253                         } else if (ainfo->storage == ArgStructByAddr) {
5254                                 g_assert (mips_is_imm16 (inst->inst_offset));
5255                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5256                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5257                         } else
5258                                 g_assert_not_reached ();
5259                 }
5260                 pos++;
5261         }
5262
5263         if (method->save_lmf) {
5264                 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5265                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5266
5267                 if (lmf_pthread_key != -1) {
5268                         g_assert_not_reached();
5269 #if 0
5270                         emit_tls_access (code, mips_temp, lmf_pthread_key);
5271 #endif
5272                         if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5273                                 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5274                                 g_assert (mips_is_imm16(offset));
5275                                 mips_addiu (code, mips_a0, mips_temp, offset);
5276                         }
5277                 } else {
5278                         /* This can/will clobber the a0-a3 registers */
5279                         mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5280                 }
5281
5282                 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5283                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5284                 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5285                 /* new_lmf->previous_lmf = *lmf_addr */
5286                 mips_lw (code, mips_at, mips_v0, 0);
5287                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5288                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5289                 /* *(lmf_addr) = sp + lmf_offset */
5290                 g_assert (mips_is_imm16(lmf_offset));
5291                 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5292                 mips_sw (code, mips_at, mips_v0, 0);
5293
5294                 /* save method info */
5295                 mips_load_const (code, mips_at, method);
5296                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5297                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5298
5299                 /* save the current IP */
5300                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5301                 mips_load_const (code, mips_at, 0x01010101);
5302                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5303         }
5304
5305         if (alloc2_size) {
5306                 if (mips_is_imm16 (-alloc2_size)) {
5307                         mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5308                 }
5309                 else {
5310                         mips_load_const (code, mips_at, -alloc2_size);
5311                         mips_addu (code, mips_sp, mips_sp, mips_at);
5312                 }
5313                 alloc_size += alloc2_size;
5314                 cfa_offset += alloc2_size;
5315                 if (cfg->frame_reg != mips_sp)
5316                         MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5317                 else
5318                         mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5319         }
5320
5321         if (tracing) {
5322 #if _MIPS_SIM == _ABIO32
5323                 cfg->arch.tracing_offset = cfg->stack_offset;
5324 #elif _MIPS_SIM == _ABIN32
5325                 /* no stack slots by default for argument regs, reserve a special block */
5326                 g_assert_not_reached ();
5327 #endif
5328                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5329         }
5330
5331         cfg->code_len = code - cfg->native_code;
5332         g_assert (cfg->code_len < cfg->code_size);
5333
5334         return code;
5335 }
5336
5337 enum {
5338         SAVE_NONE,
5339         SAVE_STRUCT,
5340         SAVE_ONE,
5341         SAVE_TWO,
5342         SAVE_FP
5343 };
5344
5345 void*
5346 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5347 {
5348         guchar *code = p;
5349         int save_mode = SAVE_NONE;
5350         int offset;
5351         MonoMethod *method = cfg->method;
5352         int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5353         int save_offset = MIPS_STACK_PARAM_OFFSET;
5354
5355         g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5356         
5357         offset = code - cfg->native_code;
5358         /* we need about 16 instructions */
5359         if (offset > (cfg->code_size - 16 * 4)) {
5360                 cfg->code_size *= 2;
5361                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5362                 code = cfg->native_code + offset;
5363         }
5364         mips_nop (code);
5365         mips_nop (code);
5366         switch (rtype) {
5367         case MONO_TYPE_VOID:
5368                 /* special case string .ctor icall */
5369                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5370                         save_mode = SAVE_ONE;
5371                 else
5372                         save_mode = SAVE_NONE;
5373                 break;
5374         case MONO_TYPE_R4:
5375         case MONO_TYPE_R8:
5376                 save_mode = SAVE_FP;
5377                 break;
5378         case MONO_TYPE_VALUETYPE:
5379                 save_mode = SAVE_STRUCT;
5380                 break;
5381         case MONO_TYPE_I8:
5382         case MONO_TYPE_U8:
5383 #if SIZEOF_REGISTER == 4
5384                 save_mode = SAVE_TWO;
5385 #elif SIZEOF_REGISTER == 8
5386                 save_mode = SAVE_ONE;
5387 #endif
5388                 break;
5389         default:
5390                 save_mode = SAVE_ONE;
5391                 break;
5392         }
5393
5394         mips_addiu (code, mips_sp, mips_sp, -32);
5395         g_assert (mips_is_imm16(save_offset));
5396         switch (save_mode) {
5397         case SAVE_TWO:
5398                 mips_sw (code, mips_v0, mips_sp, save_offset);
5399                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5400                 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5401                 if (enable_arguments) {
5402                         MIPS_MOVE (code, mips_a1, mips_v0);
5403                         MIPS_MOVE (code, mips_a2, mips_v1);
5404                 }
5405                 break;
5406         case SAVE_ONE:
5407                 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5408                 if (enable_arguments) {
5409                         MIPS_MOVE (code, mips_a1, mips_v0);
5410                 }
5411                 break;
5412         case SAVE_FP:
5413                 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5414                 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5415                 mips_lw (code, mips_a0, mips_sp, save_offset);
5416                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5417                 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5418                 break;
5419         case SAVE_STRUCT:
5420         case SAVE_NONE:
5421         default:
5422                 break;
5423         }
5424         mips_load_const (code, mips_a0, cfg->method);
5425         mips_call (code, mips_t9, func);
5426
5427         switch (save_mode) {
5428         case SAVE_TWO:
5429                 mips_lw (code, mips_v0, mips_sp, save_offset);
5430                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5431                 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5432                 break;
5433         case SAVE_ONE:
5434                 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5435                 break;
5436         case SAVE_FP:
5437                 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5438                 break;
5439         case SAVE_STRUCT:
5440         case SAVE_NONE:
5441         default:
5442                 break;
5443         }
5444         mips_addiu (code, mips_sp, mips_sp, 32);
5445         mips_nop (code);
5446         mips_nop (code);
5447         return code;
5448 }
5449
5450 guint8 *
5451 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5452 {
5453         MonoMethod *method = cfg->method;
5454         int pos = 0, i;
5455         int max_epilog_size = 16 + 20*4;
5456         int alloc2_size = 0;
5457         guint32 iregs_to_restore;
5458 #if SAVE_FP_REGS
5459         guint32 fregs_to_restore;
5460 #endif
5461
5462         if (cfg->method->save_lmf)
5463                 max_epilog_size += 128;
5464         
5465         if (mono_jit_trace_calls != NULL)
5466                 max_epilog_size += 50;
5467
5468         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5469                 max_epilog_size += 50;
5470
5471         if (code)
5472                 pos = code - cfg->native_code;
5473         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5474                 cfg->code_size *= 2;
5475                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5476                 cfg->stat_code_reallocs++;
5477         }
5478
5479         /*
5480          * Keep in sync with OP_JMP
5481          */
5482         if (code)
5483                 code = cfg->native_code + pos;
5484         else
5485                 code = cfg->native_code + cfg->code_len;
5486
5487         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5488                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5489         }
5490         if (cfg->frame_reg != mips_sp) {
5491                 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5492         }
5493         /* If the stack frame is really large, deconstruct it in two steps */
5494         if (cfg->stack_usage > ((1 << 15) - 1024)) {
5495                 alloc2_size = cfg->stack_usage - 1024;
5496                 /* partially deconstruct the stack */
5497                 mips_load_const (code, mips_at, alloc2_size);
5498                 mips_addu (code, mips_sp, mips_sp, mips_at);
5499         }
5500         pos = cfg->arch.iregs_offset - alloc2_size;
5501         iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5502         if (iregs_to_restore) {
5503                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5504                         if (iregs_to_restore & (1 << i)) {
5505                                 g_assert (mips_is_imm16(pos));
5506                                 MIPS_LW (code, i, mips_sp, pos);
5507                                 pos += SIZEOF_REGISTER;
5508                         }
5509                 }
5510         }
5511
5512 #if SAVE_FP_REGS
5513 #if 0
5514         fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5515 #else
5516         fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5517         fregs_to_restore |= (fregs_to_restore << 1);
5518 #endif
5519         if (fregs_to_restore) {
5520                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5521                         if (fregs_to_restore & (1 << i)) {
5522                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5523                                 g_assert (mips_is_imm16(pos));
5524                                 mips_lwc1 (code, i, mips_sp, pos);
5525                                 pos += FREG_SIZE
5526                         }
5527                 }
5528         }
5529 #endif
5530
5531         /* Unlink the LMF if necessary */
5532         if (method->save_lmf) {
5533                 int lmf_offset = cfg->arch.lmf_offset;
5534
5535                 /* t0 = current_lmf->previous_lmf */
5536                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5537                 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5538                 /* t1 = lmf_addr */
5539                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5540                 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5541                 /* (*lmf_addr) = previous_lmf */
5542                 mips_sw (code, mips_temp, mips_t1, 0);
5543         }
5544
5545 #if 0
5546         /* Restore the fp */
5547         mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5548 #endif
5549         /* Restore ra */
5550         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5551                 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5552                 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5553         }
5554         /* Restore the stack pointer */
5555         g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5556         mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5557
5558         /* Caller will emit either return or tail-call sequence */
5559
5560         cfg->code_len = code - cfg->native_code;
5561
5562         g_assert (cfg->code_len < cfg->code_size);
5563         return (code);
5564 }
5565
5566 void
5567 mono_arch_emit_epilog (MonoCompile *cfg)
5568 {
5569         guint8 *code;
5570
5571         code = mono_arch_emit_epilog_sub (cfg, NULL);
5572
5573         mips_jr (code, mips_ra);
5574         mips_nop (code);
5575
5576         cfg->code_len = code - cfg->native_code;
5577
5578         g_assert (cfg->code_len < cfg->code_size);
5579 }
5580
5581 /* remove once throw_exception_by_name is eliminated */
5582 #if 0
5583 static int
5584 exception_id_by_name (const char *name)
5585 {
5586         if (strcmp (name, "IndexOutOfRangeException") == 0)
5587                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5588         if (strcmp (name, "OverflowException") == 0)
5589                 return MONO_EXC_OVERFLOW;
5590         if (strcmp (name, "ArithmeticException") == 0)
5591                 return MONO_EXC_ARITHMETIC;
5592         if (strcmp (name, "DivideByZeroException") == 0)
5593                 return MONO_EXC_DIVIDE_BY_ZERO;
5594         if (strcmp (name, "InvalidCastException") == 0)
5595                 return MONO_EXC_INVALID_CAST;
5596         if (strcmp (name, "NullReferenceException") == 0)
5597                 return MONO_EXC_NULL_REF;
5598         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5599                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5600         if (strcmp (name, "ArgumentException") == 0)
5601                 return MONO_EXC_ARGUMENT;
5602         g_error ("Unknown intrinsic exception %s\n", name);
5603         return 0;
5604 }
5605 #endif
5606
5607 void
5608 mono_arch_emit_exceptions (MonoCompile *cfg)
5609 {
5610 #if 0
5611         MonoJumpInfo *patch_info;
5612         int i;
5613         guint8 *code;
5614         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5615         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5616         int max_epilog_size = 50;
5617
5618         /* count the number of exception infos */
5619      
5620         /* 
5621          * make sure we have enough space for exceptions
5622          * 24 is the simulated call to throw_exception_by_name
5623          */
5624         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5625 #if 0
5626                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5627                         i = exception_id_by_name (patch_info->data.target);
5628                         g_assert (i < MONO_EXC_INTRINS_NUM);
5629                         if (!exc_throw_found [i]) {
5630                                 max_epilog_size += 12;
5631                                 exc_throw_found [i] = TRUE;
5632                         }
5633                 }
5634 #endif
5635         }
5636
5637         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5638                 cfg->code_size *= 2;
5639                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5640                 cfg->stat_code_reallocs++;
5641         }
5642
5643         code = cfg->native_code + cfg->code_len;
5644
5645         /* add code to raise exceptions */
5646         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5647                 switch (patch_info->type) {
5648                 case MONO_PATCH_INFO_EXC: {
5649 #if 0
5650                         //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5651
5652                         i = exception_id_by_name (patch_info->data.target);
5653                         g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5654                         if (!exc_throw_pos [i]) {
5655                                 guint32 addr;
5656
5657                                 exc_throw_pos [i] = code;
5658                                 //g_print ("exc: writing stub at %p\n", code);
5659                                 mips_load_const (code, mips_a0, patch_info->data.target);
5660                                 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5661                                 mips_load_const (code, mips_t9, addr);
5662                                 mips_jr (code, mips_t9);
5663                                 mips_nop (code);
5664                         }
5665                         //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5666
5667                         /* Turn into a Relative patch, pointing at code stub */
5668                         patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5669                         patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5670 #else
5671                         g_assert_not_reached();
5672 #endif
5673                         break;
5674                 }
5675                 default:
5676                         /* do nothing */
5677                         break;
5678                 }
5679         }
5680
5681         cfg->code_len = code - cfg->native_code;
5682
5683         g_assert (cfg->code_len < cfg->code_size);
5684 #endif
5685 }
5686
5687 /*
5688  * Thread local storage support
5689  */
5690 static void
5691 setup_tls_access (void)
5692 {
5693         guint32 ptk;
5694         //guint32 *ins, *code;
5695
5696         if (tls_mode == TLS_MODE_FAILED)
5697                 return;
5698
5699         if (g_getenv ("MONO_NO_TLS")) {
5700                 tls_mode = TLS_MODE_FAILED;
5701                 return;
5702         }
5703
5704         if (tls_mode == TLS_MODE_DETECT) {
5705                 /* XXX */
5706                 tls_mode = TLS_MODE_FAILED;
5707                 return;
5708 #if 0
5709
5710                 ins = (guint32*)pthread_getspecific;
5711                 /* uncond branch to the real method */
5712                 if ((*ins >> 26) == 18) {
5713                         gint32 val;
5714                         val = (*ins & ~3) << 6;
5715                         val >>= 6;
5716                         if (*ins & 2) {
5717                                 /* absolute */
5718                                 ins = (guint32*)val;
5719                         } else {
5720                                 ins = (guint32*) ((char*)ins + val);
5721                         }
5722                 }
5723                 code = &cmplwi_1023;
5724                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5725                 code = &li_0x48;
5726                 ppc_li (code, ppc_r4, 0x48);
5727                 code = &blr_ins;
5728                 ppc_blr (code);
5729                 if (*ins == cmplwi_1023) {
5730                         int found_lwz_284 = 0;
5731                         for (ptk = 0; ptk < 20; ++ptk) {
5732                                 ++ins;
5733                                 if (!*ins || *ins == blr_ins)
5734                                         break;
5735                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5736                                         found_lwz_284 = 1;
5737                                         break;
5738                                 }
5739                         }
5740                         if (!found_lwz_284) {
5741                                 tls_mode = TLS_MODE_FAILED;
5742                                 return;
5743                         }
5744                         tls_mode = TLS_MODE_LTHREADS;
5745                 } else if (*ins == li_0x48) {
5746                         ++ins;
5747                         /* uncond branch to the real method */
5748                         if ((*ins >> 26) == 18) {
5749                                 gint32 val;
5750                                 val = (*ins & ~3) << 6;
5751                                 val >>= 6;
5752                                 if (*ins & 2) {
5753                                         /* absolute */
5754                                         ins = (guint32*)val;
5755                                 } else {
5756                                         ins = (guint32*) ((char*)ins + val);
5757                                 }
5758                                 code = &val;
5759                                 ppc_li (code, ppc_r0, 0x7FF2);
5760                                 if (ins [1] == val) {
5761                                         /* Darwin on G4, implement */
5762                                         tls_mode = TLS_MODE_FAILED;
5763                                         return;
5764                                 } else {
5765                                         code = &val;
5766                                         ppc_mfspr (code, ppc_r3, 104);
5767                                         if (ins [1] != val) {
5768                                                 tls_mode = TLS_MODE_FAILED;
5769                                                 return;
5770                                         }
5771                                         tls_mode = TLS_MODE_DARWIN_G5;
5772                                 }
5773                         } else {
5774                                 tls_mode = TLS_MODE_FAILED;
5775                                 return;
5776                         }
5777                 } else {
5778                         tls_mode = TLS_MODE_FAILED;
5779                         return;
5780                 }
5781 #endif
5782         }
5783         if (lmf_pthread_key == -1) {
5784                 ptk = mono_jit_tls_id;
5785                 if (ptk < 1024) {
5786                         /*g_print ("MonoLMF at: %d\n", ptk);*/
5787                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5788                                 init_tls_failed = 1;
5789                                 return;
5790                         }*/
5791                         lmf_pthread_key = ptk;
5792                 }
5793         }
5794         if (monothread_key == -1) {
5795                 ptk = mono_thread_get_tls_key ();
5796                 if (ptk < 1024) {
5797                         monothread_key = ptk;
5798                         /*g_print ("thread inited: %d\n", ptk);*/
5799                 } else {
5800                         /*g_print ("thread not inited yet %d\n", ptk);*/
5801                 }
5802         }
5803 }
5804
5805 void
5806 mono_arch_finish_init (void)
5807 {
5808         setup_tls_access ();
5809 }
5810
5811 void
5812 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5813 {
5814 }
5815
5816 void
5817 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5818 {
5819         int this_dreg = mips_a0;
5820         
5821         if (vt_reg != -1)
5822                 this_dreg = mips_a1;
5823
5824         /* add the this argument */
5825         if (this_reg != -1) {
5826                 MonoInst *this_ins;
5827                 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5828                 this_ins->type = this_type;
5829                 this_ins->sreg1 = this_reg;
5830                 this_ins->dreg = mono_alloc_ireg (cfg);
5831                 mono_bblock_add_inst (cfg->cbb, this_ins);
5832                 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5833         }
5834
5835         if (vt_reg != -1) {
5836                 MonoInst *vtarg;
5837                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5838                 vtarg->type = STACK_MP;
5839                 vtarg->sreg1 = vt_reg;
5840                 vtarg->dreg = mono_alloc_ireg (cfg);
5841                 mono_bblock_add_inst (cfg->cbb, vtarg);
5842                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5843         }
5844 }
5845
5846 MonoInst*
5847 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5848 {
5849         MonoInst *ins = NULL;
5850
5851         return ins;
5852 }
5853
5854 MonoInst*
5855 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5856 {
5857         return NULL;
5858 }
5859
5860 gboolean
5861 mono_arch_print_tree (MonoInst *tree, int arity)
5862 {
5863         return 0;
5864 }
5865
5866 mgreg_t
5867 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5868 {
5869         return ctx->sc_regs [reg];
5870 }
5871
5872 #define ENABLE_WRONG_METHOD_CHECK 0
5873
5874 #define MIPS_LOAD_SEQUENCE_LENGTH       8
5875 #define CMP_SIZE                        (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5876 #define BR_SIZE                         8
5877 #define LOADSTORE_SIZE                  4
5878 #define JUMP_IMM_SIZE                   16
5879 #define JUMP_IMM32_SIZE                 (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5880 #define LOAD_CONST_SIZE                 8
5881 #define JUMP_JR_SIZE                    8
5882
5883 /*
5884  * LOCKING: called with the domain lock held
5885  */
5886 gpointer
5887 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5888         gpointer fail_tramp)
5889 {
5890         int i;
5891         int size = 0;
5892         guint8 *code, *start, *patch;
5893
5894         for (i = 0; i < count; ++i) {
5895                 MonoIMTCheckItem *item = imt_entries [i];
5896
5897                 if (item->is_equals) {
5898                         if (item->check_target_idx) {
5899                                 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5900                                 if (item->has_target_code)
5901                                         item->chunk_size += LOAD_CONST_SIZE;
5902                                 else
5903                                         item->chunk_size += LOADSTORE_SIZE;
5904                         } else {
5905                                 if (fail_tramp) {
5906                                         item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5907                                                 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5908                                         if (!item->has_target_code)
5909                                                 item->chunk_size += LOADSTORE_SIZE;
5910                                 } else {
5911                                         item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5912 #if ENABLE_WRONG_METHOD_CHECK
5913                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5914 #endif
5915                                 }
5916                         }
5917                 } else {
5918                         item->chunk_size += CMP_SIZE + BR_SIZE;
5919                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5920                 }
5921                 size += item->chunk_size;
5922         }
5923         /* the initial load of the vtable address */
5924         size += MIPS_LOAD_SEQUENCE_LENGTH;
5925         if (fail_tramp) {
5926                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5927         } else {
5928                 code = mono_domain_code_reserve (domain, size);
5929         }
5930         start = code;
5931
5932         /* t7 points to the vtable */
5933         mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5934
5935         for (i = 0; i < count; ++i) {
5936                 MonoIMTCheckItem *item = imt_entries [i];
5937
5938                 item->code_target = code;
5939                 if (item->is_equals) {
5940                         if (item->check_target_idx) {
5941                                 mips_load_const (code, mips_temp, (gsize)item->key);
5942                                 item->jmp_code = code;
5943                                 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5944                                 mips_nop (code);
5945                                 if (item->has_target_code) {
5946                                         mips_load_const (code, mips_t9,
5947                                                          item->value.target_code);
5948                                 }
5949                                 else {
5950                                         mips_lw (code, mips_t9, mips_t7,
5951                                                 (sizeof (gpointer) * item->value.vtable_slot));
5952                                 }
5953                                 mips_jr (code, mips_t9);
5954                                 mips_nop (code);
5955                         } else {
5956                                 if (fail_tramp) {
5957                                         mips_load_const (code, mips_temp, (gsize)item->key);
5958                                         patch = code;
5959                                         mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5960                                         mips_nop (code);
5961                                         if (item->has_target_code) {
5962                                                 mips_load_const (code, mips_t9,
5963                                                                  item->value.target_code);
5964                                         } else {
5965                                                 g_assert (vtable);
5966                                                 mips_load_const (code, mips_at,
5967                                                                  & (vtable->vtable [item->value.vtable_slot]));
5968                                                 mips_lw (code, mips_t9, mips_at, 0);
5969                                         }
5970                                         mips_jr (code, mips_t9);
5971                                         mips_nop (code);
5972                                         mips_patch ((guint32 *)(void *)patch, (guint32)code);
5973                                         mips_load_const (code, mips_t9, fail_tramp);
5974                                         mips_jr (code, mips_t9);
5975                                         mips_nop (code);
5976                                 } else {
5977                                         /* enable the commented code to assert on wrong method */
5978 #if ENABLE_WRONG_METHOD_CHECK
5979                                         ppc_load (code, ppc_r0, (guint32)item->key);
5980                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5981                                         patch = code;
5982                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5983 #endif
5984                                         mips_lw (code, mips_t9, mips_t7,
5985                                                  (sizeof (gpointer) * item->value.vtable_slot));
5986                                         mips_jr (code, mips_t9);
5987                                         mips_nop (code);
5988
5989 #if ENABLE_WRONG_METHOD_CHECK
5990                                         ppc_patch (patch, code);
5991                                         ppc_break (code);
5992 #endif
5993                                 }
5994                         }
5995                 } else {
5996                         mips_load_const (code, mips_temp, (gulong)item->key);
5997                         mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5998
5999                         item->jmp_code = code;
6000                         mips_beq (code, mips_temp, mips_zero, 0);
6001                         mips_nop (code);
6002                 }
6003         }
6004         /* patch the branches to get to the target items */
6005         for (i = 0; i < count; ++i) {
6006                 MonoIMTCheckItem *item = imt_entries [i];
6007                 if (item->jmp_code && item->check_target_idx) {
6008                         mips_patch ((guint32 *)item->jmp_code,
6009                                    (guint32)imt_entries [item->check_target_idx]->code_target);
6010                 }
6011         }
6012
6013         if (!fail_tramp)
6014                 mono_stats.imt_thunks_size += code - start;
6015         g_assert (code - start <= size);
6016         mono_arch_flush_icache (start, size);
6017
6018         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
6019
6020         return start;
6021 }
6022
6023 MonoMethod*
6024 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6025 {
6026         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6027 }
6028
6029 MonoVTable*
6030 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6031 {
6032         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6033 }
6034
6035 /* Soft Debug support */
6036 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6037
6038 /*
6039  * mono_arch_set_breakpoint:
6040  *
6041  *   See mini-amd64.c for docs.
6042  */
6043 void
6044 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6045 {
6046         guint8 *code = ip;
6047         guint32 addr = (guint32)bp_trigger_page;
6048
6049         mips_load_const (code, mips_t9, addr);
6050         mips_lw (code, mips_t9, mips_t9, 0);
6051
6052         mono_arch_flush_icache (ip, code - ip);
6053 }
6054
6055 /*
6056  * mono_arch_clear_breakpoint:
6057  *
6058  *   See mini-amd64.c for docs.
6059  */
6060 void
6061 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6062 {
6063         guint8 *code = ip;
6064
6065         mips_nop (code);
6066         mips_nop (code);
6067         mips_nop (code);
6068
6069         mono_arch_flush_icache (ip, code - ip);
6070 }
6071         
6072 /*
6073  * mono_arch_start_single_stepping:
6074  *
6075  *   See mini-amd64.c for docs.
6076  */
6077 void
6078 mono_arch_start_single_stepping (void)
6079 {
6080         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6081 }
6082         
6083 /*
6084  * mono_arch_stop_single_stepping:
6085  *
6086  *   See mini-amd64.c for docs.
6087  */
6088 void
6089 mono_arch_stop_single_stepping (void)
6090 {
6091         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6092 }
6093
6094 /*
6095  * mono_arch_is_single_step_event:
6096  *
6097  *   See mini-amd64.c for docs.
6098  */
6099 gboolean
6100 mono_arch_is_single_step_event (void *info, void *sigctx)
6101 {
6102         siginfo_t* sinfo = (siginfo_t*) info;
6103         /* Sometimes the address is off by 4 */
6104         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6105                 return TRUE;
6106         else
6107                 return FALSE;
6108 }
6109
6110 /*
6111  * mono_arch_is_breakpoint_event:
6112  *
6113  *   See mini-amd64.c for docs.
6114  */
6115 gboolean
6116 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6117 {
6118         siginfo_t* sinfo = (siginfo_t*) info;
6119         /* Sometimes the address is off by 4 */
6120         if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6121                 return TRUE;
6122         else
6123                 return FALSE;
6124 }
6125
6126 /*
6127  * mono_arch_skip_breakpoint:
6128  *
6129  *   See mini-amd64.c for docs.
6130  */
6131 void
6132 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6133 {
6134         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6135 }
6136
6137 /*
6138  * mono_arch_skip_single_step:
6139  *
6140  *   See mini-amd64.c for docs.
6141  */
6142 void
6143 mono_arch_skip_single_step (MonoContext *ctx)
6144 {
6145         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6146 }
6147
6148 /*
6149  * mono_arch_get_seq_point_info:
6150  *
6151  *   See mini-amd64.c for docs.
6152  */
6153 gpointer
6154 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6155 {
6156         NOT_IMPLEMENTED;
6157         return NULL;
6158 }
6159
6160 void
6161 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6162 {
6163         ext->lmf.previous_lmf = prev_lmf;
6164         /* Mark that this is a MonoLMFExt */
6165         ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6166         ext->lmf.iregs [mips_sp] = (gssize)ext;
6167 }
6168
6169 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
6170
6171 gboolean
6172 mono_arch_opcode_supported (int opcode)
6173 {
6174         return FALSE;
6175 }