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