2009-03-03 Zoltan Varga <vargaz@gmail.com>
[mono-debugger.git] / mono / mini / mini-mips.c
blobb70e740b5fa4ada596d9564f1657cdc810200d80
1 /*
2 * mini-mips.c: MIPS backend for the Mono code generator
4 * Authors:
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
11 * (C) 2006 Broadcom
12 * (C) 2003 Ximian, Inc.
14 #include "mini.h"
15 #include <string.h>
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
21 #include <mono/arch/mips/mips-codegen.h>
23 #include "mini-mips.h"
24 #include "cpu-mips.h"
25 #include "trace.h"
26 #include "ir-emit.h"
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 */
33 #define SAVE_LMF 1
34 #define ALWAYS_USE_FP 1
35 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
37 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
38 #define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
40 enum {
41 TLS_MODE_DETECT,
42 TLS_MODE_FAILED,
43 TLS_MODE_LTHREADS,
44 TLS_MODE_NPTL
47 /* This mutex protects architecture specific caches */
48 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
49 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
50 static CRITICAL_SECTION mini_arch_mutex;
52 int mono_exc_esp_offset = 0;
53 static int tls_mode = TLS_MODE_DETECT;
54 static int lmf_pthread_key = -1;
55 static int monothread_key = -1;
56 static int monodomain_key = -1;
58 #undef DEBUG
59 #define DEBUG(a) if (cfg->verbose_level > 1) a
60 #undef DEBUG
61 #define DEBUG(a) a
62 #undef DEBUG
63 #define DEBUG(a)
65 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
66 do { \
67 code = mips_emit_exc_by_name (code, exc_name); \
68 cfg->bb_exit->max_offset += 16; \
69 } while (0)
72 #define emit_linuxthreads_tls(code,dreg,key) do {\
73 int off1, off2; \
74 off1 = offsets_from_pthread_key ((key), &off2); \
75 g_assert_not_reached (); \
76 ppc_lwz ((code), (dreg), off1, ppc_r2); \
77 ppc_lwz ((code), (dreg), off2, (dreg)); \
78 } while (0);
81 #define emit_tls_access(code,dreg,key) do { \
82 switch (tls_mode) { \
83 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
84 default: g_assert_not_reached (); \
85 } \
86 } while (0)
88 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
89 MonoInst *inst; \
90 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
91 inst->type = STACK_R8; \
92 inst->dreg = (dr); \
93 inst->inst_p0 = (void*)(addr); \
94 mono_bblock_add_inst (cfg->cbb, inst); \
95 } while (0)
97 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
98 || ((ins)->opcode == OP_ICOMPARE) \
99 || ((ins)->opcode == OP_LCOMPARE)))
100 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
101 || ((ins)->opcode == OP_ICOMPARE_IMM) \
102 || ((ins)->opcode == OP_LCOMPARE_IMM)))
104 #define INS_REWRITE(ins, op, _s1, _s2) do { \
105 int s1 = _s1; \
106 int s2 = _s2; \
107 ins->opcode = (op); \
108 ins->sreg1 = (s1); \
109 ins->sreg2 = (s2); \
110 } while (0);
112 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
113 int s1 = _s1; \
114 ins->opcode = (op); \
115 ins->sreg1 = (s1); \
116 ins->inst_imm = (_imm); \
117 } while (0);
120 typedef struct InstList InstList;
122 struct InstList {
123 InstList *prev;
124 InstList *next;
125 MonoInst *data;
128 enum {
129 RegTypeGeneral,
130 RegTypeBase,
131 RegTypeFP,
132 RegTypeStructByVal,
133 RegTypeStructByAddr
136 typedef struct {
137 gint32 offset;
138 guint16 vtsize; /* in param area */
139 guint8 reg;
140 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
141 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
142 } ArgInfo;
144 typedef struct {
145 int nargs;
146 int gr;
147 int fr;
148 gboolean gr_passed;
149 gboolean on_stack;
150 int stack_size;
151 guint32 stack_usage;
152 guint32 struct_ret;
153 ArgInfo ret;
154 ArgInfo sig_cookie;
155 ArgInfo args [1];
156 } CallInfo;
158 void patch_lui_addiu(guint32 *ip, guint32 val);
159 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
160 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
161 void mips_adjust_stackframe(MonoCompile *cfg);
162 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
163 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
166 void
167 mono_arch_flush_icache (guint8 *code, gint size)
169 /* Linux/MIPS specific */
170 cacheflush (code, size, BCACHE);
173 void
174 mono_arch_flush_register_windows (void)
178 gboolean
179 mono_arch_is_inst_imm (gint64 imm)
181 return TRUE;
184 static guint8 *
185 mips_emit_exc_by_name(guint8 *code, const char *name)
187 guint32 addr;
189 mips_load_const (code, mips_a0, name);
190 addr = (guint32) mono_arch_get_throw_exception_by_name ();
191 mips_load_const (code, mips_t9, addr);
192 mips_jalr (code, mips_t9, mips_ra);
193 mips_nop (code);
195 return code;
199 guint8 *
200 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
202 if (mips_is_imm16 (v))
203 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
204 else {
205 #ifdef SIZEOF_REGISTER == 8
206 if (v != (long) v) {
207 /* v is not a sign-extended 32-bit value */
208 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
209 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
210 mips_dsll (code, dreg, dreg, 16);
211 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
212 mips_dsll (code, dreg, dreg, 16);
213 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
214 return code;
216 #endif
217 if (((guint32)v) & (1 << 15)) {
218 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
220 else {
221 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
223 if (((guint32)v) & 0xffff)
224 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
226 return code;
229 guint8 *
230 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
232 #if LONG_BRANCH
233 int br_offset = 5;
234 #endif
236 g_assert (ins);
237 #if LONG_BRANCH
238 /* Invert test and emit branch around jump */
239 switch (op) {
240 case OP_MIPS_BEQ:
241 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
242 mips_nop (code);
243 break;
244 case OP_MIPS_BNE:
245 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
246 mips_nop (code);
247 break;
248 case OP_MIPS_BGEZ:
249 mips_bltz (code, ins->sreg1, br_offset);
250 mips_nop (code);
251 break;
252 case OP_MIPS_BGTZ:
253 mips_blez (code, ins->sreg1, br_offset);
254 mips_nop (code);
255 break;
256 case OP_MIPS_BLEZ:
257 mips_bgtz (code, ins->sreg1, br_offset);
258 mips_nop (code);
259 break;
260 case OP_MIPS_BLTZ:
261 mips_bgez (code, ins->sreg1, br_offset);
262 mips_nop (code);
263 break;
264 default:
265 g_assert_not_reached ();
267 if (ins->flags & MONO_INST_BRLABEL)
268 mono_add_patch_info (cfg, code - cfg->native_code,
269 MONO_PATCH_INFO_LABEL, ins->inst_i0);
270 else
271 mono_add_patch_info (cfg, code - cfg->native_code,
272 MONO_PATCH_INFO_BB, ins->inst_true_bb);
273 mips_lui (code, mips_at, mips_zero, 0);
274 mips_addiu (code, mips_at, mips_at, 0);
275 mips_jr (code, mips_at);
276 mips_nop (code);
277 #else
278 if (ins->flags & MONO_INST_BRLABEL)
279 mono_add_patch_info (cfg, code - cfg->native_code,
280 MONO_PATCH_INFO_LABEL, ins->inst_i0);
281 else
282 mono_add_patch_info (cfg, code - cfg->native_code,
283 MONO_PATCH_INFO_BB, ins->inst_true_bb);
284 switch (op) {
285 case OP_MIPS_BEQ:
286 mips_beq (code, ins->sreg1, ins->sreg2, 0);
287 mips_nop (code);
288 break;
289 case OP_MIPS_BNE:
290 mips_bne (code, ins->sreg1, ins->sreg2, 0);
291 mips_nop (code);
292 break;
293 case OP_MIPS_BGEZ:
294 mips_bgez (code, ins->sreg1, 0);
295 mips_nop (code);
296 break;
297 case OP_MIPS_BGTZ:
298 mips_bgtz (code, ins->sreg1, 0);
299 mips_nop (code);
300 break;
301 case OP_MIPS_BLEZ:
302 mips_blez (code, ins->sreg1, 0);
303 mips_nop (code);
304 break;
305 case OP_MIPS_BLTZ:
306 mips_bltz (code, ins->sreg1, 0);
307 mips_nop (code);
308 break;
309 default:
310 g_assert_not_reached ();
312 #endif
313 return (code);
316 /* XXX - big-endian dependent? */
317 void
318 patch_lui_addiu(guint32 *ip, guint32 val)
320 guint16 *__lui_addiu = (guint16*)(void *)(ip);
322 #if 0
323 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
324 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
325 fflush (stdout);
326 #endif
327 if (((guint32)(val)) & (1 << 15))
328 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
329 else
330 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
331 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
332 mono_arch_flush_icache ((guint8 *)ip, 8);
335 guint32 trap_target;
336 void
337 mips_patch (guint32 *code, guint32 target)
339 guint32 ins = *code;
340 guint32 op = ins >> 26;
341 guint32 diff, offset;
343 g_assert (trap_target != target);
344 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
345 switch (op) {
346 case 0x00: /* jr ra */
347 if (ins == 0x3e00008)
348 break;
349 g_assert_not_reached ();
350 break;
351 case 0x02: /* j */
352 case 0x03: /* jal */
353 g_assert (!(target & 0x03));
354 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
355 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
356 *code = ins;
357 mono_arch_flush_icache ((guint8 *)code, 4);
358 break;
359 case 0x01: /* BLTZ */
360 case 0x04: /* BEQ */
361 case 0x05: /* BNE */
362 case 0x06: /* BLEZ */
363 case 0x07: /* BGTZ */
364 case 0x11: /* bc1t */
365 diff = target - (guint32)(code + 1);
366 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
367 g_assert (!(diff & 0x03));
368 offset = ((gint32)diff) >> 2;
369 g_assert (((int)offset) == ((int)(short)offset));
370 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
371 *code = ins;
372 mono_arch_flush_icache ((guint8 *)code, 4);
373 break;
374 case 0x0f: /* LUI / ADDIU pair */
375 patch_lui_addiu (code, target);
376 mono_arch_flush_icache ((guint8 *)code, 8);
377 break;
379 default:
380 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
381 g_assert_not_reached ();
385 #if 0
386 static int
387 offsets_from_pthread_key (guint32 key, int *offset2)
389 int idx1 = key / 32;
390 int idx2 = key % 32;
391 *offset2 = idx2 * sizeof (gpointer);
392 return 284 + idx1 * sizeof (gpointer);
394 #endif
396 const char*
397 mono_arch_regname (int reg) {
398 #if _MIPS_SIM == _ABIO32
399 static const char * rnames[] = {
400 "zero", "at", "v0", "v1",
401 "a0", "a1", "a2", "a3",
402 "t0", "t1", "t2", "t3",
403 "t4", "t5", "t6", "t7",
404 "s0", "s1", "s2", "s3",
405 "s4", "s5", "s6", "s7",
406 "t8", "t9", "k0", "k1",
407 "gp", "sp", "fp", "ra"
409 #elif _MIPS_SIM == _ABIN32
410 static const char * rnames[] = {
411 "zero", "at", "v0", "v1",
412 "a0", "a1", "a2", "a3",
413 "a4", "a5", "a6", "a7",
414 "t0", "t1", "t2", "t3",
415 "s0", "s1", "s2", "s3",
416 "s4", "s5", "s6", "s7",
417 "t8", "t9", "k0", "k1",
418 "gp", "sp", "fp", "ra"
420 #endif
421 if (reg >= 0 && reg < 32)
422 return rnames [reg];
423 return "unknown";
426 const char*
427 mono_arch_fregname (int reg) {
428 static const char * rnames[] = {
429 "f0", "f1", "f2", "f3",
430 "f4", "f5", "f6", "f7",
431 "f8", "f9", "f10", "f11",
432 "f12", "f13", "f14", "f15",
433 "f16", "f17", "f18", "f19",
434 "f20", "f21", "f22", "f23",
435 "f24", "f25", "f26", "f27",
436 "f28", "f29", "f30", "f31"
438 if (reg >= 0 && reg < 32)
439 return rnames [reg];
440 return "unknown";
443 /* this function overwrites at */
444 static guint8*
445 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
447 /* XXX write a loop, not an unrolled loop */
448 while (size > 0) {
449 mips_lw (code, mips_at, sreg, soffset);
450 mips_sw (code, mips_at, dreg, doffset);
451 size -= 4;
452 soffset += 4;
453 doffset += 4;
455 return code;
459 * mono_arch_get_argument_info:
460 * @csig: a method signature
461 * @param_count: the number of parameters to consider
462 * @arg_info: an array to store the result infos
464 * Gathers information on parameters such as size, alignment and
465 * padding. arg_info should be large enought to hold param_count + 1 entries.
467 * Returns the size of the activation frame.
470 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
472 int k, frame_size = 0;
473 guint32 size, align, pad;
474 int offset = 0;
476 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
477 frame_size += sizeof (gpointer);
478 offset += 4;
481 arg_info [0].offset = offset;
483 if (csig->hasthis) {
484 frame_size += sizeof (gpointer);
485 offset += 4;
488 arg_info [0].size = frame_size;
490 for (k = 0; k < param_count; k++) {
491 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
493 /* ignore alignment for now */
494 align = 1;
496 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
497 arg_info [k].pad = pad;
498 frame_size += size;
499 arg_info [k + 1].pad = 0;
500 arg_info [k + 1].size = size;
501 offset += pad;
502 arg_info [k + 1].offset = offset;
503 offset += size;
506 align = MONO_ARCH_FRAME_ALIGNMENT;
507 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
508 arg_info [k].pad = pad;
510 return frame_size;
514 gpointer
515 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
517 /* FIXME: handle returning a struct */
518 if (MONO_TYPE_ISSTRUCT (sig->ret))
519 return (gpointer)regs [mips_a1];
520 return (gpointer)regs [mips_a0];
524 * Initialize the cpu to execute managed code.
526 void
527 mono_arch_cpu_init (void)
532 * Initialize architecture specific code.
534 void
535 mono_arch_init (void)
537 InitializeCriticalSection (&mini_arch_mutex);
541 * Cleanup architecture specific code.
543 void
544 mono_arch_cleanup (void)
546 DeleteCriticalSection (&mini_arch_mutex);
550 * This function returns the optimizations supported on this cpu.
552 guint32
553 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
555 guint32 opts = 0;
557 /* no mips-specific optimizations yet */
558 *exclude_mask = 0;
559 return opts;
562 static gboolean
563 is_regsize_var (MonoType *t) {
564 if (t->byref)
565 return TRUE;
566 t = mono_type_get_underlying_type (t);
567 switch (t->type) {
568 case MONO_TYPE_I4:
569 case MONO_TYPE_U4:
570 #if (SIZEOF_REGISTER == 8)
571 case MONO_TYPE_I8:
572 case MONO_TYPE_U8:
573 #endif
574 case MONO_TYPE_I:
575 case MONO_TYPE_U:
576 case MONO_TYPE_PTR:
577 case MONO_TYPE_FNPTR:
578 return TRUE;
579 case MONO_TYPE_OBJECT:
580 case MONO_TYPE_STRING:
581 case MONO_TYPE_CLASS:
582 case MONO_TYPE_SZARRAY:
583 case MONO_TYPE_ARRAY:
584 return TRUE;
585 case MONO_TYPE_GENERICINST:
586 if (!mono_type_generic_inst_is_valuetype (t))
587 return TRUE;
588 return FALSE;
589 case MONO_TYPE_VALUETYPE:
590 return FALSE;
592 return FALSE;
595 GList *
596 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
598 GList *vars = NULL;
599 int i;
601 for (i = 0; i < cfg->num_varinfo; i++) {
602 MonoInst *ins = cfg->varinfo [i];
603 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
605 /* unused vars */
606 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
607 continue;
609 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
610 continue;
612 /* we can only allocate 32 bit values */
613 if (is_regsize_var (ins->inst_vtype)) {
614 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
615 g_assert (i == vmv->idx);
616 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
620 return vars;
623 GList *
624 mono_arch_get_global_int_regs (MonoCompile *cfg)
626 GList *regs = NULL;
628 regs = g_list_prepend (regs, (gpointer)mips_s0);
629 regs = g_list_prepend (regs, (gpointer)mips_s1);
630 regs = g_list_prepend (regs, (gpointer)mips_s2);
631 regs = g_list_prepend (regs, (gpointer)mips_s3);
632 regs = g_list_prepend (regs, (gpointer)mips_s4);
633 //regs = g_list_prepend (regs, (gpointer)mips_s5);
634 regs = g_list_prepend (regs, (gpointer)mips_s6);
635 regs = g_list_prepend (regs, (gpointer)mips_s7);
637 return regs;
641 * mono_arch_regalloc_cost:
643 * Return the cost, in number of memory references, of the action of
644 * allocating the variable VMV into a register during global register
645 * allocation.
647 guint32
648 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
650 /* FIXME: */
651 return 2;
654 static void
655 args_onto_stack (CallInfo *info)
657 g_assert (!info->on_stack);
658 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
659 info->on_stack = TRUE;
660 info->stack_size = MIPS_STACK_PARAM_OFFSET;
663 #if _MIPS_SIM == _ABIO32
665 * O32 calling convention version
668 static void
669 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
670 /* First, see if we need to drop onto the stack */
671 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
672 args_onto_stack (info);
674 /* Now, place the argument */
675 if (info->on_stack) {
676 ainfo->regtype = RegTypeBase;
677 ainfo->reg = mips_sp; /* in the caller */
678 ainfo->offset = info->stack_size;
680 else {
681 ainfo->regtype = RegTypeGeneral;
682 ainfo->reg = info->gr;
683 info->gr += 1;
684 info->gr_passed = TRUE;
686 info->stack_size += 4;
689 static void
690 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
691 /* First, see if we need to drop onto the stack */
692 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
693 args_onto_stack (info);
695 /* Now, place the argument */
696 if (info->on_stack) {
697 g_assert (info->stack_size % 4 == 0);
698 info->stack_size += (info->stack_size % 8);
700 ainfo->regtype = RegTypeBase;
701 ainfo->reg = mips_sp; /* in the caller */
702 ainfo->offset = info->stack_size;
704 else {
705 // info->gr must be a0 or a2
706 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
707 g_assert(info->gr <= MIPS_LAST_ARG_REG);
709 ainfo->regtype = RegTypeGeneral;
710 ainfo->reg = info->gr;
711 info->gr += 2;
712 info->gr_passed = TRUE;
714 info->stack_size += 8;
717 static void
718 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
719 /* First, see if we need to drop onto the stack */
720 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
721 args_onto_stack (info);
723 /* Now, place the argument */
724 if (info->on_stack) {
725 ainfo->regtype = RegTypeBase;
726 ainfo->reg = mips_sp; /* in the caller */
727 ainfo->offset = info->stack_size;
729 else {
730 /* Only use FP regs for args if no int args passed yet */
731 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
732 ainfo->regtype = RegTypeFP;
733 ainfo->reg = info->fr;
734 /* Even though it's a single-precision float, it takes up two FP regs */
735 info->fr += 2;
736 /* FP and GP slots do not overlap */
737 info->gr += 1;
739 else {
740 /* Passing single-precision float arg in a GP register
741 * such as: func (0, 1.0, 2, 3);
742 * In this case, only one 'gr' register is consumed.
744 ainfo->regtype = RegTypeGeneral;
745 ainfo->reg = info->gr;
747 info->gr += 1;
748 info->gr_passed = TRUE;
751 info->stack_size += 4;
754 static void
755 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
756 /* First, see if we need to drop onto the stack */
757 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
758 args_onto_stack (info);
760 /* Now, place the argument */
761 if (info->on_stack) {
762 g_assert(info->stack_size % 4 == 0);
763 info->stack_size += (info->stack_size % 8);
765 ainfo->regtype = RegTypeBase;
766 ainfo->reg = mips_sp; /* in the caller */
767 ainfo->offset = info->stack_size;
769 else {
770 /* Only use FP regs for args if no int args passed yet */
771 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
772 ainfo->regtype = RegTypeFP;
773 ainfo->reg = info->fr;
774 info->fr += 2;
775 /* FP and GP slots do not overlap */
776 info->gr += 2;
778 else {
779 // info->gr must be a0 or a2
780 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
781 g_assert(info->gr <= MIPS_LAST_ARG_REG);
783 ainfo->regtype = RegTypeGeneral;
784 ainfo->reg = info->gr;
785 info->gr += 2;
786 info->gr_passed = TRUE;
789 info->stack_size += 8;
791 #elif _MIPS_SIM == _ABIN32
793 * N32 calling convention version
796 static void
797 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
798 /* First, see if we need to drop onto the stack */
799 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
800 args_onto_stack (info);
802 /* Now, place the argument */
803 if (info->on_stack) {
804 ainfo->regtype = RegTypeBase;
805 ainfo->reg = mips_sp; /* in the caller */
806 ainfo->offset = info->stack_size;
807 info->stack_size += SIZEOF_REGISTER;
809 else {
810 ainfo->regtype = RegTypeGeneral;
811 ainfo->reg = info->gr;
812 info->gr += 1;
813 info->gr_passed = TRUE;
817 static void
818 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
819 /* First, see if we need to drop onto the stack */
820 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
821 args_onto_stack (info);
823 /* Now, place the argument */
824 if (info->on_stack) {
825 g_assert (info->stack_size % 4 == 0);
826 info->stack_size += (info->stack_size % 8);
828 ainfo->regtype = RegTypeBase;
829 ainfo->reg = mips_sp; /* in the caller */
830 ainfo->offset = info->stack_size;
831 info->stack_size += SIZEOF_REGISTER;
833 else {
834 g_assert (info->gr <= MIPS_LAST_ARG_REG);
836 ainfo->regtype = RegTypeGeneral;
837 ainfo->reg = info->gr;
838 info->gr += 1;
839 info->gr_passed = TRUE;
843 static void
844 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
845 /* First, see if we need to drop onto the stack */
846 if (!info->on_stack) {
847 if (info->gr > MIPS_LAST_ARG_REG)
848 args_onto_stack (info);
849 else if (info->fr > MIPS_LAST_FPARG_REG)
850 args_onto_stack (info);
853 /* Now, place the argument */
854 if (info->on_stack) {
855 ainfo->regtype = RegTypeBase;
856 ainfo->reg = mips_sp; /* in the caller */
857 ainfo->offset = info->stack_size;
858 info->stack_size += FREG_SIZE;
860 else {
861 ainfo->regtype = RegTypeFP;
862 ainfo->reg = info->fr;
863 info->fr += 1;
864 /* FP and GP slots do not overlap */
865 info->gr += 1;
869 static void
870 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
871 /* First, see if we need to drop onto the stack */
872 if (!info->on_stack) {
873 if (info->gr > MIPS_LAST_ARG_REG)
874 args_onto_stack (info);
875 else if (info->fr > MIPS_LAST_FPARG_REG)
876 args_onto_stack (info);
879 /* Now, place the argument */
880 if (info->on_stack) {
881 g_assert(info->stack_size % 4 == 0);
882 info->stack_size += (info->stack_size % 8);
884 ainfo->regtype = RegTypeBase;
885 ainfo->reg = mips_sp; /* in the caller */
886 ainfo->offset = info->stack_size;
887 info->stack_size += FREG_SIZE;
889 else {
890 ainfo->regtype = RegTypeFP;
891 ainfo->reg = info->fr;
892 info->fr += 1;
893 /* FP and GP slots do not overlap */
894 info->gr += 1;
897 #endif
899 static CallInfo*
900 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
902 guint i;
903 int n = sig->hasthis + sig->param_count;
904 guint32 simpletype;
905 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
907 cinfo->fr = MIPS_FIRST_FPARG_REG;
908 cinfo->gr = MIPS_FIRST_ARG_REG;
909 cinfo->stack_size = 0;
911 DEBUG(printf("calculate_sizes\n"));
913 /* handle returning a struct */
914 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
915 cinfo->struct_ret = cinfo->gr;
916 add_int32_arg (cinfo, &cinfo->ret);
919 n = 0;
920 if (sig->hasthis) {
921 add_int32_arg (cinfo, cinfo->args + n);
922 n++;
924 DEBUG(printf("params: %d\n", sig->param_count));
925 for (i = 0; i < sig->param_count; ++i) {
926 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
927 /* Prevent implicit arguments and sig_cookie from
928 being passed in registers */
929 args_onto_stack (cinfo);
930 /* Emit the signature cookie just before the implicit arguments */
931 add_int32_arg (cinfo, &cinfo->sig_cookie);
933 DEBUG(printf("param %d: ", i));
934 if (sig->params [i]->byref) {
935 DEBUG(printf("byref\n"));
936 add_int32_arg (cinfo, &cinfo->args[n]);
937 n++;
938 continue;
940 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
941 switch (simpletype) {
942 case MONO_TYPE_BOOLEAN:
943 case MONO_TYPE_I1:
944 case MONO_TYPE_U1:
945 DEBUG(printf("1 byte\n"));
946 cinfo->args [n].size = 1;
947 add_int32_arg (cinfo, &cinfo->args[n]);
948 n++;
949 break;
950 case MONO_TYPE_CHAR:
951 case MONO_TYPE_I2:
952 case MONO_TYPE_U2:
953 DEBUG(printf("2 bytes\n"));
954 cinfo->args [n].size = 2;
955 add_int32_arg (cinfo, &cinfo->args[n]);
956 n++;
957 break;
958 case MONO_TYPE_I4:
959 case MONO_TYPE_U4:
960 DEBUG(printf("4 bytes\n"));
961 cinfo->args [n].size = 4;
962 add_int32_arg (cinfo, &cinfo->args[n]);
963 n++;
964 break;
965 case MONO_TYPE_I:
966 case MONO_TYPE_U:
967 case MONO_TYPE_PTR:
968 case MONO_TYPE_FNPTR:
969 case MONO_TYPE_CLASS:
970 case MONO_TYPE_OBJECT:
971 case MONO_TYPE_STRING:
972 case MONO_TYPE_SZARRAY:
973 case MONO_TYPE_ARRAY:
974 cinfo->args [n].size = sizeof (gpointer);
975 add_int32_arg (cinfo, &cinfo->args[n]);
976 n++;
977 break;
978 case MONO_TYPE_GENERICINST:
979 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
980 cinfo->args [n].size = sizeof (gpointer);
981 add_int32_arg (cinfo, &cinfo->args[n]);
982 n++;
983 break;
985 /* Fall through */
986 case MONO_TYPE_VALUETYPE: {
987 int j;
988 int nwords = 0;
989 int has_offset = FALSE;
990 ArgInfo dummy_arg;
991 gint size, alignment;
992 MonoClass *klass;
994 klass = mono_class_from_mono_type (sig->params [i]);
995 if (is_pinvoke)
996 size = mono_class_native_size (klass, NULL);
997 else
998 size = mono_class_value_size (klass, NULL);
999 alignment = mono_class_min_align (klass);
1000 #if MIPS_PASS_STRUCTS_BY_VALUE
1001 /* Need to do alignment if struct contains long or double */
1002 if (alignment > 4) {
1003 if (cinfo->stack_size & (alignment - 1)) {
1004 add_int32_arg (cinfo, &dummy_arg);
1006 g_assert (!(cinfo->stack_size & (alignment - 1)));
1009 #if 0
1010 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1011 mono_class_native_size (sig->params [i]->data.klass, NULL),
1012 cinfo->stack_size, alignment);
1013 #endif
1014 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1015 g_assert (cinfo->args [n].size == 0);
1016 g_assert (cinfo->args [n].vtsize == 0);
1017 for (j = 0; j < nwords; ++j) {
1018 if (j == 0) {
1019 add_int32_arg (cinfo, &cinfo->args [n]);
1020 if (cinfo->on_stack)
1021 has_offset = TRUE;
1022 } else {
1023 add_int32_arg (cinfo, &dummy_arg);
1024 if (!has_offset && cinfo->on_stack) {
1025 cinfo->args [n].offset = dummy_arg.offset;
1026 has_offset = TRUE;
1029 if (cinfo->on_stack)
1030 cinfo->args [n].vtsize += 1;
1031 else
1032 cinfo->args [n].size += 1;
1034 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1035 cinfo->args [n].regtype = RegTypeStructByVal;
1036 #else
1037 add_int32_arg (cinfo, &cinfo->args[n]);
1038 cinfo->args [n].regtype = RegTypeStructByAddr;
1039 #endif
1040 n++;
1041 break;
1043 case MONO_TYPE_TYPEDBYREF: {
1044 /* keep in sync or merge with the valuetype case */
1045 #if MIPS_PASS_STRUCTS_BY_VALUE
1047 int size = sizeof (MonoTypedRef);
1048 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1049 cinfo->args [n].regtype = RegTypeStructByVal;
1050 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
1051 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
1052 int n_in_regs = rest >= nwords? nwords: rest;
1053 cinfo->args [n].size = n_in_regs;
1054 cinfo->args [n].vtsize = nwords - n_in_regs;
1055 cinfo->args [n].reg = cinfo->gr;
1056 cinfo->gr += n_in_regs;
1057 cinfo->gr_passed = TRUE;
1058 } else {
1059 cinfo->args [n].size = 0;
1060 cinfo->args [n].vtsize = nwords;
1062 if (cinfo->args [n].vtsize > 0) {
1063 if (!cinfo->on_stack)
1064 args_onto_stack (cinfo);
1065 g_assert(cinfo->on_stack);
1066 cinfo->args [n].offset = cinfo->stack_size;
1067 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
1068 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
1071 #else
1072 add_int32_arg (cinfo, &cinfo->args[n]);
1073 cinfo->args [n].regtype = RegTypeStructByAddr;
1074 #endif
1075 n++;
1076 break;
1078 case MONO_TYPE_U8:
1079 case MONO_TYPE_I8:
1080 DEBUG(printf("8 bytes\n"));
1081 cinfo->args [n].size = 8;
1082 add_int64_arg (cinfo, &cinfo->args[n]);
1083 n++;
1084 break;
1085 case MONO_TYPE_R4:
1086 DEBUG(printf("R4\n"));
1087 cinfo->args [n].size = 4;
1088 add_float32_arg (cinfo, &cinfo->args[n]);
1089 n++;
1090 break;
1091 case MONO_TYPE_R8:
1092 DEBUG(printf("R8\n"));
1093 cinfo->args [n].size = 8;
1094 add_float64_arg (cinfo, &cinfo->args[n]);
1095 n++;
1096 break;
1097 default:
1098 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1103 simpletype = mono_type_get_underlying_type (sig->ret)->type;
1104 switch (simpletype) {
1105 case MONO_TYPE_BOOLEAN:
1106 case MONO_TYPE_I1:
1107 case MONO_TYPE_U1:
1108 case MONO_TYPE_I2:
1109 case MONO_TYPE_U2:
1110 case MONO_TYPE_CHAR:
1111 case MONO_TYPE_I4:
1112 case MONO_TYPE_U4:
1113 case MONO_TYPE_I:
1114 case MONO_TYPE_U:
1115 case MONO_TYPE_PTR:
1116 case MONO_TYPE_FNPTR:
1117 case MONO_TYPE_CLASS:
1118 case MONO_TYPE_OBJECT:
1119 case MONO_TYPE_SZARRAY:
1120 case MONO_TYPE_ARRAY:
1121 case MONO_TYPE_STRING:
1122 cinfo->ret.reg = mips_v0;
1123 break;
1124 case MONO_TYPE_U8:
1125 case MONO_TYPE_I8:
1126 cinfo->ret.reg = mips_v0;
1127 break;
1128 case MONO_TYPE_R4:
1129 case MONO_TYPE_R8:
1130 cinfo->ret.reg = mips_f0;
1131 cinfo->ret.regtype = RegTypeFP;
1132 break;
1133 case MONO_TYPE_GENERICINST:
1134 if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
1135 cinfo->ret.reg = mips_v0;
1136 break;
1138 break;
1139 case MONO_TYPE_VALUETYPE:
1140 break;
1141 case MONO_TYPE_TYPEDBYREF:
1142 case MONO_TYPE_VOID:
1143 break;
1144 default:
1145 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1149 /* align stack size to 16 */
1150 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1152 cinfo->stack_usage = cinfo->stack_size;
1153 return cinfo;
1158 * Set var information according to the calling convention. mips version.
1159 * The locals var stuff should most likely be split in another method.
1161 void
1162 mono_arch_allocate_vars (MonoCompile *cfg)
1164 MonoMethodSignature *sig;
1165 MonoMethodHeader *header;
1166 MonoInst *inst;
1167 int i, offset, size, align, curinst;
1168 int frame_reg = mips_sp;
1169 guint32 iregs_to_save = 0;
1170 #if SAVE_FP_REGS
1171 guint32 fregs_to_restore;
1172 #endif
1174 /* spill down, we'll fix it in a separate pass */
1175 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1177 /* allow room for the vararg method args: void* and long/double */
1178 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1179 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1181 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1182 * call convs needs to be handled this way.
1184 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1185 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1187 /* gtk-sharp and other broken code will dllimport vararg functions even with
1188 * non-varargs signatures. Since there is little hope people will get this right
1189 * we assume they won't.
1191 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1192 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1194 /* a0-a3 always present */
1195 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1197 header = mono_method_get_header (cfg->method);
1199 sig = mono_method_signature (cfg->method);
1202 * We use the frame register also for any method that has
1203 * exception clauses. This way, when the handlers are called,
1204 * the code will reference local variables using the frame reg instead of
1205 * the stack pointer: if we had to restore the stack pointer, we'd
1206 * corrupt the method frames that are already on the stack (since
1207 * filters get called before stack unwinding happens) when the filter
1208 * code would call any method (this also applies to finally etc.).
1211 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1212 frame_reg = mips_fp;
1213 cfg->frame_reg = frame_reg;
1214 if (frame_reg != mips_sp) {
1215 cfg->used_int_regs |= 1 << frame_reg;
1218 offset = 0;
1219 curinst = 0;
1220 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1221 /* FIXME: handle long and FP values */
1222 switch (mono_type_get_underlying_type (sig->ret)->type) {
1223 case MONO_TYPE_VOID:
1224 break;
1225 case MONO_TYPE_R4:
1226 case MONO_TYPE_R8:
1227 cfg->ret->opcode = OP_REGVAR;
1228 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1229 break;
1230 default:
1231 cfg->ret->opcode = OP_REGVAR;
1232 cfg->ret->inst_c0 = mips_v0;
1233 break;
1236 /* Space for outgoing parameters, including a0-a3 */
1237 offset += cfg->param_area;
1239 /* allow room to save the return value (if it's a struct) */
1240 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1241 offset += 8;
1243 if (sig->call_convention == MONO_CALL_VARARG) {
1244 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1247 /* Now handle the local variables */
1249 curinst = cfg->locals_start;
1250 for (i = curinst; i < cfg->num_varinfo; ++i) {
1251 inst = cfg->varinfo [i];
1252 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1253 continue;
1255 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1256 * pinvoke wrappers when they call functions returning structure
1258 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1259 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
1260 else
1261 size = mono_type_size (inst->inst_vtype, &align);
1263 offset += align - 1;
1264 offset &= ~(align - 1);
1265 inst->inst_offset = offset;
1266 inst->opcode = OP_REGOFFSET;
1267 inst->inst_basereg = frame_reg;
1268 offset += size;
1269 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1272 /* Space for LMF (if needed) */
1273 #if SAVE_LMF
1274 if (cfg->method->save_lmf) {
1275 /* align the offset to 16 bytes */
1276 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1277 cfg->arch.lmf_offset = offset;
1278 offset += sizeof (MonoLMF);
1280 #endif
1282 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1283 * args or return vals. Extra stack space avoids this in a lot of cases.
1285 offset += EXTRA_STACK_SPACE;
1287 /* Space for saved registers */
1288 cfg->arch.iregs_offset = offset;
1289 #if SAVE_ALL_REGS
1290 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1291 #else
1292 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1293 #endif
1294 if (iregs_to_save) {
1295 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1296 if (iregs_to_save & (1 << i)) {
1297 offset += SIZEOF_REGISTER;
1302 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1303 * args or return vals. Extra stack space avoids this in a lot of cases.
1305 offset += EXTRA_STACK_SPACE;
1307 /* saved float registers */
1308 #if SAVE_FP_REGS
1309 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1310 if (fregs_to_restore) {
1311 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1312 if (fregs_to_restore & (1 << i)) {
1313 offset += sizeof(double);
1317 #endif
1319 #if _MIPS_SIM == _ABIO32
1320 /* Now add space for saving the ra */
1321 offset += SIZEOF_VOID_P;
1323 /* change sign? */
1324 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1325 cfg->stack_offset = offset;
1326 cfg->arch.local_alloc_offset = cfg->stack_offset;
1327 #endif
1330 * Now allocate stack slots for the int arg regs (a0 - a3)
1331 * On MIPS o32, these are just above the incoming stack pointer
1332 * Even if the arg has been assigned to a regvar, it gets a stack slot
1335 /* Return struct-by-value results in a hidden first argument */
1336 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1337 cfg->vret_addr->opcode = OP_REGOFFSET;
1338 cfg->vret_addr->inst_c0 = mips_a0;
1339 cfg->vret_addr->inst_offset = offset;
1340 cfg->vret_addr->inst_basereg = frame_reg;
1341 offset += SIZEOF_REGISTER;
1344 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1345 inst = cfg->args [i];
1346 if (inst->opcode != OP_REGVAR) {
1347 MonoType *arg_type;
1349 if (sig->hasthis && (i == 0))
1350 arg_type = &mono_defaults.object_class->byval_arg;
1351 else
1352 arg_type = sig->params [i - sig->hasthis];
1354 inst->opcode = OP_REGOFFSET;
1355 size = mono_type_size (arg_type, &align);
1357 if (size < SIZEOF_REGISTER) {
1358 size = SIZEOF_REGISTER;
1359 align = SIZEOF_REGISTER;
1361 inst->inst_basereg = frame_reg;
1362 offset = (offset + align - 1) & ~(align - 1);
1363 inst->inst_offset = offset;
1364 offset += size;
1365 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1366 cfg->sig_cookie += size;
1367 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1369 else {
1370 #if _MIPS_SIM == _ABIO32
1371 /* o32: Even a0-a3 get stack slots */
1372 size = SIZEOF_REGISTER;
1373 align = SIZEOF_REGISTER;
1374 inst->inst_basereg = frame_reg;
1375 offset = (offset + align - 1) & ~(align - 1);
1376 inst->inst_offset = offset;
1377 offset += size;
1378 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1379 cfg->sig_cookie += size;
1380 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1381 #endif
1384 #if _MIPS_SIM == _ABIN32
1385 /* Now add space for saving the ra */
1386 offset += SIZEOF_VOID_P;
1388 /* change sign? */
1389 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1390 cfg->stack_offset = offset;
1391 cfg->arch.local_alloc_offset = cfg->stack_offset;
1392 #endif
1395 void
1396 mono_arch_create_vars (MonoCompile *cfg)
1398 MonoMethodSignature *sig;
1400 sig = mono_method_signature (cfg->method);
1402 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1403 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1404 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1405 printf ("vret_addr = ");
1406 mono_print_ins (cfg->vret_addr);
1411 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1412 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1416 * take the arguments and generate the arch-specific
1417 * instructions to properly call the function in call.
1418 * This includes pushing, moving arguments to the right register
1419 * etc.
1420 * Issue: who does the spilling if needed, and when?
1422 static void
1423 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1425 int sig_reg = mono_alloc_ireg (cfg);
1427 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1428 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1429 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1432 void
1433 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1435 MonoInst *in, *ins;
1436 MonoMethodSignature *sig;
1437 int i, n;
1438 CallInfo *cinfo;
1439 int is_virtual = 0;
1441 sig = call->signature;
1442 n = sig->param_count + sig->hasthis;
1444 cinfo = calculate_sizes (sig, sig->pinvoke);
1445 if (cinfo->struct_ret)
1446 call->used_iregs |= 1 << cinfo->struct_ret;
1448 for (i = 0; i < n; ++i) {
1449 ArgInfo *ainfo = cinfo->args + i;
1450 MonoType *t;
1452 if (i >= sig->hasthis)
1453 t = sig->params [i - sig->hasthis];
1454 else
1455 t = &mono_defaults.int_class->byval_arg;
1456 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1458 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1459 emit_sig_cookie (cfg, call, cinfo);
1460 if (is_virtual && i == 0) {
1461 /* the argument will be attached to the call instrucion */
1462 in = call->args [i];
1463 call->used_iregs |= 1 << ainfo->reg;
1464 continue;
1466 in = call->args [i];
1467 if (ainfo->regtype == RegTypeGeneral) {
1468 #if SIZEOF_REGISTER == 4
1469 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1470 MONO_INST_NEW (cfg, ins, OP_MOVE);
1471 ins->dreg = mono_alloc_ireg (cfg);
1472 ins->sreg1 = in->dreg + 1;
1473 MONO_ADD_INS (cfg->cbb, ins);
1474 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1476 MONO_INST_NEW (cfg, ins, OP_MOVE);
1477 ins->dreg = mono_alloc_ireg (cfg);
1478 ins->sreg1 = in->dreg + 2;
1479 MONO_ADD_INS (cfg->cbb, ins);
1480 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1481 } else
1482 #endif
1483 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1484 int freg;
1486 #if PROMOTE_R4_TO_R8
1487 /* ??? - convert to single first? */
1488 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1489 ins->dreg = mono_alloc_freg (cfg);
1490 ins->sreg1 = in->dreg;
1491 MONO_ADD_INS (cfg->cbb, ins);
1492 freg = ins->dreg;
1493 #else
1494 freg = in->dreg;
1495 #endif
1496 /* trying to load float value into int registers */
1497 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1498 ins->dreg = mono_alloc_ireg (cfg);
1499 ins->sreg1 = freg;
1500 MONO_ADD_INS (cfg->cbb, ins);
1501 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1502 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1503 /* trying to load float value into int registers */
1504 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1505 ins->dreg = mono_alloc_ireg (cfg);
1506 ins->sreg1 = in->dreg;
1507 MONO_ADD_INS (cfg->cbb, ins);
1508 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1509 } else {
1510 MONO_INST_NEW (cfg, ins, OP_MOVE);
1511 ins->dreg = mono_alloc_ireg (cfg);
1512 ins->sreg1 = in->dreg;
1513 MONO_ADD_INS (cfg->cbb, ins);
1514 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1516 } else if (ainfo->regtype == RegTypeStructByAddr) {
1517 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1518 ins->opcode = OP_OUTARG_VT;
1519 ins->sreg1 = in->dreg;
1520 ins->klass = in->klass;
1521 ins->inst_p0 = call;
1522 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1523 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1524 MONO_ADD_INS (cfg->cbb, ins);
1525 } else if (ainfo->regtype == RegTypeStructByVal) {
1526 /* this is further handled in mono_arch_emit_outarg_vt () */
1527 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1528 ins->opcode = OP_OUTARG_VT;
1529 ins->sreg1 = in->dreg;
1530 ins->klass = in->klass;
1531 ins->inst_p0 = call;
1532 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1533 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1534 MONO_ADD_INS (cfg->cbb, ins);
1535 } else if (ainfo->regtype == RegTypeBase) {
1536 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1537 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1538 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1539 if (t->type == MONO_TYPE_R8)
1540 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1541 else
1542 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1543 } else {
1544 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1546 } else if (ainfo->regtype == RegTypeFP) {
1547 if (t->type == MONO_TYPE_VALUETYPE) {
1548 /* this is further handled in mono_arch_emit_outarg_vt () */
1549 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1550 ins->opcode = OP_OUTARG_VT;
1551 ins->sreg1 = in->dreg;
1552 ins->klass = in->klass;
1553 ins->inst_p0 = call;
1554 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1555 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1556 MONO_ADD_INS (cfg->cbb, ins);
1558 cfg->flags |= MONO_CFG_HAS_FPOUT;
1559 } else {
1560 int dreg = mono_alloc_freg (cfg);
1562 if (ainfo->size == 4) {
1563 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1564 } else {
1565 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1566 ins->dreg = dreg;
1567 ins->sreg1 = in->dreg;
1568 MONO_ADD_INS (cfg->cbb, ins);
1571 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1572 cfg->flags |= MONO_CFG_HAS_FPOUT;
1574 } else {
1575 g_assert_not_reached ();
1579 /* Emit the signature cookie in the case that there is no
1580 additional argument */
1581 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1582 emit_sig_cookie (cfg, call, cinfo);
1584 if (cinfo->struct_ret) {
1585 MonoInst *vtarg;
1587 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1588 vtarg->sreg1 = call->vret_var->dreg;
1589 vtarg->dreg = mono_alloc_preg (cfg);
1590 MONO_ADD_INS (cfg->cbb, vtarg);
1592 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1594 #if 0
1596 * Reverse the call->out_args list.
1599 MonoInst *prev = NULL, *list = call->out_args, *next;
1600 while (list) {
1601 next = list->next;
1602 list->next = prev;
1603 prev = list;
1604 list = next;
1606 call->out_args = prev;
1608 #endif
1609 call->stack_usage = cinfo->stack_usage;
1610 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1611 #if _MIPS_SIM == _ABIO32
1612 /* a0-a3 always present */
1613 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1614 #endif
1615 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1616 cfg->flags |= MONO_CFG_HAS_CALLS;
1618 * should set more info in call, such as the stack space
1619 * used by the args that needs to be added back to esp
1622 g_free (cinfo);
1625 void
1626 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1628 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1629 ArgInfo *ainfo = ins->inst_p1;
1630 int ovf_size = ainfo->vtsize;
1631 int doffset = ainfo->offset;
1632 int i, soffset, dreg;
1634 if (ainfo->regtype == RegTypeStructByVal) {
1635 #if 1
1636 if (cfg->verbose_level > 0) {
1637 char* nm = mono_method_full_name (cfg->method, TRUE);
1638 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1639 nm, doffset, ainfo->size, ovf_size);
1640 g_free (nm);
1642 #endif
1644 soffset = 0;
1645 for (i = 0; i < ainfo->size; ++i) {
1646 dreg = mono_alloc_ireg (cfg);
1647 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1648 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1649 soffset += SIZEOF_REGISTER;
1651 if (ovf_size != 0) {
1652 mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1654 } else if (ainfo->regtype == RegTypeFP) {
1655 int tmpr = mono_alloc_freg (cfg);
1657 if (ainfo->size == 4)
1658 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1659 else
1660 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1661 dreg = mono_alloc_freg (cfg);
1662 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1663 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1664 } else {
1665 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1666 MonoInst *load;
1667 guint32 size;
1669 /* FIXME: alignment? */
1670 if (call->signature->pinvoke) {
1671 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1672 vtcopy->backend.is_pinvoke = 1;
1673 } else {
1674 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1676 if (size > 0)
1677 g_assert (ovf_size > 0);
1679 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1680 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1682 if (ainfo->offset)
1683 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1684 else
1685 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1689 void
1690 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1692 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1693 mono_method_signature (method)->ret);
1695 if (!ret->byref) {
1696 #if (SIZEOF_REGISTER == 4)
1697 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1698 MonoInst *ins;
1700 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1701 ins->sreg1 = val->dreg + 1;
1702 ins->sreg2 = val->dreg + 2;
1703 MONO_ADD_INS (cfg->cbb, ins);
1704 return;
1706 #endif
1707 if (ret->type == MONO_TYPE_R8) {
1708 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1709 return;
1711 if (ret->type == MONO_TYPE_R4) {
1712 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1713 return;
1716 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1719 void
1720 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1722 MonoInst *ins, *n, *last_ins = NULL;
1724 if (cfg->verbose_level > 2)
1725 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1727 ins = bb->code;
1728 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1729 if (cfg->verbose_level > 2)
1730 mono_print_ins_index (0, ins);
1732 switch (ins->opcode) {
1733 #if 0
1734 case OP_LOAD_MEMBASE:
1735 case OP_LOADI4_MEMBASE:
1737 * OP_IADD reg2, reg1, const1
1738 * OP_LOAD_MEMBASE const2(reg2), reg3
1739 * ->
1740 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1742 if (last_ins && (last_ins->opcode == OP_IADD_IMM || last_ins->opcode == OP_ADD_IMM) && (last_ins->dreg == ins->inst_basereg) && (last_ins->sreg1 != last_ins->dreg)){
1743 int const1 = last_ins->inst_imm;
1744 int const2 = ins->inst_offset;
1746 if (mips_is_imm16 (const1 + const2)) {
1747 ins->inst_basereg = last_ins->sreg1;
1748 ins->inst_offset = const1 + const2;
1751 break;
1752 #endif
1755 last_ins = ins;
1756 ins = ins->next;
1758 bb->last_ins = last_ins;
1761 void
1762 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1764 MonoInst *ins, *n, *last_ins = NULL;
1765 ins = bb->code;
1767 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1768 MonoInst *last_ins = ins->prev;
1770 switch (ins->opcode) {
1771 case OP_MUL_IMM:
1772 /* remove unnecessary multiplication with 1 */
1773 if (ins->inst_imm == 1) {
1774 if (ins->dreg != ins->sreg1) {
1775 ins->opcode = OP_MOVE;
1776 } else {
1777 MONO_DELETE_INS (bb, ins);
1778 continue;
1780 } else {
1781 int power2 = mono_is_power_of_two (ins->inst_imm);
1782 if (power2 > 0) {
1783 ins->opcode = OP_SHL_IMM;
1784 ins->inst_imm = power2;
1787 break;
1788 case OP_LOAD_MEMBASE:
1789 case OP_LOADI4_MEMBASE:
1791 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1792 * OP_LOAD_MEMBASE offset(basereg), reg
1794 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1795 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1796 ins->inst_basereg == last_ins->inst_destbasereg &&
1797 ins->inst_offset == last_ins->inst_offset) {
1798 if (ins->dreg == last_ins->sreg1) {
1799 MONO_DELETE_INS (bb, ins);
1800 continue;
1801 } else {
1802 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1803 ins->opcode = OP_MOVE;
1804 ins->sreg1 = last_ins->sreg1;
1806 break;
1809 * Note: reg1 must be different from the basereg in the second load
1810 * OP_LOAD_MEMBASE offset(basereg), reg1
1811 * OP_LOAD_MEMBASE offset(basereg), reg2
1812 * -->
1813 * OP_LOAD_MEMBASE offset(basereg), reg1
1814 * OP_MOVE reg1, reg2
1816 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1817 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1818 ins->inst_basereg != last_ins->dreg &&
1819 ins->inst_basereg == last_ins->inst_basereg &&
1820 ins->inst_offset == last_ins->inst_offset) {
1822 if (ins->dreg == last_ins->dreg) {
1823 MONO_DELETE_INS (bb, ins);
1824 continue;
1825 } else {
1826 ins->opcode = OP_MOVE;
1827 ins->sreg1 = last_ins->dreg;
1830 //g_assert_not_reached ();
1831 break;
1833 #if 0
1835 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1836 * OP_LOAD_MEMBASE offset(basereg), reg
1837 * -->
1838 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1839 * OP_ICONST reg, imm
1841 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1842 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1843 ins->inst_basereg == last_ins->inst_destbasereg &&
1844 ins->inst_offset == last_ins->inst_offset) {
1845 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1846 ins->opcode = OP_ICONST;
1847 ins->inst_c0 = last_ins->inst_imm;
1848 g_assert_not_reached (); // check this rule
1849 break;
1851 #endif
1852 break;
1853 case OP_LOADU1_MEMBASE:
1854 case OP_LOADI1_MEMBASE:
1855 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1856 ins->inst_basereg == last_ins->inst_destbasereg &&
1857 ins->inst_offset == last_ins->inst_offset) {
1858 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1859 ins->sreg1 = last_ins->sreg1;
1861 break;
1862 case OP_LOADU2_MEMBASE:
1863 case OP_LOADI2_MEMBASE:
1864 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1865 ins->inst_basereg == last_ins->inst_destbasereg &&
1866 ins->inst_offset == last_ins->inst_offset) {
1867 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1868 ins->sreg1 = last_ins->sreg1;
1870 break;
1871 case OP_ICONV_TO_I4:
1872 case OP_ICONV_TO_U4:
1873 case OP_MOVE:
1874 ins->opcode = OP_MOVE;
1876 * OP_MOVE reg, reg
1878 if (ins->dreg == ins->sreg1) {
1879 MONO_DELETE_INS (bb, ins);
1880 continue;
1883 * OP_MOVE sreg, dreg
1884 * OP_MOVE dreg, sreg
1886 if (last_ins && last_ins->opcode == OP_MOVE &&
1887 ins->sreg1 == last_ins->dreg &&
1888 ins->dreg == last_ins->sreg1) {
1889 MONO_DELETE_INS (bb, ins);
1890 continue;
1892 break;
1894 last_ins = ins;
1895 ins = ins->next;
1897 bb->last_ins = last_ins;
1900 void
1901 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
1903 int tmp1 = -1;
1904 int tmp2 = -1;
1905 int tmp3 = -1;
1906 int tmp4 = -1;
1907 int tmp5 = -1;
1909 switch (ins->opcode) {
1910 #if 0
1911 case OP_LCOMPARE:
1912 case OP_LCOMPARE_IMM:
1913 mono_print_ins (ins);
1914 g_assert_not_reached ();
1915 #endif
1916 case OP_LADD:
1917 tmp1 = mono_alloc_ireg (cfg);
1918 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1919 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1920 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1921 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1922 ins->opcode = OP_NOP;
1923 break;
1925 case OP_LADD_IMM:
1926 tmp1 = mono_alloc_ireg (cfg);
1927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1928 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1930 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1931 ins->opcode = OP_NOP;
1932 break;
1934 case OP_LSUB:
1935 tmp1 = mono_alloc_ireg (cfg);
1936 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1937 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1938 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1939 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1940 ins->opcode = OP_NOP;
1941 break;
1943 case OP_LSUB_IMM:
1944 tmp1 = mono_alloc_ireg (cfg);
1945 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1946 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1947 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1948 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1949 ins->opcode = OP_NOP;
1950 break;
1952 case OP_LMUL:
1953 case OP_LDIV:
1954 case OP_LDIV_UN:
1955 case OP_LREM:
1956 case OP_LREM_UN:
1957 case OP_LSHL:
1958 case OP_LSHR:
1959 case OP_LSHR_UN:
1960 mono_print_ins (ins);
1961 g_assert_not_reached ();
1963 case OP_LNEG:
1964 tmp1 = mono_alloc_ireg (cfg);
1965 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
1966 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
1967 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
1968 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1969 ins->opcode = OP_NOP;
1970 break;
1972 #if 0
1973 case OP_LNOT:
1974 #endif
1975 #if 0
1976 case OP_LCONV_TO_I1:
1977 case OP_LCONV_TO_I2:
1978 case OP_LCONV_TO_I4:
1979 case OP_LCONV_TO_I8:
1980 case OP_LCONV_TO_R4:
1981 case OP_LCONV_TO_R8:
1982 case OP_LCONV_TO_U4:
1983 case OP_LCONV_TO_U8:
1984 case OP_LCONV_TO_U2:
1985 case OP_LCONV_TO_U1:
1986 case OP_LCONV_TO_I:
1987 case OP_LCONV_TO_OVF_I:
1988 case OP_LCONV_TO_OVF_U:
1989 #endif
1990 mono_print_ins (ins);
1991 g_assert_not_reached ();
1993 case OP_LADD_OVF:
1994 tmp1 = mono_alloc_ireg (cfg);
1995 tmp2 = mono_alloc_ireg (cfg);
1996 tmp3 = mono_alloc_ireg (cfg);
1997 tmp4 = mono_alloc_ireg (cfg);
1998 tmp5 = mono_alloc_ireg (cfg);
2000 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2002 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2003 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2005 /* add the high 32-bits, and add in the carry from the low 32-bits */
2006 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2007 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2009 /* Overflow happens if
2010 * neg + neg = pos or
2011 * pos + pos = neg
2012 * XOR of the high bits returns 0 if the signs match
2013 * XOR of that with the high bit of the result return 1 if overflow.
2016 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2017 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2019 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2020 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2021 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2023 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2024 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2025 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2027 /* Now, if (tmp4 == 0) then overflow */
2028 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2029 ins->opcode = OP_NOP;
2030 break;
2032 case OP_LADD_OVF_UN:
2033 tmp1 = mono_alloc_ireg (cfg);
2034 tmp2 = mono_alloc_ireg (cfg);
2036 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2037 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2038 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2039 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2040 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2041 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2042 ins->opcode = OP_NOP;
2043 break;
2045 case OP_LMUL_OVF:
2046 case OP_LMUL_OVF_UN:
2047 mono_print_ins (ins);
2048 g_assert_not_reached ();
2050 case OP_LSUB_OVF:
2051 tmp1 = mono_alloc_ireg (cfg);
2052 tmp2 = mono_alloc_ireg (cfg);
2053 tmp3 = mono_alloc_ireg (cfg);
2054 tmp4 = mono_alloc_ireg (cfg);
2055 tmp5 = mono_alloc_ireg (cfg);
2057 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2059 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2060 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2061 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2063 /* Overflow happens if
2064 * neg - pos = pos or
2065 * pos - neg = neg
2066 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2068 * tmp1 = (lhs ^ rhs)
2069 * tmp2 = (lhs ^ result)
2070 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2073 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2074 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2075 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2076 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2078 /* Now, if (tmp4 == 1) then overflow */
2079 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2080 ins->opcode = OP_NOP;
2081 break;
2083 case OP_LSUB_OVF_UN:
2084 tmp1 = mono_alloc_ireg (cfg);
2085 tmp2 = mono_alloc_ireg (cfg);
2087 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2088 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2089 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2090 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2092 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2093 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2094 ins->opcode = OP_NOP;
2095 break;
2096 #if 0
2097 case OP_LCONV_TO_OVF_I1_UN:
2098 case OP_LCONV_TO_OVF_I2_UN:
2099 case OP_LCONV_TO_OVF_I4_UN:
2100 case OP_LCONV_TO_OVF_I8_UN:
2101 case OP_LCONV_TO_OVF_U1_UN:
2102 case OP_LCONV_TO_OVF_U2_UN:
2103 case OP_LCONV_TO_OVF_U4_UN:
2104 case OP_LCONV_TO_OVF_U8_UN:
2105 case OP_LCONV_TO_OVF_I_UN:
2106 case OP_LCONV_TO_OVF_U_UN:
2107 case OP_LCONV_TO_OVF_I1:
2108 case OP_LCONV_TO_OVF_U1:
2109 case OP_LCONV_TO_OVF_I2:
2110 case OP_LCONV_TO_OVF_U2:
2111 case OP_LCONV_TO_OVF_I4:
2112 case OP_LCONV_TO_OVF_U4:
2113 case OP_LCONV_TO_OVF_I8:
2114 case OP_LCONV_TO_OVF_U8:
2115 #endif
2116 case OP_LCEQ:
2117 case OP_LCGT:
2118 case OP_LCGT_UN:
2119 case OP_LCLT:
2120 case OP_LCLT_UN:
2121 #if 0
2122 case OP_LCONV_TO_R_UN:
2123 case OP_LCONV_TO_U:
2124 #endif
2125 case OP_LMUL_IMM:
2126 case OP_LSHL_IMM:
2127 case OP_LSHR_IMM:
2128 case OP_LSHR_UN_IMM:
2129 case OP_LDIV_IMM:
2130 case OP_LDIV_UN_IMM:
2131 case OP_LREM_IMM:
2132 case OP_LREM_UN_IMM:
2133 case OP_LBEQ:
2134 case OP_LBGE:
2135 case OP_LBGT:
2136 case OP_LBLE:
2137 case OP_LBLT:
2138 case OP_LBNE_UN:
2139 case OP_LBGE_UN:
2140 case OP_LBGT_UN:
2141 case OP_LBLE_UN:
2142 case OP_LBLT_UN:
2143 mono_print_ins (ins);
2144 g_assert_not_reached ();
2145 #if 0
2146 case OP_LCONV_TO_R8_2:
2147 case OP_LCONV_TO_R4_2:
2148 case OP_LCONV_TO_R_UN_2:
2149 #endif
2150 case OP_LCONV_TO_OVF_I4_2:
2151 tmp1 = mono_alloc_ireg (cfg);
2153 /* Overflows if reg2 != sign extension of reg1 */
2154 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2155 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2156 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2157 ins->opcode = OP_NOP;
2158 break;
2160 case OP_LMIN_UN:
2161 case OP_LMAX_UN:
2162 case OP_LMIN:
2163 case OP_LMAX:
2164 mono_print_ins (ins);
2165 g_assert_not_reached ();
2167 default:
2168 break;
2172 void
2173 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2175 int tmp1 = -1;
2176 int tmp2 = -1;
2177 int tmp3 = -1;
2178 int tmp4 = -1;
2179 int tmp5 = -1;
2181 switch (ins->opcode) {
2182 case OP_IADD_OVF:
2183 tmp1 = mono_alloc_ireg (cfg);
2184 tmp2 = mono_alloc_ireg (cfg);
2185 tmp3 = mono_alloc_ireg (cfg);
2186 tmp4 = mono_alloc_ireg (cfg);
2187 tmp5 = mono_alloc_ireg (cfg);
2189 /* add the operands */
2191 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2193 /* Overflow happens if
2194 * neg + neg = pos or
2195 * pos + pos = neg
2197 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2198 * XOR of the high bit returns 0 if the signs match
2199 * XOR of that with the high bit of the result return 1 if overflow.
2202 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2203 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2205 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2206 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2207 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2209 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2210 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2212 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2214 /* Now, if (tmp4 == 0) then overflow */
2215 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2216 ins->opcode = OP_NOP;
2217 break;
2219 case OP_IADD_OVF_UN:
2220 tmp1 = mono_alloc_ireg (cfg);
2222 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2223 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2224 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2225 ins->opcode = OP_NOP;
2226 break;
2228 case OP_ISUB_OVF:
2229 tmp1 = mono_alloc_ireg (cfg);
2230 tmp2 = mono_alloc_ireg (cfg);
2231 tmp3 = mono_alloc_ireg (cfg);
2232 tmp4 = mono_alloc_ireg (cfg);
2233 tmp5 = mono_alloc_ireg (cfg);
2235 /* add the operands */
2237 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2239 /* Overflow happens if
2240 * neg - pos = pos or
2241 * pos - neg = neg
2242 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2244 * tmp1 = (lhs ^ rhs)
2245 * tmp2 = (lhs ^ result)
2246 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2249 /* tmp3 = 1 if the signs of the two inputs differ */
2250 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2251 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2252 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2253 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2254 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2256 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2257 ins->opcode = OP_NOP;
2258 break;
2260 case OP_ISUB_OVF_UN:
2261 tmp1 = mono_alloc_ireg (cfg);
2263 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2264 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2265 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2266 ins->opcode = OP_NOP;
2267 break;
2272 static int
2273 map_to_reg_reg_op (int op)
2275 switch (op) {
2276 case OP_ADD_IMM:
2277 return OP_IADD;
2278 case OP_SUB_IMM:
2279 return OP_ISUB;
2280 case OP_AND_IMM:
2281 return OP_IAND;
2282 case OP_COMPARE_IMM:
2283 return OP_COMPARE;
2284 case OP_ICOMPARE_IMM:
2285 return OP_ICOMPARE;
2286 case OP_LCOMPARE_IMM:
2287 return OP_LCOMPARE;
2288 case OP_ADDCC_IMM:
2289 return OP_IADDCC;
2290 case OP_ADC_IMM:
2291 return OP_IADC;
2292 case OP_SUBCC_IMM:
2293 return OP_ISUBCC;
2294 case OP_SBB_IMM:
2295 return OP_ISBB;
2296 case OP_OR_IMM:
2297 return OP_IOR;
2298 case OP_XOR_IMM:
2299 return OP_IXOR;
2300 case OP_MUL_IMM:
2301 return OP_IMUL;
2302 case OP_LOAD_MEMBASE:
2303 return OP_LOAD_MEMINDEX;
2304 case OP_LOADI4_MEMBASE:
2305 return OP_LOADI4_MEMINDEX;
2306 case OP_LOADU4_MEMBASE:
2307 return OP_LOADU4_MEMINDEX;
2308 case OP_LOADU1_MEMBASE:
2309 return OP_LOADU1_MEMINDEX;
2310 case OP_LOADI2_MEMBASE:
2311 return OP_LOADI2_MEMINDEX;
2312 case OP_LOADU2_MEMBASE:
2313 return OP_LOADU2_MEMINDEX;
2314 case OP_LOADI1_MEMBASE:
2315 return OP_LOADI1_MEMINDEX;
2316 case OP_LOADR4_MEMBASE:
2317 return OP_LOADR4_MEMINDEX;
2318 case OP_LOADR8_MEMBASE:
2319 return OP_LOADR8_MEMINDEX;
2320 case OP_STOREI1_MEMBASE_REG:
2321 return OP_STOREI1_MEMINDEX;
2322 case OP_STOREI2_MEMBASE_REG:
2323 return OP_STOREI2_MEMINDEX;
2324 case OP_STOREI4_MEMBASE_REG:
2325 return OP_STOREI4_MEMINDEX;
2326 case OP_STORE_MEMBASE_REG:
2327 return OP_STORE_MEMINDEX;
2328 case OP_STORER4_MEMBASE_REG:
2329 return OP_STORER4_MEMINDEX;
2330 case OP_STORER8_MEMBASE_REG:
2331 return OP_STORER8_MEMINDEX;
2332 case OP_STORE_MEMBASE_IMM:
2333 return OP_STORE_MEMBASE_REG;
2334 case OP_STOREI1_MEMBASE_IMM:
2335 return OP_STOREI1_MEMBASE_REG;
2336 case OP_STOREI2_MEMBASE_IMM:
2337 return OP_STOREI2_MEMBASE_REG;
2338 case OP_STOREI4_MEMBASE_IMM:
2339 return OP_STOREI4_MEMBASE_REG;
2340 case OP_STOREI8_MEMBASE_IMM:
2341 return OP_STOREI8_MEMBASE_REG;
2343 return mono_op_imm_to_op (op);
2346 static int
2347 map_to_mips_op (int op)
2349 switch (op) {
2350 case OP_FBEQ:
2351 return OP_MIPS_FBEQ;
2352 case OP_FBGE:
2353 return OP_MIPS_FBGE;
2354 case OP_FBGT:
2355 return OP_MIPS_FBGT;
2356 case OP_FBLE:
2357 return OP_MIPS_FBLE;
2358 case OP_FBLT:
2359 return OP_MIPS_FBLT;
2360 case OP_FBNE_UN:
2361 return OP_MIPS_FBNE;
2362 case OP_FBGE_UN:
2363 return OP_MIPS_FBGE_UN;
2364 case OP_FBGT_UN:
2365 return OP_MIPS_FBGT_UN;
2366 case OP_FBLE_UN:
2367 return OP_MIPS_FBLE_UN;
2368 case OP_FBLT_UN:
2369 return OP_MIPS_FBLT_UN;
2371 case OP_FCEQ:
2372 case OP_FCGT:
2373 case OP_FCGT_UN:
2374 case OP_FCLT:
2375 case OP_FCLT_UN:
2376 default:
2377 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2378 g_assert_not_reached ();
2382 #define NEW_INS(cfg,after,dest,op) do { \
2383 MONO_INST_NEW((cfg), (dest), (op)); \
2384 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2385 } while (0)
2387 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2388 MonoInst *temp; \
2389 MONO_INST_NEW(cfg, temp, (op)); \
2390 mono_bblock_insert_after_ins (bb, (pos), temp); \
2391 temp->dreg = (_dreg); \
2392 temp->sreg1 = (_sreg1); \
2393 temp->sreg2 = (_sreg2); \
2394 pos = temp; \
2395 } while (0)
2397 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2398 MonoInst *temp; \
2399 MONO_INST_NEW(cfg, temp, (op)); \
2400 mono_bblock_insert_after_ins (bb, (pos), temp); \
2401 temp->dreg = (_dreg); \
2402 temp->sreg1 = (_sreg1); \
2403 temp->inst_c0 = (_imm); \
2404 pos = temp; \
2405 } while (0)
2408 * Remove from the instruction list the instructions that can't be
2409 * represented with very simple instructions with no register
2410 * requirements.
2412 void
2413 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2415 MonoInst *ins, *next, *temp, *last_ins = NULL;
2416 int imm;
2418 #if 1
2419 if (cfg->verbose_level > 2) {
2420 int idx = 0;
2422 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2423 MONO_BB_FOR_EACH_INS (bb, ins) {
2424 mono_print_ins_index (idx++, ins);
2428 #endif
2430 MONO_BB_FOR_EACH_INS (bb, ins) {
2431 loop_start:
2432 switch (ins->opcode) {
2433 case OP_COMPARE:
2434 case OP_ICOMPARE:
2435 case OP_LCOMPARE:
2436 next = ins->next;
2437 /* Branch opts can eliminate the branch */
2438 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2439 ins->opcode = OP_NOP;
2440 break;
2442 break;
2444 case OP_COMPARE_IMM:
2445 case OP_ICOMPARE_IMM:
2446 case OP_LCOMPARE_IMM:
2447 next = ins->next;
2448 /* Branch opts can eliminate the branch */
2449 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2450 ins->opcode = OP_NOP;
2451 break;
2453 if (ins->inst_imm) {
2454 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2455 temp->inst_c0 = ins->inst_imm;
2456 temp->dreg = mono_alloc_ireg (cfg);
2457 ins->sreg2 = temp->dreg;
2458 last_ins = temp;
2460 else {
2461 ins->sreg2 = mips_zero;
2463 if (ins->opcode == OP_COMPARE_IMM)
2464 ins->opcode = OP_COMPARE;
2465 else if (ins->opcode == OP_ICOMPARE_IMM)
2466 ins->opcode = OP_ICOMPARE;
2467 else if (ins->opcode == OP_LCOMPARE_IMM)
2468 ins->opcode = OP_LCOMPARE;
2469 goto loop_start;
2471 case OP_IDIV_UN_IMM:
2472 case OP_IDIV_IMM:
2473 case OP_IREM_IMM:
2474 case OP_IREM_UN_IMM:
2475 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2476 temp->inst_c0 = ins->inst_imm;
2477 temp->dreg = mono_alloc_ireg (cfg);
2478 ins->sreg2 = temp->dreg;
2479 if (ins->opcode == OP_IDIV_IMM)
2480 ins->opcode = OP_IDIV;
2481 else if (ins->opcode == OP_IREM_IMM)
2482 ins->opcode = OP_IREM;
2483 else if (ins->opcode == OP_IDIV_UN_IMM)
2484 ins->opcode = OP_IDIV_UN;
2485 else if (ins->opcode == OP_IREM_UN_IMM)
2486 ins->opcode = OP_IREM_UN;
2487 last_ins = temp;
2488 /* handle rem separately */
2489 goto loop_start;
2491 #if 0
2492 case OP_AND_IMM:
2493 case OP_OR_IMM:
2494 case OP_XOR_IMM:
2495 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2496 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2497 temp->inst_c0 = ins->inst_imm;
2498 temp->dreg = mono_alloc_ireg (cfg);
2499 ins->sreg2 = temp->dreg;
2500 ins->opcode = map_to_reg_reg_op (ins->opcode);
2502 break;
2503 #endif
2504 case OP_AND_IMM:
2505 case OP_IAND_IMM:
2506 case OP_OR_IMM:
2507 case OP_IOR_IMM:
2508 case OP_XOR_IMM:
2509 case OP_IXOR_IMM:
2510 /* unsigned 16 bit immediate */
2511 if (ins->inst_imm & 0xffff0000) {
2512 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2513 temp->inst_c0 = ins->inst_imm;
2514 temp->dreg = mono_alloc_ireg (cfg);
2515 ins->sreg2 = temp->dreg;
2516 ins->opcode = map_to_reg_reg_op (ins->opcode);
2518 break;
2520 case OP_IADD_IMM:
2521 case OP_ADD_IMM:
2522 case OP_ADDCC_IMM:
2523 /* signed 16 bit immediate */
2524 if (!mips_is_imm16 (ins->inst_imm)) {
2525 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2526 temp->inst_c0 = ins->inst_imm;
2527 temp->dreg = mono_alloc_ireg (cfg);
2528 ins->sreg2 = temp->dreg;
2529 ins->opcode = map_to_reg_reg_op (ins->opcode);
2531 break;
2533 case OP_SUB_IMM:
2534 case OP_ISUB_IMM:
2535 if (!mips_is_imm16 (-ins->inst_imm)) {
2536 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2537 temp->inst_c0 = ins->inst_imm;
2538 temp->dreg = mono_alloc_ireg (cfg);
2539 ins->sreg2 = temp->dreg;
2540 ins->opcode = map_to_reg_reg_op (ins->opcode);
2542 break;
2544 case OP_MUL_IMM:
2545 case OP_IMUL_IMM:
2546 if (ins->inst_imm == 1) {
2547 ins->opcode = OP_MOVE;
2548 break;
2550 if (ins->inst_imm == 0) {
2551 ins->opcode = OP_ICONST;
2552 ins->inst_c0 = 0;
2553 break;
2555 imm = mono_is_power_of_two (ins->inst_imm);
2556 if (imm > 0) {
2557 ins->opcode = OP_SHL_IMM;
2558 ins->inst_imm = imm;
2559 break;
2561 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2562 temp->inst_c0 = ins->inst_imm;
2563 temp->dreg = mono_alloc_ireg (cfg);
2564 ins->sreg2 = temp->dreg;
2565 ins->opcode = map_to_reg_reg_op (ins->opcode);
2566 break;
2568 case OP_LOCALLOC_IMM:
2569 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2570 temp->inst_c0 = ins->inst_imm;
2571 temp->dreg = mono_alloc_ireg (cfg);
2572 ins->sreg1 = temp->dreg;
2573 ins->opcode = OP_LOCALLOC;
2574 break;
2576 case OP_LOAD_MEMBASE:
2577 case OP_LOADI4_MEMBASE:
2578 case OP_LOADU4_MEMBASE:
2579 case OP_LOADI2_MEMBASE:
2580 case OP_LOADU2_MEMBASE:
2581 case OP_LOADI1_MEMBASE:
2582 case OP_LOADU1_MEMBASE:
2583 case OP_LOADR4_MEMBASE:
2584 case OP_LOADR8_MEMBASE:
2585 case OP_STORE_MEMBASE_REG:
2586 case OP_STOREI4_MEMBASE_REG:
2587 case OP_STOREI2_MEMBASE_REG:
2588 case OP_STOREI1_MEMBASE_REG:
2589 case OP_STORER4_MEMBASE_REG:
2590 case OP_STORER8_MEMBASE_REG:
2591 /* we can do two things: load the immed in a register
2592 * and use an indexed load, or see if the immed can be
2593 * represented as an ad_imm + a load with a smaller offset
2594 * that fits. We just do the first for now, optimize later.
2596 if (mips_is_imm16 (ins->inst_offset))
2597 break;
2598 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2599 temp->inst_c0 = ins->inst_offset;
2600 temp->dreg = mono_alloc_ireg (cfg);
2601 ins->sreg2 = temp->dreg;
2602 ins->opcode = map_to_reg_reg_op (ins->opcode);
2603 break;
2605 case OP_STORE_MEMBASE_IMM:
2606 case OP_STOREI1_MEMBASE_IMM:
2607 case OP_STOREI2_MEMBASE_IMM:
2608 case OP_STOREI4_MEMBASE_IMM:
2609 case OP_STOREI8_MEMBASE_IMM:
2610 if (!ins->inst_imm) {
2611 ins->sreg1 = mips_zero;
2612 ins->opcode = map_to_reg_reg_op (ins->opcode);
2614 else {
2615 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2616 temp->inst_c0 = ins->inst_imm;
2617 temp->dreg = mono_alloc_ireg (cfg);
2618 ins->sreg1 = temp->dreg;
2619 ins->opcode = map_to_reg_reg_op (ins->opcode);
2620 last_ins = temp;
2621 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2623 break;
2625 case OP_FCOMPARE:
2626 next = ins->next;
2627 /* Branch opts can eliminate the branch */
2628 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2629 ins->opcode = OP_NOP;
2630 break;
2632 g_assert(next);
2635 * remap compare/branch and compare/set
2636 * to MIPS specific opcodes.
2638 ins->opcode = OP_NOP;
2639 next->opcode = map_to_mips_op (next->opcode);
2640 next->sreg1 = ins->sreg1;
2641 next->sreg2 = ins->sreg2;
2642 break;
2644 #if 0
2645 case OP_R8CONST:
2646 case OP_R4CONST:
2647 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2648 temp->inst_c0 = (guint32)ins->inst_p0;
2649 temp->dreg = mono_alloc_ireg (cfg);
2650 ins->inst_basereg = temp->dreg;
2651 ins->inst_offset = 0;
2652 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2653 last_ins = temp;
2654 /* make it handle the possibly big ins->inst_offset
2655 * later optimize to use lis + load_membase
2657 goto loop_start;
2658 #endif
2659 case OP_IBEQ:
2660 g_assert (ins_is_compare(last_ins));
2661 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2662 last_ins->opcode = OP_NOP;
2663 break;
2665 case OP_IBNE_UN:
2666 g_assert (ins_is_compare(last_ins));
2667 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2668 last_ins->opcode = OP_NOP;
2669 break;
2671 case OP_IBGE:
2672 g_assert (ins_is_compare(last_ins));
2673 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2674 last_ins->dreg = mono_alloc_ireg (cfg);
2675 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2676 break;
2678 case OP_IBGE_UN:
2679 g_assert (ins_is_compare(last_ins));
2680 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2681 last_ins->dreg = mono_alloc_ireg (cfg);
2682 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2683 break;
2685 case OP_IBLT:
2686 g_assert (ins_is_compare(last_ins));
2687 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2688 last_ins->dreg = mono_alloc_ireg (cfg);
2689 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2690 break;
2692 case OP_IBLT_UN:
2693 g_assert (ins_is_compare(last_ins));
2694 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2695 last_ins->dreg = mono_alloc_ireg (cfg);
2696 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2697 break;
2699 case OP_IBLE:
2700 g_assert (ins_is_compare(last_ins));
2701 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2702 last_ins->dreg = mono_alloc_ireg (cfg);
2703 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2704 break;
2706 case OP_IBLE_UN:
2707 g_assert (ins_is_compare(last_ins));
2708 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2709 last_ins->dreg = mono_alloc_ireg (cfg);
2710 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2711 break;
2713 case OP_IBGT:
2714 g_assert (ins_is_compare(last_ins));
2715 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2716 last_ins->dreg = mono_alloc_ireg (cfg);
2717 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2718 break;
2720 case OP_IBGT_UN:
2721 g_assert (ins_is_compare(last_ins));
2722 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2723 last_ins->dreg = mono_alloc_ireg (cfg);
2724 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2725 break;
2727 case OP_CEQ:
2728 case OP_ICEQ:
2729 g_assert (ins_is_compare(last_ins));
2730 last_ins->opcode = OP_IXOR;
2731 last_ins->dreg = mono_alloc_ireg(cfg);
2732 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2733 break;
2735 case OP_CLT:
2736 case OP_ICLT:
2737 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2738 last_ins->opcode = OP_NOP;
2739 break;
2742 case OP_CLT_UN:
2743 case OP_ICLT_UN:
2744 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2745 last_ins->opcode = OP_NOP;
2746 break;
2748 case OP_CGT:
2749 case OP_ICGT:
2750 g_assert (ins_is_compare(last_ins));
2751 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2752 MONO_DELETE_INS(bb, last_ins);
2753 break;
2755 case OP_CGT_UN:
2756 case OP_ICGT_UN:
2757 g_assert (ins_is_compare(last_ins));
2758 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2759 MONO_DELETE_INS(bb, last_ins);
2760 break;
2762 case OP_COND_EXC_EQ:
2763 case OP_COND_EXC_IEQ:
2764 g_assert (ins_is_compare(last_ins));
2765 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2766 MONO_DELETE_INS(bb, last_ins);
2767 break;
2769 case OP_COND_EXC_GE:
2770 case OP_COND_EXC_IGE:
2771 g_assert (ins_is_compare(last_ins));
2772 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2773 MONO_DELETE_INS(bb, last_ins);
2774 break;
2776 case OP_COND_EXC_GT:
2777 case OP_COND_EXC_IGT:
2778 g_assert (ins_is_compare(last_ins));
2779 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2780 MONO_DELETE_INS(bb, last_ins);
2781 break;
2783 case OP_COND_EXC_LE:
2784 case OP_COND_EXC_ILE:
2785 g_assert (ins_is_compare(last_ins));
2786 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2787 MONO_DELETE_INS(bb, last_ins);
2788 break;
2790 case OP_COND_EXC_LT:
2791 case OP_COND_EXC_ILT:
2792 g_assert (ins_is_compare(last_ins));
2793 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2794 MONO_DELETE_INS(bb, last_ins);
2795 break;
2797 case OP_COND_EXC_NE_UN:
2798 case OP_COND_EXC_INE_UN:
2799 g_assert (ins_is_compare(last_ins));
2800 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2801 MONO_DELETE_INS(bb, last_ins);
2802 break;
2804 case OP_COND_EXC_GE_UN:
2805 case OP_COND_EXC_IGE_UN:
2806 g_assert (ins_is_compare(last_ins));
2807 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2808 MONO_DELETE_INS(bb, last_ins);
2809 break;
2811 case OP_COND_EXC_GT_UN:
2812 case OP_COND_EXC_IGT_UN:
2813 g_assert (ins_is_compare(last_ins));
2814 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2815 MONO_DELETE_INS(bb, last_ins);
2816 break;
2818 case OP_COND_EXC_LE_UN:
2819 case OP_COND_EXC_ILE_UN:
2820 g_assert (ins_is_compare(last_ins));
2821 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2822 MONO_DELETE_INS(bb, last_ins);
2823 break;
2825 case OP_COND_EXC_LT_UN:
2826 case OP_COND_EXC_ILT_UN:
2827 g_assert (ins_is_compare(last_ins));
2828 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2829 MONO_DELETE_INS(bb, last_ins);
2830 break;
2832 case OP_COND_EXC_OV:
2833 case OP_COND_EXC_IOV: {
2834 int tmp1, tmp2, tmp3, tmp4, tmp5;
2835 MonoInst *pos = last_ins;
2837 /* Overflow happens if
2838 * neg + neg = pos or
2839 * pos + pos = neg
2841 * (bit31s of operands match) AND (bit31 of operand
2842 * != bit31 of result)
2843 * XOR of the high bit returns 0 if the signs match
2844 * XOR of that with the high bit of the result return 1
2845 * if overflow.
2847 g_assert (last_ins->opcode == OP_IADC);
2849 tmp1 = mono_alloc_ireg (cfg);
2850 tmp2 = mono_alloc_ireg (cfg);
2851 tmp3 = mono_alloc_ireg (cfg);
2852 tmp4 = mono_alloc_ireg (cfg);
2853 tmp5 = mono_alloc_ireg (cfg);
2855 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2856 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2858 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2859 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2860 INS (pos, OP_INOT, tmp3, tmp2, -1);
2862 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2863 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2864 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2866 /* Now, if (tmp5 == 0) then overflow */
2867 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2868 ins->dreg = -1;
2869 break;
2872 case OP_COND_EXC_NO:
2873 case OP_COND_EXC_INO:
2874 g_assert_not_reached ();
2875 break;
2877 case OP_COND_EXC_C:
2878 case OP_COND_EXC_IC:
2879 g_assert_not_reached ();
2880 break;
2882 case OP_COND_EXC_NC:
2883 case OP_COND_EXC_INC:
2884 g_assert_not_reached ();
2885 break;
2888 last_ins = ins;
2890 bb->last_ins = last_ins;
2891 bb->max_vreg = cfg->next_vreg;
2893 #if 1
2894 if (cfg->verbose_level > 2) {
2895 int idx = 0;
2897 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
2898 MONO_BB_FOR_EACH_INS (bb, ins) {
2899 mono_print_ins_index (idx++, ins);
2903 #endif
2907 static guchar*
2908 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2910 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2911 #if 1
2912 mips_truncwd (code, mips_ftemp, sreg);
2913 #else
2914 mips_cvtwd (code, mips_ftemp, sreg);
2915 #endif
2916 mips_mfc1 (code, dreg, mips_ftemp);
2917 if (!is_signed) {
2918 if (size == 1)
2919 mips_andi (code, dreg, dreg, 0xff);
2920 else if (size == 2) {
2921 mips_sll (code, dreg, dreg, 16);
2922 mips_srl (code, dreg, dreg, 16);
2924 } else {
2925 if (size == 1) {
2926 mips_sll (code, dreg, dreg, 24);
2927 mips_sra (code, dreg, dreg, 24);
2929 else if (size == 2) {
2930 mips_sll (code, dreg, dreg, 16);
2931 mips_sra (code, dreg, dreg, 16);
2934 return code;
2938 * emit_load_volatile_arguments:
2940 * Load volatile arguments from the stack to the original input registers.
2941 * Required before a tail call.
2943 static guint8 *
2944 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
2946 MonoMethod *method = cfg->method;
2947 MonoMethodSignature *sig;
2948 MonoInst *inst;
2949 CallInfo *cinfo;
2950 int i;
2952 sig = mono_method_signature (method);
2953 cinfo = calculate_sizes (sig, sig->pinvoke);
2954 if (cinfo->struct_ret) {
2955 ArgInfo *ainfo = &cinfo->ret;
2956 inst = cfg->vret_addr;
2957 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2960 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2961 ArgInfo *ainfo = cinfo->args + i;
2962 inst = cfg->args [i];
2963 if (inst->opcode == OP_REGVAR) {
2964 if (ainfo->regtype == RegTypeGeneral)
2965 MIPS_MOVE (code, ainfo->reg, inst->dreg);
2966 else if (ainfo->regtype == RegTypeFP)
2967 g_assert_not_reached();
2968 else if (ainfo->regtype == RegTypeBase) {
2969 /* do nothing */
2970 } else
2971 g_assert_not_reached ();
2972 } else {
2973 if (ainfo->regtype == RegTypeGeneral) {
2974 g_assert (mips_is_imm16 (inst->inst_offset));
2975 switch (ainfo->size) {
2976 case 1:
2977 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2978 break;
2979 case 2:
2980 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2981 break;
2982 case 0: /* XXX */
2983 case 4:
2984 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2985 break;
2986 case 8:
2987 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2988 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
2989 break;
2990 default:
2991 g_assert_not_reached ();
2992 break;
2994 } else if (ainfo->regtype == RegTypeBase) {
2995 /* do nothing */
2996 } else if (ainfo->regtype == RegTypeFP) {
2997 g_assert (mips_is_imm16 (inst->inst_offset));
2998 if (ainfo->size == 8) {
2999 #if _MIPS_SIM == _ABIO32
3000 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3001 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3002 #elif _MIPS_SIM == _ABIN32
3003 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3004 #endif
3006 else if (ainfo->size == 4)
3007 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3008 else
3009 g_assert_not_reached ();
3010 } else if (ainfo->regtype == RegTypeStructByVal) {
3011 int i;
3012 int doffset = inst->inst_offset;
3014 g_assert (mips_is_imm16 (inst->inst_offset));
3015 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3016 for (i = 0; i < ainfo->size; ++i) {
3017 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3018 doffset += SIZEOF_REGISTER;
3020 } else if (ainfo->regtype == RegTypeStructByAddr) {
3021 g_assert (mips_is_imm16 (inst->inst_offset));
3022 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3023 } else
3024 g_assert_not_reached ();
3028 g_free (cinfo);
3030 return code;
3033 static guint8*
3034 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3036 int size = cfg->param_area;
3038 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3039 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3041 if (!size)
3042 return code;
3043 #if 0
3044 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3045 if (ppc_is_imm16 (-size)) {
3046 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3047 } else {
3048 ppc_load (code, ppc_r11, -size);
3049 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3051 #endif
3052 return code;
3055 static guint8*
3056 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3058 int size = cfg->param_area;
3060 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3061 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3063 if (!size)
3064 return code;
3065 #if 0
3066 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3067 if (ppc_is_imm16 (size)) {
3068 ppc_stwu (code, ppc_r0, size, ppc_sp);
3069 } else {
3070 ppc_load (code, ppc_r11, size);
3071 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3073 #endif
3074 return code;
3077 void
3078 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3080 MonoInst *ins;
3081 MonoCallInst *call;
3082 guint offset;
3083 guint8 *code = cfg->native_code + cfg->code_len;
3084 MonoInst *last_ins = NULL;
3085 guint last_offset = 0;
3086 int max_len, cpos;
3087 int ins_cnt = 0;
3089 /* we don't align basic blocks of loops on mips */
3091 if (cfg->verbose_level > 2)
3092 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3094 cpos = bb->max_offset;
3096 #if 0
3097 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3098 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3099 g_assert (!mono_compile_aot);
3100 cpos += 20;
3101 if (bb->cil_code)
3102 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3103 /* this is not thread save, but good enough */
3104 /* fixme: howto handle overflows? */
3105 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3106 mips_lw (code, mips_temp, mips_at, 0);
3107 mips_addiu (code, mips_temp, mips_temp, 1);
3108 mips_sw (code, mips_temp, mips_at, 0);
3110 #endif
3111 MONO_BB_FOR_EACH_INS (bb, ins) {
3112 offset = code - cfg->native_code;
3114 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3116 if (offset > (cfg->code_size - max_len - 16)) {
3117 cfg->code_size *= 2;
3118 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3119 code = cfg->native_code + offset;
3121 mono_debug_record_line_number (cfg, ins, offset);
3122 if (cfg->verbose_level > 2) {
3123 g_print (" @ 0x%x\t", offset);
3124 mono_print_ins_index (ins_cnt++, ins);
3126 /* Check for virtual regs that snuck by */
3127 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3129 switch (ins->opcode) {
3130 case OP_RELAXED_NOP:
3131 case OP_NOP:
3132 case OP_DUMMY_USE:
3133 case OP_DUMMY_STORE:
3134 case OP_NOT_REACHED:
3135 case OP_NOT_NULL:
3136 break;
3137 case OP_TLS_GET:
3138 g_assert_not_reached();
3139 #if 0
3140 emit_tls_access (code, ins->dreg, ins->inst_offset);
3141 #endif
3142 break;
3143 case OP_BIGMUL:
3144 mips_mult (code, ins->sreg1, ins->sreg2);
3145 mips_mflo (code, ins->dreg);
3146 mips_mfhi (code, ins->dreg+1);
3147 break;
3148 case OP_BIGMUL_UN:
3149 mips_multu (code, ins->sreg1, ins->sreg2);
3150 mips_mflo (code, ins->dreg);
3151 mips_mfhi (code, ins->dreg+1);
3152 break;
3153 case OP_MEMORY_BARRIER:
3154 #if 0
3155 ppc_sync (code);
3156 #endif
3157 break;
3158 case OP_STOREI1_MEMBASE_IMM:
3159 mips_load_const (code, mips_temp, ins->inst_imm);
3160 if (mips_is_imm16 (ins->inst_offset)) {
3161 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3162 } else {
3163 mips_load_const (code, mips_at, ins->inst_offset);
3164 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3166 break;
3167 case OP_STOREI2_MEMBASE_IMM:
3168 mips_load_const (code, mips_temp, ins->inst_imm);
3169 if (mips_is_imm16 (ins->inst_offset)) {
3170 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3171 } else {
3172 mips_load_const (code, mips_at, ins->inst_offset);
3173 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3175 break;
3176 case OP_STOREI8_MEMBASE_IMM:
3177 mips_load_const (code, mips_temp, ins->inst_imm);
3178 if (mips_is_imm16 (ins->inst_offset)) {
3179 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3180 } else {
3181 mips_load_const (code, mips_at, ins->inst_offset);
3182 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3184 break;
3185 case OP_STORE_MEMBASE_IMM:
3186 case OP_STOREI4_MEMBASE_IMM:
3187 mips_load_const (code, mips_temp, ins->inst_imm);
3188 if (mips_is_imm16 (ins->inst_offset)) {
3189 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3190 } else {
3191 mips_load_const (code, mips_at, ins->inst_offset);
3192 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3194 break;
3195 case OP_STOREI1_MEMBASE_REG:
3196 if (mips_is_imm16 (ins->inst_offset)) {
3197 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3198 } else {
3199 mips_load_const (code, mips_at, ins->inst_offset);
3200 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3201 mips_sb (code, ins->sreg1, mips_at, 0);
3203 break;
3204 case OP_STOREI2_MEMBASE_REG:
3205 if (mips_is_imm16 (ins->inst_offset)) {
3206 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3207 } else {
3208 mips_load_const (code, mips_at, ins->inst_offset);
3209 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3210 mips_sh (code, ins->sreg1, mips_at, 0);
3212 break;
3213 case OP_STORE_MEMBASE_REG:
3214 case OP_STOREI4_MEMBASE_REG:
3215 if (mips_is_imm16 (ins->inst_offset)) {
3216 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3217 } else {
3218 mips_load_const (code, mips_at, ins->inst_offset);
3219 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3220 mips_sw (code, ins->sreg1, mips_at, 0);
3222 break;
3223 case OP_STOREI8_MEMBASE_REG:
3224 if (mips_is_imm16 (ins->inst_offset)) {
3225 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3226 } else {
3227 mips_load_const (code, mips_at, ins->inst_offset);
3228 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3229 mips_sd (code, ins->sreg1, mips_at, 0);
3231 break;
3232 case OP_LOADU4_MEM:
3233 g_assert_not_reached ();
3234 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3235 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3236 break;
3237 case OP_LOADI8_MEMBASE:
3238 if (mips_is_imm16 (ins->inst_offset)) {
3239 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3240 } else {
3241 mips_load_const (code, mips_at, ins->inst_offset);
3242 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3243 mips_ld (code, ins->dreg, mips_at, 0);
3245 break;
3246 case OP_LOAD_MEMBASE:
3247 case OP_LOADI4_MEMBASE:
3248 case OP_LOADU4_MEMBASE:
3249 if (mips_is_imm16 (ins->inst_offset)) {
3250 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3251 } else {
3252 mips_load_const (code, mips_at, ins->inst_offset);
3253 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3254 mips_lw (code, ins->dreg, mips_at, 0);
3256 break;
3257 case OP_LOADI1_MEMBASE:
3258 if (mips_is_imm16 (ins->inst_offset)) {
3259 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3260 } else {
3261 mips_load_const (code, mips_at, ins->inst_offset);
3262 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3263 mips_lb (code, ins->dreg, mips_at, 0);
3265 break;
3266 case OP_LOADU1_MEMBASE:
3267 if (mips_is_imm16 (ins->inst_offset)) {
3268 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3269 } else {
3270 mips_load_const (code, mips_at, ins->inst_offset);
3271 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3272 mips_lbu (code, ins->dreg, mips_at, 0);
3274 break;
3275 case OP_LOADI2_MEMBASE:
3276 if (mips_is_imm16 (ins->inst_offset)) {
3277 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3278 } else {
3279 mips_load_const (code, mips_at, ins->inst_offset);
3280 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3281 mips_lh (code, ins->dreg, mips_at, 0);
3283 break;
3284 case OP_LOADU2_MEMBASE:
3285 if (mips_is_imm16 (ins->inst_offset)) {
3286 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3287 } else {
3288 mips_load_const (code, mips_at, ins->inst_offset);
3289 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3290 mips_lhu (code, ins->dreg, mips_at, 0);
3292 break;
3293 case OP_ICONV_TO_I1:
3294 mips_sll (code, mips_at, ins->sreg1, 24);
3295 mips_sra (code, ins->dreg, mips_at, 24);
3296 break;
3297 case OP_ICONV_TO_I2:
3298 mips_sll (code, mips_at, ins->sreg1, 16);
3299 mips_sra (code, ins->dreg, mips_at, 16);
3300 break;
3301 case OP_ICONV_TO_U1:
3302 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3303 break;
3304 case OP_ICONV_TO_U2:
3305 mips_sll (code, mips_at, ins->sreg1, 16);
3306 mips_srl (code, ins->dreg, mips_at, 16);
3307 break;
3308 case OP_MIPS_SLT:
3309 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3310 break;
3311 case OP_MIPS_SLTI:
3312 g_assert (mips_is_imm16 (ins->inst_imm));
3313 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3314 break;
3315 case OP_MIPS_SLTU:
3316 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3317 break;
3318 case OP_MIPS_SLTIU:
3319 g_assert (mips_is_imm16 (ins->inst_imm));
3320 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3321 break;
3322 case OP_BREAK:
3323 mips_break (code, 0xfd);
3324 break;
3325 case OP_IADD:
3326 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3327 break;
3328 case OP_LADD:
3329 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3330 break;
3332 case OP_ADD_IMM:
3333 case OP_IADD_IMM:
3334 g_assert (mips_is_imm16 (ins->inst_imm));
3335 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3336 break;
3337 case OP_LADD_IMM:
3338 g_assert (mips_is_imm16 (ins->inst_imm));
3339 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3340 break;
3342 case OP_ISUB:
3343 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3344 break;
3345 case OP_LSUB:
3346 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3347 break;
3349 case OP_ISUB_IMM:
3350 case OP_SUB_IMM:
3351 // we add the negated value
3352 g_assert (mips_is_imm16 (-ins->inst_imm));
3353 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3354 break;
3356 case OP_LSUB_IMM:
3357 // we add the negated value
3358 g_assert (mips_is_imm16 (-ins->inst_imm));
3359 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3360 break;
3362 case OP_IAND:
3363 case OP_LAND:
3364 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3365 break;
3367 case OP_AND_IMM:
3368 case OP_IAND_IMM:
3369 case OP_LAND_IMM:
3370 g_assert (!(ins->inst_imm & 0xffff0000));
3371 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3372 break;
3374 case OP_IDIV:
3375 case OP_IREM: {
3376 guint32 *divisor_is_m1;
3377 guint32 *divisor_is_zero;
3379 /* */
3380 mips_addiu (code, mips_at, mips_zero, 0xffff);
3381 divisor_is_m1 = (guint32 *)(void *)code;
3382 mips_bne (code, ins->sreg2, mips_at, 0);
3383 mips_nop (code);
3385 /* Divide by -1 -- throw exception */
3386 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
3388 mips_patch (divisor_is_m1, (guint32)code);
3390 /* Put divide in branch delay slot (NOT YET) */
3391 divisor_is_zero = (guint32 *)(void *)code;
3392 mips_bne (code, ins->sreg2, mips_zero, 0);
3393 mips_nop (code);
3395 /* Divide by zero -- throw exception */
3396 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3398 mips_patch (divisor_is_zero, (guint32)code);
3399 mips_div (code, ins->sreg1, ins->sreg2);
3400 if (ins->opcode == OP_IDIV)
3401 mips_mflo (code, ins->dreg);
3402 else
3403 mips_mfhi (code, ins->dreg);
3404 break;
3406 case OP_IDIV_UN:
3407 case OP_IREM_UN: {
3408 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3410 /* Put divide in branch delay slot (NOT YET) */
3411 mips_bne (code, ins->sreg2, mips_zero, 0);
3412 mips_nop (code);
3414 /* Divide by zero -- throw exception */
3415 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3417 mips_patch (divisor_is_zero, (guint32)code);
3418 mips_divu (code, ins->sreg1, ins->sreg2);
3419 if (ins->opcode == OP_IDIV_UN)
3420 mips_mflo (code, ins->dreg);
3421 else
3422 mips_mfhi (code, ins->dreg);
3423 break;
3425 case OP_DIV_IMM:
3426 g_assert_not_reached ();
3427 #if 0
3428 ppc_load (code, ppc_r11, ins->inst_imm);
3429 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3430 ppc_mfspr (code, ppc_r0, ppc_xer);
3431 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3432 /* FIXME: use OverflowException for 0x80000000/-1 */
3433 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3434 #endif
3435 g_assert_not_reached();
3436 break;
3437 case OP_REM_IMM:
3438 g_assert_not_reached ();
3439 case OP_IOR:
3440 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3441 break;
3442 case OP_OR_IMM:
3443 case OP_IOR_IMM:
3444 g_assert (!(ins->inst_imm & 0xffff0000));
3445 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3446 break;
3447 case OP_IXOR:
3448 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3449 break;
3450 case OP_XOR_IMM:
3451 case OP_IXOR_IMM:
3452 /* unsigned 16-bit immediate */
3453 g_assert (!(ins->inst_imm & 0xffff0000));
3454 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3455 break;
3456 case OP_ISHL:
3457 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3458 break;
3459 case OP_SHL_IMM:
3460 case OP_ISHL_IMM:
3461 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3462 break;
3463 case OP_ISHR:
3464 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3465 break;
3466 case OP_LSHR:
3467 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3468 break;
3469 case OP_SHR_IMM:
3470 case OP_ISHR_IMM:
3471 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3472 break;
3473 case OP_LSHR_IMM:
3474 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3475 break;
3476 case OP_SHR_UN_IMM:
3477 case OP_ISHR_UN_IMM:
3478 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3479 break;
3480 case OP_LSHR_UN_IMM:
3481 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3482 break;
3483 case OP_ISHR_UN:
3484 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3485 break;
3486 case OP_LSHR_UN:
3487 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3488 break;
3489 case OP_INOT:
3490 case OP_LNOT:
3491 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3492 break;
3493 case OP_INEG:
3494 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3495 break;
3496 case OP_LNEG:
3497 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3498 break;
3499 case OP_IMUL:
3500 #if USE_MUL
3501 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3502 #else
3503 mips_mult (code, ins->sreg1, ins->sreg2);
3504 mips_mflo (code, ins->dreg);
3505 mips_nop (code);
3506 mips_nop (code);
3507 #endif
3508 break;
3509 #if SIZEOF_REGISTER == 8
3510 case OP_LMUL:
3511 mips_dmult (code, ins->sreg1, ins->sreg2);
3512 mips_mflo (code, ins->dreg);
3513 break;
3514 #endif
3515 case OP_IMUL_OVF: {
3516 guint32 *patch;
3517 mips_mult (code, ins->sreg1, ins->sreg2);
3518 mips_mflo (code, ins->dreg);
3519 mips_mfhi (code, mips_at);
3520 mips_nop (code);
3521 mips_nop (code);
3522 mips_sra (code, mips_temp, ins->dreg, 31);
3523 patch = (guint32 *)(void *)code;
3524 mips_beq (code, mips_temp, mips_at, 0);
3525 mips_nop (code);
3526 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3527 mips_patch (patch, (guint32)code);
3528 break;
3530 case OP_IMUL_OVF_UN:
3531 #if 0
3532 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3533 #else
3534 mips_mult (code, ins->sreg1, ins->sreg2);
3535 mips_mflo (code, ins->dreg);
3536 mips_mfhi (code, mips_at);
3537 mips_nop (code);
3538 mips_nop (code);
3539 #endif
3540 /* XXX - Throw exception if we overflowed */
3541 break;
3542 case OP_ICONST:
3543 mips_load_const (code, ins->dreg, ins->inst_c0);
3544 break;
3545 #if SIZEOF_REGISTER == 8
3546 case OP_I8CONST:
3547 mips_load_const (code, ins->dreg, ins->inst_c0);
3548 break;
3549 #endif
3550 case OP_AOTCONST:
3551 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3552 mips_load (code, ins->dreg, 0);
3553 break;
3555 case OP_MIPS_MTC1S:
3556 mips_mtc1 (code, ins->dreg, ins->sreg1);
3557 break;
3558 case OP_MIPS_MTC1S_2:
3559 mips_mtc1 (code, ins->dreg, ins->sreg1);
3560 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3561 break;
3562 case OP_MIPS_MFC1S:
3563 mips_mfc1 (code, ins->dreg, ins->sreg1);
3564 break;
3565 case OP_MIPS_MTC1D:
3566 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3567 break;
3568 case OP_MIPS_MFC1D:
3569 #if 0
3570 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3571 #else
3572 mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3573 mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3574 #endif
3575 break;
3577 case OP_ICONV_TO_I4:
3578 case OP_ICONV_TO_U4:
3579 case OP_MOVE:
3580 if (ins->dreg != ins->sreg1)
3581 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3582 break;
3583 #if SIZEOF_REGISTER == 8
3584 case OP_ZEXT_I4:
3585 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3586 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3587 break;
3588 case OP_SEXT_I4:
3589 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3590 mips_dsra (code, ins->dreg, ins->dreg, 32);
3591 break;
3592 #endif
3593 case OP_SETLRET:
3594 /* Get sreg1 into v1, sreg2 into v0 */
3596 if (ins->sreg1 == mips_v0) {
3597 if (ins->sreg1 != mips_at)
3598 MIPS_MOVE (code, mips_at, ins->sreg1);
3599 if (ins->sreg2 != mips_v0)
3600 MIPS_MOVE (code, mips_v0, ins->sreg2);
3601 MIPS_MOVE (code, mips_v1, mips_at);
3603 else {
3604 if (ins->sreg2 != mips_v0)
3605 MIPS_MOVE (code, mips_v0, ins->sreg2);
3606 if (ins->sreg1 != mips_v1)
3607 MIPS_MOVE (code, mips_v1, ins->sreg1);
3609 break;
3610 case OP_FMOVE:
3611 if (ins->dreg != ins->sreg1) {
3612 mips_fmovd (code, ins->dreg, ins->sreg1);
3614 break;
3615 case OP_MIPS_CVTSD:
3616 /* Convert from double to float and leave it there */
3617 mips_cvtsd (code, ins->dreg, ins->sreg1);
3618 break;
3619 case OP_FCONV_TO_R4:
3620 #if 0
3621 mips_cvtsd (code, ins->dreg, ins->sreg1);
3622 #else
3623 /* Just a move, no precision change */
3624 if (ins->dreg != ins->sreg1) {
3625 mips_fmovd (code, ins->dreg, ins->sreg1);
3627 #endif
3628 break;
3629 case OP_JMP:
3630 code = emit_load_volatile_arguments(cfg, code);
3633 * Pop our stack, then jump to specified method (tail-call)
3634 * Keep in sync with mono_arch_emit_epilog
3636 code = mono_arch_emit_epilog_sub (cfg, code);
3638 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3639 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3640 #if LONG_BRANCH
3641 mips_lui (code, mips_t9, mips_zero, 0);
3642 mips_addiu (code, mips_t9, mips_t9, 0);
3643 mips_jr (code, mips_t9);
3644 mips_nop (code);
3645 #else
3646 mips_beq (code, mips_zero, mips_zero, 0);
3647 mips_nop (code);
3648 #endif
3649 break;
3650 case OP_CHECK_THIS:
3651 /* ensure ins->sreg1 is not NULL */
3652 mips_lw (code, mips_zero, ins->sreg1, 0);
3653 break;
3654 case OP_ARGLIST: {
3655 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3656 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3657 } else {
3658 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3659 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3661 mips_sw (code, mips_at, ins->sreg1, 0);
3662 break;
3664 case OP_FCALL:
3665 case OP_LCALL:
3666 case OP_VCALL:
3667 case OP_VCALL2:
3668 case OP_VOIDCALL:
3669 case OP_CALL:
3670 case OP_FCALL_REG:
3671 case OP_LCALL_REG:
3672 case OP_VCALL_REG:
3673 case OP_VCALL2_REG:
3674 case OP_VOIDCALL_REG:
3675 case OP_CALL_REG:
3676 case OP_FCALL_MEMBASE:
3677 case OP_LCALL_MEMBASE:
3678 case OP_VCALL_MEMBASE:
3679 case OP_VCALL2_MEMBASE:
3680 case OP_VOIDCALL_MEMBASE:
3681 case OP_CALL_MEMBASE:
3682 call = (MonoCallInst*)ins;
3683 switch (ins->opcode) {
3684 case OP_FCALL:
3685 case OP_LCALL:
3686 case OP_VCALL:
3687 case OP_VCALL2:
3688 case OP_VOIDCALL:
3689 case OP_CALL:
3690 if (ins->flags & MONO_INST_HAS_METHOD)
3691 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3692 else
3693 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3694 mips_lui (code, mips_t9, mips_zero, 0);
3695 mips_addiu (code, mips_t9, mips_t9, 0);
3696 break;
3697 case OP_FCALL_REG:
3698 case OP_LCALL_REG:
3699 case OP_VCALL_REG:
3700 case OP_VCALL2_REG:
3701 case OP_VOIDCALL_REG:
3702 case OP_CALL_REG:
3703 MIPS_MOVE (code, mips_t9, ins->sreg1);
3704 break;
3705 case OP_FCALL_MEMBASE:
3706 case OP_LCALL_MEMBASE:
3707 case OP_VCALL_MEMBASE:
3708 case OP_VCALL2_MEMBASE:
3709 case OP_VOIDCALL_MEMBASE:
3710 case OP_CALL_MEMBASE:
3711 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3712 break;
3714 mips_jalr (code, mips_t9, mips_ra);
3715 mips_nop (code);
3716 #if PROMOTE_R4_TO_R8
3717 /* returned an FP R4 (single), promote to R8 (double) in place */
3718 if ((ins->opcode == OP_FCALL ||
3719 ins->opcode == OP_FCALL_REG) &&
3720 call->signature->ret->type == MONO_TYPE_R4) {
3721 mips_cvtds (code, mips_f0, mips_f0);
3723 #endif
3724 break;
3725 case OP_LOCALLOC: {
3726 int area_offset = cfg->param_area;
3728 /* Round up ins->sreg1, mips_at ends up holding size */
3729 mips_addiu (code, mips_at, ins->sreg1, 31);
3730 mips_addiu (code, mips_temp, mips_zero, ~31);
3731 mips_and (code, mips_at, mips_at, mips_temp);
3733 mips_subu (code, mips_sp, mips_sp, mips_at);
3734 g_assert (mips_is_imm16 (area_offset));
3735 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3737 if (ins->flags & MONO_INST_INIT) {
3738 mips_move (code, mips_temp, ins->dreg);
3739 mips_sb (code, mips_zero, mips_temp, 0);
3740 mips_addiu (code, mips_at, mips_at, -1);
3741 mips_bne (code, mips_at, mips_zero, -3);
3742 mips_addiu (code, mips_temp, mips_temp, 1);
3744 break;
3746 case OP_THROW: {
3747 gpointer addr = mono_arch_get_throw_exception();
3748 mips_move (code, mips_a0, ins->sreg1);
3749 mips_load_const (code, mips_t9, addr);
3750 mips_jalr (code, mips_t9, mips_ra);
3751 mips_nop (code);
3752 mips_break (code, 0xfc);
3753 break;
3755 case OP_RETHROW: {
3756 gpointer addr = mono_arch_get_rethrow_exception();
3757 mips_move (code, mips_a0, ins->sreg1);
3758 mips_load_const (code, mips_t9, addr);
3759 mips_jalr (code, mips_t9, mips_ra);
3760 mips_nop (code);
3761 mips_break (code, 0xfb);
3762 break;
3764 case OP_START_HANDLER: {
3766 * The START_HANDLER instruction marks the beginning of
3767 * a handler block. It is called using a call
3768 * instruction, so mips_ra contains the return address.
3769 * Since the handler executes in the same stack frame
3770 * as the method itself, we can't use save/restore to
3771 * save the return address. Instead, we save it into
3772 * a dedicated variable.
3774 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3775 g_assert (spvar->inst_basereg != mips_sp);
3776 code = emit_reserve_param_area (cfg, code);
3778 if (mips_is_imm16 (spvar->inst_offset)) {
3779 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3780 } else {
3781 mips_load_const (code, mips_at, spvar->inst_offset);
3782 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3783 mips_sw (code, mips_ra, mips_at, 0);
3785 break;
3787 case OP_ENDFILTER: {
3788 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3789 g_assert (spvar->inst_basereg != mips_sp);
3790 code = emit_unreserve_param_area (cfg, code);
3792 if (ins->sreg1 != mips_v0)
3793 MIPS_MOVE (code, mips_v0, ins->sreg1);
3794 if (mips_is_imm16 (spvar->inst_offset)) {
3795 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3796 } else {
3797 mips_load_const (code, mips_at, spvar->inst_offset);
3798 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3799 mips_lw (code, mips_ra, mips_at, 0);
3801 mips_jr (code, mips_ra);
3802 mips_nop (code);
3803 break;
3805 case OP_ENDFINALLY: {
3806 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3807 g_assert (spvar->inst_basereg != mips_sp);
3808 code = emit_unreserve_param_area (cfg, code);
3809 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3810 mips_jalr (code, mips_t9, mips_ra);
3811 mips_nop (code);
3812 break;
3814 case OP_CALL_HANDLER:
3815 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3816 mips_lui (code, mips_t9, mips_zero, 0);
3817 mips_addiu (code, mips_t9, mips_t9, 0);
3818 mips_jalr (code, mips_t9, mips_ra);
3819 mips_nop (code);
3820 break;
3821 case OP_LABEL:
3822 ins->inst_c0 = code - cfg->native_code;
3823 break;
3824 case OP_BR:
3825 if (ins->flags & MONO_INST_BRLABEL) {
3826 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
3827 } else {
3828 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3830 #if LONG_BRANCH
3831 mips_lui (code, mips_at, mips_zero, 0);
3832 mips_addiu (code, mips_at, mips_at, 0);
3833 mips_jr (code, mips_at);
3834 mips_nop (code);
3835 #else
3836 mips_beq (code, mips_zero, mips_zero, 0);
3837 mips_nop (code);
3838 #endif
3839 break;
3840 case OP_BR_REG:
3841 mips_jr (code, ins->sreg1);
3842 mips_nop (code);
3843 break;
3844 case OP_SWITCH: {
3845 int i;
3847 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3848 if (offset > (cfg->code_size - max_len - 16)) {
3849 cfg->code_size += max_len;
3850 cfg->code_size *= 2;
3851 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3852 code = cfg->native_code + offset;
3854 g_assert (ins->sreg1 != -1);
3855 mips_sll (code, mips_at, ins->sreg1, 2);
3856 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3857 MIPS_MOVE (code, mips_t8, mips_ra);
3858 mips_bgezal (code, mips_zero, 1); /* bal */
3859 mips_nop (code);
3860 mips_addu (code, mips_t9, mips_ra, mips_at);
3861 /* Table is 16 or 20 bytes from target of bal above */
3862 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3863 MIPS_MOVE (code, mips_ra, mips_t8);
3864 mips_lw (code, mips_t9, mips_t9, 20);
3866 else
3867 mips_lw (code, mips_t9, mips_t9, 16);
3868 mips_jalr (code, mips_t9, mips_t8);
3869 mips_nop (code);
3870 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3871 mips_emit32 (code, 0xfefefefe);
3872 break;
3874 case OP_CEQ:
3875 case OP_ICEQ:
3876 mips_addiu (code, ins->dreg, mips_zero, 1);
3877 mips_beq (code, mips_at, mips_zero, 2);
3878 mips_nop (code);
3879 MIPS_MOVE (code, ins->dreg, mips_zero);
3880 break;
3881 case OP_CLT:
3882 case OP_CLT_UN:
3883 case OP_ICLT:
3884 case OP_ICLT_UN:
3885 mips_addiu (code, ins->dreg, mips_zero, 1);
3886 mips_bltz (code, mips_at, 2);
3887 mips_nop (code);
3888 MIPS_MOVE (code, ins->dreg, mips_zero);
3889 break;
3890 case OP_CGT:
3891 case OP_CGT_UN:
3892 case OP_ICGT:
3893 case OP_ICGT_UN:
3894 mips_addiu (code, ins->dreg, mips_zero, 1);
3895 mips_bgtz (code, mips_at, 2);
3896 mips_nop (code);
3897 MIPS_MOVE (code, ins->dreg, mips_zero);
3898 break;
3900 case OP_MIPS_COND_EXC_EQ:
3901 case OP_MIPS_COND_EXC_GE:
3902 case OP_MIPS_COND_EXC_GT:
3903 case OP_MIPS_COND_EXC_LE:
3904 case OP_MIPS_COND_EXC_LT:
3905 case OP_MIPS_COND_EXC_NE_UN:
3906 case OP_MIPS_COND_EXC_GE_UN:
3907 case OP_MIPS_COND_EXC_GT_UN:
3908 case OP_MIPS_COND_EXC_LE_UN:
3909 case OP_MIPS_COND_EXC_LT_UN:
3911 case OP_MIPS_COND_EXC_OV:
3912 case OP_MIPS_COND_EXC_NO:
3913 case OP_MIPS_COND_EXC_C:
3914 case OP_MIPS_COND_EXC_NC:
3916 case OP_MIPS_COND_EXC_IEQ:
3917 case OP_MIPS_COND_EXC_IGE:
3918 case OP_MIPS_COND_EXC_IGT:
3919 case OP_MIPS_COND_EXC_ILE:
3920 case OP_MIPS_COND_EXC_ILT:
3921 case OP_MIPS_COND_EXC_INE_UN:
3922 case OP_MIPS_COND_EXC_IGE_UN:
3923 case OP_MIPS_COND_EXC_IGT_UN:
3924 case OP_MIPS_COND_EXC_ILE_UN:
3925 case OP_MIPS_COND_EXC_ILT_UN:
3927 case OP_MIPS_COND_EXC_IOV:
3928 case OP_MIPS_COND_EXC_INO:
3929 case OP_MIPS_COND_EXC_IC:
3930 case OP_MIPS_COND_EXC_INC: {
3931 guint32 *skip;
3932 guint32 *throw;
3934 /* If the condition is true, raise the exception */
3936 /* need to reverse test to skip around exception raising */
3938 /* For the moment, branch around a branch to avoid reversing
3939 the tests. */
3941 /* Remember, an unpatched branch to 0 branches to the delay slot */
3942 switch (ins->opcode) {
3943 case OP_MIPS_COND_EXC_EQ:
3944 throw = (guint32 *)(void *)code;
3945 mips_beq (code, ins->sreg1, ins->sreg2, 0);
3946 mips_nop (code);
3947 break;
3949 case OP_MIPS_COND_EXC_NE_UN:
3950 throw = (guint32 *)(void *)code;
3951 mips_bne (code, ins->sreg1, ins->sreg2, 0);
3952 mips_nop (code);
3953 break;
3955 case OP_MIPS_COND_EXC_LE_UN:
3956 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
3957 throw = (guint32 *)(void *)code;
3958 mips_blez (code, mips_at, 0);
3959 mips_nop (code);
3960 break;
3962 case OP_MIPS_COND_EXC_GT:
3963 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
3964 throw = (guint32 *)(void *)code;
3965 mips_bne (code, mips_at, mips_zero, 0);
3966 mips_nop (code);
3967 break;
3969 case OP_MIPS_COND_EXC_GT_UN:
3970 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
3971 throw = (guint32 *)(void *)code;
3972 mips_bne (code, mips_at, mips_zero, 0);
3973 mips_nop (code);
3974 break;
3976 case OP_MIPS_COND_EXC_LT:
3977 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
3978 throw = (guint32 *)(void *)code;
3979 mips_bne (code, mips_at, mips_zero, 0);
3980 mips_nop (code);
3981 break;
3983 case OP_MIPS_COND_EXC_LT_UN:
3984 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
3985 throw = (guint32 *)(void *)code;
3986 mips_bne (code, mips_at, mips_zero, 0);
3987 mips_nop (code);
3988 break;
3990 default:
3991 /* Not yet implemented */
3992 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
3993 g_assert_not_reached ();
3995 skip = (guint32 *)(void *)code;
3996 mips_beq (code, mips_zero, mips_zero, 0);
3997 mips_nop (code);
3998 mips_patch (throw, (guint32)code);
3999 code = mips_emit_exc_by_name (code, ins->inst_p1);
4000 mips_patch (skip, (guint32)code);
4001 cfg->bb_exit->max_offset += 24;
4002 break;
4004 case OP_MIPS_BEQ:
4005 case OP_MIPS_BNE:
4006 case OP_MIPS_BGEZ:
4007 case OP_MIPS_BGTZ:
4008 case OP_MIPS_BLEZ:
4009 case OP_MIPS_BLTZ:
4010 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4011 break;
4013 /* floating point opcodes */
4014 case OP_R8CONST:
4015 #if 0
4016 if (((guint32)ins->inst_p0) & (1 << 15))
4017 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4018 else
4019 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4020 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4021 #else
4022 mips_load_const (code, mips_at, ins->inst_p0);
4023 mips_lwc1 (code, ins->dreg, mips_at, 4);
4024 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4025 #endif
4026 break;
4027 case OP_R4CONST:
4028 if (((guint32)ins->inst_p0) & (1 << 15))
4029 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4030 else
4031 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4032 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4033 #if PROMOTE_R4_TO_R8
4034 mips_cvtds (code, ins->dreg, ins->dreg);
4035 #endif
4036 break;
4037 case OP_STORER8_MEMBASE_REG:
4038 if (mips_is_imm16 (ins->inst_offset)) {
4039 #if _MIPS_SIM == _ABIO32
4040 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
4041 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
4042 #elif _MIPS_SIM == _ABIN32
4043 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4044 #endif
4045 } else {
4046 mips_load_const (code, mips_at, ins->inst_offset);
4047 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4048 mips_swc1 (code, ins->sreg1, mips_at, 4);
4049 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
4051 break;
4052 case OP_LOADR8_MEMBASE:
4053 if (mips_is_imm16 (ins->inst_offset)) {
4054 #if _MIPS_SIM == _ABIO32
4055 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
4056 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
4057 #elif _MIPS_SIM == _ABIN32
4058 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4059 #endif
4060 } else {
4061 mips_load_const (code, mips_at, ins->inst_offset);
4062 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4063 mips_lwc1 (code, ins->dreg, mips_at, 4);
4064 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4066 break;
4067 case OP_STORER4_MEMBASE_REG:
4068 g_assert (mips_is_imm16 (ins->inst_offset));
4069 #if PROMOTE_R4_TO_R8
4070 /* Need to convert ins->sreg1 to single-precision first */
4071 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4072 #endif
4073 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4074 break;
4075 case OP_MIPS_LWC1:
4076 g_assert (mips_is_imm16 (ins->inst_offset));
4077 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4078 break;
4079 case OP_LOADR4_MEMBASE:
4080 g_assert (mips_is_imm16 (ins->inst_offset));
4081 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4082 #if PROMOTE_R4_TO_R8
4083 /* Convert to double precision in place */
4084 mips_cvtds (code, ins->dreg, ins->dreg);
4085 #endif
4086 break;
4087 case OP_ICONV_TO_R_UN: {
4088 static const guint64 adjust_val = 0x41F0000000000000ULL;
4090 /* convert unsigned int to double */
4091 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4092 mips_bgez (code, ins->sreg1, 5);
4093 mips_cvtdw (code, ins->dreg, mips_ftemp);
4095 mips_load (code, mips_at, (guint32) &adjust_val);
4096 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4097 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4098 /* target is here */
4099 break;
4101 case OP_ICONV_TO_R4:
4102 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4103 mips_cvtsw (code, ins->dreg, mips_ftemp);
4104 mips_cvtds (code, ins->dreg, ins->dreg);
4105 break;
4106 case OP_ICONV_TO_R8:
4107 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4108 mips_cvtdw (code, ins->dreg, mips_ftemp);
4109 break;
4110 case OP_FCONV_TO_I1:
4111 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4112 break;
4113 case OP_FCONV_TO_U1:
4114 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4115 break;
4116 case OP_FCONV_TO_I2:
4117 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4118 break;
4119 case OP_FCONV_TO_U2:
4120 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4121 break;
4122 case OP_FCONV_TO_I4:
4123 case OP_FCONV_TO_I:
4124 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4125 break;
4126 case OP_FCONV_TO_U4:
4127 case OP_FCONV_TO_U:
4128 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4129 break;
4130 case OP_SQRT:
4131 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4132 break;
4133 case OP_FADD:
4134 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4135 break;
4136 case OP_FSUB:
4137 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4138 break;
4139 case OP_FMUL:
4140 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4141 break;
4142 case OP_FDIV:
4143 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4144 break;
4145 case OP_FNEG:
4146 mips_fnegd (code, ins->dreg, ins->sreg1);
4147 break;
4148 case OP_FCEQ:
4149 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4150 mips_addiu (code, ins->dreg, mips_zero, 1);
4151 mips_fbtrue (code, 2);
4152 mips_nop (code);
4153 MIPS_MOVE (code, ins->dreg, mips_zero);
4154 break;
4155 case OP_FCLT:
4156 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4157 mips_addiu (code, ins->dreg, mips_zero, 1);
4158 mips_fbtrue (code, 2);
4159 mips_nop (code);
4160 MIPS_MOVE (code, ins->dreg, mips_zero);
4161 break;
4162 case OP_FCLT_UN:
4163 /* Less than, or Unordered */
4164 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4165 mips_addiu (code, ins->dreg, mips_zero, 1);
4166 mips_fbtrue (code, 2);
4167 mips_nop (code);
4168 MIPS_MOVE (code, ins->dreg, mips_zero);
4169 break;
4170 case OP_FCGT:
4171 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4172 MIPS_MOVE (code, ins->dreg, mips_zero);
4173 mips_fbtrue (code, 2);
4174 mips_nop (code);
4175 mips_addiu (code, ins->dreg, mips_zero, 1);
4176 break;
4177 case OP_FCGT_UN:
4178 /* Greater than, or Unordered */
4179 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4180 MIPS_MOVE (code, ins->dreg, mips_zero);
4181 mips_fbtrue (code, 2);
4182 mips_nop (code);
4183 mips_addiu (code, ins->dreg, mips_zero, 1);
4184 break;
4185 case OP_MIPS_FBEQ:
4186 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4187 mips_nop (code);
4188 if (ins->flags & MONO_INST_BRLABEL)
4189 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
4190 else
4191 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4192 mips_fbtrue (code, 0);
4193 mips_nop (code);
4194 break;
4195 case OP_MIPS_FBNE:
4196 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4197 mips_nop (code);
4198 if (ins->flags & MONO_INST_BRLABEL)
4199 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
4200 else
4201 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4202 mips_fbfalse (code, 0);
4203 mips_nop (code);
4204 break;
4205 case OP_MIPS_FBLT:
4206 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4207 mips_nop (code);
4208 if (ins->flags & MONO_INST_BRLABEL)
4209 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
4210 else
4211 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4212 mips_fbtrue (code, 0);
4213 mips_nop (code);
4214 break;
4215 case OP_MIPS_FBLT_UN:
4216 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4217 mips_nop (code);
4218 if (ins->flags & MONO_INST_BRLABEL)
4219 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
4220 else
4221 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4222 mips_fbtrue (code, 0);
4223 mips_nop (code);
4224 break;
4225 case OP_MIPS_FBGT:
4226 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
4227 mips_nop (code);
4228 if (ins->flags & MONO_INST_BRLABEL)
4229 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
4230 else
4231 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4232 mips_fbfalse (code, 0);
4233 mips_nop (code);
4234 break;
4235 case OP_MIPS_FBGT_UN:
4236 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4237 mips_nop (code);
4238 if (ins->flags & MONO_INST_BRLABEL)
4239 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
4240 else
4241 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4242 mips_fbfalse (code, 0);
4243 mips_nop (code);
4244 break;
4245 case OP_MIPS_FBGE:
4246 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4247 mips_nop (code);
4248 if (ins->flags & MONO_INST_BRLABEL)
4249 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
4250 else
4251 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4252 mips_fbfalse (code, 0);
4253 mips_nop (code);
4254 break;
4255 case OP_MIPS_FBGE_UN:
4256 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
4257 mips_nop (code);
4258 if (ins->flags & MONO_INST_BRLABEL)
4259 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
4260 else
4261 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4262 mips_fbfalse (code, 0);
4263 mips_nop (code);
4264 break;
4265 case OP_MIPS_FBLE:
4266 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4267 mips_nop (code);
4268 if (ins->flags & MONO_INST_BRLABEL)
4269 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
4270 else
4271 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4272 mips_fbtrue (code, 0);
4273 mips_nop (code);
4274 break;
4275 case OP_MIPS_FBLE_UN:
4276 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4277 mips_nop (code);
4278 if (ins->flags & MONO_INST_BRLABEL)
4279 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0);
4280 else
4281 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4282 mips_fbtrue (code, 0);
4283 mips_nop (code);
4284 break;
4285 case OP_CKFINITE: {
4286 guint32 *branch_patch;
4288 mips_mfc1 (code, mips_at, ins->sreg1+1);
4289 mips_srl (code, mips_at, mips_at, 16+4);
4290 mips_andi (code, mips_at, mips_at, 2047);
4291 mips_addiu (code, mips_at, mips_at, -2047);
4293 branch_patch = (guint32 *)(void *)code;
4294 mips_bne (code, mips_at, mips_zero, 0);
4295 mips_nop (code);
4297 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4298 mips_patch (branch_patch, (guint32)code);
4299 mips_fmovd (code, ins->dreg, ins->sreg1);
4300 break;
4302 case OP_JUMP_TABLE:
4303 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4304 mips_load (code, ins->dreg, 0x0f0f0f0f);
4305 break;
4308 default:
4309 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4310 g_assert_not_reached ();
4313 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4314 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4315 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4316 g_assert_not_reached ();
4319 cpos += max_len;
4321 last_ins = ins;
4322 last_offset = offset;
4325 cfg->code_len = code - cfg->native_code;
4328 void
4329 mono_arch_register_lowlevel_calls (void)
4333 void
4334 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4336 MonoJumpInfo *patch_info;
4338 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4339 unsigned char *ip = patch_info->ip.i + code;
4340 const unsigned char *target = NULL;
4342 switch (patch_info->type) {
4343 case MONO_PATCH_INFO_IP:
4344 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4345 continue;
4346 case MONO_PATCH_INFO_SWITCH: {
4347 gpointer *table = (gpointer *)patch_info->data.table->table;
4348 int i;
4350 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4352 for (i = 0; i < patch_info->data.table->table_size; i++) {
4353 table [i] = (int)patch_info->data.table->table [i] + code;
4355 continue;
4357 case MONO_PATCH_INFO_METHODCONST:
4358 case MONO_PATCH_INFO_CLASS:
4359 case MONO_PATCH_INFO_IMAGE:
4360 case MONO_PATCH_INFO_FIELD:
4361 case MONO_PATCH_INFO_VTABLE:
4362 case MONO_PATCH_INFO_IID:
4363 case MONO_PATCH_INFO_SFLDA:
4364 case MONO_PATCH_INFO_LDSTR:
4365 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4366 case MONO_PATCH_INFO_LDTOKEN:
4367 case MONO_PATCH_INFO_R4:
4368 case MONO_PATCH_INFO_R8:
4369 /* from OP_AOTCONST : lui + addiu */
4370 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4371 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4372 continue;
4373 #if 0
4374 case MONO_PATCH_INFO_EXC_NAME:
4375 g_assert_not_reached ();
4376 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4377 continue;
4378 #endif
4379 case MONO_PATCH_INFO_NONE:
4380 /* everything is dealt with at epilog output time */
4381 continue;
4382 default:
4383 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4384 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4385 break;
4390 #if 0
4391 static
4392 void
4393 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4397 static
4398 void
4399 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4402 #endif
4405 * Allow tracing to work with this interface (with an optional argument)
4407 * This code is expected to be inserted just after the 'real' prolog code,
4408 * and before the first basic block. We need to allocate a 2nd, temporary
4409 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4412 void*
4413 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4415 guchar *code = p;
4416 int offset = cfg->arch.tracing_offset;
4418 mips_nop (code);
4419 mips_nop (code);
4420 mips_nop (code);
4422 /* For N32, need to know for each stack slot if it's an integer
4423 * or float argument, and save/restore the appropriate register
4425 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4426 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4427 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4428 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4429 #if _MIPS_SIM == _ABIN32
4430 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4431 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4432 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4433 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4434 #endif
4436 mips_load_const (code, mips_a0, cfg->method);
4437 mips_addiu (code, mips_a1, mips_sp, offset);
4438 mips_load_const (code, mips_t9, func);
4439 mips_jalr (code, mips_t9, mips_ra);
4440 mips_nop (code);
4442 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4443 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4444 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4445 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4446 #if _MIPS_SIM == _ABIN32
4447 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4448 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4449 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4450 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4451 #endif
4453 mips_nop (code);
4454 mips_nop (code);
4455 mips_nop (code);
4456 return code;
4459 void
4460 mips_adjust_stackframe(MonoCompile *cfg)
4462 MonoBasicBlock *bb;
4463 int delta, threshold, i;
4464 MonoMethodSignature *sig;
4465 int ra_offset;
4467 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4468 return;
4470 /* adjust cfg->stack_offset for account for down-spilling */
4471 cfg->stack_offset += SIZEOF_REGISTER;
4473 /* re-align cfg->stack_offset if needed (due to var spilling) */
4474 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4475 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4476 if (cfg->verbose_level > 2) {
4477 g_print ("mips_adjust_stackframe:\n");
4478 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4480 threshold = cfg->arch.local_alloc_offset;
4481 ra_offset = cfg->stack_offset - sizeof(gpointer);
4482 if (cfg->verbose_level > 2) {
4483 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4486 sig = mono_method_signature (cfg->method);
4487 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4488 cfg->vret_addr->inst_offset += delta;
4490 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4491 MonoInst *inst = cfg->args [i];
4493 inst->inst_offset += delta;
4497 * loads and stores based off the frame reg that (used to) lie
4498 * above the spill var area need to be increased by 'delta'
4499 * to make room for the spill vars.
4501 /* Need to find loads and stores to adjust that
4502 * are above where the spillvars were inserted, but
4503 * which are not the spillvar references themselves.
4505 * Idea - since all offsets from fp are positive, make
4506 * spillvar offsets negative to begin with so we can spot
4507 * them here.
4510 #if 1
4511 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4512 int ins_cnt = 0;
4513 MonoInst *ins;
4515 if (cfg->verbose_level > 2) {
4516 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4518 MONO_BB_FOR_EACH_INS (bb, ins) {
4519 int adj_c0 = 0;
4520 int adj_imm = 0;
4522 if (cfg->verbose_level > 2) {
4523 mono_print_ins_index (ins_cnt, ins);
4525 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp))
4526 adj_c0 = 1;
4527 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))
4528 adj_c0 = 1;
4529 /* The following two catch FP spills */
4530 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_sp))
4531 adj_c0 = 1;
4532 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_sp))
4533 adj_c0 = 1;
4534 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4535 adj_imm = 1;
4536 if (adj_c0) {
4537 if (ins->inst_c0 >= threshold) {
4538 ins->inst_c0 += delta;
4539 if (cfg->verbose_level > 2) {
4540 g_print ("adj");
4541 mono_print_ins_index (ins_cnt, ins);
4544 else if (ins->inst_c0 < 0) {
4545 ins->inst_c0 = - ins->inst_c0 - 4;
4546 if (cfg->verbose_level > 2) {
4547 g_print ("spill");
4548 mono_print_ins_index (ins_cnt, ins);
4551 g_assert (ins->inst_c0 != ra_offset);
4553 if (adj_imm) {
4554 if (ins->inst_imm >= threshold) {
4555 ins->inst_imm += delta;
4556 if (cfg->verbose_level > 2) {
4557 g_print ("adj");
4558 mono_print_ins_index (ins_cnt, ins);
4561 g_assert (ins->inst_c0 != ra_offset);
4564 ++ins_cnt;
4567 #endif
4571 * Stack frame layout:
4573 * ------------------- sp + cfg->stack_usage + cfg->param_area
4574 * param area incoming
4575 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4576 * a0-a3 incoming
4577 * ------------------- sp + cfg->stack_usage
4578 * ra
4579 * ------------------- sp + cfg->stack_usage-4
4580 * spilled regs
4581 * ------------------- sp +
4582 * MonoLMF structure optional
4583 * ------------------- sp + cfg->arch.lmf_offset
4584 * saved registers s0-s8
4585 * ------------------- sp + cfg->arch.iregs_offset
4586 * locals
4587 * ------------------- sp + cfg->param_area
4588 * param area outgoing
4589 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4590 * a0-a3 outgoing
4591 * ------------------- sp
4592 * red zone
4594 guint8 *
4595 mono_arch_emit_prolog (MonoCompile *cfg)
4597 MonoMethod *method = cfg->method;
4598 MonoMethodSignature *sig;
4599 MonoInst *inst;
4600 int alloc_size, pos, i;
4601 guint8 *code;
4602 CallInfo *cinfo;
4603 int tracing = 0;
4604 guint32 iregs_to_save = 0;
4605 #if SAVE_FP_REGS
4606 guint32 fregs_to_save = 0;
4607 #endif
4608 #if SAVE_LMF
4609 /* lmf_offset is the offset of the LMF from our stack pointer. */
4610 guint32 lmf_offset = cfg->arch.lmf_offset;
4611 #endif
4613 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4614 tracing = 1;
4616 if (tracing)
4617 cfg->flags |= MONO_CFG_HAS_CALLS;
4619 sig = mono_method_signature (method);
4620 cfg->code_size = 768 + sig->param_count * 20;
4621 code = cfg->native_code = g_malloc (cfg->code_size);
4623 if (tracing) {
4624 #if _MIPS_SIM == _ABIO32
4625 cfg->arch.tracing_offset = cfg->stack_offset;
4626 #elif _MIPS_SIM == _ABIN32
4627 /* no stack slots by default for argument regs, reserve a special block */
4628 cfg->arch.tracing_offset = cfg->stack_offset;
4629 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4630 #endif
4633 /* adjust stackframe assignments for spillvars if needed */
4634 mips_adjust_stackframe (cfg);
4636 /* stack_offset should not be changed here. */
4637 alloc_size = cfg->stack_offset;
4638 cfg->stack_usage = alloc_size;
4640 #if SAVE_ALL_REGS
4641 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4642 #else
4643 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4644 #endif
4645 #if SAVE_FP_REGS
4646 #if 0
4647 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4648 #else
4649 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4650 fregs_to_save |= (fregs_to_save << 1);
4651 #endif
4652 #endif
4653 if (alloc_size) {
4654 if (mips_is_imm16 (-alloc_size)) {
4655 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4656 } else {
4657 mips_load_const (code, mips_at, -alloc_size);
4658 mips_addu (code, mips_sp, mips_sp, mips_at);
4662 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
4663 mips_sw (code, mips_ra, mips_sp, alloc_size + MIPS_RET_ADDR_OFFSET);
4665 /* XXX - optimize this later to not save all regs if LMF constructed */
4667 if (iregs_to_save) {
4668 /* save used registers in own stack frame (at pos) */
4669 pos = cfg->arch.iregs_offset;
4670 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4671 if (iregs_to_save & (1 << i)) {
4672 g_assert (pos < cfg->stack_usage - sizeof(gpointer));
4673 MIPS_SW (code, i, mips_sp, pos);
4674 pos += SIZEOF_REGISTER;
4678 #if SAVE_LMF
4679 if (method->save_lmf) {
4680 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4681 MIPS_SW (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]));
4684 #endif
4686 #if SAVE_FP_REGS
4687 /* Save float registers */
4688 if (fregs_to_save) {
4689 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4690 if (fregs_to_save & (1 << i)) {
4691 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4692 mips_swc1 (code, i, mips_sp, pos);
4693 pos += sizeof (gulong);
4697 #if SAVE_LMF
4698 if (method->save_lmf) {
4699 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4700 mips_swc1 (code, i, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]));
4703 #endif
4704 #endif
4705 if (cfg->frame_reg != mips_sp) {
4706 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4707 #if SAVE_LMF
4708 if (method->save_lmf)
4709 MIPS_SW (code, cfg->frame_reg, mips_sp,
4710 lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]));
4711 #endif
4714 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4715 * to the t* registers, which would be clobbered by the instrumentation calls.
4717 if (tracing) {
4718 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4722 /* load arguments allocated to register from the stack */
4723 pos = 0;
4725 cinfo = calculate_sizes (sig, sig->pinvoke);
4727 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4728 ArgInfo *ainfo = &cinfo->ret;
4729 inst = cfg->vret_addr;
4730 if (inst->opcode == OP_REGVAR)
4731 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4732 else if (mips_is_imm16 (inst->inst_offset)) {
4733 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4734 } else {
4735 mips_load_const (code, mips_at, inst->inst_offset);
4736 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4737 mips_sw (code, ainfo->reg, mips_at, 0);
4740 /* Keep this in sync with emit_load_volatile_arguments */
4741 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4742 ArgInfo *ainfo = cinfo->args + i;
4743 inst = cfg->args [pos];
4745 if (cfg->verbose_level > 2)
4746 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4747 if (inst->opcode == OP_REGVAR) {
4748 /* Argument ends up in a register */
4749 if (ainfo->regtype == RegTypeGeneral)
4750 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4751 else if (ainfo->regtype == RegTypeFP) {
4752 g_assert_not_reached();
4753 #if 0
4754 ppc_fmr (code, inst->dreg, ainfo->reg);
4755 #endif
4757 else if (ainfo->regtype == RegTypeBase) {
4758 mips_lw (code, inst->dreg, mips_sp, cfg->stack_usage + ainfo->offset);
4759 } else
4760 g_assert_not_reached ();
4762 if (cfg->verbose_level > 2)
4763 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4764 } else {
4765 /* Argument ends up on the stack */
4766 if (ainfo->regtype == RegTypeGeneral) {
4767 /* Incoming parameters should be above this frame */
4768 if (cfg->verbose_level > 2)
4769 g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
4770 /* g_assert (inst->inst_offset >= alloc_size); */
4771 g_assert (mips_is_imm16 (inst->inst_offset));
4772 switch (ainfo->size) {
4773 case 1:
4774 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4775 break;
4776 case 2:
4777 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4778 break;
4779 case 0: /* XXX */
4780 case 4:
4781 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4782 break;
4783 case 8:
4784 #if (SIZEOF_REGISTER == 4)
4785 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4786 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4787 #elif (SIZEOF_REGISTER == 8)
4788 mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4789 #endif
4790 break;
4791 default:
4792 g_assert_not_reached ();
4793 break;
4795 } else if (ainfo->regtype == RegTypeBase) {
4797 * Argument comes in on the stack, and ends up on the stack
4798 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4799 * 8 and 16 bit quantities. Shorten them in place.
4801 g_assert (mips_is_imm16 (inst->inst_offset));
4802 switch (ainfo->size) {
4803 case 1:
4804 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4805 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4806 break;
4807 case 2:
4808 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4809 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4810 break;
4811 case 0: /* XXX */
4812 case 4:
4813 case 8:
4814 break;
4815 default:
4816 g_assert_not_reached ();
4818 } else if (ainfo->regtype == RegTypeFP) {
4819 g_assert (mips_is_imm16 (inst->inst_offset));
4820 if (ainfo->size == 8) {
4821 #if _MIPS_SIM == _ABIO32
4822 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4823 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4824 #elif _MIPS_SIM == _ABIN32
4825 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4826 #endif
4828 else if (ainfo->size == 4)
4829 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4830 else
4831 g_assert_not_reached ();
4832 } else if (ainfo->regtype == RegTypeStructByVal) {
4833 int i;
4834 int doffset = inst->inst_offset;
4836 g_assert (mips_is_imm16 (inst->inst_offset));
4837 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4838 /* Push the argument registers into their stack slots */
4839 for (i = 0; i < ainfo->size; ++i) {
4840 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
4841 doffset += SIZEOF_REGISTER;
4843 } else if (ainfo->regtype == RegTypeStructByAddr) {
4844 g_assert (mips_is_imm16 (inst->inst_offset));
4845 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4846 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4847 } else
4848 g_assert_not_reached ();
4850 pos++;
4853 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4854 mips_load_const (code, mips_a0, cfg->domain);
4855 mips_load_const (code, mips_t9, (gpointer)mono_jit_thread_attach);
4856 mips_jalr (code, mips_t9, mips_ra);
4857 mips_nop (code);
4860 #if SAVE_LMF
4861 if (method->save_lmf) {
4862 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4863 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4865 if (lmf_pthread_key != -1) {
4866 g_assert_not_reached();
4867 #if 0
4868 emit_tls_access (code, mips_temp, lmf_pthread_key);
4869 #endif
4870 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf))
4871 mips_addiu (code, mips_a0, mips_temp, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4872 } else {
4873 #if 0
4874 mips_addiu (code, mips_a0, mips_sp, lmf_offset);
4875 mips_load_const (code, mips_t9, (gpointer)mono_trace_lmf_prolog);
4876 mips_jalr (code, mips_t9, mips_ra);
4877 mips_nop (code);
4878 #endif
4879 /* This can/will clobber the a0-a3 registers */
4880 mips_load_const (code, mips_t9, (gpointer)mono_get_lmf_addr);
4881 mips_jalr (code, mips_t9, mips_ra);
4882 mips_nop (code);
4885 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4886 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4887 /* new_lmf->previous_lmf = *lmf_addr */
4888 mips_lw (code, mips_at, mips_v0, 0);
4889 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4890 /* *(lmf_addr) = sp + lmf_offset */
4891 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4892 mips_sw (code, mips_at, mips_v0, 0);
4894 /* save method info */
4895 mips_load_const (code, mips_at, method);
4896 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4897 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4899 /* save the current IP */
4900 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4901 mips_load_const (code, mips_at, 0x01010101);
4902 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
4904 #endif
4906 cfg->code_len = code - cfg->native_code;
4907 g_assert (cfg->code_len < cfg->code_size);
4908 g_free (cinfo);
4910 return code;
4913 enum {
4914 SAVE_NONE,
4915 SAVE_STRUCT,
4916 SAVE_ONE,
4917 SAVE_TWO,
4918 SAVE_FP
4921 void*
4922 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4924 guchar *code = p;
4925 int save_mode = SAVE_NONE;
4926 int offset;
4927 MonoMethod *method = cfg->method;
4928 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
4929 int save_offset = MIPS_STACK_PARAM_OFFSET;
4931 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
4933 offset = code - cfg->native_code;
4934 /* we need about 16 instructions */
4935 if (offset > (cfg->code_size - 16 * 4)) {
4936 cfg->code_size *= 2;
4937 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4938 code = cfg->native_code + offset;
4940 mips_nop (code);
4941 mips_nop (code);
4942 switch (rtype) {
4943 case MONO_TYPE_VOID:
4944 /* special case string .ctor icall */
4945 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
4946 save_mode = SAVE_ONE;
4947 else
4948 save_mode = SAVE_NONE;
4949 break;
4950 case MONO_TYPE_R4:
4951 case MONO_TYPE_R8:
4952 save_mode = SAVE_FP;
4953 break;
4954 case MONO_TYPE_VALUETYPE:
4955 save_mode = SAVE_STRUCT;
4956 break;
4957 case MONO_TYPE_I8:
4958 case MONO_TYPE_U8:
4959 #if SIZEOF_REGISTER == 4
4960 save_mode = SAVE_TWO;
4961 #elif SIZEOF_REGISTER == 8
4962 save_mode = SAVE_ONE;
4963 #endif
4964 break;
4965 default:
4966 save_mode = SAVE_ONE;
4967 break;
4970 mips_addiu (code, mips_sp, mips_sp, -32);
4971 switch (save_mode) {
4972 case SAVE_TWO:
4973 mips_sw (code, mips_v0, mips_sp, save_offset);
4974 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
4975 if (enable_arguments) {
4976 MIPS_MOVE (code, mips_a1, mips_v0);
4977 MIPS_MOVE (code, mips_a2, mips_v1);
4979 break;
4980 case SAVE_ONE:
4981 MIPS_SW (code, mips_v0, mips_sp, save_offset);
4982 if (enable_arguments) {
4983 MIPS_MOVE (code, mips_a1, mips_v0);
4985 break;
4986 case SAVE_FP:
4987 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
4988 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
4989 mips_lw (code, mips_a0, mips_sp, save_offset);
4990 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
4991 break;
4992 case SAVE_STRUCT:
4993 case SAVE_NONE:
4994 default:
4995 break;
4997 mips_load_const (code, mips_a0, cfg->method);
4998 mips_load_const (code, mips_t9, func);
4999 mips_jalr (code, mips_t9, mips_ra);
5000 mips_nop (code);
5002 switch (save_mode) {
5003 case SAVE_TWO:
5004 mips_lw (code, mips_v0, mips_sp, save_offset);
5005 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5006 break;
5007 case SAVE_ONE:
5008 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5009 break;
5010 case SAVE_FP:
5011 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5012 break;
5013 case SAVE_STRUCT:
5014 case SAVE_NONE:
5015 default:
5016 break;
5018 mips_addiu (code, mips_sp, mips_sp, 32);
5019 mips_nop (code);
5020 mips_nop (code);
5021 return code;
5024 guint8 *
5025 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5027 MonoMethod *method = cfg->method;
5028 int pos = 0, i;
5029 int max_epilog_size = 16 + 20*4;
5030 guint32 iregs_to_restore;
5031 #if SAVE_FP_REGS
5032 guint32 fregs_to_restore;
5033 #endif
5035 #if SAVE_LMF
5036 if (cfg->method->save_lmf)
5037 max_epilog_size += 128;
5038 #endif
5040 if (mono_jit_trace_calls != NULL)
5041 max_epilog_size += 50;
5043 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5044 max_epilog_size += 50;
5046 if (code)
5047 pos = code - cfg->native_code;
5048 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5049 cfg->code_size *= 2;
5050 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5051 mono_jit_stats.code_reallocs++;
5055 * Keep in sync with OP_JMP
5057 if (code)
5058 code = cfg->native_code + pos;
5059 else
5060 code = cfg->native_code + cfg->code_len;
5062 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5063 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5065 pos = cfg->arch.iregs_offset;
5066 if (cfg->frame_reg != mips_sp) {
5067 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5069 #if SAVE_ALL_REGS
5070 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5071 #else
5072 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5073 #endif
5074 if (iregs_to_restore) {
5075 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5076 if (iregs_to_restore & (1 << i)) {
5077 MIPS_LW (code, i, mips_sp, pos);
5078 pos += SIZEOF_REGISTER;
5083 #if SAVE_FP_REGS
5084 #if 0
5085 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5086 #else
5087 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5088 fregs_to_restore |= (fregs_to_restore << 1);
5089 #endif
5090 if (fregs_to_restore) {
5091 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5092 if (fregs_to_restore & (1 << i)) {
5093 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5094 mips_lwc1 (code, i, mips_sp, pos);
5095 pos += FREG_SIZE
5099 #endif
5100 #if SAVE_LMF
5101 /* Unlink the LMF if necessary */
5102 if (method->save_lmf) {
5103 int lmf_offset = cfg->arch.lmf_offset;
5105 /* t0 = current_lmf->previous_lmf */
5106 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5107 /* t1 = lmf_addr */
5108 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5109 /* (*lmf_addr) = previous_lmf */
5110 mips_sw (code, mips_temp, mips_t1, 0);
5112 #endif
5113 #if 0
5114 /* Restore the fp */
5115 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5116 #endif
5117 /* Correct the stack pointer */
5118 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA)
5119 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage + MIPS_RET_ADDR_OFFSET);
5120 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage);
5122 /* Caller will emit either return or tail-call sequence */
5124 cfg->code_len = code - cfg->native_code;
5126 g_assert (cfg->code_len < cfg->code_size);
5127 return (code);
5130 void
5131 mono_arch_emit_epilog (MonoCompile *cfg)
5133 guint8 *code;
5135 code = mono_arch_emit_epilog_sub (cfg, NULL);
5137 mips_jr (code, mips_ra);
5138 mips_nop (code);
5140 cfg->code_len = code - cfg->native_code;
5142 g_assert (cfg->code_len < cfg->code_size);
5145 /* remove once throw_exception_by_name is eliminated */
5146 #if 0
5147 static int
5148 exception_id_by_name (const char *name)
5150 if (strcmp (name, "IndexOutOfRangeException") == 0)
5151 return MONO_EXC_INDEX_OUT_OF_RANGE;
5152 if (strcmp (name, "OverflowException") == 0)
5153 return MONO_EXC_OVERFLOW;
5154 if (strcmp (name, "ArithmeticException") == 0)
5155 return MONO_EXC_ARITHMETIC;
5156 if (strcmp (name, "DivideByZeroException") == 0)
5157 return MONO_EXC_DIVIDE_BY_ZERO;
5158 if (strcmp (name, "InvalidCastException") == 0)
5159 return MONO_EXC_INVALID_CAST;
5160 if (strcmp (name, "NullReferenceException") == 0)
5161 return MONO_EXC_NULL_REF;
5162 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5163 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5164 g_error ("Unknown intrinsic exception %s\n", name);
5165 return 0;
5167 #endif
5169 void
5170 mono_arch_emit_exceptions (MonoCompile *cfg)
5172 #if 0
5173 MonoJumpInfo *patch_info;
5174 int i;
5175 guint8 *code;
5176 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5177 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5178 int max_epilog_size = 50;
5180 /* count the number of exception infos */
5183 * make sure we have enough space for exceptions
5184 * 24 is the simulated call to throw_exception_by_name
5186 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5187 #if 0
5188 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5189 i = exception_id_by_name (patch_info->data.target);
5190 g_assert (i < MONO_EXC_INTRINS_NUM);
5191 if (!exc_throw_found [i]) {
5192 max_epilog_size += 12;
5193 exc_throw_found [i] = TRUE;
5196 #endif
5199 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5200 cfg->code_size *= 2;
5201 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5202 mono_jit_stats.code_reallocs++;
5205 code = cfg->native_code + cfg->code_len;
5207 /* add code to raise exceptions */
5208 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5209 switch (patch_info->type) {
5210 case MONO_PATCH_INFO_EXC: {
5211 #if 0
5212 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5214 i = exception_id_by_name (patch_info->data.target);
5215 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5216 if (!exc_throw_pos [i]) {
5217 guint32 addr;
5219 exc_throw_pos [i] = code;
5220 //g_print ("exc: writing stub at %p\n", code);
5221 mips_load_const (code, mips_a0, patch_info->data.target);
5222 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5223 mips_load_const (code, mips_t9, addr);
5224 mips_jr (code, mips_t9);
5225 mips_nop (code);
5227 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5229 /* Turn into a Relative patch, pointing at code stub */
5230 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5231 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5232 #else
5233 g_assert_not_reached();
5234 #endif
5235 break;
5237 default:
5238 /* do nothing */
5239 break;
5243 cfg->code_len = code - cfg->native_code;
5245 g_assert (cfg->code_len < cfg->code_size);
5246 #endif
5250 * Thread local storage support
5252 static void
5253 setup_tls_access (void)
5255 guint32 ptk;
5256 //guint32 *ins, *code;
5258 if (tls_mode == TLS_MODE_FAILED)
5259 return;
5261 if (g_getenv ("MONO_NO_TLS")) {
5262 tls_mode = TLS_MODE_FAILED;
5263 return;
5266 if (tls_mode == TLS_MODE_DETECT) {
5267 /* XXX */
5268 tls_mode = TLS_MODE_FAILED;
5269 return;
5270 #if 0
5272 ins = (guint32*)pthread_getspecific;
5273 /* uncond branch to the real method */
5274 if ((*ins >> 26) == 18) {
5275 gint32 val;
5276 val = (*ins & ~3) << 6;
5277 val >>= 6;
5278 if (*ins & 2) {
5279 /* absolute */
5280 ins = (guint32*)val;
5281 } else {
5282 ins = (guint32*) ((char*)ins + val);
5285 code = &cmplwi_1023;
5286 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5287 code = &li_0x48;
5288 ppc_li (code, ppc_r4, 0x48);
5289 code = &blr_ins;
5290 ppc_blr (code);
5291 if (*ins == cmplwi_1023) {
5292 int found_lwz_284 = 0;
5293 for (ptk = 0; ptk < 20; ++ptk) {
5294 ++ins;
5295 if (!*ins || *ins == blr_ins)
5296 break;
5297 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5298 found_lwz_284 = 1;
5299 break;
5302 if (!found_lwz_284) {
5303 tls_mode = TLS_MODE_FAILED;
5304 return;
5306 tls_mode = TLS_MODE_LTHREADS;
5307 } else if (*ins == li_0x48) {
5308 ++ins;
5309 /* uncond branch to the real method */
5310 if ((*ins >> 26) == 18) {
5311 gint32 val;
5312 val = (*ins & ~3) << 6;
5313 val >>= 6;
5314 if (*ins & 2) {
5315 /* absolute */
5316 ins = (guint32*)val;
5317 } else {
5318 ins = (guint32*) ((char*)ins + val);
5320 code = &val;
5321 ppc_li (code, ppc_r0, 0x7FF2);
5322 if (ins [1] == val) {
5323 /* Darwin on G4, implement */
5324 tls_mode = TLS_MODE_FAILED;
5325 return;
5326 } else {
5327 code = &val;
5328 ppc_mfspr (code, ppc_r3, 104);
5329 if (ins [1] != val) {
5330 tls_mode = TLS_MODE_FAILED;
5331 return;
5333 tls_mode = TLS_MODE_DARWIN_G5;
5335 } else {
5336 tls_mode = TLS_MODE_FAILED;
5337 return;
5339 } else {
5340 tls_mode = TLS_MODE_FAILED;
5341 return;
5343 #endif
5345 if (monodomain_key == -1) {
5346 ptk = mono_domain_get_tls_key ();
5347 if (ptk < 1024) {
5348 ptk = mono_pthread_key_for_tls (ptk);
5349 if (ptk < 1024) {
5350 monodomain_key = ptk;
5354 if (lmf_pthread_key == -1) {
5355 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5356 if (ptk < 1024) {
5357 /*g_print ("MonoLMF at: %d\n", ptk);*/
5358 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5359 init_tls_failed = 1;
5360 return;
5362 lmf_pthread_key = ptk;
5365 if (monothread_key == -1) {
5366 ptk = mono_thread_get_tls_key ();
5367 if (ptk < 1024) {
5368 ptk = mono_pthread_key_for_tls (ptk);
5369 if (ptk < 1024) {
5370 monothread_key = ptk;
5371 /*g_print ("thread inited: %d\n", ptk);*/
5373 } else {
5374 /*g_print ("thread not inited yet %d\n", ptk);*/
5379 void
5380 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5382 setup_tls_access ();
5385 void
5386 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5390 void
5391 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5393 int this_dreg = mips_a0;
5395 if (vt_reg != -1)
5396 this_dreg = mips_a1;
5398 /* add the this argument */
5399 if (this_reg != -1) {
5400 MonoInst *this;
5401 MONO_INST_NEW (cfg, this, OP_MOVE);
5402 this->type = this_type;
5403 this->sreg1 = this_reg;
5404 this->dreg = mono_alloc_ireg (cfg);
5405 mono_bblock_add_inst (cfg->cbb, this);
5406 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5409 if (vt_reg != -1) {
5410 MonoInst *vtarg;
5411 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5412 vtarg->type = STACK_MP;
5413 vtarg->sreg1 = vt_reg;
5414 vtarg->dreg = mono_alloc_ireg (cfg);
5415 mono_bblock_add_inst (cfg->cbb, vtarg);
5416 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5420 MonoInst*
5421 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5423 MonoInst *ins = NULL;
5425 return ins;
5428 MonoInst*
5429 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5431 return NULL;
5434 gboolean
5435 mono_arch_print_tree (MonoInst *tree, int arity)
5437 return 0;
5440 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5442 MonoInst* ins;
5444 setup_tls_access ();
5445 if (monodomain_key == -1)
5446 return NULL;
5448 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5449 ins->inst_offset = monodomain_key;
5450 return ins;
5453 MonoInst*
5454 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
5456 MonoInst* ins;
5458 setup_tls_access ();
5459 if (monothread_key == -1)
5460 return NULL;
5462 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5463 ins->inst_offset = monothread_key;
5464 return ins;
5467 gpointer
5468 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5470 /* FIXME: implement */
5471 g_assert_not_reached ();
5474 #ifdef MONO_ARCH_HAVE_IMT
5476 #define CMP_SIZE 12
5477 #define BR_SIZE 4
5478 #define JUMP_IMM_SIZE 12
5479 #define JUMP_IMM32_SIZE 16
5480 #define ENABLE_WRONG_METHOD_CHECK 0
5483 * LOCKING: called with the domain lock held
5485 gpointer
5486 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5487 gpointer fail_tramp)
5489 NOT_IMPLEMENTED;
5490 #if 0
5491 int i;
5492 int size = 0;
5493 guint8 *code, *start;
5495 for (i = 0; i < count; ++i) {
5496 MonoIMTCheckItem *item = imt_entries [i];
5497 if (item->is_equals) {
5498 if (item->check_target_idx) {
5499 if (!item->compare_done)
5500 item->chunk_size += CMP_SIZE;
5501 if (fail_tramp)
5502 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
5503 else
5504 item->chunk_size += BR_SIZE + JUMP_IMM_SIZE;
5505 } else {
5506 if (fail_tramp) {
5507 item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
5508 } else {
5509 item->chunk_size += JUMP_IMM_SIZE;
5510 #if ENABLE_WRONG_METHOD_CHECK
5511 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5512 #endif
5515 } else {
5516 item->chunk_size += CMP_SIZE + BR_SIZE;
5517 imt_entries [item->check_target_idx]->compare_done = TRUE;
5519 size += item->chunk_size;
5521 if (fail_tramp) {
5522 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5523 } else {
5524 /* the initial load of the vtable address */
5525 size += 8;
5526 code = mono_domain_code_reserve (domain, size);
5528 start = code;
5529 if (!fail_tramp)
5530 ppc_load (code, ppc_r11, (guint32)(& (vtable->vtable [0])));
5531 for (i = 0; i < count; ++i) {
5532 MonoIMTCheckItem *item = imt_entries [i];
5533 item->code_target = code;
5534 if (item->is_equals) {
5535 if (item->check_target_idx) {
5536 if (!item->compare_done) {
5537 ppc_load (code, ppc_r0, (guint32)item->key);
5538 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5540 item->jmp_code = code;
5541 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5542 if (fail_tramp)
5543 ppc_load (code, ppc_r0, item->value.target_code);
5544 else
5545 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5546 ppc_mtctr (code, ppc_r0);
5547 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5548 } else {
5549 if (fail_tramp) {
5550 ppc_load (code, ppc_r0, (guint32)item->key);
5551 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5552 item->jmp_code = code;
5553 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5554 ppc_load (code, ppc_r0, item->value.target_code);
5555 ppc_mtctr (code, ppc_r0);
5556 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5557 ppc_patch (item->jmp_code, code);
5558 ppc_load (code, ppc_r0, fail_tramp);
5559 ppc_mtctr (code, ppc_r0);
5560 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5561 item->jmp_code = NULL;
5562 } else {
5563 /* enable the commented code to assert on wrong method */
5564 #if ENABLE_WRONG_METHOD_CHECK
5565 ppc_load (code, ppc_r0, (guint32)item->key);
5566 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5567 item->jmp_code = code;
5568 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5569 #endif
5570 ppc_lwz (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
5571 ppc_mtctr (code, ppc_r0);
5572 ppc_bcctr (code, PPC_BR_ALWAYS, 0);
5573 #if ENABLE_WRONG_METHOD_CHECK
5574 ppc_patch (item->jmp_code, code);
5575 ppc_break (code);
5576 item->jmp_code = NULL;
5577 #endif
5580 } else {
5581 ppc_load (code, ppc_r0, (guint32)item->key);
5582 ppc_cmpl (code, 0, 0, MONO_ARCH_IMT_REG, ppc_r0);
5583 item->jmp_code = code;
5584 ppc_bc (code, PPC_BR_FALSE, PPC_BR_LT, 0);
5587 /* patch the branches to get to the target items */
5588 for (i = 0; i < count; ++i) {
5589 MonoIMTCheckItem *item = imt_entries [i];
5590 if (item->jmp_code) {
5591 if (item->check_target_idx) {
5592 ppc_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5597 if (!fail_tramp)
5598 mono_stats.imt_thunks_size += code - start;
5599 g_assert (code - start <= size);
5600 mono_arch_flush_icache (start, size);
5601 return start;
5602 #endif
5605 MonoMethod*
5606 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
5608 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5611 MonoObject*
5612 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
5614 return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
5616 #endif
5618 MonoVTable*
5619 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
5621 NOT_IMPLEMENTED;
5622 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];