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