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