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