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