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