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