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