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