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