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