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