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