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