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