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