New test.
[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 = cfg->header;
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                         /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3817                         mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3818                         break;
3819                 case OP_LABEL:
3820                         ins->inst_c0 = code - cfg->native_code;
3821                         break;
3822                 case OP_BR:
3823                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3824 #if LONG_BRANCH
3825                         mips_lui (code, mips_at, mips_zero, 0);
3826                         mips_addiu (code, mips_at, mips_at, 0);
3827                         mips_jr (code, mips_at);
3828                         mips_nop (code);
3829 #else
3830                         mips_beq (code, mips_zero, mips_zero, 0);
3831                         mips_nop (code);
3832 #endif
3833                         break;
3834                 case OP_BR_REG:
3835                         mips_jr (code, ins->sreg1);
3836                         mips_nop (code);
3837                         break;
3838                 case OP_SWITCH: {
3839                         int i;
3840
3841                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
3842                         if (offset > (cfg->code_size - max_len - 16)) {
3843                                 cfg->code_size += max_len;
3844                                 cfg->code_size *= 2;
3845                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3846                                 code = cfg->native_code + offset;
3847                         }
3848                         g_assert (ins->sreg1 != -1);
3849                         mips_sll (code, mips_at, ins->sreg1, 2);
3850                         if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3851                                 MIPS_MOVE (code, mips_t8, mips_ra);
3852                         mips_bgezal (code, mips_zero, 1);       /* bal */
3853                         mips_nop (code);
3854                         mips_addu (code, mips_t9, mips_ra, mips_at);
3855                         /* Table is 16 or 20 bytes from target of bal above */
3856                         if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3857                                 MIPS_MOVE (code, mips_ra, mips_t8);
3858                                 mips_lw (code, mips_t9, mips_t9, 20);
3859                         }
3860                         else
3861                                 mips_lw (code, mips_t9, mips_t9, 16);
3862                         mips_jalr (code, mips_t9, mips_t8);
3863                         mips_nop (code);
3864                         for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3865                                 mips_emit32 (code, 0xfefefefe);
3866                         break;
3867                 }
3868                 case OP_CEQ:
3869                 case OP_ICEQ:
3870                         mips_addiu (code, ins->dreg, mips_zero, 1);
3871                         mips_beq (code, mips_at, mips_zero, 2);
3872                         mips_nop (code);
3873                         MIPS_MOVE (code, ins->dreg, mips_zero);
3874                         break;
3875                 case OP_CLT:
3876                 case OP_CLT_UN:
3877                 case OP_ICLT:
3878                 case OP_ICLT_UN:
3879                         mips_addiu (code, ins->dreg, mips_zero, 1);
3880                         mips_bltz (code, mips_at, 2);
3881                         mips_nop (code);
3882                         MIPS_MOVE (code, ins->dreg, mips_zero);
3883                         break;
3884                 case OP_CGT:
3885                 case OP_CGT_UN:
3886                 case OP_ICGT:
3887                 case OP_ICGT_UN:
3888                         mips_addiu (code, ins->dreg, mips_zero, 1);
3889                         mips_bgtz (code, mips_at, 2);
3890                         mips_nop (code);
3891                         MIPS_MOVE (code, ins->dreg, mips_zero);
3892                         break;
3893
3894                 case OP_MIPS_COND_EXC_EQ:
3895                 case OP_MIPS_COND_EXC_GE:
3896                 case OP_MIPS_COND_EXC_GT:
3897                 case OP_MIPS_COND_EXC_LE:
3898                 case OP_MIPS_COND_EXC_LT:
3899                 case OP_MIPS_COND_EXC_NE_UN:
3900                 case OP_MIPS_COND_EXC_GE_UN:
3901                 case OP_MIPS_COND_EXC_GT_UN:
3902                 case OP_MIPS_COND_EXC_LE_UN:
3903                 case OP_MIPS_COND_EXC_LT_UN:
3904
3905                 case OP_MIPS_COND_EXC_OV:
3906                 case OP_MIPS_COND_EXC_NO:
3907                 case OP_MIPS_COND_EXC_C:
3908                 case OP_MIPS_COND_EXC_NC:
3909
3910                 case OP_MIPS_COND_EXC_IEQ:
3911                 case OP_MIPS_COND_EXC_IGE:
3912                 case OP_MIPS_COND_EXC_IGT:
3913                 case OP_MIPS_COND_EXC_ILE:
3914                 case OP_MIPS_COND_EXC_ILT:
3915                 case OP_MIPS_COND_EXC_INE_UN:
3916                 case OP_MIPS_COND_EXC_IGE_UN:
3917                 case OP_MIPS_COND_EXC_IGT_UN:
3918                 case OP_MIPS_COND_EXC_ILE_UN:
3919                 case OP_MIPS_COND_EXC_ILT_UN:
3920
3921                 case OP_MIPS_COND_EXC_IOV:
3922                 case OP_MIPS_COND_EXC_INO:
3923                 case OP_MIPS_COND_EXC_IC:
3924                 case OP_MIPS_COND_EXC_INC: {
3925                         guint32 *skip;
3926                         guint32 *throw;
3927
3928                         /* If the condition is true, raise the exception */
3929
3930                         /* need to reverse test to skip around exception raising */
3931
3932                         /* For the moment, branch around a branch to avoid reversing
3933                            the tests. */
3934
3935                         /* Remember, an unpatched branch to 0 branches to the delay slot */
3936                         switch (ins->opcode) {
3937                         case OP_MIPS_COND_EXC_EQ:
3938                                 throw = (guint32 *)(void *)code;
3939                                 mips_beq (code, ins->sreg1, ins->sreg2, 0);
3940                                 mips_nop (code);
3941                                 break;
3942
3943                         case OP_MIPS_COND_EXC_NE_UN:
3944                                 throw = (guint32 *)(void *)code;
3945                                 mips_bne (code, ins->sreg1, ins->sreg2, 0);
3946                                 mips_nop (code);
3947                                 break;
3948
3949                         case OP_MIPS_COND_EXC_LE_UN:
3950                                 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
3951                                 throw = (guint32 *)(void *)code;
3952                                 mips_blez (code, mips_at, 0);
3953                                 mips_nop (code);
3954                                 break;
3955
3956                         case OP_MIPS_COND_EXC_GT:
3957                                 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
3958                                 throw = (guint32 *)(void *)code;
3959                                 mips_bne (code, mips_at, mips_zero, 0);
3960                                 mips_nop (code);
3961                                 break;
3962
3963                         case OP_MIPS_COND_EXC_GT_UN:
3964                                 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
3965                                 throw = (guint32 *)(void *)code;
3966                                 mips_bne (code, mips_at, mips_zero, 0);
3967                                 mips_nop (code);
3968                                 break;
3969
3970                         case OP_MIPS_COND_EXC_LT:
3971                                 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
3972                                 throw = (guint32 *)(void *)code;
3973                                 mips_bne (code, mips_at, mips_zero, 0);
3974                                 mips_nop (code);
3975                                 break;
3976
3977                         case OP_MIPS_COND_EXC_LT_UN:
3978                                 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
3979                                 throw = (guint32 *)(void *)code;
3980                                 mips_bne (code, mips_at, mips_zero, 0);
3981                                 mips_nop (code);
3982                                 break;
3983
3984                         default:
3985                                 /* Not yet implemented */
3986                                 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
3987                                 g_assert_not_reached ();
3988                         }
3989                         skip = (guint32 *)(void *)code;
3990                         mips_beq (code, mips_zero, mips_zero, 0);
3991                         mips_nop (code);
3992                         mips_patch (throw, (guint32)code);
3993                         code = mips_emit_exc_by_name (code, ins->inst_p1);
3994                         mips_patch (skip, (guint32)code);
3995                         cfg->bb_exit->max_offset += 24;
3996                         break;
3997                 }
3998                 case OP_MIPS_BEQ:
3999                 case OP_MIPS_BNE:
4000                 case OP_MIPS_BGEZ:
4001                 case OP_MIPS_BGTZ:
4002                 case OP_MIPS_BLEZ:
4003                 case OP_MIPS_BLTZ:
4004                         code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4005                         break;
4006
4007                 /* floating point opcodes */
4008                 case OP_R8CONST:
4009 #if 0
4010                         if (((guint32)ins->inst_p0) & (1 << 15))
4011                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4012                         else
4013                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4014                         mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4015 #else
4016                         mips_load_const (code, mips_at, ins->inst_p0);
4017                         mips_lwc1 (code, ins->dreg, mips_at, 4);
4018                         mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4019 #endif
4020                         break;
4021                 case OP_R4CONST:
4022                         if (((guint32)ins->inst_p0) & (1 << 15))
4023                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4024                         else
4025                                 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4026                         mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4027 #if PROMOTE_R4_TO_R8
4028                         mips_cvtds (code, ins->dreg, ins->dreg);
4029 #endif
4030                         break;
4031                 case OP_STORER8_MEMBASE_REG:
4032                         if (mips_is_imm16 (ins->inst_offset)) {
4033 #if _MIPS_SIM == _ABIO32
4034                                 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
4035                                 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
4036 #elif _MIPS_SIM == _ABIN32
4037                                 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4038 #endif
4039                         } else {
4040                                 mips_load_const (code, mips_at, ins->inst_offset);
4041                                 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4042                                 mips_swc1 (code, ins->sreg1, mips_at, 4);
4043                                 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
4044                         }
4045                         break;
4046                 case OP_LOADR8_MEMBASE:
4047                         if (mips_is_imm16 (ins->inst_offset)) {
4048 #if _MIPS_SIM == _ABIO32
4049                                 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
4050                                 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
4051 #elif _MIPS_SIM == _ABIN32
4052                                 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4053 #endif
4054                         } else {
4055                                 mips_load_const (code, mips_at, ins->inst_offset);
4056                                 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4057                                 mips_lwc1 (code, ins->dreg, mips_at, 4);
4058                                 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4059                         }
4060                         break;
4061                 case OP_STORER4_MEMBASE_REG:
4062                         g_assert (mips_is_imm16 (ins->inst_offset));
4063 #if PROMOTE_R4_TO_R8
4064                         /* Need to convert ins->sreg1 to single-precision first */
4065                         mips_cvtsd (code, mips_ftemp, ins->sreg1);
4066 #endif
4067                         mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4068                         break;
4069                 case OP_MIPS_LWC1:
4070                         g_assert (mips_is_imm16 (ins->inst_offset));
4071                         mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4072                         break;
4073                 case OP_LOADR4_MEMBASE:
4074                         g_assert (mips_is_imm16 (ins->inst_offset));
4075                         mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4076 #if PROMOTE_R4_TO_R8
4077                         /* Convert to double precision in place */
4078                         mips_cvtds (code, ins->dreg, ins->dreg);
4079 #endif
4080                         break;
4081                 case OP_ICONV_TO_R_UN: {
4082                         static const guint64 adjust_val = 0x41F0000000000000ULL;
4083
4084                         /* convert unsigned int to double */
4085                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4086                         mips_bgez (code, ins->sreg1, 5);
4087                         mips_cvtdw (code, ins->dreg, mips_ftemp);
4088
4089                         mips_load (code, mips_at, (guint32) &adjust_val);
4090                         mips_ldc1  (code, mips_ftemp, mips_at, 0);
4091                         mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4092                         /* target is here */
4093                         break;
4094                 }
4095                 case OP_ICONV_TO_R4:
4096                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4097                         mips_cvtsw (code, ins->dreg, mips_ftemp);
4098                         mips_cvtds (code, ins->dreg, ins->dreg);
4099                         break;
4100                 case OP_ICONV_TO_R8:
4101                         mips_mtc1 (code, mips_ftemp, ins->sreg1);
4102                         mips_cvtdw (code, ins->dreg, mips_ftemp);
4103                         break;
4104                 case OP_FCONV_TO_I1:
4105                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4106                         break;
4107                 case OP_FCONV_TO_U1:
4108                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4109                         break;
4110                 case OP_FCONV_TO_I2:
4111                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4112                         break;
4113                 case OP_FCONV_TO_U2:
4114                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4115                         break;
4116                 case OP_FCONV_TO_I4:
4117                 case OP_FCONV_TO_I:
4118                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4119                         break;
4120                 case OP_FCONV_TO_U4:
4121                 case OP_FCONV_TO_U:
4122                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4123                         break;
4124                 case OP_SQRT:
4125                         mips_fsqrtd (code, ins->dreg, ins->sreg1);
4126                         break;
4127                 case OP_FADD:
4128                         mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4129                         break;
4130                 case OP_FSUB:
4131                         mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4132                         break;          
4133                 case OP_FMUL:
4134                         mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4135                         break;          
4136                 case OP_FDIV:
4137                         mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4138                         break;          
4139                 case OP_FNEG:
4140                         mips_fnegd (code, ins->dreg, ins->sreg1);
4141                         break;          
4142                 case OP_FCEQ:
4143                         mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4144                         mips_addiu (code, ins->dreg, mips_zero, 1);
4145                         mips_fbtrue (code, 2);
4146                         mips_nop (code);
4147                         MIPS_MOVE (code, ins->dreg, mips_zero);
4148                         break;
4149                 case OP_FCLT:
4150                         mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4151                         mips_addiu (code, ins->dreg, mips_zero, 1);
4152                         mips_fbtrue (code, 2);
4153                         mips_nop (code);
4154                         MIPS_MOVE (code, ins->dreg, mips_zero);
4155                         break;
4156                 case OP_FCLT_UN:
4157                         /* Less than, or Unordered */
4158                         mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4159                         mips_addiu (code, ins->dreg, mips_zero, 1);
4160                         mips_fbtrue (code, 2);
4161                         mips_nop (code);
4162                         MIPS_MOVE (code, ins->dreg, mips_zero);
4163                         break;
4164                 case OP_FCGT:
4165                         mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4166                         MIPS_MOVE (code, ins->dreg, mips_zero);
4167                         mips_fbtrue (code, 2);
4168                         mips_nop (code);
4169                         mips_addiu (code, ins->dreg, mips_zero, 1);
4170                         break;
4171                 case OP_FCGT_UN:
4172                         /* Greater than, or Unordered */
4173                         mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4174                         MIPS_MOVE (code, ins->dreg, mips_zero);
4175                         mips_fbtrue (code, 2);
4176                         mips_nop (code);
4177                         mips_addiu (code, ins->dreg, mips_zero, 1);
4178                         break;
4179                 case OP_MIPS_FBEQ:
4180                         mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4181                         mips_nop (code);
4182                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4183                         mips_fbtrue (code, 0);
4184                         mips_nop (code);
4185                         break;
4186                 case OP_MIPS_FBNE:
4187                         mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4188                         mips_nop (code);
4189                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4190                         mips_fbfalse (code, 0);
4191                         mips_nop (code);
4192                         break;
4193                 case OP_MIPS_FBLT:
4194                         mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4195                         mips_nop (code);
4196                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4197                         mips_fbtrue (code, 0);
4198                         mips_nop (code);
4199                         break;
4200                 case OP_MIPS_FBLT_UN:
4201                         mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4202                         mips_nop (code);
4203                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4204                         mips_fbtrue (code, 0);
4205                         mips_nop (code);
4206                         break;
4207                 case OP_MIPS_FBGT:
4208                         mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
4209                         mips_nop (code);
4210                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4211                         mips_fbfalse (code, 0);
4212                         mips_nop (code);
4213                         break;
4214                 case OP_MIPS_FBGT_UN:
4215                         mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4216                         mips_nop (code);
4217                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4218                         mips_fbfalse (code, 0);
4219                         mips_nop (code);
4220                         break;
4221                 case OP_MIPS_FBGE:
4222                         mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4223                         mips_nop (code);
4224                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4225                         mips_fbfalse (code, 0);
4226                         mips_nop (code);
4227                         break;
4228                 case OP_MIPS_FBGE_UN:
4229                         mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
4230                         mips_nop (code);
4231                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4232                         mips_fbfalse (code, 0);
4233                         mips_nop (code);
4234                         break;
4235                 case OP_MIPS_FBLE:
4236                         mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4237                         mips_nop (code);
4238                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4239                         mips_fbtrue (code, 0);
4240                         mips_nop (code);
4241                         break;
4242                 case OP_MIPS_FBLE_UN:
4243                         mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4244                         mips_nop (code);
4245                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4246                         mips_fbtrue (code, 0);
4247                         mips_nop (code);
4248                         break;
4249                 case OP_CKFINITE: {
4250                         guint32 *branch_patch;
4251
4252                         mips_mfc1 (code, mips_at, ins->sreg1+1);
4253                         mips_srl (code, mips_at, mips_at, 16+4);
4254                         mips_andi (code, mips_at, mips_at, 2047);
4255                         mips_addiu (code, mips_at, mips_at, -2047);
4256
4257                         branch_patch = (guint32 *)(void *)code;
4258                         mips_bne (code, mips_at, mips_zero, 0);
4259                         mips_nop (code);
4260
4261                         EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4262                         mips_patch (branch_patch, (guint32)code);
4263                         mips_fmovd (code, ins->dreg, ins->sreg1);
4264                         break;
4265                 }
4266                 case OP_JUMP_TABLE:
4267                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4268                         mips_load (code, ins->dreg, 0x0f0f0f0f);
4269                         break;
4270
4271
4272                 default:
4273                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4274                         g_assert_not_reached ();
4275                 }
4276
4277                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4278                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4279                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4280                         g_assert_not_reached ();
4281                 }
4282                
4283                 cpos += max_len;
4284
4285                 last_ins = ins;
4286                 last_offset = offset;
4287         }
4288
4289         cfg->code_len = code - cfg->native_code;
4290 }
4291
4292 void
4293 mono_arch_register_lowlevel_calls (void)
4294 {
4295 }
4296
4297 void
4298 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4299 {
4300         MonoJumpInfo *patch_info;
4301
4302         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4303                 unsigned char *ip = patch_info->ip.i + code;
4304                 const unsigned char *target = NULL;
4305
4306                 switch (patch_info->type) {
4307                 case MONO_PATCH_INFO_IP:
4308                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4309                         continue;
4310                 case MONO_PATCH_INFO_SWITCH: {
4311                         gpointer *table = (gpointer *)patch_info->data.table->table;
4312                         int i;
4313
4314                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4315
4316                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
4317                                 table [i] = (int)patch_info->data.table->table [i] + code;
4318                         }
4319                         continue;
4320                 }
4321                 case MONO_PATCH_INFO_METHODCONST:
4322                 case MONO_PATCH_INFO_CLASS:
4323                 case MONO_PATCH_INFO_IMAGE:
4324                 case MONO_PATCH_INFO_FIELD:
4325                 case MONO_PATCH_INFO_VTABLE:
4326                 case MONO_PATCH_INFO_IID:
4327                 case MONO_PATCH_INFO_SFLDA:
4328                 case MONO_PATCH_INFO_LDSTR:
4329                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4330                 case MONO_PATCH_INFO_LDTOKEN:
4331                 case MONO_PATCH_INFO_R4:
4332                 case MONO_PATCH_INFO_R8:
4333                         /* from OP_AOTCONST : lui + addiu */
4334                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4335                         patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4336                         continue;
4337 #if 0
4338                 case MONO_PATCH_INFO_EXC_NAME:
4339                         g_assert_not_reached ();
4340                         *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4341                         continue;
4342 #endif
4343                 case MONO_PATCH_INFO_NONE:
4344                         /* everything is dealt with at epilog output time */
4345                         continue;
4346                 default:
4347                         target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4348                         mips_patch ((guint32 *)(void *)ip, (guint32)target);
4349                         break;
4350                 }
4351         }
4352 }
4353
4354 #if 0
4355 static
4356 void
4357 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4358 {
4359 }
4360
4361 static
4362 void
4363 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4364 {
4365 }
4366 #endif
4367
4368 /*
4369  * Allow tracing to work with this interface (with an optional argument)
4370  *
4371  * This code is expected to be inserted just after the 'real' prolog code,
4372  * and before the first basic block.  We need to allocate a 2nd, temporary
4373  * stack frame so that we can preserve f12-f15 as well as a0-a3.
4374  */
4375
4376 void*
4377 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4378 {
4379         guchar *code = p;
4380         int offset = cfg->arch.tracing_offset;
4381
4382         mips_nop (code);
4383         mips_nop (code);
4384         mips_nop (code);
4385
4386         /* For N32, need to know for each stack slot if it's an integer
4387          * or float argument, and save/restore the appropriate register
4388          */
4389         MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4390         MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4391         MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4392         MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4393 #if _MIPS_SIM == _ABIN32
4394         MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4395         MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4396         MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4397         MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4398 #endif
4399
4400         mips_load_const (code, mips_a0, cfg->method);
4401         mips_addiu (code, mips_a1, mips_sp, offset);
4402         mips_load_const (code, mips_t9, func);
4403         mips_jalr (code, mips_t9, mips_ra);
4404         mips_nop (code);
4405
4406         MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4407         MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4408         MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4409         MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4410 #if _MIPS_SIM == _ABIN32
4411         MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4412         MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4413         MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4414         MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4415 #endif
4416
4417         mips_nop (code);
4418         mips_nop (code);
4419         mips_nop (code);
4420         return code;
4421 }
4422
4423 void
4424 mips_adjust_stackframe(MonoCompile *cfg)
4425 {
4426         MonoBasicBlock *bb;
4427         int delta, threshold, i;
4428         MonoMethodSignature *sig;
4429         int ra_offset;
4430
4431         if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4432                 return;
4433
4434         /* adjust cfg->stack_offset for account for down-spilling */
4435         cfg->stack_offset += SIZEOF_REGISTER;
4436
4437         /* re-align cfg->stack_offset if needed (due to var spilling) */
4438         cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4439         delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4440         if (cfg->verbose_level > 2) {
4441                 g_print ("mips_adjust_stackframe:\n");
4442                 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4443         }
4444         threshold = cfg->arch.local_alloc_offset;
4445         ra_offset = cfg->stack_offset - sizeof(gpointer);
4446         if (cfg->verbose_level > 2) {
4447                 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4448         }
4449
4450         sig = mono_method_signature (cfg->method);
4451         if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4452                 cfg->vret_addr->inst_offset += delta;
4453         }
4454         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4455                 MonoInst *inst = cfg->args [i];
4456
4457                 inst->inst_offset += delta;
4458         }
4459
4460         /*
4461          * loads and stores based off the frame reg that (used to) lie
4462          * above the spill var area need to be increased by 'delta'
4463          * to make room for the spill vars.
4464          */
4465         /* Need to find loads and stores to adjust that
4466          * are above where the spillvars were inserted, but
4467          * which are not the spillvar references themselves.
4468          *
4469          * Idea - since all offsets from fp are positive, make
4470          * spillvar offsets negative to begin with so we can spot
4471          * them here.
4472          */
4473
4474 #if 1
4475         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4476                 int ins_cnt = 0;
4477                 MonoInst *ins;
4478
4479                 if (cfg->verbose_level > 2) {
4480                         g_print ("BASIC BLOCK %d:\n", bb->block_num);
4481                 }
4482                 MONO_BB_FOR_EACH_INS (bb, ins) {
4483                         int adj_c0 = 0;
4484                         int adj_imm = 0;
4485
4486                         if (cfg->verbose_level > 2) {
4487                                 mono_print_ins_index (ins_cnt, ins);
4488                         }
4489                         if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp))
4490                                 adj_c0 = 1;
4491                         if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))
4492                                 adj_c0 = 1;
4493                         /* The following two catch FP spills */
4494                         if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_sp))
4495                                 adj_c0 = 1;
4496                         if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_sp))
4497                                 adj_c0 = 1;
4498                         if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4499                                 adj_imm = 1;
4500                         if (adj_c0) {
4501                                 if (ins->inst_c0 >= threshold) {
4502                                         ins->inst_c0 += delta;
4503                                         if (cfg->verbose_level > 2) {
4504                                                 g_print ("adj");
4505                                                 mono_print_ins_index (ins_cnt, ins);
4506                                         }
4507                                 }
4508                                 else if (ins->inst_c0 < 0) {
4509                                         ins->inst_c0 = - ins->inst_c0 - 4;
4510                                         if (cfg->verbose_level > 2) {
4511                                                 g_print ("spill");
4512                                                 mono_print_ins_index (ins_cnt, ins);
4513                                         }
4514                                 }
4515                                 g_assert (ins->inst_c0 != ra_offset);
4516                         }
4517                         if (adj_imm) {
4518                                 if (ins->inst_imm >= threshold) {
4519                                         ins->inst_imm += delta;
4520                                         if (cfg->verbose_level > 2) {
4521                                                 g_print ("adj");
4522                                                 mono_print_ins_index (ins_cnt, ins);
4523                                         }
4524                                 }
4525                                 g_assert (ins->inst_c0 != ra_offset);
4526                         }
4527
4528                         ++ins_cnt;
4529                 }
4530         }
4531 #endif
4532 }
4533
4534 /*
4535  * Stack frame layout:
4536  * 
4537  *   ------------------- sp + cfg->stack_usage + cfg->param_area
4538  *      param area              incoming
4539  *   ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4540  *      a0-a3                   incoming
4541  *   ------------------- sp + cfg->stack_usage
4542  *      ra
4543  *   ------------------- sp + cfg->stack_usage-4
4544  *      spilled regs
4545  *   ------------------- sp + 
4546  *      MonoLMF structure       optional
4547  *   ------------------- sp + cfg->arch.lmf_offset
4548  *      saved registers         s0-s8
4549  *   ------------------- sp + cfg->arch.iregs_offset
4550  *      locals
4551  *   ------------------- sp + cfg->param_area
4552  *      param area              outgoing
4553  *   ------------------- sp + MIPS_STACK_PARAM_OFFSET
4554  *      a0-a3                   outgoing
4555  *   ------------------- sp
4556  *      red zone
4557  */
4558 guint8 *
4559 mono_arch_emit_prolog (MonoCompile *cfg)
4560 {
4561         MonoMethod *method = cfg->method;
4562         MonoMethodSignature *sig;
4563         MonoInst *inst;
4564         int alloc_size, pos, i;
4565         guint8 *code;
4566         CallInfo *cinfo;
4567         int tracing = 0;
4568         guint32 iregs_to_save = 0;
4569 #if SAVE_FP_REGS
4570         guint32 fregs_to_save = 0;
4571 #endif
4572 #if SAVE_LMF
4573         /* lmf_offset is the offset of the LMF from our stack pointer. */
4574         guint32 lmf_offset = cfg->arch.lmf_offset;
4575 #endif
4576
4577         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4578                 tracing = 1;
4579
4580         if (tracing)
4581                 cfg->flags |= MONO_CFG_HAS_CALLS;
4582         
4583         sig = mono_method_signature (method);
4584         cfg->code_size = 768 + sig->param_count * 20;
4585         code = cfg->native_code = g_malloc (cfg->code_size);
4586
4587         if (tracing) {
4588 #if _MIPS_SIM == _ABIO32
4589                 cfg->arch.tracing_offset = cfg->stack_offset;
4590 #elif _MIPS_SIM == _ABIN32
4591                 /* no stack slots by default for argument regs, reserve a special block */
4592                 cfg->arch.tracing_offset = cfg->stack_offset;
4593                 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4594 #endif
4595         }
4596
4597         /* adjust stackframe assignments for spillvars if needed */
4598         mips_adjust_stackframe (cfg);
4599
4600         /* stack_offset should not be changed here. */
4601         alloc_size = cfg->stack_offset;
4602         cfg->stack_usage = alloc_size;
4603
4604 #if SAVE_ALL_REGS
4605         iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4606 #else
4607         iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4608 #endif
4609 #if SAVE_FP_REGS
4610 #if 0
4611         fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4612 #else
4613         fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4614         fregs_to_save |= (fregs_to_save << 1);
4615 #endif
4616 #endif
4617         if (alloc_size) {
4618                 if (mips_is_imm16 (-alloc_size)) {
4619                         mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4620                 } else {
4621                         mips_load_const (code, mips_at, -alloc_size);
4622                         mips_addu (code, mips_sp, mips_sp, mips_at);
4623                 }
4624         }
4625
4626         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
4627                 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
4628
4629         /* XXX - optimize this later to not save all regs if LMF constructed */
4630
4631         if (iregs_to_save) {
4632                 /* save used registers in own stack frame (at pos) */
4633                 pos = cfg->arch.iregs_offset;
4634                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4635                         if (iregs_to_save & (1 << i)) {
4636                                 g_assert (pos < cfg->stack_usage - sizeof(gpointer));
4637                                 MIPS_SW (code, i, mips_sp, pos);
4638                                 pos += SIZEOF_REGISTER;
4639                         }
4640                 }
4641         }
4642 #if SAVE_LMF
4643         if (method->save_lmf) {
4644                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4645                         MIPS_SW (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
4646                 }
4647         }
4648 #endif
4649
4650 #if SAVE_FP_REGS
4651         /* Save float registers */
4652         if (fregs_to_save) {
4653                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4654                         if (fregs_to_save & (1 << i)) {
4655                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4656                                 mips_swc1 (code, i, mips_sp, pos);
4657                                 pos += sizeof (gulong);
4658                         }
4659                 }
4660         }
4661 #if SAVE_LMF
4662         if (method->save_lmf) {
4663                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4664                         mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
4665                 }
4666         }
4667 #endif
4668 #endif
4669         if (cfg->frame_reg != mips_sp) {
4670                 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4671 #if SAVE_LMF
4672                 if (method->save_lmf)
4673                         MIPS_SW (code, cfg->frame_reg, mips_sp,
4674                                  lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
4675 #endif
4676         }
4677
4678         /* Do instrumentation before assigning regvars to registers.  Because they may be assigned
4679          * to the t* registers, which would be clobbered by the instrumentation calls.
4680          */
4681         if (tracing) {
4682                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4683         }
4684
4685
4686         /* load arguments allocated to register from the stack */
4687         pos = 0;
4688
4689         cinfo = calculate_sizes (sig, sig->pinvoke);
4690
4691         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4692                 ArgInfo *ainfo = &cinfo->ret;
4693                 inst = cfg->vret_addr;
4694                 if (inst->opcode == OP_REGVAR)
4695                         MIPS_MOVE (code, inst->dreg, ainfo->reg);
4696                 else if (mips_is_imm16 (inst->inst_offset)) {
4697                         mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4698                 } else {
4699                         mips_load_const (code, mips_at, inst->inst_offset);
4700                         mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4701                         mips_sw (code, ainfo->reg, mips_at, 0);
4702                 }
4703         }
4704         /* Keep this in sync with emit_load_volatile_arguments */
4705         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4706                 ArgInfo *ainfo = cinfo->args + i;
4707                 inst = cfg->args [pos];
4708                 
4709                 if (cfg->verbose_level > 2)
4710                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4711                 if (inst->opcode == OP_REGVAR) {
4712                         /* Argument ends up in a register */
4713                         if (ainfo->regtype == RegTypeGeneral)
4714                                 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4715                         else if (ainfo->regtype == RegTypeFP) {
4716                                 g_assert_not_reached();
4717 #if 0
4718                                 ppc_fmr (code, inst->dreg, ainfo->reg);
4719 #endif
4720                         }
4721                         else if (ainfo->regtype == RegTypeBase) {
4722                                 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
4723                         } else
4724                                 g_assert_not_reached ();
4725
4726                         if (cfg->verbose_level > 2)
4727                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4728                 } else {
4729                         /* Argument ends up on the stack */
4730                         if (ainfo->regtype == RegTypeGeneral) {
4731                                 /* Incoming parameters should be above this frame */
4732                                 if (cfg->verbose_level > 2)
4733                                         g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
4734                                 /* g_assert (inst->inst_offset >= alloc_size); */
4735                                 g_assert (mips_is_imm16 (inst->inst_offset));
4736                                 switch (ainfo->size) {
4737                                 case 1:
4738                                         mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4739                                         break;
4740                                 case 2:
4741                                         mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4742                                         break;
4743                                 case 0: /* XXX */
4744                                 case 4:
4745                                         mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4746                                         break;
4747                                 case 8:
4748 #if (SIZEOF_REGISTER == 4)
4749                                         mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4750                                         mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4751 #elif (SIZEOF_REGISTER == 8)
4752                                         mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4753 #endif
4754                                         break;
4755                                 default:
4756                                         g_assert_not_reached ();
4757                                         break;
4758                                 }
4759                         } else if (ainfo->regtype == RegTypeBase) {
4760                                 /*
4761                                  * Argument comes in on the stack, and ends up on the stack
4762                                  * 1 and 2 byte args are passed as 32-bit quantities, but used as
4763                                  * 8 and 16 bit quantities.  Shorten them in place.
4764                                  */
4765                                 g_assert (mips_is_imm16 (inst->inst_offset));
4766                                 switch (ainfo->size) {
4767                                 case 1:
4768                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4769                                         mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4770                                         break;
4771                                 case 2:
4772                                         mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4773                                         mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4774                                         break;
4775                                 case 0: /* XXX */
4776                                 case 4:
4777                                 case 8:
4778                                         break;
4779                                 default:
4780                                         g_assert_not_reached ();
4781                                 }
4782                         } else if (ainfo->regtype == RegTypeFP) {
4783                                 g_assert (mips_is_imm16 (inst->inst_offset));
4784                                 if (ainfo->size == 8) {
4785 #if _MIPS_SIM == _ABIO32
4786                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4787                                         mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4788 #elif _MIPS_SIM == _ABIN32
4789                                         mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4790 #endif
4791                                 }
4792                                 else if (ainfo->size == 4)
4793                                         mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4794                                 else
4795                                         g_assert_not_reached ();
4796                         } else if (ainfo->regtype == RegTypeStructByVal) {
4797                                 int i;
4798                                 int doffset = inst->inst_offset;
4799
4800                                 g_assert (mips_is_imm16 (inst->inst_offset));
4801                                 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4802                                 /* Push the argument registers into their stack slots */
4803                                 for (i = 0; i < ainfo->size; ++i) {
4804                                         MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
4805                                         doffset += SIZEOF_REGISTER;
4806                                 }
4807                         } else if (ainfo->regtype == RegTypeStructByAddr) {
4808                                 g_assert (mips_is_imm16 (inst->inst_offset));
4809                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4810                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4811                         } else
4812                                 g_assert_not_reached ();
4813                 }
4814                 pos++;
4815         }
4816
4817         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4818                 mips_load_const (code, mips_a0, cfg->domain);
4819                 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
4820                 mips_jalr (code, mips_t9, mips_ra);
4821                 mips_nop (code);
4822         }
4823
4824 #if SAVE_LMF
4825         if (method->save_lmf) {
4826                 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4827                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4828
4829                 if (lmf_pthread_key != -1) {
4830                         g_assert_not_reached();
4831 #if 0
4832                         emit_tls_access (code, mips_temp, lmf_pthread_key);
4833 #endif
4834                         if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4835                                 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4836                 } else {
4837 #if 0
4838                         mips_addiu (code, mips_a0, mips_sp, lmf_offset);
4839                         mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
4840                         mips_jalr (code, mips_t9, mips_ra);
4841                         mips_nop (code);
4842 #endif
4843                         /* This can/will clobber the a0-a3 registers */
4844                         mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
4845                         mips_jalr (code, mips_t9, mips_ra);
4846                         mips_nop (code);
4847                 }
4848
4849                 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4850                 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4851                 /* new_lmf->previous_lmf = *lmf_addr */
4852                 mips_lw (code, mips_at, mips_v0, 0);
4853                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4854                 /* *(lmf_addr) = sp + lmf_offset */
4855                 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4856                 mips_sw (code, mips_at, mips_v0, 0);
4857
4858                 /* save method info */
4859                 mips_load_const (code, mips_at, method);
4860                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4861                 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4862
4863                 /* save the current IP */
4864                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4865                 mips_load_const (code, mips_at, 0x01010101);
4866                 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
4867         }
4868 #endif
4869
4870         cfg->code_len = code - cfg->native_code;
4871         g_assert (cfg->code_len < cfg->code_size);
4872         g_free (cinfo);
4873
4874         return code;
4875 }
4876
4877 enum {
4878         SAVE_NONE,
4879         SAVE_STRUCT,
4880         SAVE_ONE,
4881         SAVE_TWO,
4882         SAVE_FP
4883 };
4884
4885 void*
4886 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
4887 {
4888         guchar *code = p;
4889         int save_mode = SAVE_NONE;
4890         int offset;
4891         MonoMethod *method = cfg->method;
4892         int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
4893         int save_offset = MIPS_STACK_PARAM_OFFSET;
4894
4895         g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
4896         
4897         offset = code - cfg->native_code;
4898         /* we need about 16 instructions */
4899         if (offset > (cfg->code_size - 16 * 4)) {
4900                 cfg->code_size *= 2;
4901                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4902                 code = cfg->native_code + offset;
4903         }
4904         mips_nop (code);
4905         mips_nop (code);
4906         switch (rtype) {
4907         case MONO_TYPE_VOID:
4908                 /* special case string .ctor icall */
4909                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
4910                         save_mode = SAVE_ONE;
4911                 else
4912                         save_mode = SAVE_NONE;
4913                 break;
4914         case MONO_TYPE_R4:
4915         case MONO_TYPE_R8:
4916                 save_mode = SAVE_FP;
4917                 break;
4918         case MONO_TYPE_VALUETYPE:
4919                 save_mode = SAVE_STRUCT;
4920                 break;
4921         case MONO_TYPE_I8:
4922         case MONO_TYPE_U8:
4923 #if SIZEOF_REGISTER == 4
4924                 save_mode = SAVE_TWO;
4925 #elif SIZEOF_REGISTER == 8
4926                 save_mode = SAVE_ONE;
4927 #endif
4928                 break;
4929         default:
4930                 save_mode = SAVE_ONE;
4931                 break;
4932         }
4933
4934         mips_addiu (code, mips_sp, mips_sp, -32);
4935         switch (save_mode) {
4936         case SAVE_TWO:
4937                 mips_sw (code, mips_v0, mips_sp, save_offset);
4938                 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
4939                 if (enable_arguments) {
4940                         MIPS_MOVE (code, mips_a1, mips_v0);
4941                         MIPS_MOVE (code, mips_a2, mips_v1);
4942                 }
4943                 break;
4944         case SAVE_ONE:
4945                 MIPS_SW (code, mips_v0, mips_sp, save_offset);
4946                 if (enable_arguments) {
4947                         MIPS_MOVE (code, mips_a1, mips_v0);
4948                 }
4949                 break;
4950         case SAVE_FP:
4951                 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
4952                 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
4953                 mips_lw (code, mips_a0, mips_sp, save_offset);
4954                 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
4955                 break;
4956         case SAVE_STRUCT:
4957         case SAVE_NONE:
4958         default:
4959                 break;
4960         }
4961         mips_load_const (code, mips_a0, cfg->method);
4962         mips_load_const (code, mips_t9, func);
4963         mips_jalr (code, mips_t9, mips_ra);
4964         mips_nop (code);
4965
4966         switch (save_mode) {
4967         case SAVE_TWO:
4968                 mips_lw (code, mips_v0, mips_sp, save_offset);
4969                 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
4970                 break;
4971         case SAVE_ONE:
4972                 MIPS_LW (code, mips_v0, mips_sp, save_offset);
4973                 break;
4974         case SAVE_FP:
4975                 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
4976                 break;
4977         case SAVE_STRUCT:
4978         case SAVE_NONE:
4979         default:
4980                 break;
4981         }
4982         mips_addiu (code, mips_sp, mips_sp, 32);
4983         mips_nop (code);
4984         mips_nop (code);
4985         return code;
4986 }
4987
4988 guint8 *
4989 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
4990 {
4991         MonoMethod *method = cfg->method;
4992         int pos = 0, i;
4993         int max_epilog_size = 16 + 20*4;
4994         guint32 iregs_to_restore;
4995 #if SAVE_FP_REGS
4996         guint32 fregs_to_restore;
4997 #endif
4998
4999 #if SAVE_LMF
5000         if (cfg->method->save_lmf)
5001                 max_epilog_size += 128;
5002 #endif
5003         
5004         if (mono_jit_trace_calls != NULL)
5005                 max_epilog_size += 50;
5006
5007         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5008                 max_epilog_size += 50;
5009
5010         if (code)
5011                 pos = code - cfg->native_code;
5012         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5013                 cfg->code_size *= 2;
5014                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5015                 mono_jit_stats.code_reallocs++;
5016         }
5017
5018         /*
5019          * Keep in sync with OP_JMP
5020          */
5021         if (code)
5022                 code = cfg->native_code + pos;
5023         else
5024                 code = cfg->native_code + cfg->code_len;
5025
5026         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5027                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5028         }
5029         pos = cfg->arch.iregs_offset;
5030         if (cfg->frame_reg != mips_sp) {
5031                 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5032         }
5033 #if SAVE_ALL_REGS
5034         iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5035 #else
5036         iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5037 #endif
5038         if (iregs_to_restore) {
5039                 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5040                         if (iregs_to_restore & (1 << i)) {
5041                                 MIPS_LW (code, i, mips_sp, pos);
5042                                 pos += SIZEOF_REGISTER;
5043                         }
5044                 }
5045         }
5046
5047 #if SAVE_FP_REGS
5048 #if 0
5049         fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5050 #else
5051         fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5052         fregs_to_restore |= (fregs_to_restore << 1);
5053 #endif
5054         if (fregs_to_restore) {
5055                 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5056                         if (fregs_to_restore & (1 << i)) {
5057                                 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5058                                 mips_lwc1 (code, i, mips_sp, pos);
5059                                 pos += FREG_SIZE
5060                         }
5061                 }
5062         }
5063 #endif
5064 #if SAVE_LMF
5065         /* Unlink the LMF if necessary */
5066         if (method->save_lmf) {
5067                 int lmf_offset = cfg->arch.lmf_offset;
5068
5069                 /* t0 = current_lmf->previous_lmf */
5070                 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5071                 /* t1 = lmf_addr */
5072                 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5073                 /* (*lmf_addr) = previous_lmf */
5074                 mips_sw (code, mips_temp, mips_t1, 0);
5075         }
5076 #endif
5077 #if 0
5078         /* Restore the fp */
5079         mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5080 #endif
5081         /* Correct the stack pointer */
5082         if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
5083                 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
5084         mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
5085
5086         /* Caller will emit either return or tail-call sequence */
5087
5088         cfg->code_len = code - cfg->native_code;
5089
5090         g_assert (cfg->code_len < cfg->code_size);
5091         return (code);
5092 }
5093
5094 void
5095 mono_arch_emit_epilog (MonoCompile *cfg)
5096 {
5097         guint8 *code;
5098
5099         code = mono_arch_emit_epilog_sub (cfg, NULL);
5100
5101         mips_jr (code, mips_ra);
5102         mips_nop (code);
5103
5104         cfg->code_len = code - cfg->native_code;
5105
5106         g_assert (cfg->code_len < cfg->code_size);
5107 }
5108
5109 /* remove once throw_exception_by_name is eliminated */
5110 #if 0
5111 static int
5112 exception_id_by_name (const char *name)
5113 {
5114         if (strcmp (name, "IndexOutOfRangeException") == 0)
5115                 return MONO_EXC_INDEX_OUT_OF_RANGE;
5116         if (strcmp (name, "OverflowException") == 0)
5117                 return MONO_EXC_OVERFLOW;
5118         if (strcmp (name, "ArithmeticException") == 0)
5119                 return MONO_EXC_ARITHMETIC;
5120         if (strcmp (name, "DivideByZeroException") == 0)
5121                 return MONO_EXC_DIVIDE_BY_ZERO;
5122         if (strcmp (name, "InvalidCastException") == 0)
5123                 return MONO_EXC_INVALID_CAST;
5124         if (strcmp (name, "NullReferenceException") == 0)
5125                 return MONO_EXC_NULL_REF;
5126         if (strcmp (name, "ArrayTypeMismatchException") == 0)
5127                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5128         g_error ("Unknown intrinsic exception %s\n", name);
5129         return 0;
5130 }
5131 #endif
5132
5133 void
5134 mono_arch_emit_exceptions (MonoCompile *cfg)
5135 {
5136 #if 0
5137         MonoJumpInfo *patch_info;
5138         int i;
5139         guint8 *code;
5140         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5141         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5142         int max_epilog_size = 50;
5143
5144         /* count the number of exception infos */
5145      
5146         /* 
5147          * make sure we have enough space for exceptions
5148          * 24 is the simulated call to throw_exception_by_name
5149          */
5150         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5151 #if 0
5152                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5153                         i = exception_id_by_name (patch_info->data.target);
5154                         g_assert (i < MONO_EXC_INTRINS_NUM);
5155                         if (!exc_throw_found [i]) {
5156                                 max_epilog_size += 12;
5157                                 exc_throw_found [i] = TRUE;
5158                         }
5159                 }
5160 #endif
5161         }
5162
5163         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5164                 cfg->code_size *= 2;
5165                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5166                 mono_jit_stats.code_reallocs++;
5167         }
5168
5169         code = cfg->native_code + cfg->code_len;
5170
5171         /* add code to raise exceptions */
5172         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5173                 switch (patch_info->type) {
5174                 case MONO_PATCH_INFO_EXC: {
5175 #if 0
5176                         //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5177
5178                         i = exception_id_by_name (patch_info->data.target);
5179                         g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5180                         if (!exc_throw_pos [i]) {
5181                                 guint32 addr;
5182
5183                                 exc_throw_pos [i] = code;
5184                                 //g_print ("exc: writing stub at %p\n", code);
5185                                 mips_load_const (code, mips_a0, patch_info->data.target);
5186                                 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5187                                 mips_load_const (code, mips_t9, addr);
5188                                 mips_jr (code, mips_t9);
5189                                 mips_nop (code);
5190                         }
5191                         //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5192
5193                         /* Turn into a Relative patch, pointing at code stub */
5194                         patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5195                         patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5196 #else
5197                         g_assert_not_reached();
5198 #endif
5199                         break;
5200                 }
5201                 default:
5202                         /* do nothing */
5203                         break;
5204                 }
5205         }
5206
5207         cfg->code_len = code - cfg->native_code;
5208
5209         g_assert (cfg->code_len < cfg->code_size);
5210 #endif
5211 }
5212
5213 /*
5214  * Thread local storage support
5215  */
5216 static void
5217 setup_tls_access (void)
5218 {
5219         guint32 ptk;
5220         //guint32 *ins, *code;
5221
5222         if (tls_mode == TLS_MODE_FAILED)
5223                 return;
5224
5225         if (g_getenv ("MONO_NO_TLS")) {
5226                 tls_mode = TLS_MODE_FAILED;
5227                 return;
5228         }
5229
5230         if (tls_mode == TLS_MODE_DETECT) {
5231                 /* XXX */
5232                 tls_mode = TLS_MODE_FAILED;
5233                 return;
5234 #if 0
5235
5236                 ins = (guint32*)pthread_getspecific;
5237                 /* uncond branch to the real method */
5238                 if ((*ins >> 26) == 18) {
5239                         gint32 val;
5240                         val = (*ins & ~3) << 6;
5241                         val >>= 6;
5242                         if (*ins & 2) {
5243                                 /* absolute */
5244                                 ins = (guint32*)val;
5245                         } else {
5246                                 ins = (guint32*) ((char*)ins + val);
5247                         }
5248                 }
5249                 code = &cmplwi_1023;
5250                 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5251                 code = &li_0x48;
5252                 ppc_li (code, ppc_r4, 0x48);
5253                 code = &blr_ins;
5254                 ppc_blr (code);
5255                 if (*ins == cmplwi_1023) {
5256                         int found_lwz_284 = 0;
5257                         for (ptk = 0; ptk < 20; ++ptk) {
5258                                 ++ins;
5259                                 if (!*ins || *ins == blr_ins)
5260                                         break;
5261                                 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5262                                         found_lwz_284 = 1;
5263                                         break;
5264                                 }
5265                         }
5266                         if (!found_lwz_284) {
5267                                 tls_mode = TLS_MODE_FAILED;
5268                                 return;
5269                         }
5270                         tls_mode = TLS_MODE_LTHREADS;
5271                 } else if (*ins == li_0x48) {
5272                         ++ins;
5273                         /* uncond branch to the real method */
5274                         if ((*ins >> 26) == 18) {
5275                                 gint32 val;
5276                                 val = (*ins & ~3) << 6;
5277                                 val >>= 6;
5278                                 if (*ins & 2) {
5279                                         /* absolute */
5280                                         ins = (guint32*)val;
5281                                 } else {
5282                                         ins = (guint32*) ((char*)ins + val);
5283                                 }
5284                                 code = &val;
5285                                 ppc_li (code, ppc_r0, 0x7FF2);
5286                                 if (ins [1] == val) {
5287                                         /* Darwin on G4, implement */
5288                                         tls_mode = TLS_MODE_FAILED;
5289                                         return;
5290                                 } else {
5291                                         code = &val;
5292                                         ppc_mfspr (code, ppc_r3, 104);
5293                                         if (ins [1] != val) {
5294                                                 tls_mode = TLS_MODE_FAILED;
5295                                                 return;
5296                                         }
5297                                         tls_mode = TLS_MODE_DARWIN_G5;
5298                                 }
5299                         } else {
5300                                 tls_mode = TLS_MODE_FAILED;
5301                                 return;
5302                         }
5303                 } else {
5304                         tls_mode = TLS_MODE_FAILED;
5305                         return;
5306                 }
5307 #endif
5308         }
5309         if (monodomain_key == -1) {
5310                 ptk = mono_domain_get_tls_key ();
5311                 if (ptk < 1024) {
5312                         ptk = mono_pthread_key_for_tls (ptk);
5313                         if (ptk < 1024) {
5314                                 monodomain_key = ptk;
5315                         }
5316                 }
5317         }
5318         if (lmf_pthread_key == -1) {
5319                 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5320                 if (ptk < 1024) {
5321                         /*g_print ("MonoLMF at: %d\n", ptk);*/
5322                         /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5323                                 init_tls_failed = 1;
5324                                 return;
5325                         }*/
5326                         lmf_pthread_key = ptk;
5327                 }
5328         }
5329         if (monothread_key == -1) {
5330                 ptk = mono_thread_get_tls_key ();
5331                 if (ptk < 1024) {
5332                         ptk = mono_pthread_key_for_tls (ptk);
5333                         if (ptk < 1024) {
5334                                 monothread_key = ptk;
5335                                 /*g_print ("thread inited: %d\n", ptk);*/
5336                         }
5337                 } else {
5338                         /*g_print ("thread not inited yet %d\n", ptk);*/
5339                 }
5340         }
5341 }
5342
5343 void
5344 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5345 {
5346         setup_tls_access ();
5347 }
5348
5349 void
5350 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5351 {
5352 }
5353
5354 void
5355 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5356 {
5357         int this_dreg = mips_a0;
5358         
5359         if (vt_reg != -1)
5360                 this_dreg = mips_a1;
5361
5362         /* add the this argument */
5363         if (this_reg != -1) {
5364                 MonoInst *this;
5365                 MONO_INST_NEW (cfg, this, OP_MOVE);
5366                 this->type = this_type;
5367                 this->sreg1 = this_reg;
5368                 this->dreg = mono_alloc_ireg (cfg);
5369                 mono_bblock_add_inst (cfg->cbb, this);
5370                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5371         }
5372
5373         if (vt_reg != -1) {
5374                 MonoInst *vtarg;
5375                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5376                 vtarg->type = STACK_MP;
5377                 vtarg->sreg1 = vt_reg;
5378                 vtarg->dreg = mono_alloc_ireg (cfg);
5379                 mono_bblock_add_inst (cfg->cbb, vtarg);
5380                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5381         }
5382 }
5383
5384 MonoInst*
5385 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5386 {
5387         MonoInst *ins = NULL;
5388
5389         return ins;
5390 }
5391
5392 MonoInst*
5393 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5394 {
5395         return NULL;
5396 }
5397
5398 gboolean
5399 mono_arch_print_tree (MonoInst *tree, int arity)
5400 {
5401         return 0;
5402 }
5403
5404 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5405 {
5406         MonoInst* ins;
5407
5408         setup_tls_access ();
5409         if (monodomain_key == -1)
5410                 return NULL;
5411         
5412         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5413         ins->inst_offset = monodomain_key;
5414         return ins;
5415 }
5416
5417 gpointer
5418 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5419 {
5420         /* FIXME: implement */
5421         g_assert_not_reached ();
5422 }
5423
5424 #ifdef MONO_ARCH_HAVE_IMT
5425
5426 #define CMP_SIZE 12
5427 #define BR_SIZE 4
5428 #define JUMP_IMM_SIZE 12
5429 #define JUMP_IMM32_SIZE 16
5430 #define ENABLE_WRONG_METHOD_CHECK 0
5431
5432 /*
5433  * LOCKING: called with the domain lock held
5434  */
5435 gpointer
5436 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5437         gpointer fail_tramp)
5438 {
5439         NOT_IMPLEMENTED;
5440 #if 0
5441         int i;
5442         int size = 0;
5443         guint8 *code, *start;
5444
5445         for (i = 0; i < count; ++i) {
5446                 MonoIMTCheckItem *item = imt_entries [i];
5447                 if (item->is_equals) {
5448                         if (item->check_target_idx) {
5449                                 if (!item->compare_done)
5450                                         item->chunk_size += CMP_SIZE;
5451                                 if (fail_tramp)
5452                                         item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5453                                 else
5454                                         item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
5455                         } else {
5456                                 if (fail_tramp) {
5457                                         item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5458                                 } else {
5459                                         item->chunk_size += JUMP_IMM_SIZE;
5460 #if ENABLE_WRONG_METHOD_CHECK
5461                                         item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5462 #endif
5463                                 }
5464                         }
5465                 } else {
5466                         item->chunk_size += CMP_SIZE + BR_SIZE;
5467                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5468                 }
5469                 size += item->chunk_size;
5470         }
5471         if (fail_tramp) {
5472                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5473         } else {
5474                 /* the initial load of the vtable address */
5475                 size += 8;
5476                 code = mono_domain_code_reserve (domain, size);
5477         }
5478         start = code;
5479         if (!fail_tramp)
5480                 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
5481         for (i = 0; i < count; ++i) {
5482                 MonoIMTCheckItem *item = imt_entries [i];
5483                 item->code_target = code;
5484                 if (item->is_equals) {
5485                         if (item->check_target_idx) {
5486                                 if (!item->compare_done) {
5487                                         ppc_load (code, ppc_r0, (guint32)item->key);
5488                                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5489                                 }
5490                                 item->jmp_code = code;
5491                                 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5492                                 if (fail_tramp)
5493                                         ppc_load (code, ppc_r0, item->value.target_code);
5494                                 else
5495                                         ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5496                                 ppc_mtctr (code, ppc_r0);
5497                                 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5498                         } else {
5499                                 if (fail_tramp) {
5500                                         ppc_load (code, ppc_r0, (guint32)item->key);
5501                                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5502                                         item->jmp_code = code;
5503                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5504                                         ppc_load (code, ppc_r0, item->value.target_code);
5505                                         ppc_mtctr (code, ppc_r0);
5506                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5507                                         ppc_patch (item->jmp_code, code);
5508                                         ppc_load (code, ppc_r0, fail_tramp);
5509                                         ppc_mtctr (code, ppc_r0);
5510                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5511                                         item->jmp_code = NULL;
5512                                 } else {
5513                                         /* enable the commented code to assert on wrong method */
5514 #if ENABLE_WRONG_METHOD_CHECK
5515                                         ppc_load (code, ppc_r0, (guint32)item->key);
5516                                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5517                                         item->jmp_code = code;
5518                                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5519 #endif
5520                                         ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5521                                         ppc_mtctr (code, ppc_r0);
5522                                         ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5523 #if ENABLE_WRONG_METHOD_CHECK
5524                                         ppc_patch (item->jmp_code, code);
5525                                         ppc_break (code);
5526                                         item->jmp_code = NULL;
5527 #endif
5528                                 }
5529                         }
5530                 } else {
5531                         ppc_load (code, ppc_r0, (guint32)item->key);
5532                         ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5533                         item->jmp_code = code;
5534                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5535                 }
5536         }
5537         /* patch the branches to get to the target items */
5538         for (i = 0; i < count; ++i) {
5539                 MonoIMTCheckItem *item = imt_entries [i];
5540                 if (item->jmp_code) {
5541                         if (item->check_target_idx) {
5542                                 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5543                         }
5544                 }
5545         }
5546
5547         if (!fail_tramp)
5548                 mono_stats.imt_thunks_size += code - start;
5549         g_assert (code - start <= size);
5550         mono_arch_flush_icache (start, size);
5551         return start;
5552 #endif
5553 }
5554
5555 MonoMethod*
5556 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5557 {
5558         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5559 }
5560 #endif
5561
5562 MonoVTable*
5563 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5564 {
5565         NOT_IMPLEMENTED;
5566         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5567 }