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