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