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