Simplify the arm prolog/epilog generation by not saving the sp to the stack, its...
[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 *divisor_is_zero;
3426
3427                         /* */
3428                         mips_addiu (code, mips_at, mips_zero, 0xffff);
3429                         divisor_is_m1 = (guint32 *)(void *)code;
3430                         mips_bne (code, ins->sreg2, mips_at, 0);
3431                         mips_nop (code);
3432
3433                         /* Divide by -1 -- throw exception */
3434                         EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
3435
3436                         mips_patch (divisor_is_m1, (guint32)code);
3437
3438                         /* Put divide in branch delay slot (NOT YET) */
3439                         divisor_is_zero = (guint32 *)(void *)code;
3440                         mips_bne (code, ins->sreg2, mips_zero, 0);
3441                         mips_nop (code);
3442
3443                         /* Divide by zero -- throw exception */
3444                         EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3445
3446                         mips_patch (divisor_is_zero, (guint32)code);
3447                         mips_div (code, ins->sreg1, ins->sreg2);
3448                         if (ins->opcode == OP_IDIV)
3449                                 mips_mflo (code, ins->dreg);
3450                         else
3451                                 mips_mfhi (code, ins->dreg);
3452                         break;
3453                 }
3454                 case OP_IDIV_UN: 
3455                 case OP_IREM_UN: {
3456                         guint32 *divisor_is_zero = (guint32 *)(void *)code;
3457
3458                         /* Put divide in branch delay slot (NOT YET) */
3459                         mips_bne (code, ins->sreg2, mips_zero, 0);
3460                         mips_nop (code);
3461
3462                         /* Divide by zero -- throw exception */
3463                         EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3464
3465                         mips_patch (divisor_is_zero, (guint32)code);
3466                         mips_divu (code, ins->sreg1, ins->sreg2);
3467                         if (ins->opcode == OP_IDIV_UN)
3468                                 mips_mflo (code, ins->dreg);
3469                         else
3470                                 mips_mfhi (code, ins->dreg);
3471                         break;
3472                 }
3473                 case OP_DIV_IMM:
3474                         g_assert_not_reached ();
3475 #if 0
3476                         ppc_load (code, ppc_r11, ins->inst_imm);
3477                         ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3478                         ppc_mfspr (code, ppc_r0, ppc_xer);
3479                         ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3480                         /* FIXME: use OverflowException for 0x80000000/-1 */
3481                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3482 #endif
3483                         g_assert_not_reached();
3484                         break;
3485                 case OP_REM_IMM:
3486                         g_assert_not_reached ();
3487                 case OP_IOR:
3488                         mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3489                         break;
3490                 case OP_OR_IMM:
3491                 case OP_IOR_IMM:
3492                         g_assert (!(ins->inst_imm & 0xffff0000));
3493                         mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3494                         break;
3495                 case OP_IXOR:
3496                         mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3497                         break;
3498                 case OP_XOR_IMM:
3499                 case OP_IXOR_IMM:
3500                         /* unsigned 16-bit immediate */
3501                         g_assert (!(ins->inst_imm & 0xffff0000));
3502                         mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3503                         break;
3504                 case OP_ISHL:
3505                         mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3506                         break;
3507                 case OP_SHL_IMM:
3508                 case OP_ISHL_IMM:
3509                         mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3510                         break;
3511                 case OP_ISHR:
3512                         mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3513                         break;
3514                 case OP_LSHR:
3515                         mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3516                         break;
3517                 case OP_SHR_IMM:
3518                 case OP_ISHR_IMM:
3519                         mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3520                         break;
3521                 case OP_LSHR_IMM:
3522                         mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3523                         break;
3524                 case OP_SHR_UN_IMM:
3525                 case OP_ISHR_UN_IMM:
3526                         mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3527                         break;
3528                 case OP_LSHR_UN_IMM:
3529                         mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3530                         break;
3531                 case OP_ISHR_UN:
3532                         mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3533                         break;
3534                 case OP_LSHR_UN:
3535                         mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3536                         break;
3537                 case OP_INOT:
3538                 case OP_LNOT:
3539                         mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3540                         break;
3541                 case OP_INEG:
3542                         mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3543                         break;
3544                 case OP_LNEG:
3545                         mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3546                         break;
3547                 case OP_IMUL:
3548 #if USE_MUL
3549                         mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3550 #else
3551                         mips_mult (code, ins->sreg1, ins->sreg2);
3552                         mips_mflo (code, ins->dreg);
3553                         mips_nop (code);
3554                         mips_nop (code);
3555 #endif
3556                         break;
3557 #if SIZEOF_REGISTER == 8
3558                 case OP_LMUL:
3559                         mips_dmult (code, ins->sreg1, ins->sreg2);
3560                         mips_mflo (code, ins->dreg);
3561                         break;
3562 #endif
3563                 case OP_IMUL_OVF: {
3564                         guint32 *patch;
3565                         mips_mult (code, ins->sreg1, ins->sreg2);
3566                         mips_mflo (code, ins->dreg);
3567                         mips_mfhi (code, mips_at);
3568                         mips_nop (code);
3569                         mips_nop (code);
3570                         mips_sra (code, mips_temp, ins->dreg, 31);
3571                         patch = (guint32 *)(void *)code;
3572                         mips_beq (code, mips_temp, mips_at, 0);
3573                         mips_nop (code);
3574                         EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3575                         mips_patch (patch, (guint32)code);
3576                         break;
3577                 }
3578                 case OP_IMUL_OVF_UN: {
3579                         guint32 *patch;
3580                         mips_mult (code, ins->sreg1, ins->sreg2);
3581                         mips_mflo (code, ins->dreg);
3582                         mips_mfhi (code, mips_at);
3583                         mips_nop (code);
3584                         mips_nop (code);
3585                         patch = (guint32 *)(void *)code;
3586                         mips_beq (code, mips_at, mips_zero, 0);
3587                         mips_nop (code);
3588                         EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3589                         mips_patch (patch, (guint32)code);
3590                         break;
3591                 }
3592                 case OP_ICONST:
3593                         mips_load_const (code, ins->dreg, ins->inst_c0);
3594                         break;
3595 #if SIZEOF_REGISTER == 8
3596                 case OP_I8CONST:
3597                         mips_load_const (code, ins->dreg, ins->inst_c0);
3598                         break;
3599 #endif
3600                 case OP_AOTCONST:
3601                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3602                         mips_load (code, ins->dreg, 0);
3603                         break;
3604
3605                 case OP_MIPS_MTC1S:
3606                         mips_mtc1 (code, ins->dreg, ins->sreg1);
3607                         break;
3608                 case OP_MIPS_MTC1S_2:
3609                         mips_mtc1 (code, ins->dreg, ins->sreg1);
3610                         mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3611                         break;
3612                 case OP_MIPS_MFC1S:
3613                         mips_mfc1 (code, ins->dreg, ins->sreg1);
3614                         break;
3615                 case OP_MIPS_MTC1D:
3616                         mips_dmtc1 (code, ins->dreg, ins->sreg1);
3617                         break;
3618                 case OP_MIPS_MFC1D:
3619 #if 0
3620                         mips_dmfc1 (code, ins->dreg, ins->sreg1);
3621 #else
3622                         mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3623                         mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3624 #endif
3625                         break;
3626
3627                 case OP_ICONV_TO_I4:
3628                 case OP_ICONV_TO_U4:
3629                 case OP_MOVE:
3630                         if (ins->dreg != ins->sreg1)
3631                                 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3632                         break;
3633 #if SIZEOF_REGISTER == 8
3634                 case OP_ZEXT_I4:
3635                         mips_dsll (code, ins->dreg, ins->sreg1, 32);
3636                         mips_dsrl (code, ins->dreg, ins->dreg, 32);
3637                         break;
3638                 case OP_SEXT_I4:
3639                         mips_dsll (code, ins->dreg, ins->sreg1, 32);
3640                         mips_dsra (code, ins->dreg, ins->dreg, 32);
3641                         break;
3642 #endif
3643                 case OP_SETLRET:
3644                         /* Get sreg1 into v1, sreg2 into v0 */
3645
3646                         if (ins->sreg1 == mips_v0) {
3647                                 if (ins->sreg1 != mips_at)
3648                                         MIPS_MOVE (code, mips_at, ins->sreg1);
3649                                 if (ins->sreg2 != mips_v0)
3650                                         MIPS_MOVE (code, mips_v0, ins->sreg2);
3651                                 MIPS_MOVE (code, mips_v1, mips_at);
3652                         }
3653                         else {
3654                                 if (ins->sreg2 != mips_v0)
3655                                         MIPS_MOVE (code, mips_v0, ins->sreg2);
3656                                 if (ins->sreg1 != mips_v1)
3657                                         MIPS_MOVE (code, mips_v1, ins->sreg1);
3658                         }
3659                         break;
3660                 case OP_FMOVE:
3661                         if (ins->dreg != ins->sreg1) {
3662                                 mips_fmovd (code, ins->dreg, ins->sreg1);
3663                         }
3664                         break;
3665                 case OP_MIPS_CVTSD:
3666                         /* Convert from double to float and leave it there */
3667                         mips_cvtsd (code, ins->dreg, ins->sreg1);
3668                         break;
3669                 case OP_FCONV_TO_R4:
3670 #if 0
3671                         mips_cvtsd (code, ins->dreg, ins->sreg1);
3672 #else
3673                         /* Just a move, no precision change */
3674                         if (ins->dreg != ins->sreg1) {
3675                                 mips_fmovd (code, ins->dreg, ins->sreg1);
3676                         }
3677 #endif
3678                         break;
3679                 case OP_JMP:
3680                         code = emit_load_volatile_arguments(cfg, code);
3681
3682                         /*
3683                          * Pop our stack, then jump to specified method (tail-call)
3684                          * Keep in sync with mono_arch_emit_epilog
3685                          */
3686                         code = mono_arch_emit_epilog_sub (cfg, code);
3687
3688                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3689                                              MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3690                         if (cfg->arch.long_branch) {
3691                                 mips_lui (code, mips_t9, mips_zero, 0);
3692                                 mips_addiu (code, mips_t9, mips_t9, 0);
3693                                 mips_jr (code, mips_t9);
3694                                 mips_nop (code);
3695                         }
3696                         else {
3697                                 mips_beq (code, mips_zero, mips_zero, 0);
3698                                 mips_nop (code);
3699                         }
3700                         break;
3701                 case OP_CHECK_THIS:
3702                         /* ensure ins->sreg1 is not NULL */
3703                         mips_lw (code, mips_zero, ins->sreg1, 0);
3704                         break;
3705                 case OP_ARGLIST: {
3706                         if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3707                                 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3708                         } else {
3709                                 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3710                                 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3711                         }
3712                         mips_sw (code, mips_at, ins->sreg1, 0);
3713                         break;
3714                 }
3715                 case OP_FCALL:
3716                 case OP_LCALL:
3717                 case OP_VCALL:
3718                 case OP_VCALL2:
3719                 case OP_VOIDCALL:
3720                 case OP_CALL:
3721                 case OP_FCALL_REG:
3722                 case OP_LCALL_REG:
3723                 case OP_VCALL_REG:
3724                 case OP_VCALL2_REG:
3725                 case OP_VOIDCALL_REG:
3726                 case OP_CALL_REG:
3727                 case OP_FCALL_MEMBASE:
3728                 case OP_LCALL_MEMBASE:
3729                 case OP_VCALL_MEMBASE:
3730                 case OP_VCALL2_MEMBASE:
3731                 case OP_VOIDCALL_MEMBASE:
3732                 case OP_CALL_MEMBASE:
3733                         call = (MonoCallInst*)ins;
3734                         switch (ins->opcode) {
3735                         case OP_FCALL:
3736                         case OP_LCALL:
3737                         case OP_VCALL:
3738                         case OP_VCALL2:
3739                         case OP_VOIDCALL:
3740                         case OP_CALL:
3741                                 if (ins->flags & MONO_INST_HAS_METHOD) {
3742                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3743                                         mips_call (code, mips_t9, call->method);
3744                                 }
3745                                 else {
3746                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3747                                         mips_call (code, mips_t9, call->fptr);
3748                                 }
3749                                 break;
3750                         case OP_FCALL_REG:
3751                         case OP_LCALL_REG:
3752                         case OP_VCALL_REG:
3753                         case OP_VCALL2_REG:
3754                         case OP_VOIDCALL_REG:
3755                         case OP_CALL_REG:
3756                                 MIPS_MOVE (code, mips_t9, ins->sreg1);
3757                                 mips_jalr (code, mips_t9, mips_ra);
3758                                 mips_nop (code);
3759                                 break;
3760                         case OP_FCALL_MEMBASE:
3761                         case OP_LCALL_MEMBASE:
3762                         case OP_VCALL_MEMBASE:
3763                         case OP_VCALL2_MEMBASE:
3764                         case OP_VOIDCALL_MEMBASE:
3765                         case OP_CALL_MEMBASE:
3766                                 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3767                                 mips_jalr (code, mips_t9, mips_ra);
3768                                 mips_nop (code);
3769                                 break;
3770                         }
3771 #if PROMOTE_R4_TO_R8
3772                         /* returned an FP R4 (single), promote to R8 (double) in place */
3773                         if ((ins->opcode == OP_FCALL ||
3774                              ins->opcode == OP_FCALL_REG) &&
3775                             call->signature->ret->type == MONO_TYPE_R4) {
3776                                 mips_cvtds (code, mips_f0, mips_f0);
3777                         }
3778 #endif
3779                         break;
3780                 case OP_LOCALLOC: {
3781                         int area_offset = cfg->param_area;
3782
3783                         /* Round up ins->sreg1, mips_at ends up holding size */
3784                         mips_addiu (code, mips_at, ins->sreg1, 31);
3785                         mips_addiu (code, mips_temp, mips_zero, ~31);
3786                         mips_and (code, mips_at, mips_at, mips_temp);
3787
3788                         mips_subu (code, mips_sp, mips_sp, mips_at);
3789                         g_assert (mips_is_imm16 (area_offset));
3790                         mips_addiu (code, ins->dreg, mips_sp, area_offset);
3791
3792                         if (ins->flags & MONO_INST_INIT) {
3793                                 mips_move (code, mips_temp, ins->dreg);
3794                                 mips_sb (code, mips_zero, mips_temp, 0);
3795                                 mips_addiu (code, mips_at, mips_at, -1);
3796                                 mips_bne (code, mips_at, mips_zero, -3);
3797                                 mips_addiu (code, mips_temp, mips_temp, 1);
3798                         }
3799                         break;
3800                 }
3801                 case OP_THROW: {
3802                         gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3803                         mips_move (code, mips_a0, ins->sreg1);
3804                         mips_call (code, mips_t9, addr);
3805                         mips_break (code, 0xfc);
3806                         break;
3807                 }
3808                 case OP_RETHROW: {
3809                         gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3810                         mips_move (code, mips_a0, ins->sreg1);
3811                         mips_call (code, mips_t9, addr);
3812                         mips_break (code, 0xfb);
3813                         break;
3814                 }
3815                 case OP_START_HANDLER: {
3816                         /*
3817                          * The START_HANDLER instruction marks the beginning of
3818                          * a handler block. It is called using a call
3819                          * instruction, so mips_ra contains the return address.
3820                          * Since the handler executes in the same stack frame
3821                          * as the method itself, we can't use save/restore to
3822                          * save the return address. Instead, we save it into
3823                          * a dedicated variable.
3824                          */
3825                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3826                         g_assert (spvar->inst_basereg != mips_sp);
3827                         code = emit_reserve_param_area (cfg, code);
3828
3829                         if (mips_is_imm16 (spvar->inst_offset)) {
3830                                 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3831                         } else {
3832                                 mips_load_const (code, mips_at, spvar->inst_offset);
3833                                 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3834                                 mips_sw (code, mips_ra, mips_at, 0);
3835                         }
3836                         break;
3837                 }
3838                 case OP_ENDFILTER: {
3839                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3840                         g_assert (spvar->inst_basereg != mips_sp);
3841                         code = emit_unreserve_param_area (cfg, code);
3842
3843                         if (ins->sreg1 != mips_v0)
3844                                 MIPS_MOVE (code, mips_v0, ins->sreg1);
3845                         if (mips_is_imm16 (spvar->inst_offset)) {
3846                                 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3847                         } else {
3848                                 mips_load_const (code, mips_at, spvar->inst_offset);
3849                                 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3850                                 mips_lw (code, mips_ra, mips_at, 0);
3851                         }
3852                         mips_jr (code, mips_ra);
3853                         mips_nop (code);
3854                         break;
3855                 }
3856                 case OP_ENDFINALLY: {
3857                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3858                         g_assert (spvar->inst_basereg != mips_sp);
3859                         code = emit_unreserve_param_area (cfg, code);
3860                         mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3861                         mips_jalr (code, mips_t9, mips_ra);
3862                         mips_nop (code);
3863                         break;
3864                 }
3865                 case OP_CALL_HANDLER: 
3866                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3867                         mips_lui (code, mips_t9, mips_zero, 0);
3868                         mips_addiu (code, mips_t9, mips_t9, 0);
3869                         mips_jalr (code, mips_t9, mips_ra);
3870                         mips_nop (code);
3871                         /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3872                         mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3873                         break;
3874                 case OP_LABEL:
3875                         ins->inst_c0 = code - cfg->native_code;
3876                         break;
3877                 case OP_BR:
3878                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3879                         if (cfg->arch.long_branch) {
3880                                 mips_lui (code, mips_at, mips_zero, 0);
3881                                 mips_addiu (code, mips_at, mips_at, 0);
3882                                 mips_jr (code, mips_at);
3883                                 mips_nop (code);
3884                         }
3885                         else {
3886                                 mips_beq (code, mips_zero, mips_zero, 0);
3887                                 mips_nop (code);
3888                         }
3889                         break;
3890                 case OP_BR_REG:
3891                         mips_jr (code, ins->sreg1);
3892                         mips_nop (code);
3893                         break;
3894                 case OP_SWITCH: {
3895                         int i;
3896
3897                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
3898                         if (offset > (cfg->code_size - max_len - 16)) {
3899                                 cfg->code_size += max_len;
3900                                 cfg->code_size *= 2;
3901                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3902                                 code = cfg->native_code + offset;
3903                         }
3904                         g_assert (ins->sreg1 != -1);
3905                         mips_sll (code, mips_at, ins->sreg1, 2);
3906                         if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3907                                 MIPS_MOVE (code, mips_t8, mips_ra);
3908                         mips_bgezal (code, mips_zero, 1);       /* bal */
3909                         mips_nop (code);
3910                         mips_addu (code, mips_t9, mips_ra, mips_at);
3911                         /* Table is 16 or 20 bytes from target of bal above */
3912                         if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3913                                 MIPS_MOVE (code, mips_ra, mips_t8);
3914                                 mips_lw (code, mips_t9, mips_t9, 20);
3915                         }
3916                         else
3917                                 mips_lw (code, mips_t9, mips_t9, 16);
3918                         mips_jalr (code, mips_t9, mips_t8);
3919                         mips_nop (code);
3920                         for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3921                                 mips_emit32 (code, 0xfefefefe);
3922                         break;
3923                 }
3924                 case OP_CEQ:
3925                 case OP_ICEQ:
3926                         mips_addiu (code, ins->dreg, mips_zero, 1);
3927                         mips_beq (code, mips_at, mips_zero, 2);
3928                         mips_nop (code);
3929                         MIPS_MOVE (code, ins->dreg, mips_zero);
3930                         break;
3931                 case OP_CLT:
3932                 case OP_CLT_UN:
3933                 case OP_ICLT:
3934                 case OP_ICLT_UN:
3935                         mips_addiu (code, ins->dreg, mips_zero, 1);
3936                         mips_bltz (code, mips_at, 2);
3937                         mips_nop (code);
3938                         MIPS_MOVE (code, ins->dreg, mips_zero);
3939                         break;
3940                 case OP_CGT:
3941                 case OP_CGT_UN:
3942                 case OP_ICGT:
3943                 case OP_ICGT_UN:
3944                         mips_addiu (code, ins->dreg, mips_zero, 1);
3945                         mips_bgtz (code, mips_at, 2);
3946                         mips_nop (code);
3947                         MIPS_MOVE (code, ins->dreg, mips_zero);
3948                         break;
3949
3950                 case OP_MIPS_COND_EXC_EQ:
3951                 case OP_MIPS_COND_EXC_GE:
3952                 case OP_MIPS_COND_EXC_GT:
3953                 case OP_MIPS_COND_EXC_LE:
3954                 case OP_MIPS_COND_EXC_LT:
3955                 case OP_MIPS_COND_EXC_NE_UN:
3956                 case OP_MIPS_COND_EXC_GE_UN:
3957                 case OP_MIPS_COND_EXC_GT_UN:
3958                 case OP_MIPS_COND_EXC_LE_UN:
3959                 case OP_MIPS_COND_EXC_LT_UN:
3960
3961                 case OP_MIPS_COND_EXC_OV:
3962                 case OP_MIPS_COND_EXC_NO:
3963                 case OP_MIPS_COND_EXC_C:
3964                 case OP_MIPS_COND_EXC_NC:
3965
3966                 case OP_MIPS_COND_EXC_IEQ:
3967                 case OP_MIPS_COND_EXC_IGE:
3968                 case OP_MIPS_COND_EXC_IGT:
3969                 case OP_MIPS_COND_EXC_ILE:
3970                 case OP_MIPS_COND_EXC_ILT:
3971                 case OP_MIPS_COND_EXC_INE_UN:
3972                 case OP_MIPS_COND_EXC_IGE_UN:
3973                 case OP_MIPS_COND_EXC_IGT_UN:
3974                 case OP_MIPS_COND_EXC_ILE_UN:
3975                 case OP_MIPS_COND_EXC_ILT_UN:
3976
3977                 case OP_MIPS_COND_EXC_IOV:
3978                 case OP_MIPS_COND_EXC_INO:
3979                 case OP_MIPS_COND_EXC_IC:
3980                 case OP_MIPS_COND_EXC_INC: {
3981                         guint32 *skip;
3982                         guint32 *throw;
3983
3984                         /* If the condition is true, raise the exception */
3985
3986                         /* need to reverse test to skip around exception raising */
3987
3988                         /* For the moment, branch around a branch to avoid reversing
3989                            the tests. */
3990
3991                         /* Remember, an unpatched branch to 0 branches to the delay slot */
3992                         switch (ins->opcode) {
3993                         case OP_MIPS_COND_EXC_EQ:
3994                                 throw = (guint32 *)(void *)code;
3995                                 mips_beq (code, ins->sreg1, ins->sreg2, 0);
3996                                 mips_nop (code);
3997                                 break;
3998
3999                         case OP_MIPS_COND_EXC_NE_UN:
4000                                 throw = (guint32 *)(void *)code;
4001                                 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4002                                 mips_nop (code);
4003                                 break;
4004
4005                         case OP_MIPS_COND_EXC_LE_UN:
4006                                 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
4007                                 throw = (guint32 *)(void *)code;
4008                                 mips_blez (code, mips_at, 0);
4009                                 mips_nop (code);
4010                                 break;
4011
4012                         case OP_MIPS_COND_EXC_GT:
4013                                 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4014                                 throw = (guint32 *)(void *)code;
4015                                 mips_bne (code, mips_at, mips_zero, 0);
4016                                 mips_nop (code);
4017                                 break;
4018
4019                         case OP_MIPS_COND_EXC_GT_UN:
4020                                 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4021                                 throw = (guint32 *)(void *)code;
4022                                 mips_bne (code, mips_at, mips_zero, 0);
4023                                 mips_nop (code);
4024                                 break;
4025
4026                         case OP_MIPS_COND_EXC_LT:
4027                                 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4028                                 throw = (guint32 *)(void *)code;
4029                                 mips_bne (code, mips_at, mips_zero, 0);
4030                                 mips_nop (code);
4031                                 break;
4032
4033                         case OP_MIPS_COND_EXC_LT_UN:
4034                                 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4035                                 throw = (guint32 *)(void *)code;
4036                                 mips_bne (code, mips_at, mips_zero, 0);
4037                                 mips_nop (code);
4038                                 break;
4039
4040                         default:
4041                                 /* Not yet implemented */
4042                                 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4043                                 g_assert_not_reached ();
4044                         }
4045                         skip = (guint32 *)(void *)code;
4046                         mips_beq (code, mips_zero, mips_zero, 0);
4047                         mips_nop (code);
4048                         mips_patch (throw, (guint32)code);
4049                         code = mips_emit_exc_by_name (code, ins->inst_p1);
4050                         mips_patch (skip, (guint32)code);
4051                         cfg->bb_exit->max_offset += 24;
4052                         break;
4053                 }
4054                 case OP_MIPS_BEQ:
4055                 case OP_MIPS_BNE:
4056                 case OP_MIPS_BGEZ:
4057                 case OP_MIPS_BGTZ:
4058                 case OP_MIPS_BLEZ:
4059                 case OP_MIPS_BLTZ:
4060                         code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4061                         break;
4062
4063                 /* floating point opcodes */
4064                 case OP_R8CONST:
4065 #if 0
4066                         if (((guint32)ins->inst_p0) & (1 << 15))
4067                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4068                         else
4069                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4070                         mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4071 #else
4072                         mips_load_const (code, mips_at, ins->inst_p0);
4073                         mips_lwc1 (code, ins->dreg, mips_at, 4);
4074                         mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4075 #endif
4076                         break;
4077                 case OP_R4CONST:
4078                         if (((guint32)ins->inst_p0) & (1 << 15))
4079                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4080                         else
4081                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4082                         mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4083 #if PROMOTE_R4_TO_R8
4084                         mips_cvtds (code, ins->dreg, ins->dreg);
4085 #endif
4086                         break;
4087                 case OP_STORER8_MEMBASE_REG:
4088                         if (mips_is_imm16 (ins->inst_offset)) {
4089 #if _MIPS_SIM == _ABIO32
4090                                 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
4091                                 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
4092 #elif _MIPS_SIM == _ABIN32
4093                                 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4094 #endif
4095                         } else {
4096                                 mips_load_const (code, mips_at, ins->inst_offset);
4097                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4098                                 mips_swc1 (code, ins->sreg1, mips_at, 4);
4099                                 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
4100                         }
4101                         break;
4102                 case OP_LOADR8_MEMBASE:
4103                         if (mips_is_imm16 (ins->inst_offset)) {
4104 #if _MIPS_SIM == _ABIO32
4105                                 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
4106                                 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
4107 #elif _MIPS_SIM == _ABIN32
4108                                 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4109 #endif
4110                         } else {
4111                                 mips_load_const (code, mips_at, ins->inst_offset);
4112                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4113                                 mips_lwc1 (code, ins->dreg, mips_at, 4);
4114                                 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4115                         }
4116                         break;
4117                 case OP_STORER4_MEMBASE_REG:
4118                         g_assert (mips_is_imm16 (ins->inst_offset));
4119 #if PROMOTE_R4_TO_R8
4120                         /* Need to convert ins->sreg1 to single-precision first */
4121                         mips_cvtsd (code, mips_ftemp, ins->sreg1);
4122                         mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4123 #else
4124                         mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4125 #endif
4126                         break;
4127                 case OP_MIPS_LWC1:
4128                         g_assert (mips_is_imm16 (ins->inst_offset));
4129                         mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4130                         break;
4131                 case OP_LOADR4_MEMBASE:
4132                         g_assert (mips_is_imm16 (ins->inst_offset));
4133                         mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4134 #if PROMOTE_R4_TO_R8
4135                         /* Convert to double precision in place */
4136                         mips_cvtds (code, ins->dreg, ins->dreg);
4137 #endif
4138                         break;
4139                 case OP_LOADR4_MEMINDEX:
4140                         mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4141                         mips_lwc1 (code, ins->dreg, mips_at, 0);
4142                         break;
4143                 case OP_LOADR8_MEMINDEX:
4144                         mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4145 #if _MIPS_SIM == _ABIO32
4146                         mips_lwc1 (code, ins->dreg, mips_at, 0);
4147                         mips_lwc1 (code, ins->dreg+1, mips_at, 4);
4148 #elif _MIPS_SIM == _ABIN32
4149                         mips_ldc1 (code, ins->dreg, mips_at, 0);
4150 #endif
4151                         break;
4152                 case OP_STORER4_MEMINDEX:
4153                         mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4154 #if PROMOTE_R4_TO_R8
4155                         /* Need to convert ins->sreg1 to single-precision first */
4156                         mips_cvtsd (code, mips_ftemp, ins->sreg1);
4157                         mips_swc1 (code, mips_ftemp, mips_at, 0);
4158 #else
4159                         mips_swc1 (code, ins->sreg1, mips_at, 0);
4160 #endif
4161                         break;
4162                 case OP_STORER8_MEMINDEX:
4163                         mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4164 #if _MIPS_SIM == _ABIO32
4165                         mips_swc1 (code, ins->sreg1, mips_at, 0);
4166                         mips_swc1 (code, ins->sreg1+1, mips_at, 4);
4167 #elif _MIPS_SIM == _ABIN32
4168                         mips_sdc1 (code, ins->sreg1, mips_at, 0);
4169 #endif
4170                         break;
4171                 case OP_ICONV_TO_R_UN: {
4172                         static const guint64 adjust_val = 0x41F0000000000000ULL;
4173
4174                         /* convert unsigned int to double */
4175                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4176                         mips_bgez (code, ins->sreg1, 5);
4177                         mips_cvtdw (code, ins->dreg, mips_ftemp);
4178
4179                         mips_load (code, mips_at, (guint32) &adjust_val);
4180                         mips_ldc1  (code, mips_ftemp, mips_at, 0);
4181                         mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4182                         /* target is here */
4183                         break;
4184                 }
4185                 case OP_ICONV_TO_R4:
4186                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4187                         mips_cvtsw (code, ins->dreg, mips_ftemp);
4188                         mips_cvtds (code, ins->dreg, ins->dreg);
4189                         break;
4190                 case OP_ICONV_TO_R8:
4191                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4192                         mips_cvtdw (code, ins->dreg, mips_ftemp);
4193                         break;
4194                 case OP_FCONV_TO_I1:
4195                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4196                         break;
4197                 case OP_FCONV_TO_U1:
4198                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4199                         break;
4200                 case OP_FCONV_TO_I2:
4201                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4202                         break;
4203                 case OP_FCONV_TO_U2:
4204                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4205                         break;
4206                 case OP_FCONV_TO_I4:
4207                 case OP_FCONV_TO_I:
4208                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4209                         break;
4210                 case OP_FCONV_TO_U4:
4211                 case OP_FCONV_TO_U:
4212                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4213                         break;
4214                 case OP_SQRT:
4215                         mips_fsqrtd (code, ins->dreg, ins->sreg1);
4216                         break;
4217                 case OP_FADD:
4218                         mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4219                         break;
4220                 case OP_FSUB:
4221                         mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4222                         break;          
4223                 case OP_FMUL:
4224                         mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4225                         break;          
4226                 case OP_FDIV:
4227                         mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4228                         break;          
4229                 case OP_FNEG:
4230                         mips_fnegd (code, ins->dreg, ins->sreg1);
4231                         break;          
4232                 case OP_FCEQ:
4233                         mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4234                         mips_addiu (code, ins->dreg, mips_zero, 1);
4235                         mips_fbtrue (code, 2);
4236                         mips_nop (code);
4237                         MIPS_MOVE (code, ins->dreg, mips_zero);
4238                         break;
4239                 case OP_FCLT:
4240                         mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4241                         mips_addiu (code, ins->dreg, mips_zero, 1);
4242                         mips_fbtrue (code, 2);
4243                         mips_nop (code);
4244                         MIPS_MOVE (code, ins->dreg, mips_zero);
4245                         break;
4246                 case OP_FCLT_UN:
4247                         /* Less than, or Unordered */
4248                         mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4249                         mips_addiu (code, ins->dreg, mips_zero, 1);
4250                         mips_fbtrue (code, 2);
4251                         mips_nop (code);
4252                         MIPS_MOVE (code, ins->dreg, mips_zero);
4253                         break;
4254                 case OP_FCGT:
4255                         mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4256                         MIPS_MOVE (code, ins->dreg, mips_zero);
4257                         mips_fbtrue (code, 2);
4258                         mips_nop (code);
4259                         mips_addiu (code, ins->dreg, mips_zero, 1);
4260                         break;
4261                 case OP_FCGT_UN:
4262                         /* Greater than, or Unordered */
4263                         mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4264                         MIPS_MOVE (code, ins->dreg, mips_zero);
4265                         mips_fbtrue (code, 2);
4266                         mips_nop (code);
4267                         mips_addiu (code, ins->dreg, mips_zero, 1);
4268                         break;
4269                 case OP_MIPS_FBEQ:
4270                         mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4271                         mips_nop (code);
4272                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4273                         mips_fbtrue (code, 0);
4274                         mips_nop (code);
4275                         break;
4276                 case OP_MIPS_FBNE:
4277                         mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4278                         mips_nop (code);
4279                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4280                         mips_fbfalse (code, 0);
4281                         mips_nop (code);
4282                         break;
4283                 case OP_MIPS_FBLT:
4284                         mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4285                         mips_nop (code);
4286                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4287                         mips_fbtrue (code, 0);
4288                         mips_nop (code);
4289                         break;
4290                 case OP_MIPS_FBLT_UN:
4291                         mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4292                         mips_nop (code);
4293                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4294                         mips_fbtrue (code, 0);
4295                         mips_nop (code);
4296                         break;
4297                 case OP_MIPS_FBGT:
4298                         mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
4299                         mips_nop (code);
4300                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4301                         mips_fbfalse (code, 0);
4302                         mips_nop (code);
4303                         break;
4304                 case OP_MIPS_FBGT_UN:
4305                         mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4306                         mips_nop (code);
4307                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4308                         mips_fbfalse (code, 0);
4309                         mips_nop (code);
4310                         break;
4311                 case OP_MIPS_FBGE:
4312                         mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4313                         mips_nop (code);
4314                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4315                         mips_fbfalse (code, 0);
4316                         mips_nop (code);
4317                         break;
4318                 case OP_MIPS_FBGE_UN:
4319                         mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
4320                         mips_nop (code);
4321                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4322                         mips_fbfalse (code, 0);
4323                         mips_nop (code);
4324                         break;
4325                 case OP_MIPS_FBLE:
4326                         mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4327                         mips_nop (code);
4328                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4329                         mips_fbtrue (code, 0);
4330                         mips_nop (code);
4331                         break;
4332                 case OP_MIPS_FBLE_UN:
4333                         mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4334                         mips_nop (code);
4335                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4336                         mips_fbtrue (code, 0);
4337                         mips_nop (code);
4338                         break;
4339                 case OP_CKFINITE: {
4340                         guint32 *branch_patch;
4341
4342                         mips_mfc1 (code, mips_at, ins->sreg1+1);
4343                         mips_srl (code, mips_at, mips_at, 16+4);
4344                         mips_andi (code, mips_at, mips_at, 2047);
4345                         mips_addiu (code, mips_at, mips_at, -2047);
4346
4347                         branch_patch = (guint32 *)(void *)code;
4348                         mips_bne (code, mips_at, mips_zero, 0);
4349                         mips_nop (code);
4350
4351                         EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4352                         mips_patch (branch_patch, (guint32)code);
4353                         mips_fmovd (code, ins->dreg, ins->sreg1);
4354                         break;
4355                 }
4356                 case OP_JUMP_TABLE:
4357                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4358                         mips_load (code, ins->dreg, 0x0f0f0f0f);
4359                         break;
4360
4361
4362                 default:
4363                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4364                         g_assert_not_reached ();
4365                 }
4366
4367                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4368                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4369                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4370                         g_assert_not_reached ();
4371                 }
4372                
4373                 cpos += max_len;
4374
4375                 last_ins = ins;
4376                 last_offset = offset;
4377         }
4378
4379         cfg->code_len = code - cfg->native_code;
4380 }
4381
4382 void
4383 mono_arch_register_lowlevel_calls (void)
4384 {
4385 }
4386
4387 void
4388 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4389 {
4390         MonoJumpInfo *patch_info;
4391
4392         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4393                 unsigned char *ip = patch_info->ip.i + code;
4394                 const unsigned char *target = NULL;
4395
4396                 switch (patch_info->type) {
4397                 case MONO_PATCH_INFO_IP:
4398                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4399                         continue;
4400                 case MONO_PATCH_INFO_SWITCH: {
4401                         gpointer *table = (gpointer *)patch_info->data.table->table;
4402                         int i;
4403
4404                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4405
4406                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
4407                                 table [i] = (int)patch_info->data.table->table [i] + code;
4408                         }
4409                         continue;
4410                 }
4411                 case MONO_PATCH_INFO_METHODCONST:
4412                 case MONO_PATCH_INFO_CLASS:
4413                 case MONO_PATCH_INFO_IMAGE:
4414                 case MONO_PATCH_INFO_FIELD:
4415                 case MONO_PATCH_INFO_VTABLE:
4416                 case MONO_PATCH_INFO_IID:
4417                 case MONO_PATCH_INFO_SFLDA:
4418                 case MONO_PATCH_INFO_LDSTR:
4419                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4420                 case MONO_PATCH_INFO_LDTOKEN:
4421                 case MONO_PATCH_INFO_R4:
4422                 case MONO_PATCH_INFO_R8:
4423                         /* from OP_AOTCONST : lui + addiu */
4424                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4425                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4426                         continue;
4427 #if 0
4428                 case MONO_PATCH_INFO_EXC_NAME:
4429                         g_assert_not_reached ();
4430                         *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4431                         continue;
4432 #endif
4433                 case MONO_PATCH_INFO_NONE:
4434                         /* everything is dealt with at epilog output time */
4435                         continue;
4436                 default:
4437                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4438                         mips_patch ((guint32 *)(void *)ip, (guint32)target);
4439                         break;
4440                 }
4441         }
4442 }
4443
4444 #if 0
4445 static
4446 void
4447 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4448 {
4449 }
4450
4451 static
4452 void
4453 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4454 {
4455 }
4456 #endif
4457
4458 /*
4459  * Allow tracing to work with this interface (with an optional argument)
4460  *
4461  * This code is expected to be inserted just after the 'real' prolog code,
4462  * and before the first basic block.  We need to allocate a 2nd, temporary
4463  * stack frame so that we can preserve f12-f15 as well as a0-a3.
4464  */
4465
4466 void*
4467 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4468 {
4469         guchar *code = p;
4470         int offset = cfg->arch.tracing_offset;
4471
4472         mips_nop (code);
4473         mips_nop (code);
4474         mips_nop (code);
4475
4476         /* For N32, need to know for each stack slot if it's an integer
4477          * or float argument, and save/restore the appropriate register
4478          */
4479         MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4480         MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4481         MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4482         MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4483 #if _MIPS_SIM == _ABIN32
4484         MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4485         MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4486         MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4487         MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4488 #endif
4489
4490         mips_load_const (code, mips_a0, cfg->method);
4491         mips_addiu (code, mips_a1, mips_sp, offset);
4492         mips_call (code, mips_t9, func);
4493
4494         MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4495         MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4496         MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4497         MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4498 #if _MIPS_SIM == _ABIN32
4499         MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4500         MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4501         MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4502         MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4503 #endif
4504
4505         mips_nop (code);
4506         mips_nop (code);
4507         mips_nop (code);
4508         return code;
4509 }
4510
4511 void
4512 mips_adjust_stackframe(MonoCompile *cfg)
4513 {
4514         MonoBasicBlock *bb;
4515         int delta, threshold, i;
4516         MonoMethodSignature *sig;
4517         int ra_offset;
4518
4519         if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4520                 return;
4521
4522         /* adjust cfg->stack_offset for account for down-spilling */
4523         cfg->stack_offset += SIZEOF_REGISTER;
4524
4525         /* re-align cfg->stack_offset if needed (due to var spilling) */
4526         cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4527         delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4528         if (cfg->verbose_level > 2) {
4529                 g_print ("mips_adjust_stackframe:\n");
4530                 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4531         }
4532         threshold = cfg->arch.local_alloc_offset;
4533         ra_offset = cfg->stack_offset - sizeof(gpointer);
4534         if (cfg->verbose_level > 2) {
4535                 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4536         }
4537
4538         sig = mono_method_signature (cfg->method);
4539         if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4540                 cfg->vret_addr->inst_offset += delta;
4541         }
4542         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4543                 MonoInst *inst = cfg->args [i];
4544
4545                 inst->inst_offset += delta;
4546         }
4547
4548         /*
4549          * loads and stores based off the frame reg that (used to) lie
4550          * above the spill var area need to be increased by 'delta'
4551          * to make room for the spill vars.
4552          */
4553         /* Need to find loads and stores to adjust that
4554          * are above where the spillvars were inserted, but
4555          * which are not the spillvar references themselves.
4556          *
4557          * Idea - since all offsets from fp are positive, make
4558          * spillvar offsets negative to begin with so we can spot
4559          * them here.
4560          */
4561
4562 #if 1
4563         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4564                 int ins_cnt = 0;
4565                 MonoInst *ins;
4566
4567                 if (cfg->verbose_level > 2) {
4568                         g_print ("BASIC BLOCK %d:\n", bb->block_num);
4569                 }
4570                 MONO_BB_FOR_EACH_INS (bb, ins) {
4571                         int adj_c0 = 0;
4572                         int adj_imm = 0;
4573
4574                         if (cfg->verbose_level > 2) {
4575                                 mono_print_ins_index (ins_cnt, ins);
4576                         }
4577                         if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp))
4578                                 adj_c0 = 1;
4579                         if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))
4580                                 adj_c0 = 1;
4581                         /* The following two catch FP spills */
4582                         if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_sp))
4583                                 adj_c0 = 1;
4584                         if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_sp))
4585                                 adj_c0 = 1;
4586                         if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4587                                 adj_imm = 1;
4588                         if (adj_c0) {
4589                                 if (ins->inst_c0 >= threshold) {
4590                                         ins->inst_c0 += delta;
4591                                         if (cfg->verbose_level > 2) {
4592                                                 g_print ("adj");
4593                                                 mono_print_ins_index (ins_cnt, ins);
4594                                         }
4595                                 }
4596                                 else if (ins->inst_c0 < 0) {
4597                                         ins->inst_c0 = - ins->inst_c0 - 4;
4598                                         if (cfg->verbose_level > 2) {
4599                                                 g_print ("spill");
4600                                                 mono_print_ins_index (ins_cnt, ins);
4601                                         }
4602                                 }
4603                                 g_assert (ins->inst_c0 != ra_offset);
4604                         }
4605                         if (adj_imm) {
4606                                 if (ins->inst_imm >= threshold) {
4607                                         ins->inst_imm += delta;
4608                                         if (cfg->verbose_level > 2) {
4609                                                 g_print ("adj");
4610                                                 mono_print_ins_index (ins_cnt, ins);
4611                                         }
4612                                 }
4613                                 g_assert (ins->inst_c0 != ra_offset);
4614                         }
4615
4616                         ++ins_cnt;
4617                 }
4618         }
4619 #endif
4620 }
4621
4622 /*
4623  * Stack frame layout:
4624  * 
4625  *   ------------------- sp + cfg->stack_usage + cfg->param_area
4626  *      param area              incoming
4627  *   ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4628  *      a0-a3                   incoming
4629  *   ------------------- sp + cfg->stack_usage
4630  *      ra
4631  *   ------------------- sp + cfg->stack_usage-4
4632  *      spilled regs
4633  *   ------------------- sp + 
4634  *      MonoLMF structure       optional
4635  *   ------------------- sp + cfg->arch.lmf_offset
4636  *      saved registers         s0-s8
4637  *   ------------------- sp + cfg->arch.iregs_offset
4638  *      locals
4639  *   ------------------- sp + cfg->param_area
4640  *      param area              outgoing
4641  *   ------------------- sp + MIPS_STACK_PARAM_OFFSET
4642  *      a0-a3                   outgoing
4643  *   ------------------- sp
4644  *      red zone
4645  */
4646 guint8 *
4647 mono_arch_emit_prolog (MonoCompile *cfg)
4648 {
4649         MonoMethod *method = cfg->method;
4650         MonoMethodSignature *sig;
4651         MonoInst *inst;
4652         int alloc_size, pos, i;
4653         int alloc2_size = 0;
4654         guint8 *code;
4655         CallInfo *cinfo;
4656         int tracing = 0;
4657         guint32 iregs_to_save = 0;
4658 #if SAVE_FP_REGS
4659         guint32 fregs_to_save = 0;
4660 #endif
4661 #if SAVE_LMF
4662         /* lmf_offset is the offset of the LMF from our stack pointer. */
4663         guint32 lmf_offset = cfg->arch.lmf_offset;
4664 #endif
4665
4666         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4667                 tracing = 1;
4668
4669         if (tracing)
4670                 cfg->flags |= MONO_CFG_HAS_CALLS;
4671         
4672         sig = mono_method_signature (method);
4673         cfg->code_size = 768 + sig->param_count * 20;
4674         code = cfg->native_code = g_malloc (cfg->code_size);
4675
4676         if (tracing) {
4677 #if _MIPS_SIM == _ABIO32
4678                 cfg->arch.tracing_offset = cfg->stack_offset;
4679 #elif _MIPS_SIM == _ABIN32
4680                 /* no stack slots by default for argument regs, reserve a special block */
4681                 cfg->arch.tracing_offset = cfg->stack_offset;
4682                 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4683 #endif
4684         }
4685
4686         /* adjust stackframe assignments for spillvars if needed */
4687         mips_adjust_stackframe (cfg);
4688
4689         /* stack_offset should not be changed here. */
4690         alloc_size = cfg->stack_offset;
4691         cfg->stack_usage = alloc_size;
4692
4693 #if SAVE_ALL_REGS
4694         iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4695 #else
4696         iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4697 #endif
4698 #if SAVE_FP_REGS
4699 #if 0
4700         fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4701 #else
4702         fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4703         fregs_to_save |= (fregs_to_save << 1);
4704 #endif
4705 #endif
4706         /* If the stack size is too big, save 1024 bytes to start with
4707          * so the prologue can use imm16(reg) addressing, then allocate
4708          * the rest of the frame.
4709          */
4710         if (alloc_size > ((1 << 15) - 1024)) {
4711                 alloc2_size = alloc_size - 1024;
4712                 alloc_size = 1024;
4713         }
4714         if (alloc_size) {
4715                 g_assert (mips_is_imm16 (-alloc_size));
4716                 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4717         }
4718
4719         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4720                 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4721                 if (mips_is_imm16(offset))
4722                         mips_sw (code, mips_ra, mips_sp, offset);
4723                 else {
4724                         g_assert_not_reached ();
4725                 }
4726         }
4727
4728         /* XXX - optimize this later to not save all regs if LMF constructed */
4729         pos = cfg->arch.iregs_offset - alloc2_size;
4730
4731         if (iregs_to_save) {
4732                 /* save used registers in own stack frame (at pos) */
4733                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4734                         if (iregs_to_save & (1 << i)) {
4735                                 g_assert (pos < cfg->stack_usage - sizeof(gpointer));
4736                                 g_assert (mips_is_imm16(pos));
4737                                 MIPS_SW (code, i, mips_sp, pos);
4738                                 pos += SIZEOF_REGISTER;
4739                         }
4740                 }
4741         }
4742 #if SAVE_LMF
4743         if (method->save_lmf) {
4744                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4745                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4746                         g_assert (mips_is_imm16(offset));
4747                         MIPS_SW (code, i, mips_sp, offset);
4748                 }
4749         }
4750 #endif
4751
4752 #if SAVE_FP_REGS
4753         /* Save float registers */
4754         if (fregs_to_save) {
4755                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4756                         if (fregs_to_save & (1 << i)) {
4757                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4758                                 g_assert (mips_is_imm16(pos));
4759                                 mips_swc1 (code, i, mips_sp, pos);
4760                                 pos += sizeof (gulong);
4761                         }
4762                 }
4763         }
4764 #if SAVE_LMF
4765         if (method->save_lmf) {
4766                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4767                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4768                         g_assert (mips_is_imm16(offset));
4769                         mips_swc1 (code, i, mips_sp, offset);
4770                 }
4771         }
4772 #endif
4773 #endif
4774         if (cfg->frame_reg != mips_sp) {
4775                 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4776 #if SAVE_LMF
4777                 if (method->save_lmf) {
4778                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4779                         g_assert (mips_is_imm16(offset));
4780                         MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4781                 }
4782 #endif
4783         }
4784
4785         /* Do instrumentation before assigning regvars to registers.  Because they may be assigned
4786          * to the t* registers, which would be clobbered by the instrumentation calls.
4787          */
4788         if (tracing) {
4789                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4790         }
4791
4792
4793         /* load arguments allocated to register from the stack */
4794         pos = 0;
4795
4796         cinfo = calculate_sizes (sig, sig->pinvoke);
4797
4798         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4799                 ArgInfo *ainfo = &cinfo->ret;
4800                 inst = cfg->vret_addr;
4801                 if (inst->opcode == OP_REGVAR)
4802                         MIPS_MOVE (code, inst->dreg, ainfo->reg);
4803                 else if (mips_is_imm16 (inst->inst_offset)) {
4804                         mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4805                 } else {
4806                         mips_load_const (code, mips_at, inst->inst_offset);
4807                         mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4808                         mips_sw (code, ainfo->reg, mips_at, 0);
4809                 }
4810         }
4811         /* Keep this in sync with emit_load_volatile_arguments */
4812         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4813                 ArgInfo *ainfo = cinfo->args + i;
4814                 inst = cfg->args [pos];
4815                 
4816                 if (cfg->verbose_level > 2)
4817                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4818                 if (inst->opcode == OP_REGVAR) {
4819                         /* Argument ends up in a register */
4820                         if (ainfo->regtype == RegTypeGeneral)
4821                                 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4822                         else if (ainfo->regtype == RegTypeFP) {
4823                                 g_assert_not_reached();
4824 #if 0
4825                                 ppc_fmr (code, inst->dreg, ainfo->reg);
4826 #endif
4827                         }
4828                         else if (ainfo->regtype == RegTypeBase) {
4829                                 int offset = cfg->stack_usage + ainfo->offset;
4830                                 g_assert (mips_is_imm16(offset));
4831                                 mips_lw (code, inst->dreg, mips_sp, offset);
4832                         } else
4833                                 g_assert_not_reached ();
4834
4835                         if (cfg->verbose_level > 2)
4836                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4837                 } else {
4838                         /* Argument ends up on the stack */
4839                         if (ainfo->regtype == RegTypeGeneral) {
4840                                 /* Incoming parameters should be above this frame */
4841                                 if (cfg->verbose_level > 2)
4842                                         g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
4843                                 /* g_assert (inst->inst_offset >= alloc_size); */
4844                                 g_assert (mips_is_imm16 (inst->inst_offset));
4845                                 switch (ainfo->size) {
4846                                 case 1:
4847                                         mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4848                                         break;
4849                                 case 2:
4850                                         mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4851                                         break;
4852                                 case 0: /* XXX */
4853                                 case 4:
4854                                         mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4855                                         break;
4856                                 case 8:
4857 #if (SIZEOF_REGISTER == 4)
4858                                         mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4859                                         mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4860 #elif (SIZEOF_REGISTER == 8)
4861                                         mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4862 #endif
4863                                         break;
4864                                 default:
4865                                         g_assert_not_reached ();
4866                                         break;
4867                                 }
4868                         } else if (ainfo->regtype == RegTypeBase) {
4869                                 /*
4870                                  * Argument comes in on the stack, and ends up on the stack
4871                                  * 1 and 2 byte args are passed as 32-bit quantities, but used as
4872                                  * 8 and 16 bit quantities.  Shorten them in place.
4873                                  */
4874                                 g_assert (mips_is_imm16 (inst->inst_offset));
4875                                 switch (ainfo->size) {
4876                                 case 1:
4877                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4878                                         mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4879                                         break;
4880                                 case 2:
4881                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4882                                         mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4883                                         break;
4884                                 case 0: /* XXX */
4885                                 case 4:
4886                                 case 8:
4887                                         break;
4888                                 default:
4889                                         g_assert_not_reached ();
4890                                 }
4891                         } else if (ainfo->regtype == RegTypeFP) {
4892                                 g_assert (mips_is_imm16 (inst->inst_offset));
4893                                 g_assert (mips_is_imm16 (inst->inst_offset+4));
4894                                 if (ainfo->size == 8) {
4895 #if _MIPS_SIM == _ABIO32
4896                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4897                                         mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4898 #elif _MIPS_SIM == _ABIN32
4899                                         mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4900 #endif
4901                                 }
4902                                 else if (ainfo->size == 4)
4903                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4904                                 else
4905                                         g_assert_not_reached ();
4906                         } else if (ainfo->regtype == RegTypeStructByVal) {
4907                                 int i;
4908                                 int doffset = inst->inst_offset;
4909
4910                                 g_assert (mips_is_imm16 (inst->inst_offset));
4911                                 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4912                                 /* Push the argument registers into their stack slots */
4913                                 for (i = 0; i < ainfo->size; ++i) {
4914                                         g_assert (mips_is_imm16(doffset));
4915                                         MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
4916                                         doffset += SIZEOF_REGISTER;
4917                                 }
4918                         } else if (ainfo->regtype == RegTypeStructByAddr) {
4919                                 g_assert (mips_is_imm16 (inst->inst_offset));
4920                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4921                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4922                         } else
4923                                 g_assert_not_reached ();
4924                 }
4925                 pos++;
4926         }
4927
4928         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4929                 mips_load_const (code, mips_a0, cfg->domain);
4930                 mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
4931         }
4932
4933 #if SAVE_LMF
4934         if (method->save_lmf) {
4935                 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4936                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4937
4938                 if (lmf_pthread_key != -1) {
4939                         g_assert_not_reached();
4940 #if 0
4941                         emit_tls_access (code, mips_temp, lmf_pthread_key);
4942 #endif
4943                         if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
4944                                 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
4945                                 g_assert (mips_is_imm16(offset));
4946                                 mips_addiu (code, mips_a0, mips_temp, offset);
4947                         }
4948                 } else {
4949                         /* This can/will clobber the a0-a3 registers */
4950                         mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
4951                 }
4952
4953                 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4954                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
4955                 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4956                 /* new_lmf->previous_lmf = *lmf_addr */
4957                 mips_lw (code, mips_at, mips_v0, 0);
4958                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
4959                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4960                 /* *(lmf_addr) = sp + lmf_offset */
4961                 g_assert (mips_is_imm16(lmf_offset));
4962                 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4963                 mips_sw (code, mips_at, mips_v0, 0);
4964
4965                 /* save method info */
4966                 mips_load_const (code, mips_at, method);
4967                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
4968                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4969                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
4970                 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4971
4972                 /* save the current IP */
4973                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4974                 mips_load_const (code, mips_at, 0x01010101);
4975                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
4976         }
4977 #endif
4978         if (alloc2_size) {
4979                 if (mips_is_imm16 (-alloc2_size)) {
4980                         mips_addu (code, mips_sp, mips_sp, -alloc2_size);
4981                 }
4982                 else {
4983                         mips_load_const (code, mips_at, -alloc2_size);
4984                         mips_addu (code, mips_sp, mips_sp, mips_at);
4985                 }
4986                 if (cfg->frame_reg != mips_sp)
4987                         MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4988                 alloc_size += alloc2_size;
4989         }
4990
4991         cfg->code_len = code - cfg->native_code;
4992         g_assert (cfg->code_len < cfg->code_size);
4993         g_free (cinfo);
4994
4995         return code;
4996 }
4997
4998 enum {
4999         SAVE_NONE,
5000         SAVE_STRUCT,
5001         SAVE_ONE,
5002         SAVE_TWO,
5003         SAVE_FP
5004 };
5005
5006 void*
5007 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5008 {
5009         guchar *code = p;
5010         int save_mode = SAVE_NONE;
5011         int offset;
5012         MonoMethod *method = cfg->method;
5013         int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5014         int save_offset = MIPS_STACK_PARAM_OFFSET;
5015
5016         g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5017         
5018         offset = code - cfg->native_code;
5019         /* we need about 16 instructions */
5020         if (offset > (cfg->code_size - 16 * 4)) {
5021                 cfg->code_size *= 2;
5022                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5023                 code = cfg->native_code + offset;
5024         }
5025         mips_nop (code);
5026         mips_nop (code);
5027         switch (rtype) {
5028         case MONO_TYPE_VOID:
5029                 /* special case string .ctor icall */
5030                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5031                         save_mode = SAVE_ONE;
5032                 else
5033                         save_mode = SAVE_NONE;
5034                 break;
5035         case MONO_TYPE_R4:
5036         case MONO_TYPE_R8:
5037                 save_mode = SAVE_FP;
5038                 break;
5039         case MONO_TYPE_VALUETYPE:
5040                 save_mode = SAVE_STRUCT;
5041                 break;
5042         case MONO_TYPE_I8:
5043         case MONO_TYPE_U8:
5044 #if SIZEOF_REGISTER == 4
5045                 save_mode = SAVE_TWO;
5046 #elif SIZEOF_REGISTER == 8
5047                 save_mode = SAVE_ONE;
5048 #endif
5049                 break;
5050         default:
5051                 save_mode = SAVE_ONE;
5052                 break;
5053         }
5054
5055         mips_addiu (code, mips_sp, mips_sp, -32);
5056         g_assert (mips_is_imm16(save_offset));
5057         switch (save_mode) {
5058         case SAVE_TWO:
5059                 mips_sw (code, mips_v0, mips_sp, save_offset);
5060                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5061                 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5062                 if (enable_arguments) {
5063                         MIPS_MOVE (code, mips_a1, mips_v0);
5064                         MIPS_MOVE (code, mips_a2, mips_v1);
5065                 }
5066                 break;
5067         case SAVE_ONE:
5068                 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5069                 if (enable_arguments) {
5070                         MIPS_MOVE (code, mips_a1, mips_v0);
5071                 }
5072                 break;
5073         case SAVE_FP:
5074                 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5075                 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5076                 mips_lw (code, mips_a0, mips_sp, save_offset);
5077                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5078                 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5079                 break;
5080         case SAVE_STRUCT:
5081         case SAVE_NONE:
5082         default:
5083                 break;
5084         }
5085         mips_load_const (code, mips_a0, cfg->method);
5086         mips_call (code, mips_t9, func);
5087
5088         switch (save_mode) {
5089         case SAVE_TWO:
5090                 mips_lw (code, mips_v0, mips_sp, save_offset);
5091                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5092                 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5093                 break;
5094         case SAVE_ONE:
5095                 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5096                 break;
5097         case SAVE_FP:
5098                 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5099                 break;
5100         case SAVE_STRUCT:
5101         case SAVE_NONE:
5102         default:
5103                 break;
5104         }
5105         mips_addiu (code, mips_sp, mips_sp, 32);
5106         mips_nop (code);
5107         mips_nop (code);
5108         return code;
5109 }
5110
5111 guint8 *
5112 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5113 {
5114         MonoMethod *method = cfg->method;
5115         int pos = 0, i;
5116         int max_epilog_size = 16 + 20*4;
5117         int alloc2_size = 0;
5118         guint32 iregs_to_restore;
5119 #if SAVE_FP_REGS
5120         guint32 fregs_to_restore;
5121 #endif
5122
5123 #if SAVE_LMF
5124         if (cfg->method->save_lmf)
5125                 max_epilog_size += 128;
5126 #endif
5127         
5128         if (mono_jit_trace_calls != NULL)
5129                 max_epilog_size += 50;
5130
5131         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5132                 max_epilog_size += 50;
5133
5134         if (code)
5135                 pos = code - cfg->native_code;
5136         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5137                 cfg->code_size *= 2;
5138                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5139                 mono_jit_stats.code_reallocs++;
5140         }
5141
5142         /*
5143          * Keep in sync with OP_JMP
5144          */
5145         if (code)
5146                 code = cfg->native_code + pos;
5147         else
5148                 code = cfg->native_code + cfg->code_len;
5149
5150         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5151                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5152         }
5153         if (cfg->frame_reg != mips_sp) {
5154                 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5155         }
5156         /* If the stack frame is really large, deconstruct it in two steps */
5157         if (cfg->stack_usage > ((1 << 15) - 1024)) {
5158                 alloc2_size = cfg->stack_usage - 1024;
5159                 /* partially deconstruct the stack */
5160                 mips_load_const (code, mips_at, alloc2_size);
5161                 mips_addu (code, mips_sp, mips_sp, mips_at);
5162         }
5163         pos = cfg->arch.iregs_offset - alloc2_size;
5164 #if SAVE_ALL_REGS
5165         iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5166 #else
5167         iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5168 #endif
5169         if (iregs_to_restore) {
5170                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5171                         if (iregs_to_restore & (1 << i)) {
5172                                 g_assert (mips_is_imm16(pos));
5173                                 MIPS_LW (code, i, mips_sp, pos);
5174                                 pos += SIZEOF_REGISTER;
5175                         }
5176                 }
5177         }
5178
5179 #if SAVE_FP_REGS
5180 #if 0
5181         fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5182 #else
5183         fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5184         fregs_to_restore |= (fregs_to_restore << 1);
5185 #endif
5186         if (fregs_to_restore) {
5187                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5188                         if (fregs_to_restore & (1 << i)) {
5189                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5190                                 g_assert (mips_is_imm16(pos));
5191                                 mips_lwc1 (code, i, mips_sp, pos);
5192                                 pos += FREG_SIZE
5193                         }
5194                 }
5195         }
5196 #endif
5197 #if SAVE_LMF
5198         /* Unlink the LMF if necessary */
5199         if (method->save_lmf) {
5200                 int lmf_offset = cfg->arch.lmf_offset;
5201
5202                 /* t0 = current_lmf->previous_lmf */
5203                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5204                 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5205                 /* t1 = lmf_addr */
5206                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5207                 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5208                 /* (*lmf_addr) = previous_lmf */
5209                 mips_sw (code, mips_temp, mips_t1, 0);
5210         }
5211 #endif
5212 #if 0
5213         /* Restore the fp */
5214         mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5215 #endif
5216         /* Restore ra */
5217         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5218                 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5219                 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5220         }
5221         /* Restore the stack pointer */
5222         g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5223         mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5224
5225         /* Caller will emit either return or tail-call sequence */
5226
5227         cfg->code_len = code - cfg->native_code;
5228
5229         g_assert (cfg->code_len < cfg->code_size);
5230         return (code);
5231 }
5232
5233 void
5234 mono_arch_emit_epilog (MonoCompile *cfg)
5235 {
5236         guint8 *code;
5237
5238         code = mono_arch_emit_epilog_sub (cfg, NULL);
5239
5240         mips_jr (code, mips_ra);
5241         mips_nop (code);
5242
5243         cfg->code_len = code - cfg->native_code;
5244
5245         g_assert (cfg->code_len < cfg->code_size);
5246 }
5247
5248 /* remove once throw_exception_by_name is eliminated */
5249 #if 0
5250 static int
5251 exception_id_by_name (const char *name)
5252 {
5253         if (strcmp (name, "IndexOutOfRangeException") == 0)
5254                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5255         if (strcmp (name, "OverflowException") == 0)
5256                 return MONO_EXC_OVERFLOW;
5257         if (strcmp (name, "ArithmeticException") == 0)
5258                 return MONO_EXC_ARITHMETIC;
5259         if (strcmp (name, "DivideByZeroException") == 0)
5260                 return MONO_EXC_DIVIDE_BY_ZERO;
5261         if (strcmp (name, "InvalidCastException") == 0)
5262                 return MONO_EXC_INVALID_CAST;
5263         if (strcmp (name, "NullReferenceException") == 0)
5264                 return MONO_EXC_NULL_REF;
5265         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5266                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5267         if (strcmp (name, "ArgumentException") == 0)
5268                 return MONO_EXC_ARGUMENT;
5269         g_error ("Unknown intrinsic exception %s\n", name);
5270         return 0;
5271 }
5272 #endif
5273
5274 void
5275 mono_arch_emit_exceptions (MonoCompile *cfg)
5276 {
5277 #if 0
5278         MonoJumpInfo *patch_info;
5279         int i;
5280         guint8 *code;
5281         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5282         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5283         int max_epilog_size = 50;
5284
5285         /* count the number of exception infos */
5286      
5287         /* 
5288          * make sure we have enough space for exceptions
5289          * 24 is the simulated call to throw_exception_by_name
5290          */
5291         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5292 #if 0
5293                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5294                         i = exception_id_by_name (patch_info->data.target);
5295                         g_assert (i < MONO_EXC_INTRINS_NUM);
5296                         if (!exc_throw_found [i]) {
5297                                 max_epilog_size += 12;
5298                                 exc_throw_found [i] = TRUE;
5299                         }
5300                 }
5301 #endif
5302         }
5303
5304         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5305                 cfg->code_size *= 2;
5306                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5307                 mono_jit_stats.code_reallocs++;
5308         }
5309
5310         code = cfg->native_code + cfg->code_len;
5311
5312         /* add code to raise exceptions */
5313         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5314                 switch (patch_info->type) {
5315                 case MONO_PATCH_INFO_EXC: {
5316 #if 0
5317                         //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5318
5319                         i = exception_id_by_name (patch_info->data.target);
5320                         g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5321                         if (!exc_throw_pos [i]) {
5322                                 guint32 addr;
5323
5324                                 exc_throw_pos [i] = code;
5325                                 //g_print ("exc: writing stub at %p\n", code);
5326                                 mips_load_const (code, mips_a0, patch_info->data.target);
5327                                 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5328                                 mips_load_const (code, mips_t9, addr);
5329                                 mips_jr (code, mips_t9);
5330                                 mips_nop (code);
5331                         }
5332                         //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5333
5334                         /* Turn into a Relative patch, pointing at code stub */
5335                         patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5336                         patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5337 #else
5338                         g_assert_not_reached();
5339 #endif
5340                         break;
5341                 }
5342                 default:
5343                         /* do nothing */
5344                         break;
5345                 }
5346         }
5347
5348         cfg->code_len = code - cfg->native_code;
5349
5350         g_assert (cfg->code_len < cfg->code_size);
5351 #endif
5352 }
5353
5354 /*
5355  * Thread local storage support
5356  */
5357 static void
5358 setup_tls_access (void)
5359 {
5360         guint32 ptk;
5361         //guint32 *ins, *code;
5362
5363         if (tls_mode == TLS_MODE_FAILED)
5364                 return;
5365
5366         if (g_getenv ("MONO_NO_TLS")) {
5367                 tls_mode = TLS_MODE_FAILED;
5368                 return;
5369         }
5370
5371         if (tls_mode == TLS_MODE_DETECT) {
5372                 /* XXX */
5373                 tls_mode = TLS_MODE_FAILED;
5374                 return;
5375 #if 0
5376
5377                 ins = (guint32*)pthread_getspecific;
5378                 /* uncond branch to the real method */
5379                 if ((*ins >> 26) == 18) {
5380                         gint32 val;
5381                         val = (*ins & ~3) << 6;
5382                         val >>= 6;
5383                         if (*ins & 2) {
5384                                 /* absolute */
5385                                 ins = (guint32*)val;
5386                         } else {
5387                                 ins = (guint32*) ((char*)ins + val);
5388                         }
5389                 }
5390                 code = &cmplwi_1023;
5391                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5392                 code = &li_0x48;
5393                 ppc_li (code, ppc_r4, 0x48);
5394                 code = &blr_ins;
5395                 ppc_blr (code);
5396                 if (*ins == cmplwi_1023) {
5397                         int found_lwz_284 = 0;
5398                         for (ptk = 0; ptk < 20; ++ptk) {
5399                                 ++ins;
5400                                 if (!*ins || *ins == blr_ins)
5401                                         break;
5402                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5403                                         found_lwz_284 = 1;
5404                                         break;
5405                                 }
5406                         }
5407                         if (!found_lwz_284) {
5408                                 tls_mode = TLS_MODE_FAILED;
5409                                 return;
5410                         }
5411                         tls_mode = TLS_MODE_LTHREADS;
5412                 } else if (*ins == li_0x48) {
5413                         ++ins;
5414                         /* uncond branch to the real method */
5415                         if ((*ins >> 26) == 18) {
5416                                 gint32 val;
5417                                 val = (*ins & ~3) << 6;
5418                                 val >>= 6;
5419                                 if (*ins & 2) {
5420                                         /* absolute */
5421                                         ins = (guint32*)val;
5422                                 } else {
5423                                         ins = (guint32*) ((char*)ins + val);
5424                                 }
5425                                 code = &val;
5426                                 ppc_li (code, ppc_r0, 0x7FF2);
5427                                 if (ins [1] == val) {
5428                                         /* Darwin on G4, implement */
5429                                         tls_mode = TLS_MODE_FAILED;
5430                                         return;
5431                                 } else {
5432                                         code = &val;
5433                                         ppc_mfspr (code, ppc_r3, 104);
5434                                         if (ins [1] != val) {
5435                                                 tls_mode = TLS_MODE_FAILED;
5436                                                 return;
5437                                         }
5438                                         tls_mode = TLS_MODE_DARWIN_G5;
5439                                 }
5440                         } else {
5441                                 tls_mode = TLS_MODE_FAILED;
5442                                 return;
5443                         }
5444                 } else {
5445                         tls_mode = TLS_MODE_FAILED;
5446                         return;
5447                 }
5448 #endif
5449         }
5450         if (monodomain_key == -1) {
5451                 ptk = mono_domain_get_tls_key ();
5452                 if (ptk < 1024) {
5453                         ptk = mono_pthread_key_for_tls (ptk);
5454                         if (ptk < 1024) {
5455                                 monodomain_key = ptk;
5456                         }
5457                 }
5458         }
5459         if (lmf_pthread_key == -1) {
5460                 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5461                 if (ptk < 1024) {
5462                         /*g_print ("MonoLMF at: %d\n", ptk);*/
5463                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5464                                 init_tls_failed = 1;
5465                                 return;
5466                         }*/
5467                         lmf_pthread_key = ptk;
5468                 }
5469         }
5470         if (monothread_key == -1) {
5471                 ptk = mono_thread_get_tls_key ();
5472                 if (ptk < 1024) {
5473                         ptk = mono_pthread_key_for_tls (ptk);
5474                         if (ptk < 1024) {
5475                                 monothread_key = ptk;
5476                                 /*g_print ("thread inited: %d\n", ptk);*/
5477                         }
5478                 } else {
5479                         /*g_print ("thread not inited yet %d\n", ptk);*/
5480                 }
5481         }
5482 }
5483
5484 void
5485 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5486 {
5487         setup_tls_access ();
5488 }
5489
5490 void
5491 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5492 {
5493 }
5494
5495 void
5496 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5497 {
5498         int this_dreg = mips_a0;
5499         
5500         if (vt_reg != -1)
5501                 this_dreg = mips_a1;
5502
5503         /* add the this argument */
5504         if (this_reg != -1) {
5505                 MonoInst *this;
5506                 MONO_INST_NEW (cfg, this, OP_MOVE);
5507                 this->type = this_type;
5508                 this->sreg1 = this_reg;
5509                 this->dreg = mono_alloc_ireg (cfg);
5510                 mono_bblock_add_inst (cfg->cbb, this);
5511                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5512         }
5513
5514         if (vt_reg != -1) {
5515                 MonoInst *vtarg;
5516                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5517                 vtarg->type = STACK_MP;
5518                 vtarg->sreg1 = vt_reg;
5519                 vtarg->dreg = mono_alloc_ireg (cfg);
5520                 mono_bblock_add_inst (cfg->cbb, vtarg);
5521                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5522         }
5523 }
5524
5525 MonoInst*
5526 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5527 {
5528         MonoInst *ins = NULL;
5529
5530         return ins;
5531 }
5532
5533 MonoInst*
5534 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5535 {
5536         return NULL;
5537 }
5538
5539 gboolean
5540 mono_arch_print_tree (MonoInst *tree, int arity)
5541 {
5542         return 0;
5543 }
5544
5545 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5546 {
5547         MonoInst* ins;
5548
5549         setup_tls_access ();
5550         if (monodomain_key == -1)
5551                 return NULL;
5552         
5553         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5554         ins->inst_offset = monodomain_key;
5555         return ins;
5556 }
5557
5558 gpointer
5559 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5560 {
5561         /* FIXME: implement */
5562         g_assert_not_reached ();
5563 }
5564
5565 #ifdef MONO_ARCH_HAVE_IMT
5566
5567 #define ENABLE_WRONG_METHOD_CHECK 0
5568
5569 #define MIPS_LOAD_SEQUENCE_LENGTH       8
5570 #define CMP_SIZE                        (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5571 #define BR_SIZE                         8
5572 #define LOADSTORE_SIZE                  4
5573 #define JUMP_IMM_SIZE                   16
5574 #define JUMP_IMM32_SIZE                 (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5575 #define LOAD_CONST_SIZE                 8
5576 #define JUMP_JR_SIZE                    8
5577
5578 /*
5579  * LOCKING: called with the domain lock held
5580  */
5581 gpointer
5582 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5583         gpointer fail_tramp)
5584 {
5585         int i;
5586         int size = 0;
5587         guint8 *code, *start, *patch;
5588
5589         for (i = 0; i < count; ++i) {
5590                 MonoIMTCheckItem *item = imt_entries [i];
5591
5592                 item->chunk_size += LOAD_CONST_SIZE;
5593                 if (item->is_equals) {
5594                         if (item->check_target_idx) {
5595                                 item->chunk_size += BR_SIZE + LOAD_CONST_SIZE + JUMP_JR_SIZE;
5596                         } else {
5597                                 if (fail_tramp) {
5598                                         item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE * 2;
5599                                         if (!item->has_target_code)
5600                                                 item->chunk_size += LOADSTORE_SIZE;
5601                                 } else {
5602                                         item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5603 #if ENABLE_WRONG_METHOD_CHECK
5604                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5605 #endif
5606                                 }
5607                         }
5608                 } else {
5609                         item->chunk_size += BR_SIZE;
5610                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5611                 }
5612                 size += item->chunk_size;
5613         }
5614         /* the initial load of the vtable address */
5615         size += MIPS_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5616         if (fail_tramp) {
5617                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5618         } else {
5619                 code = mono_domain_code_reserve (domain, size);
5620         }
5621         start = code;
5622
5623 #if 0
5624         /*
5625          * We need to save and restore r11 because it might be
5626          * used by the caller as the vtable register, so
5627          * clobbering it will trip up the magic trampoline.
5628          *
5629          * FIXME: Get rid of this by making sure that r11 is
5630          * not used as the vtable register in interface calls.
5631          */
5632         ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5633         ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5634 #endif
5635         /* t7 points to the vtable */
5636         mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5637
5638         for (i = 0; i < count; ++i) {
5639                 MonoIMTCheckItem *item = imt_entries [i];
5640
5641                 item->code_target = code;
5642                 mips_load_const (code, mips_temp, (gsize)item->key);
5643                 if (item->is_equals) {
5644                         if (item->check_target_idx) {
5645                                 item->jmp_code = code;
5646                                 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5647                                 mips_nop (code);
5648                                 if (item->has_target_code) {
5649                                         mips_load_const (code, mips_t9,
5650                                                          item->value.target_code);
5651                                 }
5652                                 else {
5653                                         mips_lw (code, mips_t9, mips_t7,
5654                                                 (sizeof (gpointer) * item->value.vtable_slot));
5655                                 }
5656                                 mips_jr (code, mips_t9);
5657                                 mips_nop (code);
5658                         } else {
5659                                 if (fail_tramp) {
5660                                         patch = code;
5661                                         mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5662                                         mips_nop (code);
5663                                         if (item->has_target_code) {
5664                                                 mips_load_const (code, mips_t9,
5665                                                                  item->value.target_code);
5666                                         } else {
5667                                                 g_assert (vtable);
5668                                                 mips_load_const (code, mips_at,
5669                                                                  & (vtable->vtable [item->value.vtable_slot]));
5670                                                 mips_lw (code, mips_t9, mips_at, 0);
5671                                         }
5672                                         mips_jr (code, mips_t9);
5673                                         mips_nop (code);
5674                                         mips_patch ((guint32 *)(void *)patch, (guint32)code);
5675                                         mips_load_const (code, mips_at, fail_tramp);
5676                                         mips_lw (code, mips_t9, mips_at, 0);
5677                                         mips_jr (code, mips_t9);
5678                                         mips_nop (code);
5679                                 } else {
5680                                         /* enable the commented code to assert on wrong method */
5681 #if ENABLE_WRONG_METHOD_CHECK
5682                                         ppc_load (code, ppc_r0, (guint32)item->key);
5683                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5684                                         patch = code;
5685                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5686 #endif
5687                                         mips_lw (code, mips_t9, mips_t7,
5688                                                  (sizeof (gpointer) * item->value.vtable_slot));
5689                                         mips_jr (code, mips_t9);
5690                                         mips_nop (code);
5691
5692 #if ENABLE_WRONG_METHOD_CHECK
5693                                         ppc_patch (patch, code);
5694                                         ppc_break (code);
5695 #endif
5696                                 }
5697                         }
5698                 } else {
5699                         mips_load_const (code, mips_temp, (gulong)item->key);
5700                         mips_slt (code, mips_temp, mips_temp, MONO_ARCH_IMT_REG);
5701
5702                         item->jmp_code = code;
5703                         mips_bne (code, mips_temp, mips_zero, 0);
5704                         mips_nop (code);
5705                 }
5706         }
5707         /* patch the branches to get to the target items */
5708         for (i = 0; i < count; ++i) {
5709                 MonoIMTCheckItem *item = imt_entries [i];
5710                 if (item->jmp_code && item->check_target_idx) {
5711                         mips_patch ((guint32 *)item->jmp_code,
5712                                    (guint32)imt_entries [item->check_target_idx]->code_target);
5713                 }
5714         }
5715
5716         if (!fail_tramp)
5717                 mono_stats.imt_thunks_size += code - start;
5718         g_assert (code - start <= size);
5719         mono_arch_flush_icache (start, size);
5720         return start;
5721 }
5722
5723 MonoMethod*
5724 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5725 {
5726         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5727 }
5728 #endif
5729
5730 MonoVTable*
5731 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5732 {
5733         NOT_IMPLEMENTED;
5734         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5735 }