2 * mini-mips.c: MIPS backend for the Mono code generator
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)
12 * (C) 2003 Ximian, Inc.
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/utils/mono-mmap.h>
22 #include <mono/arch/mips/mips-codegen.h>
24 #include "mini-mips.h"
29 #define SAVE_FP_REGS 0
31 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
33 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
34 #define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
36 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
37 #define mips_call(c,D,v) do { \
38 guint32 _target = (guint32)(v); \
39 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
40 mips_load_const (c, D, _target); \
41 mips_jalr (c, D, mips_ra); \
44 mips_jumpl (c, _target >> 2); \
56 /* This mutex protects architecture specific caches */
57 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
58 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
59 static CRITICAL_SECTION mini_arch_mutex;
61 int mono_exc_esp_offset = 0;
62 static int tls_mode = TLS_MODE_DETECT;
63 static int lmf_pthread_key = -1;
64 static int monothread_key = -1;
65 static int monodomain_key = -1;
67 /* Whenever the host is little-endian */
68 static int little_endian;
69 /* Index of ms word/register */
70 static int ls_word_idx;
71 /* Index of ls word/register */
72 static int ms_word_idx;
73 /* Same for offsets */
74 static int ls_word_offset;
75 static int ms_word_offset;
78 * The code generated for sequence points reads from this location, which is
79 * made read-only when single stepping is enabled.
81 static gpointer ss_trigger_page;
83 /* Enabled breakpoints read from this trigger page */
84 static gpointer bp_trigger_page;
87 #define DEBUG(a) if (cfg->verbose_level > 1) a
93 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
95 code = mips_emit_exc_by_name (code, exc_name); \
96 cfg->bb_exit->max_offset += 16; \
100 #define emit_linuxthreads_tls(code,dreg,key) do {\
102 off1 = offsets_from_pthread_key ((key), &off2); \
103 g_assert_not_reached (); \
104 ppc_lwz ((code), (dreg), off1, ppc_r2); \
105 ppc_lwz ((code), (dreg), off2, (dreg)); \
109 #define emit_tls_access(code,dreg,key) do { \
110 switch (tls_mode) { \
111 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
112 default: g_assert_not_reached (); \
116 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
118 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
119 inst->type = STACK_R8; \
121 inst->inst_p0 = (void*)(addr); \
122 mono_bblock_add_inst (cfg->cbb, inst); \
125 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
126 || ((ins)->opcode == OP_ICOMPARE) \
127 || ((ins)->opcode == OP_LCOMPARE)))
128 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
129 || ((ins)->opcode == OP_ICOMPARE_IMM) \
130 || ((ins)->opcode == OP_LCOMPARE_IMM)))
132 #define INS_REWRITE(ins, op, _s1, _s2) do { \
135 ins->opcode = (op); \
140 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
142 ins->opcode = (op); \
144 ins->inst_imm = (_imm); \
148 typedef struct InstList InstList;
166 guint16 vtsize; /* in param area */
169 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
178 gboolean vtype_retaddr;
187 void patch_lui_addiu(guint32 *ip, guint32 val);
188 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
189 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
190 void mips_adjust_stackframe(MonoCompile *cfg);
191 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
192 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
195 /* Not defined in asm/cachectl.h */
196 int cacheflush(char *addr, int nbytes, int cache);
199 mono_arch_flush_icache (guint8 *code, gint size)
201 /* Linux/MIPS specific */
202 cacheflush ((char*)code, size, BCACHE);
206 mono_arch_flush_register_windows (void)
211 mono_arch_is_inst_imm (gint64 imm)
217 mips_emit_exc_by_name(guint8 *code, const char *name)
220 MonoClass *exc_class;
222 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
223 g_assert (exc_class);
225 mips_load_const (code, mips_a0, exc_class->type_token);
226 addr = mono_get_throw_corlib_exception ();
227 mips_call (code, mips_t9, addr);
233 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
235 if (mips_is_imm16 (v))
236 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
238 #if SIZEOF_REGISTER == 8
240 /* v is not a sign-extended 32-bit value */
241 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
242 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
243 mips_dsll (code, dreg, dreg, 16);
244 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
245 mips_dsll (code, dreg, dreg, 16);
246 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
250 if (((guint32)v) & (1 << 15)) {
251 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
254 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
256 if (((guint32)v) & 0xffff)
257 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
263 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
266 if (cfg->arch.long_branch) {
269 /* Invert test and emit branch around jump */
272 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
276 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
280 mips_bltz (code, ins->sreg1, br_offset);
284 mips_blez (code, ins->sreg1, br_offset);
288 mips_bgtz (code, ins->sreg1, br_offset);
292 mips_bgez (code, ins->sreg1, br_offset);
296 g_assert_not_reached ();
298 mono_add_patch_info (cfg, code - cfg->native_code,
299 MONO_PATCH_INFO_BB, ins->inst_true_bb);
300 mips_lui (code, mips_at, mips_zero, 0);
301 mips_addiu (code, mips_at, mips_at, 0);
302 mips_jr (code, mips_at);
306 mono_add_patch_info (cfg, code - cfg->native_code,
307 MONO_PATCH_INFO_BB, ins->inst_true_bb);
310 mips_beq (code, ins->sreg1, ins->sreg2, 0);
314 mips_bne (code, ins->sreg1, ins->sreg2, 0);
318 mips_bgez (code, ins->sreg1, 0);
322 mips_bgtz (code, ins->sreg1, 0);
326 mips_blez (code, ins->sreg1, 0);
330 mips_bltz (code, ins->sreg1, 0);
334 g_assert_not_reached ();
340 /* XXX - big-endian dependent? */
342 patch_lui_addiu(guint32 *ip, guint32 val)
344 guint16 *__lui_addiu = (guint16*)(void *)(ip);
347 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
348 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
351 if (((guint32)(val)) & (1 << 15))
352 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
354 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
355 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
356 mono_arch_flush_icache ((guint8 *)ip, 8);
361 mips_patch (guint32 *code, guint32 target)
364 guint32 op = ins >> 26;
365 guint32 diff, offset;
367 g_assert (trap_target != target);
368 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
370 case 0x00: /* jr ra */
371 if (ins == 0x3e00008)
373 g_assert_not_reached ();
377 g_assert (!(target & 0x03));
378 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
379 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
381 mono_arch_flush_icache ((guint8 *)code, 4);
383 case 0x01: /* BLTZ */
386 case 0x06: /* BLEZ */
387 case 0x07: /* BGTZ */
388 case 0x11: /* bc1t */
389 diff = target - (guint32)(code + 1);
390 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
391 g_assert (!(diff & 0x03));
392 offset = ((gint32)diff) >> 2;
393 if (((int)offset) != ((int)(short)offset))
394 g_assert (((int)offset) == ((int)(short)offset));
395 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
397 mono_arch_flush_icache ((guint8 *)code, 4);
399 case 0x0f: /* LUI / ADDIU pair */
400 g_assert ((code[1] >> 26) == 0x9);
401 patch_lui_addiu (code, target);
402 mono_arch_flush_icache ((guint8 *)code, 8);
406 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
407 g_assert_not_reached ();
413 offsets_from_pthread_key (guint32 key, int *offset2)
417 *offset2 = idx2 * sizeof (gpointer);
418 return 284 + idx1 * sizeof (gpointer);
422 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
425 mono_arch_regname (int reg) {
426 #if _MIPS_SIM == _ABIO32
427 static const char * rnames[] = {
428 "zero", "at", "v0", "v1",
429 "a0", "a1", "a2", "a3",
430 "t0", "t1", "t2", "t3",
431 "t4", "t5", "t6", "t7",
432 "s0", "s1", "s2", "s3",
433 "s4", "s5", "s6", "s7",
434 "t8", "t9", "k0", "k1",
435 "gp", "sp", "fp", "ra"
437 #elif _MIPS_SIM == _ABIN32
438 static const char * rnames[] = {
439 "zero", "at", "v0", "v1",
440 "a0", "a1", "a2", "a3",
441 "a4", "a5", "a6", "a7",
442 "t0", "t1", "t2", "t3",
443 "s0", "s1", "s2", "s3",
444 "s4", "s5", "s6", "s7",
445 "t8", "t9", "k0", "k1",
446 "gp", "sp", "fp", "ra"
449 if (reg >= 0 && reg < 32)
455 mono_arch_fregname (int reg) {
456 static const char * rnames[] = {
457 "f0", "f1", "f2", "f3",
458 "f4", "f5", "f6", "f7",
459 "f8", "f9", "f10", "f11",
460 "f12", "f13", "f14", "f15",
461 "f16", "f17", "f18", "f19",
462 "f20", "f21", "f22", "f23",
463 "f24", "f25", "f26", "f27",
464 "f28", "f29", "f30", "f31"
466 if (reg >= 0 && reg < 32)
471 /* this function overwrites at */
473 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
475 /* XXX write a loop, not an unrolled loop */
477 mips_lw (code, mips_at, sreg, soffset);
478 mips_sw (code, mips_at, dreg, doffset);
487 * mono_arch_get_argument_info:
488 * @csig: a method signature
489 * @param_count: the number of parameters to consider
490 * @arg_info: an array to store the result infos
492 * Gathers information on parameters such as size, alignment and
493 * padding. arg_info should be large enought to hold param_count + 1 entries.
495 * Returns the size of the activation frame.
498 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
500 int k, frame_size = 0;
501 guint32 size, align, pad;
504 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
505 frame_size += sizeof (gpointer);
509 arg_info [0].offset = offset;
512 frame_size += sizeof (gpointer);
516 arg_info [0].size = frame_size;
518 for (k = 0; k < param_count; k++) {
519 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
521 /* ignore alignment for now */
524 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
525 arg_info [k].pad = pad;
527 arg_info [k + 1].pad = 0;
528 arg_info [k + 1].size = size;
530 arg_info [k + 1].offset = offset;
534 align = MONO_ARCH_FRAME_ALIGNMENT;
535 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
536 arg_info [k].pad = pad;
541 /* The delegate object plus 3 params */
542 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
545 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
547 guint8 *code, *start;
550 start = code = mono_global_codeman_reserve (16);
552 /* Replace the this argument with the target */
553 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
554 mips_lw (code, mips_a0, mips_a0, G_STRUCT_OFFSET (MonoDelegate, target));
555 mips_jr (code, mips_temp);
558 g_assert ((code - start) <= 16);
560 mono_arch_flush_icache (start, 16);
564 size = 16 + param_count * 4;
565 start = code = mono_global_codeman_reserve (size);
567 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
568 /* slide down the arguments */
569 for (i = 0; i < param_count; ++i) {
570 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
572 mips_jr (code, mips_temp);
575 g_assert ((code - start) <= size);
577 mono_arch_flush_icache (start, size);
581 *code_size = code - start;
587 * mono_arch_get_delegate_invoke_impls:
589 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
593 mono_arch_get_delegate_invoke_impls (void)
600 code = get_delegate_invoke_impl (TRUE, 0, &code_len);
601 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
603 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
604 code = get_delegate_invoke_impl (FALSE, i, &code_len);
605 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
612 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
614 guint8 *code, *start;
616 /* FIXME: Support more cases */
617 if (MONO_TYPE_ISSTRUCT (sig->ret))
621 static guint8* cached = NULL;
622 mono_mini_arch_lock ();
624 mono_mini_arch_unlock ();
629 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
631 start = get_delegate_invoke_impl (TRUE, 0, NULL);
633 mono_mini_arch_unlock ();
636 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
639 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
641 for (i = 0; i < sig->param_count; ++i)
642 if (!mono_is_regsize_var (sig->params [i]))
645 mono_mini_arch_lock ();
646 code = cache [sig->param_count];
648 mono_mini_arch_unlock ();
653 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
654 start = mono_aot_get_trampoline (name);
657 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
659 cache [sig->param_count] = start;
660 mono_mini_arch_unlock ();
668 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
671 return (gpointer)regs [mips_a0];
675 * Initialize the cpu to execute managed code.
678 mono_arch_cpu_init (void)
680 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
689 ls_word_offset = ls_word_idx * 4;
690 ms_word_offset = ms_word_idx * 4;
694 * Initialize architecture specific code.
697 mono_arch_init (void)
699 InitializeCriticalSection (&mini_arch_mutex);
701 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
702 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
703 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
707 * Cleanup architecture specific code.
710 mono_arch_cleanup (void)
712 DeleteCriticalSection (&mini_arch_mutex);
716 * This function returns the optimizations supported on this cpu.
719 mono_arch_cpu_optimizations (guint32 *exclude_mask)
723 /* no mips-specific optimizations yet */
729 * This function test for all SIMD functions supported.
731 * Returns a bitmask corresponding to all supported versions.
735 mono_arch_cpu_enumerate_simd_versions (void)
737 /* SIMD is currently unimplemented */
742 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
747 for (i = 0; i < cfg->num_varinfo; i++) {
748 MonoInst *ins = cfg->varinfo [i];
749 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
752 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
755 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
758 /* we can only allocate 32 bit values */
759 if (mono_is_regsize_var (ins->inst_vtype)) {
760 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
761 g_assert (i == vmv->idx);
762 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
770 mono_arch_get_global_int_regs (MonoCompile *cfg)
774 regs = g_list_prepend (regs, (gpointer)mips_s0);
775 regs = g_list_prepend (regs, (gpointer)mips_s1);
776 regs = g_list_prepend (regs, (gpointer)mips_s2);
777 regs = g_list_prepend (regs, (gpointer)mips_s3);
778 regs = g_list_prepend (regs, (gpointer)mips_s4);
779 //regs = g_list_prepend (regs, (gpointer)mips_s5);
780 regs = g_list_prepend (regs, (gpointer)mips_s6);
781 regs = g_list_prepend (regs, (gpointer)mips_s7);
787 * mono_arch_regalloc_cost:
789 * Return the cost, in number of memory references, of the action of
790 * allocating the variable VMV into a register during global register
794 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
801 args_onto_stack (CallInfo *info)
803 g_assert (!info->on_stack);
804 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
805 info->on_stack = TRUE;
806 info->stack_size = MIPS_STACK_PARAM_OFFSET;
809 #if _MIPS_SIM == _ABIO32
811 * O32 calling convention version
815 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
816 /* First, see if we need to drop onto the stack */
817 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
818 args_onto_stack (info);
820 /* Now, place the argument */
821 if (info->on_stack) {
822 ainfo->storage = ArgOnStack;
823 ainfo->reg = mips_sp; /* in the caller */
824 ainfo->offset = info->stack_size;
827 ainfo->storage = ArgInIReg;
828 ainfo->reg = info->gr;
830 info->gr_passed = TRUE;
832 info->stack_size += 4;
836 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
837 /* First, see if we need to drop onto the stack */
838 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
839 args_onto_stack (info);
841 /* Now, place the argument */
842 if (info->on_stack) {
843 g_assert (info->stack_size % 4 == 0);
844 info->stack_size += (info->stack_size % 8);
846 ainfo->storage = ArgOnStack;
847 ainfo->reg = mips_sp; /* in the caller */
848 ainfo->offset = info->stack_size;
851 // info->gr must be a0 or a2
852 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
853 g_assert(info->gr <= MIPS_LAST_ARG_REG);
855 ainfo->storage = ArgInIReg;
856 ainfo->reg = info->gr;
858 info->gr_passed = TRUE;
860 info->stack_size += 8;
864 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
865 /* First, see if we need to drop onto the stack */
866 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
867 args_onto_stack (info);
869 /* Now, place the argument */
870 if (info->on_stack) {
871 ainfo->storage = ArgOnStack;
872 ainfo->reg = mips_sp; /* in the caller */
873 ainfo->offset = info->stack_size;
876 /* Only use FP regs for args if no int args passed yet */
877 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
878 ainfo->storage = ArgInFReg;
879 ainfo->reg = info->fr;
880 /* Even though it's a single-precision float, it takes up two FP regs */
882 /* FP and GP slots do not overlap */
886 /* Passing single-precision float arg in a GP register
887 * such as: func (0, 1.0, 2, 3);
888 * In this case, only one 'gr' register is consumed.
890 ainfo->storage = ArgInIReg;
891 ainfo->reg = info->gr;
894 info->gr_passed = TRUE;
897 info->stack_size += 4;
901 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
902 /* First, see if we need to drop onto the stack */
903 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
904 args_onto_stack (info);
906 /* Now, place the argument */
907 if (info->on_stack) {
908 g_assert(info->stack_size % 4 == 0);
909 info->stack_size += (info->stack_size % 8);
911 ainfo->storage = ArgOnStack;
912 ainfo->reg = mips_sp; /* in the caller */
913 ainfo->offset = info->stack_size;
916 /* Only use FP regs for args if no int args passed yet */
917 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
918 ainfo->storage = ArgInFReg;
919 ainfo->reg = info->fr;
921 /* FP and GP slots do not overlap */
925 // info->gr must be a0 or a2
926 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
927 g_assert(info->gr <= MIPS_LAST_ARG_REG);
929 ainfo->storage = ArgInIReg;
930 ainfo->reg = info->gr;
932 info->gr_passed = TRUE;
935 info->stack_size += 8;
937 #elif _MIPS_SIM == _ABIN32
939 * N32 calling convention version
943 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
944 /* First, see if we need to drop onto the stack */
945 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
946 args_onto_stack (info);
948 /* Now, place the argument */
949 if (info->on_stack) {
950 ainfo->storage = ArgOnStack;
951 ainfo->reg = mips_sp; /* in the caller */
952 ainfo->offset = info->stack_size;
953 info->stack_size += SIZEOF_REGISTER;
956 ainfo->storage = ArgInIReg;
957 ainfo->reg = info->gr;
959 info->gr_passed = TRUE;
964 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
965 /* First, see if we need to drop onto the stack */
966 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
967 args_onto_stack (info);
969 /* Now, place the argument */
970 if (info->on_stack) {
971 g_assert (info->stack_size % 4 == 0);
972 info->stack_size += (info->stack_size % 8);
974 ainfo->storage = ArgOnStack;
975 ainfo->reg = mips_sp; /* in the caller */
976 ainfo->offset = info->stack_size;
977 info->stack_size += SIZEOF_REGISTER;
980 g_assert (info->gr <= MIPS_LAST_ARG_REG);
982 ainfo->storage = ArgInIReg;
983 ainfo->reg = info->gr;
985 info->gr_passed = TRUE;
990 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
991 /* First, see if we need to drop onto the stack */
992 if (!info->on_stack) {
993 if (info->gr > MIPS_LAST_ARG_REG)
994 args_onto_stack (info);
995 else if (info->fr > MIPS_LAST_FPARG_REG)
996 args_onto_stack (info);
999 /* Now, place the argument */
1000 if (info->on_stack) {
1001 ainfo->storage = ArgOnStack;
1002 ainfo->reg = mips_sp; /* in the caller */
1003 ainfo->offset = info->stack_size;
1004 info->stack_size += FREG_SIZE;
1007 ainfo->storage = ArgInFReg;
1008 ainfo->reg = info->fr;
1010 /* FP and GP slots do not overlap */
1016 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1017 /* First, see if we need to drop onto the stack */
1018 if (!info->on_stack) {
1019 if (info->gr > MIPS_LAST_ARG_REG)
1020 args_onto_stack (info);
1021 else if (info->fr > MIPS_LAST_FPARG_REG)
1022 args_onto_stack (info);
1025 /* Now, place the argument */
1026 if (info->on_stack) {
1027 g_assert(info->stack_size % 4 == 0);
1028 info->stack_size += (info->stack_size % 8);
1030 ainfo->storage = ArgOnStack;
1031 ainfo->reg = mips_sp; /* in the caller */
1032 ainfo->offset = info->stack_size;
1033 info->stack_size += FREG_SIZE;
1036 ainfo->storage = ArgInFReg;
1037 ainfo->reg = info->fr;
1039 /* FP and GP slots do not overlap */
1046 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
1049 int n = sig->hasthis + sig->param_count;
1051 MonoType* simpletype;
1053 gboolean is_pinvoke = sig->pinvoke;
1056 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1058 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1060 cinfo->fr = MIPS_FIRST_FPARG_REG;
1061 cinfo->gr = MIPS_FIRST_ARG_REG;
1062 cinfo->stack_size = 0;
1064 DEBUG(printf("calculate_sizes\n"));
1066 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1070 /* handle returning a struct */
1071 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1072 cinfo->struct_ret = cinfo->gr;
1073 add_int32_arg (cinfo, &cinfo->ret);
1077 add_int32_arg (cinfo, cinfo->args + n);
1082 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1083 * the first argument, allowing 'this' to be always passed in the first arg reg.
1084 * Also do this if the first argument is a reference type, since virtual calls
1085 * are sometimes made using calli without sig->hasthis set, like in the delegate
1088 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1090 add_int32_arg (cinfo, cinfo->args + n);
1093 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1097 add_int32_arg (cinfo, &cinfo->ret);
1098 cinfo->struct_ret = cinfo->ret.reg;
1102 add_int32_arg (cinfo, cinfo->args + n);
1106 if (cinfo->vtype_retaddr) {
1107 add_int32_arg (cinfo, &cinfo->ret);
1108 cinfo->struct_ret = cinfo->ret.reg;
1113 DEBUG(printf("params: %d\n", sig->param_count));
1114 for (i = pstart; i < sig->param_count; ++i) {
1115 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1116 /* Prevent implicit arguments and sig_cookie from
1117 being passed in registers */
1118 args_onto_stack (cinfo);
1119 /* Emit the signature cookie just before the implicit arguments */
1120 add_int32_arg (cinfo, &cinfo->sig_cookie);
1122 DEBUG(printf("param %d: ", i));
1123 simpletype = mini_type_get_underlying_type (gsctx, sig->params [i]);
1124 switch (simpletype->type) {
1125 case MONO_TYPE_BOOLEAN:
1128 DEBUG(printf("1 byte\n"));
1129 cinfo->args [n].size = 1;
1130 add_int32_arg (cinfo, &cinfo->args[n]);
1133 case MONO_TYPE_CHAR:
1136 DEBUG(printf("2 bytes\n"));
1137 cinfo->args [n].size = 2;
1138 add_int32_arg (cinfo, &cinfo->args[n]);
1143 DEBUG(printf("4 bytes\n"));
1144 cinfo->args [n].size = 4;
1145 add_int32_arg (cinfo, &cinfo->args[n]);
1151 case MONO_TYPE_FNPTR:
1152 case MONO_TYPE_CLASS:
1153 case MONO_TYPE_OBJECT:
1154 case MONO_TYPE_STRING:
1155 case MONO_TYPE_SZARRAY:
1156 case MONO_TYPE_ARRAY:
1157 cinfo->args [n].size = sizeof (gpointer);
1158 add_int32_arg (cinfo, &cinfo->args[n]);
1161 case MONO_TYPE_GENERICINST:
1162 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1163 cinfo->args [n].size = sizeof (gpointer);
1164 add_int32_arg (cinfo, &cinfo->args[n]);
1169 case MONO_TYPE_TYPEDBYREF:
1170 case MONO_TYPE_VALUETYPE: {
1173 int has_offset = FALSE;
1175 gint size, alignment;
1178 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1179 size = sizeof (MonoTypedRef);
1180 alignment = sizeof (gpointer);
1182 klass = mono_class_from_mono_type (sig->params [i]);
1184 size = mono_class_native_size (klass, NULL);
1186 size = mono_class_value_size (klass, NULL);
1187 alignment = mono_class_min_align (klass);
1189 #if MIPS_PASS_STRUCTS_BY_VALUE
1190 /* Need to do alignment if struct contains long or double */
1191 if (alignment > 4) {
1192 /* Drop onto stack *before* looking at
1193 stack_size, if required. */
1194 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1195 args_onto_stack (cinfo);
1196 if (cinfo->stack_size & (alignment - 1)) {
1197 add_int32_arg (cinfo, &dummy_arg);
1199 g_assert (!(cinfo->stack_size & (alignment - 1)));
1203 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1204 mono_class_native_size (sig->params [i]->data.klass, NULL),
1205 cinfo->stack_size, alignment);
1207 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1208 g_assert (cinfo->args [n].size == 0);
1209 g_assert (cinfo->args [n].vtsize == 0);
1210 for (j = 0; j < nwords; ++j) {
1212 add_int32_arg (cinfo, &cinfo->args [n]);
1213 if (cinfo->on_stack)
1216 add_int32_arg (cinfo, &dummy_arg);
1217 if (!has_offset && cinfo->on_stack) {
1218 cinfo->args [n].offset = dummy_arg.offset;
1222 if (cinfo->on_stack)
1223 cinfo->args [n].vtsize += 1;
1225 cinfo->args [n].size += 1;
1227 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1228 cinfo->args [n].storage = ArgStructByVal;
1230 add_int32_arg (cinfo, &cinfo->args[n]);
1231 cinfo->args [n].storage = ArgStructByAddr;
1238 DEBUG(printf("8 bytes\n"));
1239 cinfo->args [n].size = 8;
1240 add_int64_arg (cinfo, &cinfo->args[n]);
1244 DEBUG(printf("R4\n"));
1245 cinfo->args [n].size = 4;
1246 add_float32_arg (cinfo, &cinfo->args[n]);
1250 DEBUG(printf("R8\n"));
1251 cinfo->args [n].size = 8;
1252 add_float64_arg (cinfo, &cinfo->args[n]);
1256 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1260 /* Handle the case where there are no implicit arguments */
1261 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1262 /* Prevent implicit arguments and sig_cookie from
1263 being passed in registers */
1264 args_onto_stack (cinfo);
1265 /* Emit the signature cookie just before the implicit arguments */
1266 add_int32_arg (cinfo, &cinfo->sig_cookie);
1270 simpletype = mini_type_get_underlying_type (gsctx, sig->ret);
1271 switch (simpletype->type) {
1272 case MONO_TYPE_BOOLEAN:
1277 case MONO_TYPE_CHAR:
1283 case MONO_TYPE_FNPTR:
1284 case MONO_TYPE_CLASS:
1285 case MONO_TYPE_OBJECT:
1286 case MONO_TYPE_SZARRAY:
1287 case MONO_TYPE_ARRAY:
1288 case MONO_TYPE_STRING:
1289 cinfo->ret.reg = mips_v0;
1293 cinfo->ret.reg = mips_v0;
1297 cinfo->ret.reg = mips_f0;
1298 cinfo->ret.storage = ArgInFReg;
1300 case MONO_TYPE_GENERICINST:
1301 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1302 cinfo->ret.reg = mips_v0;
1306 case MONO_TYPE_VALUETYPE:
1307 case MONO_TYPE_TYPEDBYREF:
1309 case MONO_TYPE_VOID:
1312 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1316 /* align stack size to 16 */
1317 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1319 cinfo->stack_usage = cinfo->stack_size;
1323 G_GNUC_UNUSED static void
1328 G_GNUC_UNUSED static gboolean
1331 static int count = 0;
1334 if (!getenv ("COUNT"))
1337 if (count == atoi (getenv ("COUNT"))) {
1341 if (count > atoi (getenv ("COUNT"))) {
1349 debug_omit_fp (void)
1352 return debug_count ();
1359 * mono_arch_compute_omit_fp:
1361 * Determine whenever the frame pointer can be eliminated.
1364 mono_arch_compute_omit_fp (MonoCompile *cfg)
1366 MonoMethodSignature *sig;
1367 MonoMethodHeader *header;
1371 if (cfg->arch.omit_fp_computed)
1374 header = cfg->header;
1376 sig = mono_method_signature (cfg->method);
1378 if (!cfg->arch.cinfo)
1379 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1380 cinfo = cfg->arch.cinfo;
1383 * FIXME: Remove some of the restrictions.
1385 cfg->arch.omit_fp = TRUE;
1386 cfg->arch.omit_fp_computed = TRUE;
1388 if (cfg->disable_omit_fp)
1389 cfg->arch.omit_fp = FALSE;
1390 if (!debug_omit_fp ())
1391 cfg->arch.omit_fp = FALSE;
1392 if (cfg->method->save_lmf)
1393 cfg->arch.omit_fp = FALSE;
1394 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1395 cfg->arch.omit_fp = FALSE;
1396 if (header->num_clauses)
1397 cfg->arch.omit_fp = FALSE;
1398 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1399 cfg->arch.omit_fp = FALSE;
1400 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1401 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1402 cfg->arch.omit_fp = FALSE;
1404 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1405 * there are stack arguments.
1408 if (cinfo->stack_usage)
1409 cfg->arch.omit_fp = FALSE;
1413 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1414 MonoInst *ins = cfg->varinfo [i];
1417 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1420 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1424 * Set var information according to the calling convention. mips version.
1425 * The locals var stuff should most likely be split in another method.
1428 mono_arch_allocate_vars (MonoCompile *cfg)
1430 MonoMethodSignature *sig;
1431 MonoMethodHeader *header;
1433 int i, offset, size, align, curinst;
1434 int frame_reg = mips_sp;
1435 guint32 iregs_to_save = 0;
1437 guint32 fregs_to_restore;
1441 sig = mono_method_signature (cfg->method);
1443 if (!cfg->arch.cinfo)
1444 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1445 cinfo = cfg->arch.cinfo;
1447 mono_arch_compute_omit_fp (cfg);
1449 /* spill down, we'll fix it in a separate pass */
1450 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1452 /* allow room for the vararg method args: void* and long/double */
1453 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1454 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1456 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1457 * call convs needs to be handled this way.
1459 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1460 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1462 /* gtk-sharp and other broken code will dllimport vararg functions even with
1463 * non-varargs signatures. Since there is little hope people will get this right
1464 * we assume they won't.
1466 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1467 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1469 /* a0-a3 always present */
1470 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1472 header = cfg->header;
1474 if (cfg->arch.omit_fp)
1475 frame_reg = mips_sp;
1477 frame_reg = mips_fp;
1478 cfg->frame_reg = frame_reg;
1479 if (frame_reg != mips_sp) {
1480 cfg->used_int_regs |= 1 << frame_reg;
1485 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1486 /* FIXME: handle long and FP values */
1487 switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
1488 case MONO_TYPE_VOID:
1492 cfg->ret->opcode = OP_REGVAR;
1493 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1496 cfg->ret->opcode = OP_REGVAR;
1497 cfg->ret->inst_c0 = mips_v0;
1501 /* Space for outgoing parameters, including a0-a3 */
1502 offset += cfg->param_area;
1504 /* allow room to save the return value (if it's a struct) */
1505 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1508 /* Now handle the local variables */
1510 curinst = cfg->locals_start;
1511 for (i = curinst; i < cfg->num_varinfo; ++i) {
1512 inst = cfg->varinfo [i];
1513 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1516 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1517 * pinvoke wrappers when they call functions returning structure
1519 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1520 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1522 size = mono_type_size (inst->inst_vtype, &align);
1524 offset += align - 1;
1525 offset &= ~(align - 1);
1526 inst->inst_offset = offset;
1527 inst->opcode = OP_REGOFFSET;
1528 inst->inst_basereg = frame_reg;
1530 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1533 /* Space for LMF (if needed) */
1534 if (cfg->method->save_lmf) {
1535 /* align the offset to 16 bytes */
1536 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1537 cfg->arch.lmf_offset = offset;
1538 offset += sizeof (MonoLMF);
1541 if (sig->call_convention == MONO_CALL_VARARG) {
1545 /* Allocate a local slot to hold the sig cookie address */
1546 offset += align - 1;
1547 offset &= ~(align - 1);
1548 cfg->sig_cookie = offset;
1552 offset += SIZEOF_REGISTER - 1;
1553 offset &= ~(SIZEOF_REGISTER - 1);
1555 /* Space for saved registers */
1556 cfg->arch.iregs_offset = offset;
1557 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1558 if (iregs_to_save) {
1559 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1560 if (iregs_to_save & (1 << i)) {
1561 offset += SIZEOF_REGISTER;
1566 /* saved float registers */
1568 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1569 if (fregs_to_restore) {
1570 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1571 if (fregs_to_restore & (1 << i)) {
1572 offset += sizeof(double);
1578 #if _MIPS_SIM == _ABIO32
1579 /* Now add space for saving the ra */
1580 offset += SIZEOF_VOID_P;
1583 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1584 cfg->stack_offset = offset;
1585 cfg->arch.local_alloc_offset = cfg->stack_offset;
1589 * Now allocate stack slots for the int arg regs (a0 - a3)
1590 * On MIPS o32, these are just above the incoming stack pointer
1591 * Even if the arg has been assigned to a regvar, it gets a stack slot
1594 /* Return struct-by-value results in a hidden first argument */
1595 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1596 cfg->vret_addr->opcode = OP_REGOFFSET;
1597 cfg->vret_addr->inst_c0 = mips_a0;
1598 cfg->vret_addr->inst_offset = offset;
1599 cfg->vret_addr->inst_basereg = frame_reg;
1600 offset += SIZEOF_REGISTER;
1603 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1604 inst = cfg->args [i];
1605 if (inst->opcode != OP_REGVAR) {
1608 if (sig->hasthis && (i == 0))
1609 arg_type = &mono_defaults.object_class->byval_arg;
1611 arg_type = sig->params [i - sig->hasthis];
1613 inst->opcode = OP_REGOFFSET;
1614 size = mono_type_size (arg_type, &align);
1616 if (size < SIZEOF_REGISTER) {
1617 size = SIZEOF_REGISTER;
1618 align = SIZEOF_REGISTER;
1620 inst->inst_basereg = frame_reg;
1621 offset = (offset + align - 1) & ~(align - 1);
1622 inst->inst_offset = offset;
1624 if (cfg->verbose_level > 1)
1625 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1628 #if _MIPS_SIM == _ABIO32
1629 /* o32: Even a0-a3 get stack slots */
1630 size = SIZEOF_REGISTER;
1631 align = SIZEOF_REGISTER;
1632 inst->inst_basereg = frame_reg;
1633 offset = (offset + align - 1) & ~(align - 1);
1634 inst->inst_offset = offset;
1636 if (cfg->verbose_level > 1)
1637 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1641 #if _MIPS_SIM == _ABIN32
1642 /* Now add space for saving the ra */
1643 offset += SIZEOF_VOID_P;
1646 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1647 cfg->stack_offset = offset;
1648 cfg->arch.local_alloc_offset = cfg->stack_offset;
1653 mono_arch_create_vars (MonoCompile *cfg)
1655 MonoMethodSignature *sig;
1657 sig = mono_method_signature (cfg->method);
1659 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1660 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1661 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1662 printf ("vret_addr = ");
1663 mono_print_ins (cfg->vret_addr);
1668 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1669 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1673 * take the arguments and generate the arch-specific
1674 * instructions to properly call the function in call.
1675 * This includes pushing, moving arguments to the right register
1677 * Issue: who does the spilling if needed, and when?
1680 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1682 MonoMethodSignature *tmp_sig;
1685 if (call->tail_call)
1688 /* FIXME: Add support for signature tokens to AOT */
1689 cfg->disable_aot = TRUE;
1692 * mono_ArgIterator_Setup assumes the signature cookie is
1693 * passed first and all the arguments which were before it are
1694 * passed on the stack after the signature. So compensate by
1695 * passing a different signature.
1697 tmp_sig = mono_metadata_signature_dup (call->signature);
1698 tmp_sig->param_count -= call->signature->sentinelpos;
1699 tmp_sig->sentinelpos = 0;
1700 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1702 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1703 sig_arg->dreg = mono_alloc_ireg (cfg);
1704 sig_arg->inst_p0 = tmp_sig;
1705 MONO_ADD_INS (cfg->cbb, sig_arg);
1707 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1711 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1714 MonoMethodSignature *sig;
1719 sig = call->signature;
1720 n = sig->param_count + sig->hasthis;
1722 cinfo = get_call_info (NULL, cfg->mempool, sig);
1723 if (cinfo->struct_ret)
1724 call->used_iregs |= 1 << cinfo->struct_ret;
1726 for (i = 0; i < n; ++i) {
1727 ArgInfo *ainfo = cinfo->args + i;
1730 if (i >= sig->hasthis)
1731 t = sig->params [i - sig->hasthis];
1733 t = &mono_defaults.int_class->byval_arg;
1734 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1736 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1737 /* Emit the signature cookie just before the implicit arguments */
1738 emit_sig_cookie (cfg, call, cinfo);
1741 if (is_virtual && i == 0) {
1742 /* the argument will be attached to the call instrucion */
1743 in = call->args [i];
1744 call->used_iregs |= 1 << ainfo->reg;
1747 in = call->args [i];
1748 if (ainfo->storage == ArgInIReg) {
1749 #if SIZEOF_REGISTER == 4
1750 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1751 MONO_INST_NEW (cfg, ins, OP_MOVE);
1752 ins->dreg = mono_alloc_ireg (cfg);
1753 ins->sreg1 = in->dreg + 1;
1754 MONO_ADD_INS (cfg->cbb, ins);
1755 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1757 MONO_INST_NEW (cfg, ins, OP_MOVE);
1758 ins->dreg = mono_alloc_ireg (cfg);
1759 ins->sreg1 = in->dreg + 2;
1760 MONO_ADD_INS (cfg->cbb, ins);
1761 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1764 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1767 #if PROMOTE_R4_TO_R8
1768 /* ??? - convert to single first? */
1769 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1770 ins->dreg = mono_alloc_freg (cfg);
1771 ins->sreg1 = in->dreg;
1772 MONO_ADD_INS (cfg->cbb, ins);
1777 /* trying to load float value into int registers */
1778 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1779 ins->dreg = mono_alloc_ireg (cfg);
1781 MONO_ADD_INS (cfg->cbb, ins);
1782 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1783 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1784 /* trying to load float value into int registers */
1785 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1786 ins->dreg = mono_alloc_ireg (cfg);
1787 ins->sreg1 = in->dreg;
1788 MONO_ADD_INS (cfg->cbb, ins);
1789 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1791 MONO_INST_NEW (cfg, ins, OP_MOVE);
1792 ins->dreg = mono_alloc_ireg (cfg);
1793 ins->sreg1 = in->dreg;
1794 MONO_ADD_INS (cfg->cbb, ins);
1795 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1797 } else if (ainfo->storage == ArgStructByAddr) {
1798 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1799 ins->opcode = OP_OUTARG_VT;
1800 ins->sreg1 = in->dreg;
1801 ins->klass = in->klass;
1802 ins->inst_p0 = call;
1803 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1804 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1805 MONO_ADD_INS (cfg->cbb, ins);
1806 } else if (ainfo->storage == ArgStructByVal) {
1807 /* this is further handled in mono_arch_emit_outarg_vt () */
1808 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1809 ins->opcode = OP_OUTARG_VT;
1810 ins->sreg1 = in->dreg;
1811 ins->klass = in->klass;
1812 ins->inst_p0 = call;
1813 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1814 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1815 MONO_ADD_INS (cfg->cbb, ins);
1816 } else if (ainfo->storage == ArgOnStack) {
1817 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1818 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1819 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1820 if (t->type == MONO_TYPE_R8)
1821 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1823 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1825 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1827 } else if (ainfo->storage == ArgInFReg) {
1828 if (t->type == MONO_TYPE_VALUETYPE) {
1829 /* this is further handled in mono_arch_emit_outarg_vt () */
1830 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1831 ins->opcode = OP_OUTARG_VT;
1832 ins->sreg1 = in->dreg;
1833 ins->klass = in->klass;
1834 ins->inst_p0 = call;
1835 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1836 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1837 MONO_ADD_INS (cfg->cbb, ins);
1839 cfg->flags |= MONO_CFG_HAS_FPOUT;
1841 int dreg = mono_alloc_freg (cfg);
1843 if (ainfo->size == 4) {
1844 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1846 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1848 ins->sreg1 = in->dreg;
1849 MONO_ADD_INS (cfg->cbb, ins);
1852 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1853 cfg->flags |= MONO_CFG_HAS_FPOUT;
1856 g_assert_not_reached ();
1860 /* Handle the case where there are no implicit arguments */
1861 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1862 emit_sig_cookie (cfg, call, cinfo);
1864 if (cinfo->struct_ret) {
1867 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1868 vtarg->sreg1 = call->vret_var->dreg;
1869 vtarg->dreg = mono_alloc_preg (cfg);
1870 MONO_ADD_INS (cfg->cbb, vtarg);
1872 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1876 * Reverse the call->out_args list.
1879 MonoInst *prev = NULL, *list = call->out_args, *next;
1886 call->out_args = prev;
1889 call->stack_usage = cinfo->stack_usage;
1890 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1891 #if _MIPS_SIM == _ABIO32
1892 /* a0-a3 always present */
1893 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1895 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1896 cfg->flags |= MONO_CFG_HAS_CALLS;
1898 * should set more info in call, such as the stack space
1899 * used by the args that needs to be added back to esp
1904 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1906 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1907 ArgInfo *ainfo = ins->inst_p1;
1908 int ovf_size = ainfo->vtsize;
1909 int doffset = ainfo->offset;
1910 int i, soffset, dreg;
1912 if (ainfo->storage == ArgStructByVal) {
1914 if (cfg->verbose_level > 0) {
1915 char* nm = mono_method_full_name (cfg->method, TRUE);
1916 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1917 nm, doffset, ainfo->size, ovf_size);
1923 for (i = 0; i < ainfo->size; ++i) {
1924 dreg = mono_alloc_ireg (cfg);
1925 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1926 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1927 soffset += SIZEOF_REGISTER;
1929 if (ovf_size != 0) {
1930 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1932 } else if (ainfo->storage == ArgInFReg) {
1933 int tmpr = mono_alloc_freg (cfg);
1935 if (ainfo->size == 4)
1936 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1938 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1939 dreg = mono_alloc_freg (cfg);
1940 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1941 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1943 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1947 /* FIXME: alignment? */
1948 if (call->signature->pinvoke) {
1949 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1950 vtcopy->backend.is_pinvoke = 1;
1952 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1955 g_assert (ovf_size > 0);
1957 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1958 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1961 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1963 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1968 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1970 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1971 mono_method_signature (method)->ret);
1974 #if (SIZEOF_REGISTER == 4)
1975 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1978 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1979 ins->sreg1 = val->dreg + 1;
1980 ins->sreg2 = val->dreg + 2;
1981 MONO_ADD_INS (cfg->cbb, ins);
1985 if (ret->type == MONO_TYPE_R8) {
1986 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1989 if (ret->type == MONO_TYPE_R4) {
1990 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1994 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1998 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2000 MonoInst *ins, *n, *last_ins = NULL;
2002 if (cfg->verbose_level > 2)
2003 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
2006 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2007 if (cfg->verbose_level > 2)
2008 mono_print_ins_index (0, ins);
2010 switch (ins->opcode) {
2012 case OP_LOAD_MEMBASE:
2013 case OP_LOADI4_MEMBASE:
2015 * OP_IADD reg2, reg1, const1
2016 * OP_LOAD_MEMBASE const2(reg2), reg3
2018 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
2020 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)){
2021 int const1 = last_ins->inst_imm;
2022 int const2 = ins->inst_offset;
2024 if (mips_is_imm16 (const1 + const2)) {
2025 ins->inst_basereg = last_ins->sreg1;
2026 ins->inst_offset = const1 + const2;
2036 bb->last_ins = last_ins;
2040 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2042 MonoInst *ins, *n, *last_ins = NULL;
2045 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2046 MonoInst *last_ins = ins->prev;
2048 switch (ins->opcode) {
2050 /* remove unnecessary multiplication with 1 */
2051 if (ins->inst_imm == 1) {
2052 if (ins->dreg != ins->sreg1) {
2053 ins->opcode = OP_MOVE;
2055 MONO_DELETE_INS (bb, ins);
2059 int power2 = mono_is_power_of_two (ins->inst_imm);
2061 ins->opcode = OP_SHL_IMM;
2062 ins->inst_imm = power2;
2066 case OP_LOAD_MEMBASE:
2067 case OP_LOADI4_MEMBASE:
2069 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2070 * OP_LOAD_MEMBASE offset(basereg), reg
2072 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2073 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2074 ins->inst_basereg == last_ins->inst_destbasereg &&
2075 ins->inst_offset == last_ins->inst_offset) {
2076 if (ins->dreg == last_ins->sreg1) {
2077 MONO_DELETE_INS (bb, ins);
2080 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2081 ins->opcode = OP_MOVE;
2082 ins->sreg1 = last_ins->sreg1;
2087 * Note: reg1 must be different from the basereg in the second load
2088 * OP_LOAD_MEMBASE offset(basereg), reg1
2089 * OP_LOAD_MEMBASE offset(basereg), reg2
2091 * OP_LOAD_MEMBASE offset(basereg), reg1
2092 * OP_MOVE reg1, reg2
2094 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2095 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2096 ins->inst_basereg != last_ins->dreg &&
2097 ins->inst_basereg == last_ins->inst_basereg &&
2098 ins->inst_offset == last_ins->inst_offset) {
2100 if (ins->dreg == last_ins->dreg) {
2101 MONO_DELETE_INS (bb, ins);
2104 ins->opcode = OP_MOVE;
2105 ins->sreg1 = last_ins->dreg;
2108 //g_assert_not_reached ();
2113 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2114 * OP_LOAD_MEMBASE offset(basereg), reg
2116 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2117 * OP_ICONST reg, imm
2119 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2120 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2121 ins->inst_basereg == last_ins->inst_destbasereg &&
2122 ins->inst_offset == last_ins->inst_offset) {
2123 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2124 ins->opcode = OP_ICONST;
2125 ins->inst_c0 = last_ins->inst_imm;
2126 g_assert_not_reached (); // check this rule
2131 case OP_LOADU1_MEMBASE:
2132 case OP_LOADI1_MEMBASE:
2133 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2134 ins->inst_basereg == last_ins->inst_destbasereg &&
2135 ins->inst_offset == last_ins->inst_offset) {
2136 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2137 ins->sreg1 = last_ins->sreg1;
2140 case OP_LOADU2_MEMBASE:
2141 case OP_LOADI2_MEMBASE:
2142 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2143 ins->inst_basereg == last_ins->inst_destbasereg &&
2144 ins->inst_offset == last_ins->inst_offset) {
2145 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2146 ins->sreg1 = last_ins->sreg1;
2149 case OP_ICONV_TO_I4:
2150 case OP_ICONV_TO_U4:
2152 ins->opcode = OP_MOVE;
2156 if (ins->dreg == ins->sreg1) {
2157 MONO_DELETE_INS (bb, ins);
2161 * OP_MOVE sreg, dreg
2162 * OP_MOVE dreg, sreg
2164 if (last_ins && last_ins->opcode == OP_MOVE &&
2165 ins->sreg1 == last_ins->dreg &&
2166 ins->dreg == last_ins->sreg1) {
2167 MONO_DELETE_INS (bb, ins);
2175 bb->last_ins = last_ins;
2179 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2187 switch (ins->opcode) {
2190 case OP_LCOMPARE_IMM:
2191 mono_print_ins (ins);
2192 g_assert_not_reached ();
2195 tmp1 = mono_alloc_ireg (cfg);
2196 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2197 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2198 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2199 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2204 tmp1 = mono_alloc_ireg (cfg);
2205 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2206 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2207 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2208 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2213 tmp1 = mono_alloc_ireg (cfg);
2214 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2215 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2216 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2217 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2222 tmp1 = mono_alloc_ireg (cfg);
2223 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2224 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2225 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2226 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2238 mono_print_ins (ins);
2239 g_assert_not_reached ();
2242 tmp1 = mono_alloc_ireg (cfg);
2243 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2244 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2245 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2246 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2254 case OP_LCONV_TO_I1:
2255 case OP_LCONV_TO_I2:
2256 case OP_LCONV_TO_I4:
2257 case OP_LCONV_TO_I8:
2258 case OP_LCONV_TO_R4:
2259 case OP_LCONV_TO_R8:
2260 case OP_LCONV_TO_U4:
2261 case OP_LCONV_TO_U8:
2262 case OP_LCONV_TO_U2:
2263 case OP_LCONV_TO_U1:
2265 case OP_LCONV_TO_OVF_I:
2266 case OP_LCONV_TO_OVF_U:
2268 mono_print_ins (ins);
2269 g_assert_not_reached ();
2272 tmp1 = mono_alloc_ireg (cfg);
2273 tmp2 = mono_alloc_ireg (cfg);
2274 tmp3 = mono_alloc_ireg (cfg);
2275 tmp4 = mono_alloc_ireg (cfg);
2276 tmp5 = mono_alloc_ireg (cfg);
2278 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2280 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2281 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2283 /* add the high 32-bits, and add in the carry from the low 32-bits */
2284 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2285 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2287 /* Overflow happens if
2288 * neg + neg = pos or
2290 * XOR of the high bits returns 0 if the signs match
2291 * XOR of that with the high bit of the result return 1 if overflow.
2294 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2295 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2297 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2298 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2299 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2301 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2302 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2303 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2305 /* Now, if (tmp4 == 0) then overflow */
2306 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2310 case OP_LADD_OVF_UN:
2311 tmp1 = mono_alloc_ireg (cfg);
2312 tmp2 = mono_alloc_ireg (cfg);
2314 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2315 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2316 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2317 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2318 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2319 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2324 case OP_LMUL_OVF_UN:
2325 mono_print_ins (ins);
2326 g_assert_not_reached ();
2329 tmp1 = mono_alloc_ireg (cfg);
2330 tmp2 = mono_alloc_ireg (cfg);
2331 tmp3 = mono_alloc_ireg (cfg);
2332 tmp4 = mono_alloc_ireg (cfg);
2333 tmp5 = mono_alloc_ireg (cfg);
2335 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2337 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2338 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2339 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2341 /* Overflow happens if
2342 * neg - pos = pos or
2344 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2346 * tmp1 = (lhs ^ rhs)
2347 * tmp2 = (lhs ^ result)
2348 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2351 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2352 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2353 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2354 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2356 /* Now, if (tmp4 == 1) then overflow */
2357 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2361 case OP_LSUB_OVF_UN:
2362 tmp1 = mono_alloc_ireg (cfg);
2363 tmp2 = mono_alloc_ireg (cfg);
2365 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2366 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2367 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2368 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2370 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2371 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2375 case OP_LCONV_TO_OVF_I1_UN:
2376 case OP_LCONV_TO_OVF_I2_UN:
2377 case OP_LCONV_TO_OVF_I4_UN:
2378 case OP_LCONV_TO_OVF_I8_UN:
2379 case OP_LCONV_TO_OVF_U1_UN:
2380 case OP_LCONV_TO_OVF_U2_UN:
2381 case OP_LCONV_TO_OVF_U4_UN:
2382 case OP_LCONV_TO_OVF_U8_UN:
2383 case OP_LCONV_TO_OVF_I_UN:
2384 case OP_LCONV_TO_OVF_U_UN:
2385 case OP_LCONV_TO_OVF_I1:
2386 case OP_LCONV_TO_OVF_U1:
2387 case OP_LCONV_TO_OVF_I2:
2388 case OP_LCONV_TO_OVF_U2:
2389 case OP_LCONV_TO_OVF_I4:
2390 case OP_LCONV_TO_OVF_U4:
2391 case OP_LCONV_TO_OVF_I8:
2392 case OP_LCONV_TO_OVF_U8:
2400 case OP_LCONV_TO_R_UN:
2406 case OP_LSHR_UN_IMM:
2408 case OP_LDIV_UN_IMM:
2410 case OP_LREM_UN_IMM:
2421 mono_print_ins (ins);
2422 g_assert_not_reached ();
2424 case OP_LCONV_TO_R8_2:
2425 case OP_LCONV_TO_R4_2:
2426 case OP_LCONV_TO_R_UN_2:
2428 case OP_LCONV_TO_OVF_I4_2:
2429 tmp1 = mono_alloc_ireg (cfg);
2431 /* Overflows if reg2 != sign extension of reg1 */
2432 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2433 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2434 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2442 mono_print_ins (ins);
2443 g_assert_not_reached ();
2451 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2459 switch (ins->opcode) {
2461 tmp1 = mono_alloc_ireg (cfg);
2462 tmp2 = mono_alloc_ireg (cfg);
2463 tmp3 = mono_alloc_ireg (cfg);
2464 tmp4 = mono_alloc_ireg (cfg);
2465 tmp5 = mono_alloc_ireg (cfg);
2467 /* add the operands */
2469 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2471 /* Overflow happens if
2472 * neg + neg = pos or
2475 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2476 * XOR of the high bit returns 0 if the signs match
2477 * XOR of that with the high bit of the result return 1 if overflow.
2480 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2481 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2483 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2484 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2485 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2487 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2488 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2490 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2492 /* Now, if (tmp5 == 0) then overflow */
2493 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2494 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2495 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2499 case OP_IADD_OVF_UN:
2500 tmp1 = mono_alloc_ireg (cfg);
2502 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2503 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2504 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2505 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2506 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2511 tmp1 = mono_alloc_ireg (cfg);
2512 tmp2 = mono_alloc_ireg (cfg);
2513 tmp3 = mono_alloc_ireg (cfg);
2514 tmp4 = mono_alloc_ireg (cfg);
2515 tmp5 = mono_alloc_ireg (cfg);
2517 /* add the operands */
2519 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2521 /* Overflow happens if
2522 * neg - pos = pos or
2524 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2526 * tmp1 = (lhs ^ rhs)
2527 * tmp2 = (lhs ^ result)
2528 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2531 /* tmp3 = 1 if the signs of the two inputs differ */
2532 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2533 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2534 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2535 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2536 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2538 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2539 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2540 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2544 case OP_ISUB_OVF_UN:
2545 tmp1 = mono_alloc_ireg (cfg);
2547 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2548 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2549 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2550 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2551 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2558 map_to_reg_reg_op (int op)
2567 case OP_COMPARE_IMM:
2569 case OP_ICOMPARE_IMM:
2571 case OP_LCOMPARE_IMM:
2587 case OP_LOAD_MEMBASE:
2588 return OP_LOAD_MEMINDEX;
2589 case OP_LOADI4_MEMBASE:
2590 return OP_LOADI4_MEMINDEX;
2591 case OP_LOADU4_MEMBASE:
2592 return OP_LOADU4_MEMINDEX;
2593 case OP_LOADU1_MEMBASE:
2594 return OP_LOADU1_MEMINDEX;
2595 case OP_LOADI2_MEMBASE:
2596 return OP_LOADI2_MEMINDEX;
2597 case OP_LOADU2_MEMBASE:
2598 return OP_LOADU2_MEMINDEX;
2599 case OP_LOADI1_MEMBASE:
2600 return OP_LOADI1_MEMINDEX;
2601 case OP_LOADR4_MEMBASE:
2602 return OP_LOADR4_MEMINDEX;
2603 case OP_LOADR8_MEMBASE:
2604 return OP_LOADR8_MEMINDEX;
2605 case OP_STOREI1_MEMBASE_REG:
2606 return OP_STOREI1_MEMINDEX;
2607 case OP_STOREI2_MEMBASE_REG:
2608 return OP_STOREI2_MEMINDEX;
2609 case OP_STOREI4_MEMBASE_REG:
2610 return OP_STOREI4_MEMINDEX;
2611 case OP_STORE_MEMBASE_REG:
2612 return OP_STORE_MEMINDEX;
2613 case OP_STORER4_MEMBASE_REG:
2614 return OP_STORER4_MEMINDEX;
2615 case OP_STORER8_MEMBASE_REG:
2616 return OP_STORER8_MEMINDEX;
2617 case OP_STORE_MEMBASE_IMM:
2618 return OP_STORE_MEMBASE_REG;
2619 case OP_STOREI1_MEMBASE_IMM:
2620 return OP_STOREI1_MEMBASE_REG;
2621 case OP_STOREI2_MEMBASE_IMM:
2622 return OP_STOREI2_MEMBASE_REG;
2623 case OP_STOREI4_MEMBASE_IMM:
2624 return OP_STOREI4_MEMBASE_REG;
2625 case OP_STOREI8_MEMBASE_IMM:
2626 return OP_STOREI8_MEMBASE_REG;
2628 return mono_op_imm_to_op (op);
2632 map_to_mips_op (int op)
2636 return OP_MIPS_FBEQ;
2638 return OP_MIPS_FBGE;
2640 return OP_MIPS_FBGT;
2642 return OP_MIPS_FBLE;
2644 return OP_MIPS_FBLT;
2646 return OP_MIPS_FBNE;
2648 return OP_MIPS_FBGE_UN;
2650 return OP_MIPS_FBGT_UN;
2652 return OP_MIPS_FBLE_UN;
2654 return OP_MIPS_FBLT_UN;
2662 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2663 g_assert_not_reached ();
2667 #define NEW_INS(cfg,after,dest,op) do { \
2668 MONO_INST_NEW((cfg), (dest), (op)); \
2669 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2672 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2674 MONO_INST_NEW(cfg, temp, (op)); \
2675 mono_bblock_insert_after_ins (bb, (pos), temp); \
2676 temp->dreg = (_dreg); \
2677 temp->sreg1 = (_sreg1); \
2678 temp->sreg2 = (_sreg2); \
2682 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2684 MONO_INST_NEW(cfg, temp, (op)); \
2685 mono_bblock_insert_after_ins (bb, (pos), temp); \
2686 temp->dreg = (_dreg); \
2687 temp->sreg1 = (_sreg1); \
2688 temp->inst_c0 = (_imm); \
2693 * Remove from the instruction list the instructions that can't be
2694 * represented with very simple instructions with no register
2698 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2700 MonoInst *ins, *next, *temp, *last_ins = NULL;
2704 if (cfg->verbose_level > 2) {
2707 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2708 MONO_BB_FOR_EACH_INS (bb, ins) {
2709 mono_print_ins_index (idx++, ins);
2715 MONO_BB_FOR_EACH_INS (bb, ins) {
2717 switch (ins->opcode) {
2722 /* Branch opts can eliminate the branch */
2723 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2729 case OP_COMPARE_IMM:
2730 case OP_ICOMPARE_IMM:
2731 case OP_LCOMPARE_IMM:
2733 /* Branch opts can eliminate the branch */
2734 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2738 if (ins->inst_imm) {
2739 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2740 temp->inst_c0 = ins->inst_imm;
2741 temp->dreg = mono_alloc_ireg (cfg);
2742 ins->sreg2 = temp->dreg;
2746 ins->sreg2 = mips_zero;
2748 if (ins->opcode == OP_COMPARE_IMM)
2749 ins->opcode = OP_COMPARE;
2750 else if (ins->opcode == OP_ICOMPARE_IMM)
2751 ins->opcode = OP_ICOMPARE;
2752 else if (ins->opcode == OP_LCOMPARE_IMM)
2753 ins->opcode = OP_LCOMPARE;
2756 case OP_IDIV_UN_IMM:
2759 case OP_IREM_UN_IMM:
2760 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2761 temp->inst_c0 = ins->inst_imm;
2762 temp->dreg = mono_alloc_ireg (cfg);
2763 ins->sreg2 = temp->dreg;
2764 if (ins->opcode == OP_IDIV_IMM)
2765 ins->opcode = OP_IDIV;
2766 else if (ins->opcode == OP_IREM_IMM)
2767 ins->opcode = OP_IREM;
2768 else if (ins->opcode == OP_IDIV_UN_IMM)
2769 ins->opcode = OP_IDIV_UN;
2770 else if (ins->opcode == OP_IREM_UN_IMM)
2771 ins->opcode = OP_IREM_UN;
2773 /* handle rem separately */
2780 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2781 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2782 temp->inst_c0 = ins->inst_imm;
2783 temp->dreg = mono_alloc_ireg (cfg);
2784 ins->sreg2 = temp->dreg;
2785 ins->opcode = map_to_reg_reg_op (ins->opcode);
2795 /* unsigned 16 bit immediate */
2796 if (ins->inst_imm & 0xffff0000) {
2797 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2798 temp->inst_c0 = ins->inst_imm;
2799 temp->dreg = mono_alloc_ireg (cfg);
2800 ins->sreg2 = temp->dreg;
2801 ins->opcode = map_to_reg_reg_op (ins->opcode);
2808 /* signed 16 bit immediate */
2809 if (!mips_is_imm16 (ins->inst_imm)) {
2810 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2811 temp->inst_c0 = ins->inst_imm;
2812 temp->dreg = mono_alloc_ireg (cfg);
2813 ins->sreg2 = temp->dreg;
2814 ins->opcode = map_to_reg_reg_op (ins->opcode);
2820 if (!mips_is_imm16 (-ins->inst_imm)) {
2821 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2822 temp->inst_c0 = ins->inst_imm;
2823 temp->dreg = mono_alloc_ireg (cfg);
2824 ins->sreg2 = temp->dreg;
2825 ins->opcode = map_to_reg_reg_op (ins->opcode);
2831 if (ins->inst_imm == 1) {
2832 ins->opcode = OP_MOVE;
2835 if (ins->inst_imm == 0) {
2836 ins->opcode = OP_ICONST;
2840 imm = mono_is_power_of_two (ins->inst_imm);
2842 ins->opcode = OP_SHL_IMM;
2843 ins->inst_imm = imm;
2846 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2847 temp->inst_c0 = ins->inst_imm;
2848 temp->dreg = mono_alloc_ireg (cfg);
2849 ins->sreg2 = temp->dreg;
2850 ins->opcode = map_to_reg_reg_op (ins->opcode);
2853 case OP_LOCALLOC_IMM:
2854 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2855 temp->inst_c0 = ins->inst_imm;
2856 temp->dreg = mono_alloc_ireg (cfg);
2857 ins->sreg1 = temp->dreg;
2858 ins->opcode = OP_LOCALLOC;
2861 case OP_LOADR4_MEMBASE:
2862 case OP_STORER4_MEMBASE_REG:
2863 /* we can do two things: load the immed in a register
2864 * and use an indexed load, or see if the immed can be
2865 * represented as an ad_imm + a load with a smaller offset
2866 * that fits. We just do the first for now, optimize later.
2868 if (mips_is_imm16 (ins->inst_offset))
2870 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2871 temp->inst_c0 = ins->inst_offset;
2872 temp->dreg = mono_alloc_ireg (cfg);
2873 ins->sreg2 = temp->dreg;
2874 ins->opcode = map_to_reg_reg_op (ins->opcode);
2877 case OP_STORE_MEMBASE_IMM:
2878 case OP_STOREI1_MEMBASE_IMM:
2879 case OP_STOREI2_MEMBASE_IMM:
2880 case OP_STOREI4_MEMBASE_IMM:
2881 case OP_STOREI8_MEMBASE_IMM:
2882 if (!ins->inst_imm) {
2883 ins->sreg1 = mips_zero;
2884 ins->opcode = map_to_reg_reg_op (ins->opcode);
2887 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2888 temp->inst_c0 = ins->inst_imm;
2889 temp->dreg = mono_alloc_ireg (cfg);
2890 ins->sreg1 = temp->dreg;
2891 ins->opcode = map_to_reg_reg_op (ins->opcode);
2893 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2899 /* Branch opts can eliminate the branch */
2900 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2907 * remap compare/branch and compare/set
2908 * to MIPS specific opcodes.
2910 next->opcode = map_to_mips_op (next->opcode);
2911 next->sreg1 = ins->sreg1;
2912 next->sreg2 = ins->sreg2;
2919 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2920 temp->inst_c0 = (guint32)ins->inst_p0;
2921 temp->dreg = mono_alloc_ireg (cfg);
2922 ins->inst_basereg = temp->dreg;
2923 ins->inst_offset = 0;
2924 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2926 /* make it handle the possibly big ins->inst_offset
2927 * later optimize to use lis + load_membase
2932 g_assert (ins_is_compare(last_ins));
2933 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2934 NULLIFY_INS(last_ins);
2938 g_assert (ins_is_compare(last_ins));
2939 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2940 NULLIFY_INS(last_ins);
2944 g_assert (ins_is_compare(last_ins));
2945 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2946 last_ins->dreg = mono_alloc_ireg (cfg);
2947 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2951 g_assert (ins_is_compare(last_ins));
2952 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2953 last_ins->dreg = mono_alloc_ireg (cfg);
2954 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2958 g_assert (ins_is_compare(last_ins));
2959 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2960 last_ins->dreg = mono_alloc_ireg (cfg);
2961 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2965 g_assert (ins_is_compare(last_ins));
2966 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2967 last_ins->dreg = mono_alloc_ireg (cfg);
2968 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2972 g_assert (ins_is_compare(last_ins));
2973 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2974 last_ins->dreg = mono_alloc_ireg (cfg);
2975 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2979 g_assert (ins_is_compare(last_ins));
2980 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2981 last_ins->dreg = mono_alloc_ireg (cfg);
2982 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2986 g_assert (ins_is_compare(last_ins));
2987 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2988 last_ins->dreg = mono_alloc_ireg (cfg);
2989 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2993 g_assert (ins_is_compare(last_ins));
2994 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2995 last_ins->dreg = mono_alloc_ireg (cfg);
2996 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
3001 g_assert (ins_is_compare(last_ins));
3002 last_ins->opcode = OP_IXOR;
3003 last_ins->dreg = mono_alloc_ireg(cfg);
3004 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
3009 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
3010 NULLIFY_INS(last_ins);
3016 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
3017 NULLIFY_INS(last_ins);
3022 g_assert (ins_is_compare(last_ins));
3023 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
3024 MONO_DELETE_INS(bb, last_ins);
3029 g_assert (ins_is_compare(last_ins));
3030 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3031 MONO_DELETE_INS(bb, last_ins);
3034 case OP_COND_EXC_EQ:
3035 case OP_COND_EXC_IEQ:
3036 g_assert (ins_is_compare(last_ins));
3037 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3038 MONO_DELETE_INS(bb, last_ins);
3041 case OP_COND_EXC_GE:
3042 case OP_COND_EXC_IGE:
3043 g_assert (ins_is_compare(last_ins));
3044 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3045 MONO_DELETE_INS(bb, last_ins);
3048 case OP_COND_EXC_GT:
3049 case OP_COND_EXC_IGT:
3050 g_assert (ins_is_compare(last_ins));
3051 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3052 MONO_DELETE_INS(bb, last_ins);
3055 case OP_COND_EXC_LE:
3056 case OP_COND_EXC_ILE:
3057 g_assert (ins_is_compare(last_ins));
3058 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3059 MONO_DELETE_INS(bb, last_ins);
3062 case OP_COND_EXC_LT:
3063 case OP_COND_EXC_ILT:
3064 g_assert (ins_is_compare(last_ins));
3065 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3066 MONO_DELETE_INS(bb, last_ins);
3069 case OP_COND_EXC_NE_UN:
3070 case OP_COND_EXC_INE_UN:
3071 g_assert (ins_is_compare(last_ins));
3072 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3073 MONO_DELETE_INS(bb, last_ins);
3076 case OP_COND_EXC_GE_UN:
3077 case OP_COND_EXC_IGE_UN:
3078 g_assert (ins_is_compare(last_ins));
3079 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3080 MONO_DELETE_INS(bb, last_ins);
3083 case OP_COND_EXC_GT_UN:
3084 case OP_COND_EXC_IGT_UN:
3085 g_assert (ins_is_compare(last_ins));
3086 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3087 MONO_DELETE_INS(bb, last_ins);
3090 case OP_COND_EXC_LE_UN:
3091 case OP_COND_EXC_ILE_UN:
3092 g_assert (ins_is_compare(last_ins));
3093 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3094 MONO_DELETE_INS(bb, last_ins);
3097 case OP_COND_EXC_LT_UN:
3098 case OP_COND_EXC_ILT_UN:
3099 g_assert (ins_is_compare(last_ins));
3100 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3101 MONO_DELETE_INS(bb, last_ins);
3104 case OP_COND_EXC_OV:
3105 case OP_COND_EXC_IOV: {
3106 int tmp1, tmp2, tmp3, tmp4, tmp5;
3107 MonoInst *pos = last_ins;
3109 /* Overflow happens if
3110 * neg + neg = pos or
3113 * (bit31s of operands match) AND (bit31 of operand
3114 * != bit31 of result)
3115 * XOR of the high bit returns 0 if the signs match
3116 * XOR of that with the high bit of the result return 1
3119 g_assert (last_ins->opcode == OP_IADC);
3121 tmp1 = mono_alloc_ireg (cfg);
3122 tmp2 = mono_alloc_ireg (cfg);
3123 tmp3 = mono_alloc_ireg (cfg);
3124 tmp4 = mono_alloc_ireg (cfg);
3125 tmp5 = mono_alloc_ireg (cfg);
3127 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3128 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3130 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3131 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3132 INS (pos, OP_INOT, tmp3, tmp2, -1);
3134 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3135 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3136 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3138 /* Now, if (tmp5 == 0) then overflow */
3139 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3144 case OP_COND_EXC_NO:
3145 case OP_COND_EXC_INO:
3146 g_assert_not_reached ();
3150 case OP_COND_EXC_IC:
3151 g_assert_not_reached ();
3154 case OP_COND_EXC_NC:
3155 case OP_COND_EXC_INC:
3156 g_assert_not_reached ();
3162 bb->last_ins = last_ins;
3163 bb->max_vreg = cfg->next_vreg;
3166 if (cfg->verbose_level > 2) {
3169 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3170 MONO_BB_FOR_EACH_INS (bb, ins) {
3171 mono_print_ins_index (idx++, ins);
3180 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3182 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3184 mips_truncwd (code, mips_ftemp, sreg);
3186 mips_cvtwd (code, mips_ftemp, sreg);
3188 mips_mfc1 (code, dreg, mips_ftemp);
3191 mips_andi (code, dreg, dreg, 0xff);
3192 else if (size == 2) {
3193 mips_sll (code, dreg, dreg, 16);
3194 mips_srl (code, dreg, dreg, 16);
3198 mips_sll (code, dreg, dreg, 24);
3199 mips_sra (code, dreg, dreg, 24);
3201 else if (size == 2) {
3202 mips_sll (code, dreg, dreg, 16);
3203 mips_sra (code, dreg, dreg, 16);
3210 * emit_load_volatile_arguments:
3212 * Load volatile arguments from the stack to the original input registers.
3213 * Required before a tail call.
3216 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3218 MonoMethod *method = cfg->method;
3219 MonoMethodSignature *sig;
3224 sig = mono_method_signature (method);
3226 if (!cfg->arch.cinfo)
3227 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
3228 cinfo = cfg->arch.cinfo;
3230 if (cinfo->struct_ret) {
3231 ArgInfo *ainfo = &cinfo->ret;
3232 inst = cfg->vret_addr;
3233 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3236 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3237 ArgInfo *ainfo = cinfo->args + i;
3238 inst = cfg->args [i];
3239 if (inst->opcode == OP_REGVAR) {
3240 if (ainfo->storage == ArgInIReg)
3241 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3242 else if (ainfo->storage == ArgInFReg)
3243 g_assert_not_reached();
3244 else if (ainfo->storage == ArgOnStack) {
3247 g_assert_not_reached ();
3249 if (ainfo->storage == ArgInIReg) {
3250 g_assert (mips_is_imm16 (inst->inst_offset));
3251 switch (ainfo->size) {
3253 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3256 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3260 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3263 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3264 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3267 g_assert_not_reached ();
3270 } else if (ainfo->storage == ArgOnStack) {
3272 } else if (ainfo->storage == ArgInFReg) {
3273 g_assert (mips_is_imm16 (inst->inst_offset));
3274 if (ainfo->size == 8) {
3275 #if _MIPS_SIM == _ABIO32
3276 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3277 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3278 #elif _MIPS_SIM == _ABIN32
3279 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3282 else if (ainfo->size == 4)
3283 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3285 g_assert_not_reached ();
3286 } else if (ainfo->storage == ArgStructByVal) {
3288 int doffset = inst->inst_offset;
3290 g_assert (mips_is_imm16 (inst->inst_offset));
3291 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3292 for (i = 0; i < ainfo->size; ++i) {
3293 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3294 doffset += SIZEOF_REGISTER;
3296 } else if (ainfo->storage == ArgStructByAddr) {
3297 g_assert (mips_is_imm16 (inst->inst_offset));
3298 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3300 g_assert_not_reached ();
3308 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3310 int size = cfg->param_area;
3312 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3313 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3318 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3319 if (ppc_is_imm16 (-size)) {
3320 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3322 ppc_load (code, ppc_r11, -size);
3323 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3330 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3332 int size = cfg->param_area;
3334 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3335 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3340 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3341 if (ppc_is_imm16 (size)) {
3342 ppc_stwu (code, ppc_r0, size, ppc_sp);
3344 ppc_load (code, ppc_r11, size);
3345 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3352 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3357 guint8 *code = cfg->native_code + cfg->code_len;
3358 MonoInst *last_ins = NULL;
3359 guint last_offset = 0;
3363 /* we don't align basic blocks of loops on mips */
3365 if (cfg->verbose_level > 2)
3366 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3368 cpos = bb->max_offset;
3371 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3372 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3373 g_assert (!mono_compile_aot);
3376 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3377 /* this is not thread save, but good enough */
3378 /* fixme: howto handle overflows? */
3379 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3380 mips_lw (code, mips_temp, mips_at, 0);
3381 mips_addiu (code, mips_temp, mips_temp, 1);
3382 mips_sw (code, mips_temp, mips_at, 0);
3385 MONO_BB_FOR_EACH_INS (bb, ins) {
3386 offset = code - cfg->native_code;
3388 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3390 if (offset > (cfg->code_size - max_len - 16)) {
3391 cfg->code_size *= 2;
3392 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3393 code = cfg->native_code + offset;
3395 mono_debug_record_line_number (cfg, ins, offset);
3396 if (cfg->verbose_level > 2) {
3397 g_print (" @ 0x%x\t", offset);
3398 mono_print_ins_index (ins_cnt++, ins);
3400 /* Check for virtual regs that snuck by */
3401 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3403 switch (ins->opcode) {
3404 case OP_RELAXED_NOP:
3407 case OP_DUMMY_STORE:
3408 case OP_NOT_REACHED:
3411 case OP_SEQ_POINT: {
3412 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3413 guint32 addr = (guint32)ss_trigger_page;
3415 mips_load_const (code, mips_t9, addr);
3416 mips_lw (code, mips_t9, mips_t9, 0);
3419 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3422 * A placeholder for a possible breakpoint inserted by
3423 * mono_arch_set_breakpoint ().
3425 /* mips_load_const () + mips_lw */
3432 g_assert_not_reached();
3434 emit_tls_access (code, ins->dreg, ins->inst_offset);
3438 mips_mult (code, ins->sreg1, ins->sreg2);
3439 mips_mflo (code, ins->dreg);
3440 mips_mfhi (code, ins->dreg+1);
3443 mips_multu (code, ins->sreg1, ins->sreg2);
3444 mips_mflo (code, ins->dreg);
3445 mips_mfhi (code, ins->dreg+1);
3447 case OP_MEMORY_BARRIER:
3452 case OP_STOREI1_MEMBASE_IMM:
3453 mips_load_const (code, mips_temp, ins->inst_imm);
3454 if (mips_is_imm16 (ins->inst_offset)) {
3455 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3457 mips_load_const (code, mips_at, ins->inst_offset);
3458 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3461 case OP_STOREI2_MEMBASE_IMM:
3462 mips_load_const (code, mips_temp, ins->inst_imm);
3463 if (mips_is_imm16 (ins->inst_offset)) {
3464 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3466 mips_load_const (code, mips_at, ins->inst_offset);
3467 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3470 case OP_STOREI8_MEMBASE_IMM:
3471 mips_load_const (code, mips_temp, ins->inst_imm);
3472 if (mips_is_imm16 (ins->inst_offset)) {
3473 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3475 mips_load_const (code, mips_at, ins->inst_offset);
3476 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3479 case OP_STORE_MEMBASE_IMM:
3480 case OP_STOREI4_MEMBASE_IMM:
3481 mips_load_const (code, mips_temp, ins->inst_imm);
3482 if (mips_is_imm16 (ins->inst_offset)) {
3483 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3485 mips_load_const (code, mips_at, ins->inst_offset);
3486 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3489 case OP_STOREI1_MEMBASE_REG:
3490 if (mips_is_imm16 (ins->inst_offset)) {
3491 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3493 mips_load_const (code, mips_at, ins->inst_offset);
3494 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3495 mips_sb (code, ins->sreg1, mips_at, 0);
3498 case OP_STOREI2_MEMBASE_REG:
3499 if (mips_is_imm16 (ins->inst_offset)) {
3500 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3502 mips_load_const (code, mips_at, ins->inst_offset);
3503 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3504 mips_sh (code, ins->sreg1, mips_at, 0);
3507 case OP_STORE_MEMBASE_REG:
3508 case OP_STOREI4_MEMBASE_REG:
3509 if (mips_is_imm16 (ins->inst_offset)) {
3510 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3512 mips_load_const (code, mips_at, ins->inst_offset);
3513 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3514 mips_sw (code, ins->sreg1, mips_at, 0);
3517 case OP_STOREI8_MEMBASE_REG:
3518 if (mips_is_imm16 (ins->inst_offset)) {
3519 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3521 mips_load_const (code, mips_at, ins->inst_offset);
3522 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3523 mips_sd (code, ins->sreg1, mips_at, 0);
3527 g_assert_not_reached ();
3528 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3529 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3531 case OP_LOADI8_MEMBASE:
3532 if (mips_is_imm16 (ins->inst_offset)) {
3533 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3535 mips_load_const (code, mips_at, ins->inst_offset);
3536 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3537 mips_ld (code, ins->dreg, mips_at, 0);
3540 case OP_LOAD_MEMBASE:
3541 case OP_LOADI4_MEMBASE:
3542 case OP_LOADU4_MEMBASE:
3543 g_assert (ins->dreg != -1);
3544 if (mips_is_imm16 (ins->inst_offset)) {
3545 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3547 mips_load_const (code, mips_at, ins->inst_offset);
3548 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3549 mips_lw (code, ins->dreg, mips_at, 0);
3552 case OP_LOADI1_MEMBASE:
3553 if (mips_is_imm16 (ins->inst_offset)) {
3554 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3556 mips_load_const (code, mips_at, ins->inst_offset);
3557 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3558 mips_lb (code, ins->dreg, mips_at, 0);
3561 case OP_LOADU1_MEMBASE:
3562 if (mips_is_imm16 (ins->inst_offset)) {
3563 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3565 mips_load_const (code, mips_at, ins->inst_offset);
3566 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3567 mips_lbu (code, ins->dreg, mips_at, 0);
3570 case OP_LOADI2_MEMBASE:
3571 if (mips_is_imm16 (ins->inst_offset)) {
3572 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3574 mips_load_const (code, mips_at, ins->inst_offset);
3575 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3576 mips_lh (code, ins->dreg, mips_at, 0);
3579 case OP_LOADU2_MEMBASE:
3580 if (mips_is_imm16 (ins->inst_offset)) {
3581 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3583 mips_load_const (code, mips_at, ins->inst_offset);
3584 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3585 mips_lhu (code, ins->dreg, mips_at, 0);
3588 case OP_ICONV_TO_I1:
3589 mips_sll (code, mips_at, ins->sreg1, 24);
3590 mips_sra (code, ins->dreg, mips_at, 24);
3592 case OP_ICONV_TO_I2:
3593 mips_sll (code, mips_at, ins->sreg1, 16);
3594 mips_sra (code, ins->dreg, mips_at, 16);
3596 case OP_ICONV_TO_U1:
3597 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3599 case OP_ICONV_TO_U2:
3600 mips_sll (code, mips_at, ins->sreg1, 16);
3601 mips_srl (code, ins->dreg, mips_at, 16);
3604 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3607 g_assert (mips_is_imm16 (ins->inst_imm));
3608 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3611 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3614 g_assert (mips_is_imm16 (ins->inst_imm));
3615 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3619 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3620 * So instead of emitting a trap, we emit a call a C function and place a
3623 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3624 (gpointer)"mono_break");
3625 mips_load (code, mips_t9, 0x1f1f1f1f);
3626 mips_jalr (code, mips_t9, mips_ra);
3630 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3633 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3638 g_assert (mips_is_imm16 (ins->inst_imm));
3639 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3642 g_assert (mips_is_imm16 (ins->inst_imm));
3643 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3647 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3650 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3655 // we add the negated value
3656 g_assert (mips_is_imm16 (-ins->inst_imm));
3657 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3661 // we add the negated value
3662 g_assert (mips_is_imm16 (-ins->inst_imm));
3663 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3668 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3674 g_assert (!(ins->inst_imm & 0xffff0000));
3675 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3680 guint32 *divisor_is_m1;
3681 guint32 *dividend_is_minvalue;
3682 guint32 *divisor_is_zero;
3684 mips_load_const (code, mips_at, -1);
3685 divisor_is_m1 = (guint32 *)(void *)code;
3686 mips_bne (code, ins->sreg2, mips_at, 0);
3687 mips_lui (code, mips_at, mips_zero, 0x8000);
3688 dividend_is_minvalue = (guint32 *)(void *)code;
3689 mips_bne (code, ins->sreg1, mips_at, 0);
3692 /* Divide Int32.MinValue by -1 -- throw exception */
3693 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3695 mips_patch (divisor_is_m1, (guint32)code);
3696 mips_patch (dividend_is_minvalue, (guint32)code);
3698 /* Put divide in branch delay slot (NOT YET) */
3699 divisor_is_zero = (guint32 *)(void *)code;
3700 mips_bne (code, ins->sreg2, mips_zero, 0);
3703 /* Divide by zero -- throw exception */
3704 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3706 mips_patch (divisor_is_zero, (guint32)code);
3707 mips_div (code, ins->sreg1, ins->sreg2);
3708 if (ins->opcode == OP_IDIV)
3709 mips_mflo (code, ins->dreg);
3711 mips_mfhi (code, ins->dreg);
3716 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3718 /* Put divide in branch delay slot (NOT YET) */
3719 mips_bne (code, ins->sreg2, mips_zero, 0);
3722 /* Divide by zero -- throw exception */
3723 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3725 mips_patch (divisor_is_zero, (guint32)code);
3726 mips_divu (code, ins->sreg1, ins->sreg2);
3727 if (ins->opcode == OP_IDIV_UN)
3728 mips_mflo (code, ins->dreg);
3730 mips_mfhi (code, ins->dreg);
3734 g_assert_not_reached ();
3736 ppc_load (code, ppc_r11, ins->inst_imm);
3737 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3738 ppc_mfspr (code, ppc_r0, ppc_xer);
3739 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3740 /* FIXME: use OverflowException for 0x80000000/-1 */
3741 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3743 g_assert_not_reached();
3746 g_assert_not_reached ();
3748 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3752 g_assert (!(ins->inst_imm & 0xffff0000));
3753 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3756 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3760 /* unsigned 16-bit immediate */
3761 g_assert (!(ins->inst_imm & 0xffff0000));
3762 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3765 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3769 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3772 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3775 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3779 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3782 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3785 case OP_ISHR_UN_IMM:
3786 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3788 case OP_LSHR_UN_IMM:
3789 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3792 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3795 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3799 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3802 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3805 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3809 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3811 mips_mult (code, ins->sreg1, ins->sreg2);
3812 mips_mflo (code, ins->dreg);
3817 #if SIZEOF_REGISTER == 8
3819 mips_dmult (code, ins->sreg1, ins->sreg2);
3820 mips_mflo (code, ins->dreg);
3825 mips_mult (code, ins->sreg1, ins->sreg2);
3826 mips_mflo (code, ins->dreg);
3827 mips_mfhi (code, mips_at);
3830 mips_sra (code, mips_temp, ins->dreg, 31);
3831 patch = (guint32 *)(void *)code;
3832 mips_beq (code, mips_temp, mips_at, 0);
3834 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3835 mips_patch (patch, (guint32)code);
3838 case OP_IMUL_OVF_UN: {
3840 mips_mult (code, ins->sreg1, ins->sreg2);
3841 mips_mflo (code, ins->dreg);
3842 mips_mfhi (code, mips_at);
3845 patch = (guint32 *)(void *)code;
3846 mips_beq (code, mips_at, mips_zero, 0);
3848 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3849 mips_patch (patch, (guint32)code);
3853 mips_load_const (code, ins->dreg, ins->inst_c0);
3855 #if SIZEOF_REGISTER == 8
3857 mips_load_const (code, ins->dreg, ins->inst_c0);
3861 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3862 mips_load (code, ins->dreg, 0);
3866 mips_mtc1 (code, ins->dreg, ins->sreg1);
3868 case OP_MIPS_MTC1S_2:
3869 mips_mtc1 (code, ins->dreg, ins->sreg1);
3870 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3873 mips_mfc1 (code, ins->dreg, ins->sreg1);
3876 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3880 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3882 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3883 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3887 case OP_ICONV_TO_I4:
3888 case OP_ICONV_TO_U4:
3890 if (ins->dreg != ins->sreg1)
3891 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3893 #if SIZEOF_REGISTER == 8
3895 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3896 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3899 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3900 mips_dsra (code, ins->dreg, ins->dreg, 32);
3904 int lsreg = mips_v0 + ls_word_idx;
3905 int msreg = mips_v0 + ms_word_idx;
3907 /* Get sreg1 into lsreg, sreg2 into msreg */
3909 if (ins->sreg1 == msreg) {
3910 if (ins->sreg1 != mips_at)
3911 MIPS_MOVE (code, mips_at, ins->sreg1);
3912 if (ins->sreg2 != msreg)
3913 MIPS_MOVE (code, msreg, ins->sreg2);
3914 MIPS_MOVE (code, lsreg, mips_at);
3917 if (ins->sreg2 != msreg)
3918 MIPS_MOVE (code, msreg, ins->sreg2);
3919 if (ins->sreg1 != lsreg)
3920 MIPS_MOVE (code, lsreg, ins->sreg1);
3925 if (ins->dreg != ins->sreg1) {
3926 mips_fmovd (code, ins->dreg, ins->sreg1);
3930 /* Convert from double to float and leave it there */
3931 mips_cvtsd (code, ins->dreg, ins->sreg1);
3933 case OP_FCONV_TO_R4:
3935 mips_cvtsd (code, ins->dreg, ins->sreg1);
3937 /* Just a move, no precision change */
3938 if (ins->dreg != ins->sreg1) {
3939 mips_fmovd (code, ins->dreg, ins->sreg1);
3944 code = emit_load_volatile_arguments(cfg, code);
3947 * Pop our stack, then jump to specified method (tail-call)
3948 * Keep in sync with mono_arch_emit_epilog
3950 code = mono_arch_emit_epilog_sub (cfg, code);
3952 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3953 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3954 mips_load (code, mips_t9, 0);
3955 mips_jr (code, mips_t9);
3959 /* ensure ins->sreg1 is not NULL */
3960 mips_lw (code, mips_zero, ins->sreg1, 0);
3963 g_assert (mips_is_imm16 (cfg->sig_cookie));
3964 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3965 mips_sw (code, mips_at, ins->sreg1, 0);
3978 case OP_VOIDCALL_REG:
3980 case OP_FCALL_MEMBASE:
3981 case OP_LCALL_MEMBASE:
3982 case OP_VCALL_MEMBASE:
3983 case OP_VCALL2_MEMBASE:
3984 case OP_VOIDCALL_MEMBASE:
3985 case OP_CALL_MEMBASE:
3986 call = (MonoCallInst*)ins;
3987 switch (ins->opcode) {
3994 if (ins->flags & MONO_INST_HAS_METHOD) {
3995 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3996 mips_load (code, mips_t9, call->method);
3999 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4000 mips_load (code, mips_t9, call->fptr);
4002 mips_jalr (code, mips_t9, mips_ra);
4009 case OP_VOIDCALL_REG:
4011 MIPS_MOVE (code, mips_t9, ins->sreg1);
4012 mips_jalr (code, mips_t9, mips_ra);
4015 case OP_FCALL_MEMBASE:
4016 case OP_LCALL_MEMBASE:
4017 case OP_VCALL_MEMBASE:
4018 case OP_VCALL2_MEMBASE:
4019 case OP_VOIDCALL_MEMBASE:
4020 case OP_CALL_MEMBASE:
4021 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
4022 mips_jalr (code, mips_t9, mips_ra);
4026 #if PROMOTE_R4_TO_R8
4027 /* returned an FP R4 (single), promote to R8 (double) in place */
4028 switch (ins->opcode) {
4031 case OP_FCALL_MEMBASE:
4032 if (call->signature->ret->type == MONO_TYPE_R4)
4033 mips_cvtds (code, mips_f0, mips_f0);
4041 int area_offset = cfg->param_area;
4043 /* Round up ins->sreg1, mips_at ends up holding size */
4044 mips_addiu (code, mips_at, ins->sreg1, 31);
4045 mips_addiu (code, mips_temp, mips_zero, ~31);
4046 mips_and (code, mips_at, mips_at, mips_temp);
4048 mips_subu (code, mips_sp, mips_sp, mips_at);
4049 g_assert (mips_is_imm16 (area_offset));
4050 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4052 if (ins->flags & MONO_INST_INIT) {
4055 buf = (guint32*)(void*)code;
4056 mips_beq (code, mips_at, mips_zero, 0);
4059 mips_move (code, mips_temp, ins->dreg);
4060 mips_sb (code, mips_zero, mips_temp, 0);
4061 mips_addiu (code, mips_at, mips_at, -1);
4062 mips_bne (code, mips_at, mips_zero, -3);
4063 mips_addiu (code, mips_temp, mips_temp, 1);
4065 mips_patch (buf, (guint32)code);
4070 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4071 mips_move (code, mips_a0, ins->sreg1);
4072 mips_call (code, mips_t9, addr);
4073 mips_break (code, 0xfc);
4077 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4078 mips_move (code, mips_a0, ins->sreg1);
4079 mips_call (code, mips_t9, addr);
4080 mips_break (code, 0xfb);
4083 case OP_START_HANDLER: {
4085 * The START_HANDLER instruction marks the beginning of
4086 * a handler block. It is called using a call
4087 * instruction, so mips_ra contains the return address.
4088 * Since the handler executes in the same stack frame
4089 * as the method itself, we can't use save/restore to
4090 * save the return address. Instead, we save it into
4091 * a dedicated variable.
4093 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4094 g_assert (spvar->inst_basereg != mips_sp);
4095 code = emit_reserve_param_area (cfg, code);
4097 if (mips_is_imm16 (spvar->inst_offset)) {
4098 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4100 mips_load_const (code, mips_at, spvar->inst_offset);
4101 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4102 mips_sw (code, mips_ra, mips_at, 0);
4106 case OP_ENDFILTER: {
4107 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4108 g_assert (spvar->inst_basereg != mips_sp);
4109 code = emit_unreserve_param_area (cfg, code);
4111 if (ins->sreg1 != mips_v0)
4112 MIPS_MOVE (code, mips_v0, ins->sreg1);
4113 if (mips_is_imm16 (spvar->inst_offset)) {
4114 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4116 mips_load_const (code, mips_at, spvar->inst_offset);
4117 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4118 mips_lw (code, mips_ra, mips_at, 0);
4120 mips_jr (code, mips_ra);
4124 case OP_ENDFINALLY: {
4125 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4126 g_assert (spvar->inst_basereg != mips_sp);
4127 code = emit_unreserve_param_area (cfg, code);
4128 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4129 mips_jalr (code, mips_t9, mips_ra);
4133 case OP_CALL_HANDLER:
4134 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4135 mips_lui (code, mips_t9, mips_zero, 0);
4136 mips_addiu (code, mips_t9, mips_t9, 0);
4137 mips_jalr (code, mips_t9, mips_ra);
4139 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4140 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4143 ins->inst_c0 = code - cfg->native_code;
4146 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4147 if (cfg->arch.long_branch) {
4148 mips_lui (code, mips_at, mips_zero, 0);
4149 mips_addiu (code, mips_at, mips_at, 0);
4150 mips_jr (code, mips_at);
4154 mips_beq (code, mips_zero, mips_zero, 0);
4159 mips_jr (code, ins->sreg1);
4165 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4166 if (offset > (cfg->code_size - max_len - 16)) {
4167 cfg->code_size += max_len;
4168 cfg->code_size *= 2;
4169 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4170 code = cfg->native_code + offset;
4172 g_assert (ins->sreg1 != -1);
4173 mips_sll (code, mips_at, ins->sreg1, 2);
4174 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4175 MIPS_MOVE (code, mips_t8, mips_ra);
4176 mips_bgezal (code, mips_zero, 1); /* bal */
4178 mips_addu (code, mips_t9, mips_ra, mips_at);
4179 /* Table is 16 or 20 bytes from target of bal above */
4180 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4181 MIPS_MOVE (code, mips_ra, mips_t8);
4182 mips_lw (code, mips_t9, mips_t9, 20);
4185 mips_lw (code, mips_t9, mips_t9, 16);
4186 mips_jalr (code, mips_t9, mips_t8);
4188 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4189 mips_emit32 (code, 0xfefefefe);
4194 mips_addiu (code, ins->dreg, mips_zero, 1);
4195 mips_beq (code, mips_at, mips_zero, 2);
4197 MIPS_MOVE (code, ins->dreg, mips_zero);
4203 mips_addiu (code, ins->dreg, mips_zero, 1);
4204 mips_bltz (code, mips_at, 2);
4206 MIPS_MOVE (code, ins->dreg, mips_zero);
4212 mips_addiu (code, ins->dreg, mips_zero, 1);
4213 mips_bgtz (code, mips_at, 2);
4215 MIPS_MOVE (code, ins->dreg, mips_zero);
4218 case OP_MIPS_COND_EXC_EQ:
4219 case OP_MIPS_COND_EXC_GE:
4220 case OP_MIPS_COND_EXC_GT:
4221 case OP_MIPS_COND_EXC_LE:
4222 case OP_MIPS_COND_EXC_LT:
4223 case OP_MIPS_COND_EXC_NE_UN:
4224 case OP_MIPS_COND_EXC_GE_UN:
4225 case OP_MIPS_COND_EXC_GT_UN:
4226 case OP_MIPS_COND_EXC_LE_UN:
4227 case OP_MIPS_COND_EXC_LT_UN:
4229 case OP_MIPS_COND_EXC_OV:
4230 case OP_MIPS_COND_EXC_NO:
4231 case OP_MIPS_COND_EXC_C:
4232 case OP_MIPS_COND_EXC_NC:
4234 case OP_MIPS_COND_EXC_IEQ:
4235 case OP_MIPS_COND_EXC_IGE:
4236 case OP_MIPS_COND_EXC_IGT:
4237 case OP_MIPS_COND_EXC_ILE:
4238 case OP_MIPS_COND_EXC_ILT:
4239 case OP_MIPS_COND_EXC_INE_UN:
4240 case OP_MIPS_COND_EXC_IGE_UN:
4241 case OP_MIPS_COND_EXC_IGT_UN:
4242 case OP_MIPS_COND_EXC_ILE_UN:
4243 case OP_MIPS_COND_EXC_ILT_UN:
4245 case OP_MIPS_COND_EXC_IOV:
4246 case OP_MIPS_COND_EXC_INO:
4247 case OP_MIPS_COND_EXC_IC:
4248 case OP_MIPS_COND_EXC_INC: {
4252 /* If the condition is true, raise the exception */
4254 /* need to reverse test to skip around exception raising */
4256 /* For the moment, branch around a branch to avoid reversing
4259 /* Remember, an unpatched branch to 0 branches to the delay slot */
4260 switch (ins->opcode) {
4261 case OP_MIPS_COND_EXC_EQ:
4262 throw = (guint32 *)(void *)code;
4263 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4267 case OP_MIPS_COND_EXC_NE_UN:
4268 throw = (guint32 *)(void *)code;
4269 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4273 case OP_MIPS_COND_EXC_LE_UN:
4274 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4275 throw = (guint32 *)(void *)code;
4276 mips_beq (code, mips_at, mips_zero, 0);
4280 case OP_MIPS_COND_EXC_GT:
4281 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4282 throw = (guint32 *)(void *)code;
4283 mips_bne (code, mips_at, mips_zero, 0);
4287 case OP_MIPS_COND_EXC_GT_UN:
4288 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4289 throw = (guint32 *)(void *)code;
4290 mips_bne (code, mips_at, mips_zero, 0);
4294 case OP_MIPS_COND_EXC_LT:
4295 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4296 throw = (guint32 *)(void *)code;
4297 mips_bne (code, mips_at, mips_zero, 0);
4301 case OP_MIPS_COND_EXC_LT_UN:
4302 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4303 throw = (guint32 *)(void *)code;
4304 mips_bne (code, mips_at, mips_zero, 0);
4309 /* Not yet implemented */
4310 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4311 g_assert_not_reached ();
4313 skip = (guint32 *)(void *)code;
4314 mips_beq (code, mips_zero, mips_zero, 0);
4316 mips_patch (throw, (guint32)code);
4317 code = mips_emit_exc_by_name (code, ins->inst_p1);
4318 mips_patch (skip, (guint32)code);
4319 cfg->bb_exit->max_offset += 24;
4328 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4331 /* floating point opcodes */
4334 if (((guint32)ins->inst_p0) & (1 << 15))
4335 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4337 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4338 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4340 mips_load_const (code, mips_at, ins->inst_p0);
4341 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4342 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4346 if (((guint32)ins->inst_p0) & (1 << 15))
4347 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4349 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4350 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4351 #if PROMOTE_R4_TO_R8
4352 mips_cvtds (code, ins->dreg, ins->dreg);
4355 case OP_STORER8_MEMBASE_REG:
4356 if (mips_is_imm16 (ins->inst_offset)) {
4357 #if _MIPS_SIM == _ABIO32
4358 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4359 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4360 #elif _MIPS_SIM == _ABIN32
4361 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4364 mips_load_const (code, mips_at, ins->inst_offset);
4365 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4366 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4367 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4370 case OP_LOADR8_MEMBASE:
4371 if (mips_is_imm16 (ins->inst_offset)) {
4372 #if _MIPS_SIM == _ABIO32
4373 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4374 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4375 #elif _MIPS_SIM == _ABIN32
4376 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4379 mips_load_const (code, mips_at, ins->inst_offset);
4380 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4381 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4382 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4385 case OP_STORER4_MEMBASE_REG:
4386 g_assert (mips_is_imm16 (ins->inst_offset));
4387 #if PROMOTE_R4_TO_R8
4388 /* Need to convert ins->sreg1 to single-precision first */
4389 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4390 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4392 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4396 g_assert (mips_is_imm16 (ins->inst_offset));
4397 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4399 case OP_LOADR4_MEMBASE:
4400 g_assert (mips_is_imm16 (ins->inst_offset));
4401 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4402 #if PROMOTE_R4_TO_R8
4403 /* Convert to double precision in place */
4404 mips_cvtds (code, ins->dreg, ins->dreg);
4407 case OP_LOADR4_MEMINDEX:
4408 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4409 mips_lwc1 (code, ins->dreg, mips_at, 0);
4411 case OP_LOADR8_MEMINDEX:
4412 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4413 #if _MIPS_SIM == _ABIO32
4414 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4415 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4416 #elif _MIPS_SIM == _ABIN32
4417 mips_ldc1 (code, ins->dreg, mips_at, 0);
4420 case OP_STORER4_MEMINDEX:
4421 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4422 #if PROMOTE_R4_TO_R8
4423 /* Need to convert ins->sreg1 to single-precision first */
4424 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4425 mips_swc1 (code, mips_ftemp, mips_at, 0);
4427 mips_swc1 (code, ins->sreg1, mips_at, 0);
4430 case OP_STORER8_MEMINDEX:
4431 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4432 #if _MIPS_SIM == _ABIO32
4433 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4434 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4435 #elif _MIPS_SIM == _ABIN32
4436 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4439 case OP_ICONV_TO_R_UN: {
4440 static const guint64 adjust_val = 0x41F0000000000000ULL;
4442 /* convert unsigned int to double */
4443 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4444 mips_bgez (code, ins->sreg1, 5);
4445 mips_cvtdw (code, ins->dreg, mips_ftemp);
4447 mips_load (code, mips_at, (guint32) &adjust_val);
4448 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4449 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4450 /* target is here */
4453 case OP_ICONV_TO_R4:
4454 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4455 mips_cvtsw (code, ins->dreg, mips_ftemp);
4456 mips_cvtds (code, ins->dreg, ins->dreg);
4458 case OP_ICONV_TO_R8:
4459 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4460 mips_cvtdw (code, ins->dreg, mips_ftemp);
4462 case OP_FCONV_TO_I1:
4463 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4465 case OP_FCONV_TO_U1:
4466 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4468 case OP_FCONV_TO_I2:
4469 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4471 case OP_FCONV_TO_U2:
4472 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4474 case OP_FCONV_TO_I4:
4476 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4478 case OP_FCONV_TO_U4:
4480 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4483 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4486 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4489 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4492 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4495 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4498 mips_fnegd (code, ins->dreg, ins->sreg1);
4501 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4502 mips_addiu (code, ins->dreg, mips_zero, 1);
4503 mips_fbtrue (code, 2);
4505 MIPS_MOVE (code, ins->dreg, mips_zero);
4508 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4509 mips_addiu (code, ins->dreg, mips_zero, 1);
4510 mips_fbtrue (code, 2);
4512 MIPS_MOVE (code, ins->dreg, mips_zero);
4515 /* Less than, or Unordered */
4516 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4517 mips_addiu (code, ins->dreg, mips_zero, 1);
4518 mips_fbtrue (code, 2);
4520 MIPS_MOVE (code, ins->dreg, mips_zero);
4523 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4524 MIPS_MOVE (code, ins->dreg, mips_zero);
4525 mips_fbtrue (code, 2);
4527 mips_addiu (code, ins->dreg, mips_zero, 1);
4530 /* Greater than, or Unordered */
4531 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4532 MIPS_MOVE (code, ins->dreg, mips_zero);
4533 mips_fbtrue (code, 2);
4535 mips_addiu (code, ins->dreg, mips_zero, 1);
4540 case OP_MIPS_FBLT_UN:
4542 case OP_MIPS_FBGT_UN:
4544 case OP_MIPS_FBGE_UN:
4546 case OP_MIPS_FBLE_UN: {
4548 gboolean is_true = TRUE, is_ordered = FALSE;
4549 guint32 *buf = NULL;
4551 switch (ins->opcode) {
4565 case OP_MIPS_FBLT_UN:
4566 cond = MIPS_FPU_ULT;
4574 case OP_MIPS_FBGT_UN:
4575 cond = MIPS_FPU_OLE;
4583 case OP_MIPS_FBGE_UN:
4584 cond = MIPS_FPU_OLT;
4588 cond = MIPS_FPU_OLE;
4592 case OP_MIPS_FBLE_UN:
4593 cond = MIPS_FPU_ULE;
4597 g_assert_not_reached ();
4601 /* Skip the check if unordered */
4602 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4604 buf = (guint32*)code;
4605 mips_fbtrue (code, 0);
4609 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4611 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4613 mips_fbtrue (code, 0);
4615 mips_fbfalse (code, 0);
4619 mips_patch (buf, (guint32)code);
4623 guint32 *branch_patch;
4625 mips_mfc1 (code, mips_at, ins->sreg1+1);
4626 mips_srl (code, mips_at, mips_at, 16+4);
4627 mips_andi (code, mips_at, mips_at, 2047);
4628 mips_addiu (code, mips_at, mips_at, -2047);
4630 branch_patch = (guint32 *)(void *)code;
4631 mips_bne (code, mips_at, mips_zero, 0);
4634 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4635 mips_patch (branch_patch, (guint32)code);
4636 mips_fmovd (code, ins->dreg, ins->sreg1);
4640 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4641 mips_load (code, ins->dreg, 0x0f0f0f0f);
4646 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4647 g_assert_not_reached ();
4650 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4651 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4652 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4653 g_assert_not_reached ();
4659 last_offset = offset;
4662 cfg->code_len = code - cfg->native_code;
4666 mono_arch_register_lowlevel_calls (void)
4671 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4673 MonoJumpInfo *patch_info;
4675 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4676 unsigned char *ip = patch_info->ip.i + code;
4677 const unsigned char *target = NULL;
4679 switch (patch_info->type) {
4680 case MONO_PATCH_INFO_IP:
4681 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4683 case MONO_PATCH_INFO_SWITCH: {
4684 gpointer *table = (gpointer *)patch_info->data.table->table;
4687 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4689 for (i = 0; i < patch_info->data.table->table_size; i++) {
4690 table [i] = (int)patch_info->data.table->table [i] + code;
4694 case MONO_PATCH_INFO_METHODCONST:
4695 case MONO_PATCH_INFO_CLASS:
4696 case MONO_PATCH_INFO_IMAGE:
4697 case MONO_PATCH_INFO_FIELD:
4698 case MONO_PATCH_INFO_VTABLE:
4699 case MONO_PATCH_INFO_IID:
4700 case MONO_PATCH_INFO_SFLDA:
4701 case MONO_PATCH_INFO_LDSTR:
4702 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4703 case MONO_PATCH_INFO_LDTOKEN:
4704 case MONO_PATCH_INFO_R4:
4705 case MONO_PATCH_INFO_R8:
4706 /* from OP_AOTCONST : lui + addiu */
4707 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4708 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4711 case MONO_PATCH_INFO_EXC_NAME:
4712 g_assert_not_reached ();
4713 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4716 case MONO_PATCH_INFO_NONE:
4717 /* everything is dealt with at epilog output time */
4720 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4721 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4728 * Allow tracing to work with this interface (with an optional argument)
4730 * This code is expected to be inserted just after the 'real' prolog code,
4731 * and before the first basic block. We need to allocate a 2nd, temporary
4732 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4736 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4739 int offset = cfg->arch.tracing_offset;
4745 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4746 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4747 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4748 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4749 #if _MIPS_SIM == _ABIN32
4751 /* FIXME: Need a separate region for these */
4752 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4753 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4754 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4755 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4759 mips_load_const (code, mips_a0, cfg->method);
4760 mips_addiu (code, mips_a1, mips_sp, offset);
4761 mips_call (code, mips_t9, func);
4764 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4765 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4766 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4767 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4768 #if _MIPS_SIM == _ABIN32
4771 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4772 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4773 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4774 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4785 mips_adjust_stackframe(MonoCompile *cfg)
4788 int delta, threshold, i;
4789 MonoMethodSignature *sig;
4792 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4795 /* adjust cfg->stack_offset for account for down-spilling */
4796 cfg->stack_offset += SIZEOF_REGISTER;
4798 /* re-align cfg->stack_offset if needed (due to var spilling) */
4799 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4800 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4801 if (cfg->verbose_level > 2) {
4802 g_print ("mips_adjust_stackframe:\n");
4803 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4805 threshold = cfg->arch.local_alloc_offset;
4806 ra_offset = cfg->stack_offset - sizeof(gpointer);
4807 if (cfg->verbose_level > 2) {
4808 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4811 sig = mono_method_signature (cfg->method);
4812 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4813 cfg->vret_addr->inst_offset += delta;
4815 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4816 MonoInst *inst = cfg->args [i];
4818 inst->inst_offset += delta;
4822 * loads and stores based off the frame reg that (used to) lie
4823 * above the spill var area need to be increased by 'delta'
4824 * to make room for the spill vars.
4826 /* Need to find loads and stores to adjust that
4827 * are above where the spillvars were inserted, but
4828 * which are not the spillvar references themselves.
4830 * Idea - since all offsets from fp are positive, make
4831 * spillvar offsets negative to begin with so we can spot
4836 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4840 if (cfg->verbose_level > 2) {
4841 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4843 MONO_BB_FOR_EACH_INS (bb, ins) {
4847 if (cfg->verbose_level > 2) {
4848 mono_print_ins_index (ins_cnt, ins);
4850 /* The == mips_sp tests catch FP spills */
4851 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4852 (ins->inst_basereg == mips_sp))) {
4853 switch (ins->opcode) {
4854 case OP_LOADI8_MEMBASE:
4855 case OP_LOADR8_MEMBASE:
4862 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4863 (ins->dreg == mips_sp))) {
4864 switch (ins->opcode) {
4865 case OP_STOREI8_MEMBASE_REG:
4866 case OP_STORER8_MEMBASE_REG:
4867 case OP_STOREI8_MEMBASE_IMM:
4875 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4878 if (ins->inst_c0 >= threshold) {
4879 ins->inst_c0 += delta;
4880 if (cfg->verbose_level > 2) {
4882 mono_print_ins_index (ins_cnt, ins);
4885 else if (ins->inst_c0 < 0) {
4886 /* Adj_c0 holds the size of the datatype. */
4887 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4888 if (cfg->verbose_level > 2) {
4890 mono_print_ins_index (ins_cnt, ins);
4893 g_assert (ins->inst_c0 != ra_offset);
4896 if (ins->inst_imm >= threshold) {
4897 ins->inst_imm += delta;
4898 if (cfg->verbose_level > 2) {
4900 mono_print_ins_index (ins_cnt, ins);
4903 g_assert (ins->inst_c0 != ra_offset);
4913 * Stack frame layout:
4915 * ------------------- sp + cfg->stack_usage + cfg->param_area
4916 * param area incoming
4917 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4919 * ------------------- sp + cfg->stack_usage
4921 * ------------------- sp + cfg->stack_usage-4
4923 * ------------------- sp +
4924 * MonoLMF structure optional
4925 * ------------------- sp + cfg->arch.lmf_offset
4926 * saved registers s0-s8
4927 * ------------------- sp + cfg->arch.iregs_offset
4929 * ------------------- sp + cfg->param_area
4930 * param area outgoing
4931 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4933 * ------------------- sp
4937 mono_arch_emit_prolog (MonoCompile *cfg)
4939 MonoMethod *method = cfg->method;
4940 MonoMethodSignature *sig;
4942 int alloc_size, pos, i, max_offset;
4943 int alloc2_size = 0;
4947 guint32 iregs_to_save = 0;
4949 guint32 fregs_to_save = 0;
4951 /* lmf_offset is the offset of the LMF from our stack pointer. */
4952 guint32 lmf_offset = cfg->arch.lmf_offset;
4956 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4960 cfg->flags |= MONO_CFG_HAS_CALLS;
4962 sig = mono_method_signature (method);
4963 cfg->code_size = 768 + sig->param_count * 20;
4964 code = cfg->native_code = g_malloc (cfg->code_size);
4967 * compute max_offset in order to use short forward jumps.
4970 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4971 MonoInst *ins = bb->code;
4972 bb->max_offset = max_offset;
4974 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4977 MONO_BB_FOR_EACH_INS (bb, ins)
4978 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4980 if (max_offset > 0xffff)
4981 cfg->arch.long_branch = TRUE;
4984 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4985 * This means that we have to adjust the offsets inside instructions which reference
4986 * arguments received on the stack, since the initial offset doesn't take into
4987 * account spill slots.
4989 mips_adjust_stackframe (cfg);
4991 /* Offset between current sp and the CFA */
4993 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4995 /* stack_offset should not be changed here. */
4996 alloc_size = cfg->stack_offset;
4997 cfg->stack_usage = alloc_size;
4999 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5002 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5004 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
5005 fregs_to_save |= (fregs_to_save << 1);
5008 /* If the stack size is too big, save 1024 bytes to start with
5009 * so the prologue can use imm16(reg) addressing, then allocate
5010 * the rest of the frame.
5012 if (alloc_size > ((1 << 15) - 1024)) {
5013 alloc2_size = alloc_size - 1024;
5017 g_assert (mips_is_imm16 (-alloc_size));
5018 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
5019 cfa_offset = alloc_size;
5020 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5023 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5024 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5025 if (mips_is_imm16(offset))
5026 mips_sw (code, mips_ra, mips_sp, offset);
5028 g_assert_not_reached ();
5030 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5031 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5034 /* XXX - optimize this later to not save all regs if LMF constructed */
5035 pos = cfg->arch.iregs_offset - alloc2_size;
5037 if (iregs_to_save) {
5038 /* save used registers in own stack frame (at pos) */
5039 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5040 if (iregs_to_save & (1 << i)) {
5041 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5042 g_assert (mips_is_imm16(pos));
5043 MIPS_SW (code, i, mips_sp, pos);
5044 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5045 pos += SIZEOF_REGISTER;
5050 // FIXME: Don't save registers twice if there is an LMF
5051 // s8 has to be special cased since it is overwritten with the updated value
5053 if (method->save_lmf) {
5054 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5055 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5056 g_assert (mips_is_imm16(offset));
5057 if (MIPS_LMF_IREGMASK & (1 << i))
5058 MIPS_SW (code, i, mips_sp, offset);
5063 /* Save float registers */
5064 if (fregs_to_save) {
5065 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5066 if (fregs_to_save & (1 << i)) {
5067 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5068 g_assert (mips_is_imm16(pos));
5069 mips_swc1 (code, i, mips_sp, pos);
5070 pos += sizeof (gulong);
5075 if (method->save_lmf) {
5076 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5077 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5078 g_assert (mips_is_imm16(offset));
5079 mips_swc1 (code, i, mips_sp, offset);
5084 if (cfg->frame_reg != mips_sp) {
5085 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5086 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5088 if (method->save_lmf) {
5089 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5090 g_assert (mips_is_imm16(offset));
5091 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5095 /* store runtime generic context */
5096 if (cfg->rgctx_var) {
5097 MonoInst *ins = cfg->rgctx_var;
5099 g_assert (ins->opcode == OP_REGOFFSET);
5101 g_assert (mips_is_imm16 (ins->inst_offset));
5102 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5105 /* load arguments allocated to register from the stack */
5108 if (!cfg->arch.cinfo)
5109 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
5110 cinfo = cfg->arch.cinfo;
5112 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5113 ArgInfo *ainfo = &cinfo->ret;
5114 inst = cfg->vret_addr;
5115 if (inst->opcode == OP_REGVAR)
5116 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5117 else if (mips_is_imm16 (inst->inst_offset)) {
5118 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5120 mips_load_const (code, mips_at, inst->inst_offset);
5121 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5122 mips_sw (code, ainfo->reg, mips_at, 0);
5126 if (sig->call_convention == MONO_CALL_VARARG) {
5127 ArgInfo *cookie = &cinfo->sig_cookie;
5128 int offset = alloc_size + cookie->offset;
5130 /* Save the sig cookie address */
5131 g_assert (cookie->storage == ArgOnStack);
5133 g_assert (mips_is_imm16(offset));
5134 mips_addi (code, mips_at, cfg->frame_reg, offset);
5135 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5138 /* Keep this in sync with emit_load_volatile_arguments */
5139 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5140 ArgInfo *ainfo = cinfo->args + i;
5141 inst = cfg->args [pos];
5143 if (cfg->verbose_level > 2)
5144 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5145 if (inst->opcode == OP_REGVAR) {
5146 /* Argument ends up in a register */
5147 if (ainfo->storage == ArgInIReg)
5148 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5149 else if (ainfo->storage == ArgInFReg) {
5150 g_assert_not_reached();
5152 ppc_fmr (code, inst->dreg, ainfo->reg);
5155 else if (ainfo->storage == ArgOnStack) {
5156 int offset = cfg->stack_usage + ainfo->offset;
5157 g_assert (mips_is_imm16(offset));
5158 mips_lw (code, inst->dreg, mips_sp, offset);
5160 g_assert_not_reached ();
5162 if (cfg->verbose_level > 2)
5163 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5165 /* Argument ends up on the stack */
5166 if (ainfo->storage == ArgInIReg) {
5168 /* Incoming parameters should be above this frame */
5169 if (cfg->verbose_level > 2)
5170 g_print ("stack slot at %d of %d+%d\n",
5171 inst->inst_offset, alloc_size, alloc2_size);
5172 /* g_assert (inst->inst_offset >= alloc_size); */
5173 g_assert (inst->inst_basereg == cfg->frame_reg);
5174 basereg_offset = inst->inst_offset - alloc2_size;
5175 g_assert (mips_is_imm16 (basereg_offset));
5176 switch (ainfo->size) {
5178 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5181 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5185 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5188 #if (SIZEOF_REGISTER == 4)
5189 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5190 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5191 #elif (SIZEOF_REGISTER == 8)
5192 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5196 g_assert_not_reached ();
5199 } else if (ainfo->storage == ArgOnStack) {
5201 * Argument comes in on the stack, and ends up on the stack
5202 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5203 * 8 and 16 bit quantities. Shorten them in place.
5205 g_assert (mips_is_imm16 (inst->inst_offset));
5206 switch (ainfo->size) {
5208 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5209 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5212 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5213 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5220 g_assert_not_reached ();
5222 } else if (ainfo->storage == ArgInFReg) {
5223 g_assert (mips_is_imm16 (inst->inst_offset));
5224 g_assert (mips_is_imm16 (inst->inst_offset+4));
5225 if (ainfo->size == 8) {
5226 #if _MIPS_SIM == _ABIO32
5227 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5228 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5229 #elif _MIPS_SIM == _ABIN32
5230 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5233 else if (ainfo->size == 4)
5234 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5236 g_assert_not_reached ();
5237 } else if (ainfo->storage == ArgStructByVal) {
5239 int doffset = inst->inst_offset;
5241 g_assert (mips_is_imm16 (inst->inst_offset));
5242 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5243 /* Push the argument registers into their stack slots */
5244 for (i = 0; i < ainfo->size; ++i) {
5245 g_assert (mips_is_imm16(doffset));
5246 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5247 doffset += SIZEOF_REGISTER;
5249 } else if (ainfo->storage == ArgStructByAddr) {
5250 g_assert (mips_is_imm16 (inst->inst_offset));
5251 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5252 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5254 g_assert_not_reached ();
5259 if (method->save_lmf) {
5260 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5261 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5263 if (lmf_pthread_key != -1) {
5264 g_assert_not_reached();
5266 emit_tls_access (code, mips_temp, lmf_pthread_key);
5268 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5269 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5270 g_assert (mips_is_imm16(offset));
5271 mips_addiu (code, mips_a0, mips_temp, offset);
5274 /* This can/will clobber the a0-a3 registers */
5275 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5278 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5279 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5280 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5281 /* new_lmf->previous_lmf = *lmf_addr */
5282 mips_lw (code, mips_at, mips_v0, 0);
5283 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5284 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5285 /* *(lmf_addr) = sp + lmf_offset */
5286 g_assert (mips_is_imm16(lmf_offset));
5287 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5288 mips_sw (code, mips_at, mips_v0, 0);
5290 /* save method info */
5291 mips_load_const (code, mips_at, method);
5292 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5293 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5295 /* save the current IP */
5296 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5297 mips_load_const (code, mips_at, 0x01010101);
5298 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5302 if (mips_is_imm16 (-alloc2_size)) {
5303 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5306 mips_load_const (code, mips_at, -alloc2_size);
5307 mips_addu (code, mips_sp, mips_sp, mips_at);
5309 alloc_size += alloc2_size;
5310 cfa_offset += alloc2_size;
5311 if (cfg->frame_reg != mips_sp)
5312 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5314 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5318 #if _MIPS_SIM == _ABIO32
5319 cfg->arch.tracing_offset = cfg->stack_offset;
5320 #elif _MIPS_SIM == _ABIN32
5321 /* no stack slots by default for argument regs, reserve a special block */
5322 g_assert_not_reached ();
5324 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5327 cfg->code_len = code - cfg->native_code;
5328 g_assert (cfg->code_len < cfg->code_size);
5342 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5345 int save_mode = SAVE_NONE;
5347 MonoMethod *method = cfg->method;
5348 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type;
5349 int save_offset = MIPS_STACK_PARAM_OFFSET;
5351 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5353 offset = code - cfg->native_code;
5354 /* we need about 16 instructions */
5355 if (offset > (cfg->code_size - 16 * 4)) {
5356 cfg->code_size *= 2;
5357 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5358 code = cfg->native_code + offset;
5363 case MONO_TYPE_VOID:
5364 /* special case string .ctor icall */
5365 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5366 save_mode = SAVE_ONE;
5368 save_mode = SAVE_NONE;
5372 save_mode = SAVE_FP;
5374 case MONO_TYPE_VALUETYPE:
5375 save_mode = SAVE_STRUCT;
5379 #if SIZEOF_REGISTER == 4
5380 save_mode = SAVE_TWO;
5381 #elif SIZEOF_REGISTER == 8
5382 save_mode = SAVE_ONE;
5386 save_mode = SAVE_ONE;
5390 mips_addiu (code, mips_sp, mips_sp, -32);
5391 g_assert (mips_is_imm16(save_offset));
5392 switch (save_mode) {
5394 mips_sw (code, mips_v0, mips_sp, save_offset);
5395 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5396 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5397 if (enable_arguments) {
5398 MIPS_MOVE (code, mips_a1, mips_v0);
5399 MIPS_MOVE (code, mips_a2, mips_v1);
5403 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5404 if (enable_arguments) {
5405 MIPS_MOVE (code, mips_a1, mips_v0);
5409 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5410 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5411 mips_lw (code, mips_a0, mips_sp, save_offset);
5412 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5413 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5420 mips_load_const (code, mips_a0, cfg->method);
5421 mips_call (code, mips_t9, func);
5423 switch (save_mode) {
5425 mips_lw (code, mips_v0, mips_sp, save_offset);
5426 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5427 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5430 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5433 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5440 mips_addiu (code, mips_sp, mips_sp, 32);
5447 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5449 MonoMethod *method = cfg->method;
5451 int max_epilog_size = 16 + 20*4;
5452 int alloc2_size = 0;
5453 guint32 iregs_to_restore;
5455 guint32 fregs_to_restore;
5458 if (cfg->method->save_lmf)
5459 max_epilog_size += 128;
5461 if (mono_jit_trace_calls != NULL)
5462 max_epilog_size += 50;
5464 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5465 max_epilog_size += 50;
5468 pos = code - cfg->native_code;
5469 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5470 cfg->code_size *= 2;
5471 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5472 cfg->stat_code_reallocs++;
5476 * Keep in sync with OP_JMP
5479 code = cfg->native_code + pos;
5481 code = cfg->native_code + cfg->code_len;
5483 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5484 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5486 if (cfg->frame_reg != mips_sp) {
5487 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5489 /* If the stack frame is really large, deconstruct it in two steps */
5490 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5491 alloc2_size = cfg->stack_usage - 1024;
5492 /* partially deconstruct the stack */
5493 mips_load_const (code, mips_at, alloc2_size);
5494 mips_addu (code, mips_sp, mips_sp, mips_at);
5496 pos = cfg->arch.iregs_offset - alloc2_size;
5497 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5498 if (iregs_to_restore) {
5499 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5500 if (iregs_to_restore & (1 << i)) {
5501 g_assert (mips_is_imm16(pos));
5502 MIPS_LW (code, i, mips_sp, pos);
5503 pos += SIZEOF_REGISTER;
5510 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5512 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5513 fregs_to_restore |= (fregs_to_restore << 1);
5515 if (fregs_to_restore) {
5516 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5517 if (fregs_to_restore & (1 << i)) {
5518 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5519 g_assert (mips_is_imm16(pos));
5520 mips_lwc1 (code, i, mips_sp, pos);
5527 /* Unlink the LMF if necessary */
5528 if (method->save_lmf) {
5529 int lmf_offset = cfg->arch.lmf_offset;
5531 /* t0 = current_lmf->previous_lmf */
5532 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5533 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5535 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5536 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5537 /* (*lmf_addr) = previous_lmf */
5538 mips_sw (code, mips_temp, mips_t1, 0);
5542 /* Restore the fp */
5543 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5546 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5547 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5548 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5550 /* Restore the stack pointer */
5551 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5552 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5554 /* Caller will emit either return or tail-call sequence */
5556 cfg->code_len = code - cfg->native_code;
5558 g_assert (cfg->code_len < cfg->code_size);
5563 mono_arch_emit_epilog (MonoCompile *cfg)
5567 code = mono_arch_emit_epilog_sub (cfg, NULL);
5569 mips_jr (code, mips_ra);
5572 cfg->code_len = code - cfg->native_code;
5574 g_assert (cfg->code_len < cfg->code_size);
5577 /* remove once throw_exception_by_name is eliminated */
5580 exception_id_by_name (const char *name)
5582 if (strcmp (name, "IndexOutOfRangeException") == 0)
5583 return MONO_EXC_INDEX_OUT_OF_RANGE;
5584 if (strcmp (name, "OverflowException") == 0)
5585 return MONO_EXC_OVERFLOW;
5586 if (strcmp (name, "ArithmeticException") == 0)
5587 return MONO_EXC_ARITHMETIC;
5588 if (strcmp (name, "DivideByZeroException") == 0)
5589 return MONO_EXC_DIVIDE_BY_ZERO;
5590 if (strcmp (name, "InvalidCastException") == 0)
5591 return MONO_EXC_INVALID_CAST;
5592 if (strcmp (name, "NullReferenceException") == 0)
5593 return MONO_EXC_NULL_REF;
5594 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5595 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5596 if (strcmp (name, "ArgumentException") == 0)
5597 return MONO_EXC_ARGUMENT;
5598 g_error ("Unknown intrinsic exception %s\n", name);
5604 mono_arch_emit_exceptions (MonoCompile *cfg)
5607 MonoJumpInfo *patch_info;
5610 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5611 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5612 int max_epilog_size = 50;
5614 /* count the number of exception infos */
5617 * make sure we have enough space for exceptions
5618 * 24 is the simulated call to throw_exception_by_name
5620 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5622 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5623 i = exception_id_by_name (patch_info->data.target);
5624 g_assert (i < MONO_EXC_INTRINS_NUM);
5625 if (!exc_throw_found [i]) {
5626 max_epilog_size += 12;
5627 exc_throw_found [i] = TRUE;
5633 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5634 cfg->code_size *= 2;
5635 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5636 cfg->stat_code_reallocs++;
5639 code = cfg->native_code + cfg->code_len;
5641 /* add code to raise exceptions */
5642 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5643 switch (patch_info->type) {
5644 case MONO_PATCH_INFO_EXC: {
5646 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5648 i = exception_id_by_name (patch_info->data.target);
5649 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5650 if (!exc_throw_pos [i]) {
5653 exc_throw_pos [i] = code;
5654 //g_print ("exc: writing stub at %p\n", code);
5655 mips_load_const (code, mips_a0, patch_info->data.target);
5656 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5657 mips_load_const (code, mips_t9, addr);
5658 mips_jr (code, mips_t9);
5661 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5663 /* Turn into a Relative patch, pointing at code stub */
5664 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5665 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5667 g_assert_not_reached();
5677 cfg->code_len = code - cfg->native_code;
5679 g_assert (cfg->code_len < cfg->code_size);
5684 * Thread local storage support
5687 setup_tls_access (void)
5690 //guint32 *ins, *code;
5692 if (tls_mode == TLS_MODE_FAILED)
5695 if (g_getenv ("MONO_NO_TLS")) {
5696 tls_mode = TLS_MODE_FAILED;
5700 if (tls_mode == TLS_MODE_DETECT) {
5702 tls_mode = TLS_MODE_FAILED;
5706 ins = (guint32*)pthread_getspecific;
5707 /* uncond branch to the real method */
5708 if ((*ins >> 26) == 18) {
5710 val = (*ins & ~3) << 6;
5714 ins = (guint32*)val;
5716 ins = (guint32*) ((char*)ins + val);
5719 code = &cmplwi_1023;
5720 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5722 ppc_li (code, ppc_r4, 0x48);
5725 if (*ins == cmplwi_1023) {
5726 int found_lwz_284 = 0;
5727 for (ptk = 0; ptk < 20; ++ptk) {
5729 if (!*ins || *ins == blr_ins)
5731 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5736 if (!found_lwz_284) {
5737 tls_mode = TLS_MODE_FAILED;
5740 tls_mode = TLS_MODE_LTHREADS;
5741 } else if (*ins == li_0x48) {
5743 /* uncond branch to the real method */
5744 if ((*ins >> 26) == 18) {
5746 val = (*ins & ~3) << 6;
5750 ins = (guint32*)val;
5752 ins = (guint32*) ((char*)ins + val);
5755 ppc_li (code, ppc_r0, 0x7FF2);
5756 if (ins [1] == val) {
5757 /* Darwin on G4, implement */
5758 tls_mode = TLS_MODE_FAILED;
5762 ppc_mfspr (code, ppc_r3, 104);
5763 if (ins [1] != val) {
5764 tls_mode = TLS_MODE_FAILED;
5767 tls_mode = TLS_MODE_DARWIN_G5;
5770 tls_mode = TLS_MODE_FAILED;
5774 tls_mode = TLS_MODE_FAILED;
5779 if (monodomain_key == -1) {
5780 ptk = mono_domain_get_tls_key ();
5782 monodomain_key = ptk;
5784 if (lmf_pthread_key == -1) {
5785 ptk = mono_jit_tls_id;
5787 /*g_print ("MonoLMF at: %d\n", ptk);*/
5788 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5789 init_tls_failed = 1;
5792 lmf_pthread_key = ptk;
5795 if (monothread_key == -1) {
5796 ptk = mono_thread_get_tls_key ();
5798 monothread_key = ptk;
5799 /*g_print ("thread inited: %d\n", ptk);*/
5801 /*g_print ("thread not inited yet %d\n", ptk);*/
5807 mono_arch_finish_init (void)
5809 setup_tls_access ();
5813 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5818 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5820 int this_dreg = mips_a0;
5823 this_dreg = mips_a1;
5825 /* add the this argument */
5826 if (this_reg != -1) {
5828 MONO_INST_NEW (cfg, this, OP_MOVE);
5829 this->type = this_type;
5830 this->sreg1 = this_reg;
5831 this->dreg = mono_alloc_ireg (cfg);
5832 mono_bblock_add_inst (cfg->cbb, this);
5833 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5838 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5839 vtarg->type = STACK_MP;
5840 vtarg->sreg1 = vt_reg;
5841 vtarg->dreg = mono_alloc_ireg (cfg);
5842 mono_bblock_add_inst (cfg->cbb, vtarg);
5843 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5848 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5850 MonoInst *ins = NULL;
5856 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5862 mono_arch_print_tree (MonoInst *tree, int arity)
5867 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5871 setup_tls_access ();
5872 if (monodomain_key == -1)
5875 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5876 ins->inst_offset = monodomain_key;
5881 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5883 return ctx->sc_regs [reg];
5886 #ifdef MONO_ARCH_HAVE_IMT
5888 #define ENABLE_WRONG_METHOD_CHECK 0
5890 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5891 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5893 #define LOADSTORE_SIZE 4
5894 #define JUMP_IMM_SIZE 16
5895 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5896 #define LOAD_CONST_SIZE 8
5897 #define JUMP_JR_SIZE 8
5900 * LOCKING: called with the domain lock held
5903 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5904 gpointer fail_tramp)
5908 guint8 *code, *start, *patch;
5910 for (i = 0; i < count; ++i) {
5911 MonoIMTCheckItem *item = imt_entries [i];
5913 if (item->is_equals) {
5914 if (item->check_target_idx) {
5915 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5916 if (item->has_target_code)
5917 item->chunk_size += LOAD_CONST_SIZE;
5919 item->chunk_size += LOADSTORE_SIZE;
5922 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5923 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5924 if (!item->has_target_code)
5925 item->chunk_size += LOADSTORE_SIZE;
5927 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5928 #if ENABLE_WRONG_METHOD_CHECK
5929 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5934 item->chunk_size += CMP_SIZE + BR_SIZE;
5935 imt_entries [item->check_target_idx]->compare_done = TRUE;
5937 size += item->chunk_size;
5939 /* the initial load of the vtable address */
5940 size += MIPS_LOAD_SEQUENCE_LENGTH;
5942 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5944 code = mono_domain_code_reserve (domain, size);
5948 /* t7 points to the vtable */
5949 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5951 for (i = 0; i < count; ++i) {
5952 MonoIMTCheckItem *item = imt_entries [i];
5954 item->code_target = code;
5955 if (item->is_equals) {
5956 if (item->check_target_idx) {
5957 mips_load_const (code, mips_temp, (gsize)item->key);
5958 item->jmp_code = code;
5959 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5961 if (item->has_target_code) {
5962 mips_load_const (code, mips_t9,
5963 item->value.target_code);
5966 mips_lw (code, mips_t9, mips_t7,
5967 (sizeof (gpointer) * item->value.vtable_slot));
5969 mips_jr (code, mips_t9);
5973 mips_load_const (code, mips_temp, (gsize)item->key);
5975 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5977 if (item->has_target_code) {
5978 mips_load_const (code, mips_t9,
5979 item->value.target_code);
5982 mips_load_const (code, mips_at,
5983 & (vtable->vtable [item->value.vtable_slot]));
5984 mips_lw (code, mips_t9, mips_at, 0);
5986 mips_jr (code, mips_t9);
5988 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5989 mips_load_const (code, mips_t9, fail_tramp);
5990 mips_jr (code, mips_t9);
5993 /* enable the commented code to assert on wrong method */
5994 #if ENABLE_WRONG_METHOD_CHECK
5995 ppc_load (code, ppc_r0, (guint32)item->key);
5996 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5998 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
6000 mips_lw (code, mips_t9, mips_t7,
6001 (sizeof (gpointer) * item->value.vtable_slot));
6002 mips_jr (code, mips_t9);
6005 #if ENABLE_WRONG_METHOD_CHECK
6006 ppc_patch (patch, code);
6012 mips_load_const (code, mips_temp, (gulong)item->key);
6013 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
6015 item->jmp_code = code;
6016 mips_beq (code, mips_temp, mips_zero, 0);
6020 /* patch the branches to get to the target items */
6021 for (i = 0; i < count; ++i) {
6022 MonoIMTCheckItem *item = imt_entries [i];
6023 if (item->jmp_code && item->check_target_idx) {
6024 mips_patch ((guint32 *)item->jmp_code,
6025 (guint32)imt_entries [item->check_target_idx]->code_target);
6030 mono_stats.imt_thunks_size += code - start;
6031 g_assert (code - start <= size);
6032 mono_arch_flush_icache (start, size);
6037 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6039 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6044 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6046 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6049 /* Soft Debug support */
6050 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6053 * mono_arch_set_breakpoint:
6055 * See mini-amd64.c for docs.
6058 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6061 guint32 addr = (guint32)bp_trigger_page;
6063 mips_load_const (code, mips_t9, addr);
6064 mips_lw (code, mips_t9, mips_t9, 0);
6066 mono_arch_flush_icache (ip, code - ip);
6070 * mono_arch_clear_breakpoint:
6072 * See mini-amd64.c for docs.
6075 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6083 mono_arch_flush_icache (ip, code - ip);
6087 * mono_arch_start_single_stepping:
6089 * See mini-amd64.c for docs.
6092 mono_arch_start_single_stepping (void)
6094 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6098 * mono_arch_stop_single_stepping:
6100 * See mini-amd64.c for docs.
6103 mono_arch_stop_single_stepping (void)
6105 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6109 * mono_arch_is_single_step_event:
6111 * See mini-amd64.c for docs.
6114 mono_arch_is_single_step_event (void *info, void *sigctx)
6116 siginfo_t* sinfo = (siginfo_t*) info;
6117 /* Sometimes the address is off by 4 */
6118 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6125 * mono_arch_is_breakpoint_event:
6127 * See mini-amd64.c for docs.
6130 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6132 siginfo_t* sinfo = (siginfo_t*) info;
6133 /* Sometimes the address is off by 4 */
6134 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6141 * mono_arch_skip_breakpoint:
6143 * See mini-amd64.c for docs.
6146 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6148 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6152 * mono_arch_skip_single_step:
6154 * See mini-amd64.c for docs.
6157 mono_arch_skip_single_step (MonoContext *ctx)
6159 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6163 * mono_arch_get_seq_point_info:
6165 * See mini-amd64.c for docs.
6168 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6174 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */