Merge pull request #1345 from mattleibow/websocket-continuation-frame-fix
[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)
4675 {
4676         MonoJumpInfo *patch_info;
4677         MonoError error;
4678
4679         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4680                 unsigned char *ip = patch_info->ip.i + code;
4681                 const unsigned char *target = NULL;
4682
4683                 switch (patch_info->type) {
4684                 case MONO_PATCH_INFO_IP:
4685                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4686                         continue;
4687                 case MONO_PATCH_INFO_SWITCH: {
4688                         gpointer *table = (gpointer *)patch_info->data.table->table;
4689                         int i;
4690
4691                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4692
4693                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
4694                                 table [i] = (int)patch_info->data.table->table [i] + code;
4695                         }
4696                         continue;
4697                 }
4698                 case MONO_PATCH_INFO_METHODCONST:
4699                 case MONO_PATCH_INFO_CLASS:
4700                 case MONO_PATCH_INFO_IMAGE:
4701                 case MONO_PATCH_INFO_FIELD:
4702                 case MONO_PATCH_INFO_VTABLE:
4703                 case MONO_PATCH_INFO_IID:
4704                 case MONO_PATCH_INFO_SFLDA:
4705                 case MONO_PATCH_INFO_LDSTR:
4706                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4707                 case MONO_PATCH_INFO_LDTOKEN:
4708                 case MONO_PATCH_INFO_R4:
4709                 case MONO_PATCH_INFO_R8:
4710                         /* from OP_AOTCONST : lui + addiu */
4711                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, &error);
4712                         mono_error_raise_exception (&error); /* FIXME: don't raise here */
4713                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4714                         continue;
4715 #if 0
4716                 case MONO_PATCH_INFO_EXC_NAME:
4717                         g_assert_not_reached ();
4718                         *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4719                         continue;
4720 #endif
4721                 case MONO_PATCH_INFO_NONE:
4722                         /* everything is dealt with at epilog output time */
4723                         continue;
4724                 default:
4725                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, &error);
4726                         mono_error_raise_exception (&error); /* FIXME: don't raise here */
4727                         mips_patch ((guint32 *)(void *)ip, (guint32)target);
4728                         break;
4729                 }
4730         }
4731 }
4732
4733 /*
4734  * Allow tracing to work with this interface (with an optional argument)
4735  *
4736  * This code is expected to be inserted just after the 'real' prolog code,
4737  * and before the first basic block.  We need to allocate a 2nd, temporary
4738  * stack frame so that we can preserve f12-f15 as well as a0-a3.
4739  */
4740
4741 void*
4742 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4743 {
4744         guchar *code = p;
4745         int offset = cfg->arch.tracing_offset;
4746
4747         mips_nop (code);
4748         mips_nop (code);
4749         mips_nop (code);
4750
4751         MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4752         MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4753         MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4754         MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4755 #if _MIPS_SIM == _ABIN32
4756         NOT_IMPLEMENTED;
4757         /* FIXME: Need a separate region for these */
4758         MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4759         MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4760         MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4761         MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4762         */
4763 #endif
4764
4765         mips_load_const (code, mips_a0, cfg->method);
4766         mips_addiu (code, mips_a1, mips_sp, offset);
4767         mips_call (code, mips_t9, func);
4768         mips_nop (code);
4769
4770         MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4771         MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4772         MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4773         MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4774 #if _MIPS_SIM == _ABIN32
4775         NOT_IMPLEMENTED;
4776         /*
4777         MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4778         MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4779         MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4780         MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4781         */
4782 #endif
4783
4784         mips_nop (code);
4785         mips_nop (code);
4786         mips_nop (code);
4787         return code;
4788 }
4789
4790 void
4791 mips_adjust_stackframe(MonoCompile *cfg)
4792 {
4793         MonoBasicBlock *bb;
4794         int delta, threshold, i;
4795         MonoMethodSignature *sig;
4796         int ra_offset;
4797
4798         if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4799                 return;
4800
4801         /* adjust cfg->stack_offset for account for down-spilling */
4802         cfg->stack_offset += SIZEOF_REGISTER;
4803
4804         /* re-align cfg->stack_offset if needed (due to var spilling) */
4805         cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4806         delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4807         if (cfg->verbose_level > 2) {
4808                 g_print ("mips_adjust_stackframe:\n");
4809                 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4810         }
4811         threshold = cfg->arch.local_alloc_offset;
4812         ra_offset = cfg->stack_offset - sizeof(gpointer);
4813         if (cfg->verbose_level > 2) {
4814                 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4815         }
4816
4817         sig = mono_method_signature (cfg->method);
4818         if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4819                 cfg->vret_addr->inst_offset += delta;
4820         }
4821         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4822                 MonoInst *inst = cfg->args [i];
4823
4824                 inst->inst_offset += delta;
4825         }
4826
4827         /*
4828          * loads and stores based off the frame reg that (used to) lie
4829          * above the spill var area need to be increased by 'delta'
4830          * to make room for the spill vars.
4831          */
4832         /* Need to find loads and stores to adjust that
4833          * are above where the spillvars were inserted, but
4834          * which are not the spillvar references themselves.
4835          *
4836          * Idea - since all offsets from fp are positive, make
4837          * spillvar offsets negative to begin with so we can spot
4838          * them here.
4839          */
4840
4841 #if 1
4842         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4843                 int ins_cnt = 0;
4844                 MonoInst *ins;
4845
4846                 if (cfg->verbose_level > 2) {
4847                         g_print ("BASIC BLOCK %d:\n", bb->block_num);
4848                 }
4849                 MONO_BB_FOR_EACH_INS (bb, ins) {
4850                         int adj_c0 = 0;
4851                         int adj_imm = 0;
4852
4853                         if (cfg->verbose_level > 2) {
4854                                 mono_print_ins_index (ins_cnt, ins);
4855                         }
4856                         /* The == mips_sp tests catch FP spills */
4857                         if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4858                                                           (ins->inst_basereg == mips_sp))) {
4859                                 switch (ins->opcode) {
4860                                 case OP_LOADI8_MEMBASE:
4861                                 case OP_LOADR8_MEMBASE:
4862                                         adj_c0 = 8;
4863                                         break;
4864                                 default:
4865                                         adj_c0 = 4;
4866                                         break;
4867                                 }
4868                         } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4869                                                                   (ins->dreg == mips_sp))) {
4870                                 switch (ins->opcode) {
4871                                 case OP_STOREI8_MEMBASE_REG:
4872                                 case OP_STORER8_MEMBASE_REG:
4873                                 case OP_STOREI8_MEMBASE_IMM:
4874                                         adj_c0 = 8;
4875                                         break;
4876                                 default:
4877                                         adj_c0 = 4;
4878                                         break;
4879                                 }
4880                         }
4881                         if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4882                                 adj_imm = 1;
4883                         if (adj_c0) {
4884                                 if (ins->inst_c0 >= threshold) {
4885                                         ins->inst_c0 += delta;
4886                                         if (cfg->verbose_level > 2) {
4887                                                 g_print ("adj");
4888                                                 mono_print_ins_index (ins_cnt, ins);
4889                                         }
4890                                 }
4891                                 else if (ins->inst_c0 < 0) {
4892                                         /* Adj_c0 holds the size of the datatype. */
4893                                         ins->inst_c0 = - ins->inst_c0 - adj_c0;
4894                                         if (cfg->verbose_level > 2) {
4895                                                 g_print ("spill");
4896                                                 mono_print_ins_index (ins_cnt, ins);
4897                                         }
4898                                 }
4899                                 g_assert (ins->inst_c0 != ra_offset);
4900                         }
4901                         if (adj_imm) {
4902                                 if (ins->inst_imm >= threshold) {
4903                                         ins->inst_imm += delta;
4904                                         if (cfg->verbose_level > 2) {
4905                                                 g_print ("adj");
4906                                                 mono_print_ins_index (ins_cnt, ins);
4907                                         }
4908                                 }
4909                                 g_assert (ins->inst_c0 != ra_offset);
4910                         }
4911
4912                         ++ins_cnt;
4913                 }
4914         }
4915 #endif
4916 }
4917
4918 /*
4919  * Stack frame layout:
4920  * 
4921  *   ------------------- sp + cfg->stack_usage + cfg->param_area
4922  *      param area              incoming
4923  *   ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4924  *      a0-a3                   incoming
4925  *   ------------------- sp + cfg->stack_usage
4926  *      ra
4927  *   ------------------- sp + cfg->stack_usage-4
4928  *      spilled regs
4929  *   ------------------- sp + 
4930  *      MonoLMF structure       optional
4931  *   ------------------- sp + cfg->arch.lmf_offset
4932  *      saved registers         s0-s8
4933  *   ------------------- sp + cfg->arch.iregs_offset
4934  *      locals
4935  *   ------------------- sp + cfg->param_area
4936  *      param area              outgoing
4937  *   ------------------- sp + MIPS_STACK_PARAM_OFFSET
4938  *      a0-a3                   outgoing
4939  *   ------------------- sp
4940  *      red zone
4941  */
4942 guint8 *
4943 mono_arch_emit_prolog (MonoCompile *cfg)
4944 {
4945         MonoMethod *method = cfg->method;
4946         MonoMethodSignature *sig;
4947         MonoInst *inst;
4948         int alloc_size, pos, i, max_offset;
4949         int alloc2_size = 0;
4950         guint8 *code;
4951         CallInfo *cinfo;
4952         int tracing = 0;
4953         guint32 iregs_to_save = 0;
4954 #if SAVE_FP_REGS
4955         guint32 fregs_to_save = 0;
4956 #endif
4957         /* lmf_offset is the offset of the LMF from our stack pointer. */
4958         guint32 lmf_offset = cfg->arch.lmf_offset;
4959         int cfa_offset = 0;
4960         MonoBasicBlock *bb;
4961
4962         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4963                 tracing = 1;
4964
4965         if (tracing)
4966                 cfg->flags |= MONO_CFG_HAS_CALLS;
4967         
4968         sig = mono_method_signature (method);
4969         cfg->code_size = 768 + sig->param_count * 20;
4970         code = cfg->native_code = g_malloc (cfg->code_size);
4971
4972         /* 
4973          * compute max_offset in order to use short forward jumps.
4974          */
4975         max_offset = 0;
4976         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4977                 MonoInst *ins = bb->code;
4978                 bb->max_offset = max_offset;
4979
4980                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4981                         max_offset += 6; 
4982
4983                 MONO_BB_FOR_EACH_INS (bb, ins)
4984                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4985         }
4986         if (max_offset > 0xffff)
4987                 cfg->arch.long_branch = TRUE;
4988
4989         /*
4990          * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4991          * This means that we have to adjust the offsets inside instructions which reference
4992          * arguments received on the stack, since the initial offset doesn't take into
4993          * account spill slots.
4994          */
4995         mips_adjust_stackframe (cfg);
4996
4997         /* Offset between current sp and the CFA */
4998         cfa_offset = 0;
4999         mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
5000
5001         /* stack_offset should not be changed here. */
5002         alloc_size = cfg->stack_offset;
5003         cfg->stack_usage = alloc_size;
5004
5005         iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5006 #if SAVE_FP_REGS
5007 #if 0
5008         fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5009 #else
5010         fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
5011         fregs_to_save |= (fregs_to_save << 1);
5012 #endif
5013 #endif
5014         /* If the stack size is too big, save 1024 bytes to start with
5015          * so the prologue can use imm16(reg) addressing, then allocate
5016          * the rest of the frame.
5017          */
5018         if (alloc_size > ((1 << 15) - 1024)) {
5019                 alloc2_size = alloc_size - 1024;
5020                 alloc_size = 1024;
5021         }
5022         if (alloc_size) {
5023                 g_assert (mips_is_imm16 (-alloc_size));
5024                 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
5025                 cfa_offset = alloc_size;
5026                 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5027         }
5028
5029         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5030                 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5031                 if (mips_is_imm16(offset))
5032                         mips_sw (code, mips_ra, mips_sp, offset);
5033                 else {
5034                         g_assert_not_reached ();
5035                 }
5036                 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5037                 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5038         }
5039
5040         /* XXX - optimize this later to not save all regs if LMF constructed */
5041         pos = cfg->arch.iregs_offset - alloc2_size;
5042
5043         if (iregs_to_save) {
5044                 /* save used registers in own stack frame (at pos) */
5045                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5046                         if (iregs_to_save & (1 << i)) {
5047                                 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5048                                 g_assert (mips_is_imm16(pos));
5049                                 MIPS_SW (code, i, mips_sp, pos);
5050                                 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5051                                 pos += SIZEOF_REGISTER;
5052                         }
5053                 }
5054         }
5055
5056         // FIXME: Don't save registers twice if there is an LMF
5057         // s8 has to be special cased since it is overwritten with the updated value
5058         // below
5059         if (method->save_lmf) {
5060                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5061                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5062                         g_assert (mips_is_imm16(offset));
5063                         if (MIPS_LMF_IREGMASK & (1 << i))
5064                                 MIPS_SW (code, i, mips_sp, offset);
5065                 }
5066         }
5067
5068 #if SAVE_FP_REGS
5069         /* Save float registers */
5070         if (fregs_to_save) {
5071                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5072                         if (fregs_to_save & (1 << i)) {
5073                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5074                                 g_assert (mips_is_imm16(pos));
5075                                 mips_swc1 (code, i, mips_sp, pos);
5076                                 pos += sizeof (gulong);
5077                         }
5078                 }
5079         }
5080
5081         if (method->save_lmf) {
5082                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5083                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5084                         g_assert (mips_is_imm16(offset));
5085                         mips_swc1 (code, i, mips_sp, offset);
5086                 }
5087         }
5088
5089 #endif
5090         if (cfg->frame_reg != mips_sp) {
5091                 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5092                 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5093
5094                 if (method->save_lmf) {
5095                         int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5096                         g_assert (mips_is_imm16(offset));
5097                         MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5098                 }
5099         }
5100
5101         /* store runtime generic context */
5102         if (cfg->rgctx_var) {
5103                 MonoInst *ins = cfg->rgctx_var;
5104
5105                 g_assert (ins->opcode == OP_REGOFFSET);
5106
5107                 g_assert (mips_is_imm16 (ins->inst_offset));
5108                 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5109         }
5110
5111         /* load arguments allocated to register from the stack */
5112         pos = 0;
5113
5114         if (!cfg->arch.cinfo)
5115                 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
5116         cinfo = cfg->arch.cinfo;
5117
5118         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5119                 ArgInfo *ainfo = &cinfo->ret;
5120                 inst = cfg->vret_addr;
5121                 if (inst->opcode == OP_REGVAR)
5122                         MIPS_MOVE (code, inst->dreg, ainfo->reg);
5123                 else if (mips_is_imm16 (inst->inst_offset)) {
5124                         mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5125                 } else {
5126                         mips_load_const (code, mips_at, inst->inst_offset);
5127                         mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5128                         mips_sw (code, ainfo->reg, mips_at, 0);
5129                 }
5130         }
5131
5132         if (sig->call_convention == MONO_CALL_VARARG) {
5133                 ArgInfo *cookie = &cinfo->sig_cookie;
5134                 int offset = alloc_size + cookie->offset;
5135
5136                 /* Save the sig cookie address */
5137                 g_assert (cookie->storage == ArgOnStack);
5138
5139                 g_assert (mips_is_imm16(offset));
5140                 mips_addi (code, mips_at, cfg->frame_reg, offset);
5141                 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5142         }
5143
5144         /* Keep this in sync with emit_load_volatile_arguments */
5145         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5146                 ArgInfo *ainfo = cinfo->args + i;
5147                 inst = cfg->args [pos];
5148                 
5149                 if (cfg->verbose_level > 2)
5150                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5151                 if (inst->opcode == OP_REGVAR) {
5152                         /* Argument ends up in a register */
5153                         if (ainfo->storage == ArgInIReg)
5154                                 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5155                         else if (ainfo->storage == ArgInFReg) {
5156                                 g_assert_not_reached();
5157 #if 0
5158                                 ppc_fmr (code, inst->dreg, ainfo->reg);
5159 #endif
5160                         }
5161                         else if (ainfo->storage == ArgOnStack) {
5162                                 int offset = cfg->stack_usage + ainfo->offset;
5163                                 g_assert (mips_is_imm16(offset));
5164                                 mips_lw (code, inst->dreg, mips_sp, offset);
5165                         } else
5166                                 g_assert_not_reached ();
5167
5168                         if (cfg->verbose_level > 2)
5169                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5170                 } else {
5171                         /* Argument ends up on the stack */
5172                         if (ainfo->storage == ArgInIReg) {
5173                                 int basereg_offset;
5174                                 /* Incoming parameters should be above this frame */
5175                                 if (cfg->verbose_level > 2)
5176                                         g_print ("stack slot at %d of %d+%d\n",
5177                                                  inst->inst_offset, alloc_size, alloc2_size);
5178                                 /* g_assert (inst->inst_offset >= alloc_size); */
5179                                 g_assert (inst->inst_basereg == cfg->frame_reg);
5180                                 basereg_offset = inst->inst_offset - alloc2_size;
5181                                 g_assert (mips_is_imm16 (basereg_offset));
5182                                 switch (ainfo->size) {
5183                                 case 1:
5184                                         mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5185                                         break;
5186                                 case 2:
5187                                         mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5188                                         break;
5189                                 case 0: /* XXX */
5190                                 case 4:
5191                                         mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5192                                         break;
5193                                 case 8:
5194 #if (SIZEOF_REGISTER == 4)
5195                                         mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5196                                         mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5197 #elif (SIZEOF_REGISTER == 8)
5198                                         mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5199 #endif
5200                                         break;
5201                                 default:
5202                                         g_assert_not_reached ();
5203                                         break;
5204                                 }
5205                         } else if (ainfo->storage == ArgOnStack) {
5206                                 /*
5207                                  * Argument comes in on the stack, and ends up on the stack
5208                                  * 1 and 2 byte args are passed as 32-bit quantities, but used as
5209                                  * 8 and 16 bit quantities.  Shorten them in place.
5210                                  */
5211                                 g_assert (mips_is_imm16 (inst->inst_offset));
5212                                 switch (ainfo->size) {
5213                                 case 1:
5214                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5215                                         mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5216                                         break;
5217                                 case 2:
5218                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5219                                         mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5220                                         break;
5221                                 case 0: /* XXX */
5222                                 case 4:
5223                                 case 8:
5224                                         break;
5225                                 default:
5226                                         g_assert_not_reached ();
5227                                 }
5228                         } else if (ainfo->storage == ArgInFReg) {
5229                                 g_assert (mips_is_imm16 (inst->inst_offset));
5230                                 g_assert (mips_is_imm16 (inst->inst_offset+4));
5231                                 if (ainfo->size == 8) {
5232 #if _MIPS_SIM == _ABIO32
5233                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5234                                         mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5235 #elif _MIPS_SIM == _ABIN32
5236                                         mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5237 #endif
5238                                 }
5239                                 else if (ainfo->size == 4)
5240                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5241                                 else
5242                                         g_assert_not_reached ();
5243                         } else if (ainfo->storage == ArgStructByVal) {
5244                                 int i;
5245                                 int doffset = inst->inst_offset;
5246
5247                                 g_assert (mips_is_imm16 (inst->inst_offset));
5248                                 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5249                                 /* Push the argument registers into their stack slots */
5250                                 for (i = 0; i < ainfo->size; ++i) {
5251                                         g_assert (mips_is_imm16(doffset));
5252                                         MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5253                                         doffset += SIZEOF_REGISTER;
5254                                 }
5255                         } else if (ainfo->storage == ArgStructByAddr) {
5256                                 g_assert (mips_is_imm16 (inst->inst_offset));
5257                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5258                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5259                         } else
5260                                 g_assert_not_reached ();
5261                 }
5262                 pos++;
5263         }
5264
5265         if (method->save_lmf) {
5266                 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5267                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5268
5269                 if (lmf_pthread_key != -1) {
5270                         g_assert_not_reached();
5271 #if 0
5272                         emit_tls_access (code, mips_temp, lmf_pthread_key);
5273 #endif
5274                         if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5275                                 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5276                                 g_assert (mips_is_imm16(offset));
5277                                 mips_addiu (code, mips_a0, mips_temp, offset);
5278                         }
5279                 } else {
5280                         /* This can/will clobber the a0-a3 registers */
5281                         mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5282                 }
5283
5284                 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5285                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5286                 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5287                 /* new_lmf->previous_lmf = *lmf_addr */
5288                 mips_lw (code, mips_at, mips_v0, 0);
5289                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5290                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5291                 /* *(lmf_addr) = sp + lmf_offset */
5292                 g_assert (mips_is_imm16(lmf_offset));
5293                 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5294                 mips_sw (code, mips_at, mips_v0, 0);
5295
5296                 /* save method info */
5297                 mips_load_const (code, mips_at, method);
5298                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5299                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5300
5301                 /* save the current IP */
5302                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5303                 mips_load_const (code, mips_at, 0x01010101);
5304                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5305         }
5306
5307         if (alloc2_size) {
5308                 if (mips_is_imm16 (-alloc2_size)) {
5309                         mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5310                 }
5311                 else {
5312                         mips_load_const (code, mips_at, -alloc2_size);
5313                         mips_addu (code, mips_sp, mips_sp, mips_at);
5314                 }
5315                 alloc_size += alloc2_size;
5316                 cfa_offset += alloc2_size;
5317                 if (cfg->frame_reg != mips_sp)
5318                         MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5319                 else
5320                         mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5321         }
5322
5323         if (tracing) {
5324 #if _MIPS_SIM == _ABIO32
5325                 cfg->arch.tracing_offset = cfg->stack_offset;
5326 #elif _MIPS_SIM == _ABIN32
5327                 /* no stack slots by default for argument regs, reserve a special block */
5328                 g_assert_not_reached ();
5329 #endif
5330                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5331         }
5332
5333         cfg->code_len = code - cfg->native_code;
5334         g_assert (cfg->code_len < cfg->code_size);
5335
5336         return code;
5337 }
5338
5339 enum {
5340         SAVE_NONE,
5341         SAVE_STRUCT,
5342         SAVE_ONE,
5343         SAVE_TWO,
5344         SAVE_FP
5345 };
5346
5347 void*
5348 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5349 {
5350         guchar *code = p;
5351         int save_mode = SAVE_NONE;
5352         int offset;
5353         MonoMethod *method = cfg->method;
5354         int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5355         int save_offset = MIPS_STACK_PARAM_OFFSET;
5356
5357         g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5358         
5359         offset = code - cfg->native_code;
5360         /* we need about 16 instructions */
5361         if (offset > (cfg->code_size - 16 * 4)) {
5362                 cfg->code_size *= 2;
5363                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5364                 code = cfg->native_code + offset;
5365         }
5366         mips_nop (code);
5367         mips_nop (code);
5368         switch (rtype) {
5369         case MONO_TYPE_VOID:
5370                 /* special case string .ctor icall */
5371                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5372                         save_mode = SAVE_ONE;
5373                 else
5374                         save_mode = SAVE_NONE;
5375                 break;
5376         case MONO_TYPE_R4:
5377         case MONO_TYPE_R8:
5378                 save_mode = SAVE_FP;
5379                 break;
5380         case MONO_TYPE_VALUETYPE:
5381                 save_mode = SAVE_STRUCT;
5382                 break;
5383         case MONO_TYPE_I8:
5384         case MONO_TYPE_U8:
5385 #if SIZEOF_REGISTER == 4
5386                 save_mode = SAVE_TWO;
5387 #elif SIZEOF_REGISTER == 8
5388                 save_mode = SAVE_ONE;
5389 #endif
5390                 break;
5391         default:
5392                 save_mode = SAVE_ONE;
5393                 break;
5394         }
5395
5396         mips_addiu (code, mips_sp, mips_sp, -32);
5397         g_assert (mips_is_imm16(save_offset));
5398         switch (save_mode) {
5399         case SAVE_TWO:
5400                 mips_sw (code, mips_v0, mips_sp, save_offset);
5401                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5402                 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5403                 if (enable_arguments) {
5404                         MIPS_MOVE (code, mips_a1, mips_v0);
5405                         MIPS_MOVE (code, mips_a2, mips_v1);
5406                 }
5407                 break;
5408         case SAVE_ONE:
5409                 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5410                 if (enable_arguments) {
5411                         MIPS_MOVE (code, mips_a1, mips_v0);
5412                 }
5413                 break;
5414         case SAVE_FP:
5415                 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5416                 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5417                 mips_lw (code, mips_a0, mips_sp, save_offset);
5418                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5419                 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5420                 break;
5421         case SAVE_STRUCT:
5422         case SAVE_NONE:
5423         default:
5424                 break;
5425         }
5426         mips_load_const (code, mips_a0, cfg->method);
5427         mips_call (code, mips_t9, func);
5428
5429         switch (save_mode) {
5430         case SAVE_TWO:
5431                 mips_lw (code, mips_v0, mips_sp, save_offset);
5432                 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5433                 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5434                 break;
5435         case SAVE_ONE:
5436                 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5437                 break;
5438         case SAVE_FP:
5439                 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5440                 break;
5441         case SAVE_STRUCT:
5442         case SAVE_NONE:
5443         default:
5444                 break;
5445         }
5446         mips_addiu (code, mips_sp, mips_sp, 32);
5447         mips_nop (code);
5448         mips_nop (code);
5449         return code;
5450 }
5451
5452 guint8 *
5453 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5454 {
5455         MonoMethod *method = cfg->method;
5456         int pos = 0, i;
5457         int max_epilog_size = 16 + 20*4;
5458         int alloc2_size = 0;
5459         guint32 iregs_to_restore;
5460 #if SAVE_FP_REGS
5461         guint32 fregs_to_restore;
5462 #endif
5463
5464         if (cfg->method->save_lmf)
5465                 max_epilog_size += 128;
5466         
5467         if (mono_jit_trace_calls != NULL)
5468                 max_epilog_size += 50;
5469
5470         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5471                 max_epilog_size += 50;
5472
5473         if (code)
5474                 pos = code - cfg->native_code;
5475         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5476                 cfg->code_size *= 2;
5477                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5478                 cfg->stat_code_reallocs++;
5479         }
5480
5481         /*
5482          * Keep in sync with OP_JMP
5483          */
5484         if (code)
5485                 code = cfg->native_code + pos;
5486         else
5487                 code = cfg->native_code + cfg->code_len;
5488
5489         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5490                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5491         }
5492         if (cfg->frame_reg != mips_sp) {
5493                 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5494         }
5495         /* If the stack frame is really large, deconstruct it in two steps */
5496         if (cfg->stack_usage > ((1 << 15) - 1024)) {
5497                 alloc2_size = cfg->stack_usage - 1024;
5498                 /* partially deconstruct the stack */
5499                 mips_load_const (code, mips_at, alloc2_size);
5500                 mips_addu (code, mips_sp, mips_sp, mips_at);
5501         }
5502         pos = cfg->arch.iregs_offset - alloc2_size;
5503         iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5504         if (iregs_to_restore) {
5505                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5506                         if (iregs_to_restore & (1 << i)) {
5507                                 g_assert (mips_is_imm16(pos));
5508                                 MIPS_LW (code, i, mips_sp, pos);
5509                                 pos += SIZEOF_REGISTER;
5510                         }
5511                 }
5512         }
5513
5514 #if SAVE_FP_REGS
5515 #if 0
5516         fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5517 #else
5518         fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5519         fregs_to_restore |= (fregs_to_restore << 1);
5520 #endif
5521         if (fregs_to_restore) {
5522                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5523                         if (fregs_to_restore & (1 << i)) {
5524                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5525                                 g_assert (mips_is_imm16(pos));
5526                                 mips_lwc1 (code, i, mips_sp, pos);
5527                                 pos += FREG_SIZE
5528                         }
5529                 }
5530         }
5531 #endif
5532
5533         /* Unlink the LMF if necessary */
5534         if (method->save_lmf) {
5535                 int lmf_offset = cfg->arch.lmf_offset;
5536
5537                 /* t0 = current_lmf->previous_lmf */
5538                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5539                 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5540                 /* t1 = lmf_addr */
5541                 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5542                 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5543                 /* (*lmf_addr) = previous_lmf */
5544                 mips_sw (code, mips_temp, mips_t1, 0);
5545         }
5546
5547 #if 0
5548         /* Restore the fp */
5549         mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5550 #endif
5551         /* Restore ra */
5552         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5553                 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5554                 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5555         }
5556         /* Restore the stack pointer */
5557         g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5558         mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5559
5560         /* Caller will emit either return or tail-call sequence */
5561
5562         cfg->code_len = code - cfg->native_code;
5563
5564         g_assert (cfg->code_len < cfg->code_size);
5565         return (code);
5566 }
5567
5568 void
5569 mono_arch_emit_epilog (MonoCompile *cfg)
5570 {
5571         guint8 *code;
5572
5573         code = mono_arch_emit_epilog_sub (cfg, NULL);
5574
5575         mips_jr (code, mips_ra);
5576         mips_nop (code);
5577
5578         cfg->code_len = code - cfg->native_code;
5579
5580         g_assert (cfg->code_len < cfg->code_size);
5581 }
5582
5583 /* remove once throw_exception_by_name is eliminated */
5584 #if 0
5585 static int
5586 exception_id_by_name (const char *name)
5587 {
5588         if (strcmp (name, "IndexOutOfRangeException") == 0)
5589                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5590         if (strcmp (name, "OverflowException") == 0)
5591                 return MONO_EXC_OVERFLOW;
5592         if (strcmp (name, "ArithmeticException") == 0)
5593                 return MONO_EXC_ARITHMETIC;
5594         if (strcmp (name, "DivideByZeroException") == 0)
5595                 return MONO_EXC_DIVIDE_BY_ZERO;
5596         if (strcmp (name, "InvalidCastException") == 0)
5597                 return MONO_EXC_INVALID_CAST;
5598         if (strcmp (name, "NullReferenceException") == 0)
5599                 return MONO_EXC_NULL_REF;
5600         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5601                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5602         if (strcmp (name, "ArgumentException") == 0)
5603                 return MONO_EXC_ARGUMENT;
5604         g_error ("Unknown intrinsic exception %s\n", name);
5605         return 0;
5606 }
5607 #endif
5608
5609 void
5610 mono_arch_emit_exceptions (MonoCompile *cfg)
5611 {
5612 #if 0
5613         MonoJumpInfo *patch_info;
5614         int i;
5615         guint8 *code;
5616         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5617         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5618         int max_epilog_size = 50;
5619
5620         /* count the number of exception infos */
5621      
5622         /* 
5623          * make sure we have enough space for exceptions
5624          * 24 is the simulated call to throw_exception_by_name
5625          */
5626         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5627 #if 0
5628                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5629                         i = exception_id_by_name (patch_info->data.target);
5630                         g_assert (i < MONO_EXC_INTRINS_NUM);
5631                         if (!exc_throw_found [i]) {
5632                                 max_epilog_size += 12;
5633                                 exc_throw_found [i] = TRUE;
5634                         }
5635                 }
5636 #endif
5637         }
5638
5639         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5640                 cfg->code_size *= 2;
5641                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5642                 cfg->stat_code_reallocs++;
5643         }
5644
5645         code = cfg->native_code + cfg->code_len;
5646
5647         /* add code to raise exceptions */
5648         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5649                 switch (patch_info->type) {
5650                 case MONO_PATCH_INFO_EXC: {
5651 #if 0
5652                         //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5653
5654                         i = exception_id_by_name (patch_info->data.target);
5655                         g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5656                         if (!exc_throw_pos [i]) {
5657                                 guint32 addr;
5658
5659                                 exc_throw_pos [i] = code;
5660                                 //g_print ("exc: writing stub at %p\n", code);
5661                                 mips_load_const (code, mips_a0, patch_info->data.target);
5662                                 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5663                                 mips_load_const (code, mips_t9, addr);
5664                                 mips_jr (code, mips_t9);
5665                                 mips_nop (code);
5666                         }
5667                         //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5668
5669                         /* Turn into a Relative patch, pointing at code stub */
5670                         patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5671                         patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5672 #else
5673                         g_assert_not_reached();
5674 #endif
5675                         break;
5676                 }
5677                 default:
5678                         /* do nothing */
5679                         break;
5680                 }
5681         }
5682
5683         cfg->code_len = code - cfg->native_code;
5684
5685         g_assert (cfg->code_len < cfg->code_size);
5686 #endif
5687 }
5688
5689 /*
5690  * Thread local storage support
5691  */
5692 static void
5693 setup_tls_access (void)
5694 {
5695         guint32 ptk;
5696         //guint32 *ins, *code;
5697
5698         if (tls_mode == TLS_MODE_FAILED)
5699                 return;
5700
5701         if (g_getenv ("MONO_NO_TLS")) {
5702                 tls_mode = TLS_MODE_FAILED;
5703                 return;
5704         }
5705
5706         if (tls_mode == TLS_MODE_DETECT) {
5707                 /* XXX */
5708                 tls_mode = TLS_MODE_FAILED;
5709                 return;
5710 #if 0
5711
5712                 ins = (guint32*)pthread_getspecific;
5713                 /* uncond branch to the real method */
5714                 if ((*ins >> 26) == 18) {
5715                         gint32 val;
5716                         val = (*ins & ~3) << 6;
5717                         val >>= 6;
5718                         if (*ins & 2) {
5719                                 /* absolute */
5720                                 ins = (guint32*)val;
5721                         } else {
5722                                 ins = (guint32*) ((char*)ins + val);
5723                         }
5724                 }
5725                 code = &cmplwi_1023;
5726                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5727                 code = &li_0x48;
5728                 ppc_li (code, ppc_r4, 0x48);
5729                 code = &blr_ins;
5730                 ppc_blr (code);
5731                 if (*ins == cmplwi_1023) {
5732                         int found_lwz_284 = 0;
5733                         for (ptk = 0; ptk < 20; ++ptk) {
5734                                 ++ins;
5735                                 if (!*ins || *ins == blr_ins)
5736                                         break;
5737                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5738                                         found_lwz_284 = 1;
5739                                         break;
5740                                 }
5741                         }
5742                         if (!found_lwz_284) {
5743                                 tls_mode = TLS_MODE_FAILED;
5744                                 return;
5745                         }
5746                         tls_mode = TLS_MODE_LTHREADS;
5747                 } else if (*ins == li_0x48) {
5748                         ++ins;
5749                         /* uncond branch to the real method */
5750                         if ((*ins >> 26) == 18) {
5751                                 gint32 val;
5752                                 val = (*ins & ~3) << 6;
5753                                 val >>= 6;
5754                                 if (*ins & 2) {
5755                                         /* absolute */
5756                                         ins = (guint32*)val;
5757                                 } else {
5758                                         ins = (guint32*) ((char*)ins + val);
5759                                 }
5760                                 code = &val;
5761                                 ppc_li (code, ppc_r0, 0x7FF2);
5762                                 if (ins [1] == val) {
5763                                         /* Darwin on G4, implement */
5764                                         tls_mode = TLS_MODE_FAILED;
5765                                         return;
5766                                 } else {
5767                                         code = &val;
5768                                         ppc_mfspr (code, ppc_r3, 104);
5769                                         if (ins [1] != val) {
5770                                                 tls_mode = TLS_MODE_FAILED;
5771                                                 return;
5772                                         }
5773                                         tls_mode = TLS_MODE_DARWIN_G5;
5774                                 }
5775                         } else {
5776                                 tls_mode = TLS_MODE_FAILED;
5777                                 return;
5778                         }
5779                 } else {
5780                         tls_mode = TLS_MODE_FAILED;
5781                         return;
5782                 }
5783 #endif
5784         }
5785         if (lmf_pthread_key == -1) {
5786                 ptk = mono_jit_tls_id;
5787                 if (ptk < 1024) {
5788                         /*g_print ("MonoLMF at: %d\n", ptk);*/
5789                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5790                                 init_tls_failed = 1;
5791                                 return;
5792                         }*/
5793                         lmf_pthread_key = ptk;
5794                 }
5795         }
5796         if (monothread_key == -1) {
5797                 ptk = mono_thread_get_tls_key ();
5798                 if (ptk < 1024) {
5799                         monothread_key = ptk;
5800                         /*g_print ("thread inited: %d\n", ptk);*/
5801                 } else {
5802                         /*g_print ("thread not inited yet %d\n", ptk);*/
5803                 }
5804         }
5805 }
5806
5807 void
5808 mono_arch_finish_init (void)
5809 {
5810         setup_tls_access ();
5811 }
5812
5813 void
5814 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5815 {
5816 }
5817
5818 void
5819 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5820 {
5821         int this_dreg = mips_a0;
5822         
5823         if (vt_reg != -1)
5824                 this_dreg = mips_a1;
5825
5826         /* add the this argument */
5827         if (this_reg != -1) {
5828                 MonoInst *this_ins;
5829                 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5830                 this_ins->type = this_type;
5831                 this_ins->sreg1 = this_reg;
5832                 this_ins->dreg = mono_alloc_ireg (cfg);
5833                 mono_bblock_add_inst (cfg->cbb, this_ins);
5834                 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5835         }
5836
5837         if (vt_reg != -1) {
5838                 MonoInst *vtarg;
5839                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5840                 vtarg->type = STACK_MP;
5841                 vtarg->sreg1 = vt_reg;
5842                 vtarg->dreg = mono_alloc_ireg (cfg);
5843                 mono_bblock_add_inst (cfg->cbb, vtarg);
5844                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5845         }
5846 }
5847
5848 MonoInst*
5849 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5850 {
5851         MonoInst *ins = NULL;
5852
5853         return ins;
5854 }
5855
5856 MonoInst*
5857 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5858 {
5859         return NULL;
5860 }
5861
5862 gboolean
5863 mono_arch_print_tree (MonoInst *tree, int arity)
5864 {
5865         return 0;
5866 }
5867
5868 mgreg_t
5869 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5870 {
5871         return ctx->sc_regs [reg];
5872 }
5873
5874 #define ENABLE_WRONG_METHOD_CHECK 0
5875
5876 #define MIPS_LOAD_SEQUENCE_LENGTH       8
5877 #define CMP_SIZE                        (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5878 #define BR_SIZE                         8
5879 #define LOADSTORE_SIZE                  4
5880 #define JUMP_IMM_SIZE                   16
5881 #define JUMP_IMM32_SIZE                 (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5882 #define LOAD_CONST_SIZE                 8
5883 #define JUMP_JR_SIZE                    8
5884
5885 /*
5886  * LOCKING: called with the domain lock held
5887  */
5888 gpointer
5889 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5890         gpointer fail_tramp)
5891 {
5892         int i;
5893         int size = 0;
5894         guint8 *code, *start, *patch;
5895
5896         for (i = 0; i < count; ++i) {
5897                 MonoIMTCheckItem *item = imt_entries [i];
5898
5899                 if (item->is_equals) {
5900                         if (item->check_target_idx) {
5901                                 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5902                                 if (item->has_target_code)
5903                                         item->chunk_size += LOAD_CONST_SIZE;
5904                                 else
5905                                         item->chunk_size += LOADSTORE_SIZE;
5906                         } else {
5907                                 if (fail_tramp) {
5908                                         item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5909                                                 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5910                                         if (!item->has_target_code)
5911                                                 item->chunk_size += LOADSTORE_SIZE;
5912                                 } else {
5913                                         item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5914 #if ENABLE_WRONG_METHOD_CHECK
5915                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5916 #endif
5917                                 }
5918                         }
5919                 } else {
5920                         item->chunk_size += CMP_SIZE + BR_SIZE;
5921                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5922                 }
5923                 size += item->chunk_size;
5924         }
5925         /* the initial load of the vtable address */
5926         size += MIPS_LOAD_SEQUENCE_LENGTH;
5927         if (fail_tramp) {
5928                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5929         } else {
5930                 code = mono_domain_code_reserve (domain, size);
5931         }
5932         start = code;
5933
5934         /* t7 points to the vtable */
5935         mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5936
5937         for (i = 0; i < count; ++i) {
5938                 MonoIMTCheckItem *item = imt_entries [i];
5939
5940                 item->code_target = code;
5941                 if (item->is_equals) {
5942                         if (item->check_target_idx) {
5943                                 mips_load_const (code, mips_temp, (gsize)item->key);
5944                                 item->jmp_code = code;
5945                                 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5946                                 mips_nop (code);
5947                                 if (item->has_target_code) {
5948                                         mips_load_const (code, mips_t9,
5949                                                          item->value.target_code);
5950                                 }
5951                                 else {
5952                                         mips_lw (code, mips_t9, mips_t7,
5953                                                 (sizeof (gpointer) * item->value.vtable_slot));
5954                                 }
5955                                 mips_jr (code, mips_t9);
5956                                 mips_nop (code);
5957                         } else {
5958                                 if (fail_tramp) {
5959                                         mips_load_const (code, mips_temp, (gsize)item->key);
5960                                         patch = code;
5961                                         mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5962                                         mips_nop (code);
5963                                         if (item->has_target_code) {
5964                                                 mips_load_const (code, mips_t9,
5965                                                                  item->value.target_code);
5966                                         } else {
5967                                                 g_assert (vtable);
5968                                                 mips_load_const (code, mips_at,
5969                                                                  & (vtable->vtable [item->value.vtable_slot]));
5970                                                 mips_lw (code, mips_t9, mips_at, 0);
5971                                         }
5972                                         mips_jr (code, mips_t9);
5973                                         mips_nop (code);
5974                                         mips_patch ((guint32 *)(void *)patch, (guint32)code);
5975                                         mips_load_const (code, mips_t9, fail_tramp);
5976                                         mips_jr (code, mips_t9);
5977                                         mips_nop (code);
5978                                 } else {
5979                                         /* enable the commented code to assert on wrong method */
5980 #if ENABLE_WRONG_METHOD_CHECK
5981                                         ppc_load (code, ppc_r0, (guint32)item->key);
5982                                         ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5983                                         patch = code;
5984                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5985 #endif
5986                                         mips_lw (code, mips_t9, mips_t7,
5987                                                  (sizeof (gpointer) * item->value.vtable_slot));
5988                                         mips_jr (code, mips_t9);
5989                                         mips_nop (code);
5990
5991 #if ENABLE_WRONG_METHOD_CHECK
5992                                         ppc_patch (patch, code);
5993                                         ppc_break (code);
5994 #endif
5995                                 }
5996                         }
5997                 } else {
5998                         mips_load_const (code, mips_temp, (gulong)item->key);
5999                         mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
6000
6001                         item->jmp_code = code;
6002                         mips_beq (code, mips_temp, mips_zero, 0);
6003                         mips_nop (code);
6004                 }
6005         }
6006         /* patch the branches to get to the target items */
6007         for (i = 0; i < count; ++i) {
6008                 MonoIMTCheckItem *item = imt_entries [i];
6009                 if (item->jmp_code && item->check_target_idx) {
6010                         mips_patch ((guint32 *)item->jmp_code,
6011                                    (guint32)imt_entries [item->check_target_idx]->code_target);
6012                 }
6013         }
6014
6015         if (!fail_tramp)
6016                 mono_stats.imt_thunks_size += code - start;
6017         g_assert (code - start <= size);
6018         mono_arch_flush_icache (start, size);
6019
6020         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
6021
6022         return start;
6023 }
6024
6025 MonoMethod*
6026 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6027 {
6028         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6029 }
6030
6031 MonoVTable*
6032 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6033 {
6034         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6035 }
6036
6037 /* Soft Debug support */
6038 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6039
6040 /*
6041  * mono_arch_set_breakpoint:
6042  *
6043  *   See mini-amd64.c for docs.
6044  */
6045 void
6046 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6047 {
6048         guint8 *code = ip;
6049         guint32 addr = (guint32)bp_trigger_page;
6050
6051         mips_load_const (code, mips_t9, addr);
6052         mips_lw (code, mips_t9, mips_t9, 0);
6053
6054         mono_arch_flush_icache (ip, code - ip);
6055 }
6056
6057 /*
6058  * mono_arch_clear_breakpoint:
6059  *
6060  *   See mini-amd64.c for docs.
6061  */
6062 void
6063 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6064 {
6065         guint8 *code = ip;
6066
6067         mips_nop (code);
6068         mips_nop (code);
6069         mips_nop (code);
6070
6071         mono_arch_flush_icache (ip, code - ip);
6072 }
6073         
6074 /*
6075  * mono_arch_start_single_stepping:
6076  *
6077  *   See mini-amd64.c for docs.
6078  */
6079 void
6080 mono_arch_start_single_stepping (void)
6081 {
6082         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6083 }
6084         
6085 /*
6086  * mono_arch_stop_single_stepping:
6087  *
6088  *   See mini-amd64.c for docs.
6089  */
6090 void
6091 mono_arch_stop_single_stepping (void)
6092 {
6093         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6094 }
6095
6096 /*
6097  * mono_arch_is_single_step_event:
6098  *
6099  *   See mini-amd64.c for docs.
6100  */
6101 gboolean
6102 mono_arch_is_single_step_event (void *info, void *sigctx)
6103 {
6104         siginfo_t* sinfo = (siginfo_t*) info;
6105         /* Sometimes the address is off by 4 */
6106         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6107                 return TRUE;
6108         else
6109                 return FALSE;
6110 }
6111
6112 /*
6113  * mono_arch_is_breakpoint_event:
6114  *
6115  *   See mini-amd64.c for docs.
6116  */
6117 gboolean
6118 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6119 {
6120         siginfo_t* sinfo = (siginfo_t*) info;
6121         /* Sometimes the address is off by 4 */
6122         if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6123                 return TRUE;
6124         else
6125                 return FALSE;
6126 }
6127
6128 /*
6129  * mono_arch_skip_breakpoint:
6130  *
6131  *   See mini-amd64.c for docs.
6132  */
6133 void
6134 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6135 {
6136         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6137 }
6138
6139 /*
6140  * mono_arch_skip_single_step:
6141  *
6142  *   See mini-amd64.c for docs.
6143  */
6144 void
6145 mono_arch_skip_single_step (MonoContext *ctx)
6146 {
6147         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6148 }
6149
6150 /*
6151  * mono_arch_get_seq_point_info:
6152  *
6153  *   See mini-amd64.c for docs.
6154  */
6155 gpointer
6156 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6157 {
6158         NOT_IMPLEMENTED;
6159         return NULL;
6160 }
6161
6162 void
6163 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6164 {
6165         ext->lmf.previous_lmf = prev_lmf;
6166         /* Mark that this is a MonoLMFExt */
6167         ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6168         ext->lmf.iregs [mips_sp] = (gssize)ext;
6169 }
6170
6171 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
6172
6173 gboolean
6174 mono_arch_opcode_supported (int opcode)
6175 {
6176         return FALSE;
6177 }