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