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