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