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