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