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