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