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/abi-details.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/utils/mono-mmap.h>
22 #include <mono/utils/mono-hwcap.h>
24 #include <mono/arch/mips/mips-codegen.h>
26 #include "mini-mips.h"
31 #define SAVE_FP_REGS 0
33 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
35 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
36 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
37 remember to update cpu-mips.md if you change this */
39 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
40 #define mips_call(c,D,v) do { \
41 guint32 _target = (guint32)(v); \
42 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
43 mips_load_const (c, D, _target); \
44 mips_jalr (c, D, mips_ra); \
47 mips_jumpl (c, _target >> 2); \
59 /* This mutex protects architecture specific caches */
60 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
61 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
62 static mono_mutex_t mini_arch_mutex;
64 int mono_exc_esp_offset = 0;
66 /* Whenever the host is little-endian */
67 static int little_endian;
68 /* Index of ms word/register */
69 static int ls_word_idx;
70 /* Index of ls word/register */
71 static int ms_word_idx;
72 /* Same for offsets */
73 static int ls_word_offset;
74 static int ms_word_offset;
77 * The code generated for sequence points reads from this location, which is
78 * made read-only when single stepping is enabled.
80 static gpointer ss_trigger_page;
82 /* Enabled breakpoints read from this trigger page */
83 static gpointer bp_trigger_page;
86 #define DEBUG(a) if (cfg->verbose_level > 1) a
92 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
94 code = mips_emit_exc_by_name (code, exc_name); \
95 cfg->bb_exit->max_offset += 16; \
98 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
100 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
101 inst->type = STACK_R8; \
103 inst->inst_p0 = (void*)(addr); \
104 mono_bblock_add_inst (cfg->cbb, inst); \
107 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
108 || ((ins)->opcode == OP_ICOMPARE) \
109 || ((ins)->opcode == OP_LCOMPARE)))
110 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
111 || ((ins)->opcode == OP_ICOMPARE_IMM) \
112 || ((ins)->opcode == OP_LCOMPARE_IMM)))
114 #define INS_REWRITE(ins, op, _s1, _s2) do { \
117 ins->opcode = (op); \
122 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
124 ins->opcode = (op); \
126 ins->inst_imm = (_imm); \
130 typedef struct InstList InstList;
148 guint16 vtsize; /* in param area */
151 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
160 gboolean vtype_retaddr;
169 void patch_lui_addiu(guint32 *ip, guint32 val);
170 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
171 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
172 void mips_adjust_stackframe(MonoCompile *cfg);
173 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
174 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
177 /* Not defined in asm/cachectl.h */
178 int cacheflush(char *addr, int nbytes, int cache);
181 mono_arch_flush_icache (guint8 *code, gint size)
183 /* Linux/MIPS specific */
184 cacheflush ((char*)code, size, BCACHE);
188 mono_arch_flush_register_windows (void)
193 mono_arch_is_inst_imm (gint64 imm)
199 mips_emit_exc_by_name(guint8 *code, const char *name)
202 MonoClass *exc_class;
204 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", name);
206 mips_load_const (code, mips_a0, exc_class->type_token);
207 addr = mono_get_throw_corlib_exception ();
208 mips_call (code, mips_t9, addr);
214 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
216 if (mips_is_imm16 (v))
217 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
219 #if SIZEOF_REGISTER == 8
221 /* v is not a sign-extended 32-bit value */
222 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
223 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
224 mips_dsll (code, dreg, dreg, 16);
225 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
226 mips_dsll (code, dreg, dreg, 16);
227 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
231 if (((guint32)v) & (1 << 15)) {
232 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
235 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
237 if (((guint32)v) & 0xffff)
238 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
244 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
247 if (cfg->arch.long_branch) {
250 /* Invert test and emit branch around jump */
253 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
257 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
261 mips_bltz (code, ins->sreg1, br_offset);
265 mips_blez (code, ins->sreg1, br_offset);
269 mips_bgtz (code, ins->sreg1, br_offset);
273 mips_bgez (code, ins->sreg1, br_offset);
277 g_assert_not_reached ();
279 mono_add_patch_info (cfg, code - cfg->native_code,
280 MONO_PATCH_INFO_BB, ins->inst_true_bb);
281 mips_lui (code, mips_at, mips_zero, 0);
282 mips_addiu (code, mips_at, mips_at, 0);
283 mips_jr (code, mips_at);
287 mono_add_patch_info (cfg, code - cfg->native_code,
288 MONO_PATCH_INFO_BB, ins->inst_true_bb);
291 mips_beq (code, ins->sreg1, ins->sreg2, 0);
295 mips_bne (code, ins->sreg1, ins->sreg2, 0);
299 mips_bgez (code, ins->sreg1, 0);
303 mips_bgtz (code, ins->sreg1, 0);
307 mips_blez (code, ins->sreg1, 0);
311 mips_bltz (code, ins->sreg1, 0);
315 g_assert_not_reached ();
321 /* XXX - big-endian dependent? */
323 patch_lui_addiu(guint32 *ip, guint32 val)
325 guint16 *__lui_addiu = (guint16*)(void *)(ip);
328 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
329 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
332 if (((guint32)(val)) & (1 << 15))
333 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
335 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
336 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
337 mono_arch_flush_icache ((guint8 *)ip, 8);
342 mips_patch (guint32 *code, guint32 target)
345 guint32 op = ins >> 26;
346 guint32 diff, offset;
348 g_assert (trap_target != target);
349 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
351 case 0x00: /* jr ra */
352 if (ins == 0x3e00008)
354 g_assert_not_reached ();
358 g_assert (!(target & 0x03));
359 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
360 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
362 mono_arch_flush_icache ((guint8 *)code, 4);
364 case 0x01: /* BLTZ */
367 case 0x06: /* BLEZ */
368 case 0x07: /* BGTZ */
369 case 0x11: /* bc1t */
370 diff = target - (guint32)(code + 1);
371 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
372 g_assert (!(diff & 0x03));
373 offset = ((gint32)diff) >> 2;
374 if (((int)offset) != ((int)(short)offset))
375 g_assert (((int)offset) == ((int)(short)offset));
376 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
378 mono_arch_flush_icache ((guint8 *)code, 4);
380 case 0x0f: /* LUI / ADDIU pair */
381 g_assert ((code[1] >> 26) == 0x9);
382 patch_lui_addiu (code, target);
383 mono_arch_flush_icache ((guint8 *)code, 8);
387 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
388 g_assert_not_reached ();
392 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
395 mono_arch_regname (int reg) {
396 #if _MIPS_SIM == _ABIO32
397 static const char * rnames[] = {
398 "zero", "at", "v0", "v1",
399 "a0", "a1", "a2", "a3",
400 "t0", "t1", "t2", "t3",
401 "t4", "t5", "t6", "t7",
402 "s0", "s1", "s2", "s3",
403 "s4", "s5", "s6", "s7",
404 "t8", "t9", "k0", "k1",
405 "gp", "sp", "fp", "ra"
407 #elif _MIPS_SIM == _ABIN32
408 static const char * rnames[] = {
409 "zero", "at", "v0", "v1",
410 "a0", "a1", "a2", "a3",
411 "a4", "a5", "a6", "a7",
412 "t0", "t1", "t2", "t3",
413 "s0", "s1", "s2", "s3",
414 "s4", "s5", "s6", "s7",
415 "t8", "t9", "k0", "k1",
416 "gp", "sp", "fp", "ra"
419 if (reg >= 0 && reg < 32)
425 mono_arch_fregname (int reg) {
426 static const char * rnames[] = {
427 "f0", "f1", "f2", "f3",
428 "f4", "f5", "f6", "f7",
429 "f8", "f9", "f10", "f11",
430 "f12", "f13", "f14", "f15",
431 "f16", "f17", "f18", "f19",
432 "f20", "f21", "f22", "f23",
433 "f24", "f25", "f26", "f27",
434 "f28", "f29", "f30", "f31"
436 if (reg >= 0 && reg < 32)
441 /* this function overwrites at */
443 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
445 /* XXX write a loop, not an unrolled loop */
447 mips_lw (code, mips_at, sreg, soffset);
448 mips_sw (code, mips_at, dreg, doffset);
457 * mono_arch_get_argument_info:
458 * @csig: a method signature
459 * @param_count: the number of parameters to consider
460 * @arg_info: an array to store the result infos
462 * Gathers information on parameters such as size, alignment and
463 * padding. arg_info should be large enought to hold param_count + 1 entries.
465 * Returns the size of the activation frame.
468 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
470 int k, frame_size = 0;
471 guint32 size, align, pad;
474 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
475 frame_size += sizeof (gpointer);
479 arg_info [0].offset = offset;
482 frame_size += sizeof (gpointer);
486 arg_info [0].size = frame_size;
488 for (k = 0; k < param_count; k++) {
489 size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
491 /* ignore alignment for now */
494 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
495 arg_info [k].pad = pad;
497 arg_info [k + 1].pad = 0;
498 arg_info [k + 1].size = size;
500 arg_info [k + 1].offset = offset;
504 align = MONO_ARCH_FRAME_ALIGNMENT;
505 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
506 arg_info [k].pad = pad;
511 /* The delegate object plus 3 params */
512 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
515 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
517 guint8 *code, *start;
520 start = code = mono_global_codeman_reserve (16);
522 /* Replace the this argument with the target */
523 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
524 mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
525 mips_jr (code, mips_temp);
528 g_assert ((code - start) <= 16);
530 mono_arch_flush_icache (start, 16);
534 size = 16 + param_count * 4;
535 start = code = mono_global_codeman_reserve (size);
537 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
538 /* slide down the arguments */
539 for (i = 0; i < param_count; ++i) {
540 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
542 mips_jr (code, mips_temp);
545 g_assert ((code - start) <= size);
547 mono_arch_flush_icache (start, size);
551 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
553 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
554 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
562 * mono_arch_get_delegate_invoke_impls:
564 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
568 mono_arch_get_delegate_invoke_impls (void)
574 get_delegate_invoke_impl (&info, TRUE, 0);
575 res = g_slist_prepend (res, info);
577 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
578 get_delegate_invoke_impl (&info, FALSE, i);
579 res = g_slist_prepend (res, info);
586 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
588 guint8 *code, *start;
590 /* FIXME: Support more cases */
591 if (MONO_TYPE_ISSTRUCT (sig->ret))
595 static guint8* cached = NULL;
596 mono_mini_arch_lock ();
598 mono_mini_arch_unlock ();
603 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
606 start = get_delegate_invoke_impl (&info, TRUE, 0);
607 mono_tramp_info_register (info, NULL);
610 mono_mini_arch_unlock ();
613 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
616 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
618 for (i = 0; i < sig->param_count; ++i)
619 if (!mono_is_regsize_var (sig->params [i]))
622 mono_mini_arch_lock ();
623 code = cache [sig->param_count];
625 mono_mini_arch_unlock ();
630 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
631 start = mono_aot_get_trampoline (name);
635 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
636 mono_tramp_info_register (info, NULL);
638 cache [sig->param_count] = start;
639 mono_mini_arch_unlock ();
647 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
653 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
656 return (gpointer)regs [mips_a0];
660 * Initialize the cpu to execute managed code.
663 mono_arch_cpu_init (void)
665 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
674 ls_word_offset = ls_word_idx * 4;
675 ms_word_offset = ms_word_idx * 4;
679 * Initialize architecture specific code.
682 mono_arch_init (void)
684 mono_os_mutex_init_recursive (&mini_arch_mutex);
686 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
687 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
688 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
692 * Cleanup architecture specific code.
695 mono_arch_cleanup (void)
697 mono_os_mutex_destroy (&mini_arch_mutex);
701 * This function returns the optimizations supported on this cpu.
704 mono_arch_cpu_optimizations (guint32 *exclude_mask)
708 /* no mips-specific optimizations yet */
714 * This function test for all SIMD functions supported.
716 * Returns a bitmask corresponding to all supported versions.
720 mono_arch_cpu_enumerate_simd_versions (void)
722 /* SIMD is currently unimplemented */
727 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
732 for (i = 0; i < cfg->num_varinfo; i++) {
733 MonoInst *ins = cfg->varinfo [i];
734 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
737 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
740 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
743 /* we can only allocate 32 bit values */
744 if (mono_is_regsize_var (ins->inst_vtype)) {
745 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
746 g_assert (i == vmv->idx);
747 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
755 mono_arch_get_global_int_regs (MonoCompile *cfg)
759 regs = g_list_prepend (regs, (gpointer)mips_s0);
760 regs = g_list_prepend (regs, (gpointer)mips_s1);
761 regs = g_list_prepend (regs, (gpointer)mips_s2);
762 regs = g_list_prepend (regs, (gpointer)mips_s3);
763 regs = g_list_prepend (regs, (gpointer)mips_s4);
764 //regs = g_list_prepend (regs, (gpointer)mips_s5);
765 regs = g_list_prepend (regs, (gpointer)mips_s6);
766 regs = g_list_prepend (regs, (gpointer)mips_s7);
772 * mono_arch_regalloc_cost:
774 * Return the cost, in number of memory references, of the action of
775 * allocating the variable VMV into a register during global register
779 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
786 args_onto_stack (CallInfo *info)
788 g_assert (!info->on_stack);
789 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
790 info->on_stack = TRUE;
791 info->stack_size = MIPS_STACK_PARAM_OFFSET;
794 #if _MIPS_SIM == _ABIO32
796 * O32 calling convention version
800 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
801 /* First, see if we need to drop onto the stack */
802 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
803 args_onto_stack (info);
805 /* Now, place the argument */
806 if (info->on_stack) {
807 ainfo->storage = ArgOnStack;
808 ainfo->reg = mips_sp; /* in the caller */
809 ainfo->offset = info->stack_size;
812 ainfo->storage = ArgInIReg;
813 ainfo->reg = info->gr;
815 info->gr_passed = TRUE;
817 info->stack_size += 4;
821 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
822 /* First, see if we need to drop onto the stack */
823 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
824 args_onto_stack (info);
826 /* Now, place the argument */
827 if (info->on_stack) {
828 g_assert (info->stack_size % 4 == 0);
829 info->stack_size += (info->stack_size % 8);
831 ainfo->storage = ArgOnStack;
832 ainfo->reg = mips_sp; /* in the caller */
833 ainfo->offset = info->stack_size;
836 // info->gr must be a0 or a2
837 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
838 g_assert(info->gr <= MIPS_LAST_ARG_REG);
840 ainfo->storage = ArgInIReg;
841 ainfo->reg = info->gr;
843 info->gr_passed = TRUE;
845 info->stack_size += 8;
849 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
850 /* First, see if we need to drop onto the stack */
851 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
852 args_onto_stack (info);
854 /* Now, place the argument */
855 if (info->on_stack) {
856 ainfo->storage = ArgOnStack;
857 ainfo->reg = mips_sp; /* in the caller */
858 ainfo->offset = info->stack_size;
861 /* Only use FP regs for args if no int args passed yet */
862 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
863 ainfo->storage = ArgInFReg;
864 ainfo->reg = info->fr;
865 /* Even though it's a single-precision float, it takes up two FP regs */
867 /* FP and GP slots do not overlap */
871 /* Passing single-precision float arg in a GP register
872 * such as: func (0, 1.0, 2, 3);
873 * In this case, only one 'gr' register is consumed.
875 ainfo->storage = ArgInIReg;
876 ainfo->reg = info->gr;
879 info->gr_passed = TRUE;
882 info->stack_size += 4;
886 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
887 /* First, see if we need to drop onto the stack */
888 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
889 args_onto_stack (info);
891 /* Now, place the argument */
892 if (info->on_stack) {
893 g_assert(info->stack_size % 4 == 0);
894 info->stack_size += (info->stack_size % 8);
896 ainfo->storage = ArgOnStack;
897 ainfo->reg = mips_sp; /* in the caller */
898 ainfo->offset = info->stack_size;
901 /* Only use FP regs for args if no int args passed yet */
902 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
903 ainfo->storage = ArgInFReg;
904 ainfo->reg = info->fr;
906 /* FP and GP slots do not overlap */
910 // info->gr must be a0 or a2
911 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
912 g_assert(info->gr <= MIPS_LAST_ARG_REG);
914 ainfo->storage = ArgInIReg;
915 ainfo->reg = info->gr;
917 info->gr_passed = TRUE;
920 info->stack_size += 8;
922 #elif _MIPS_SIM == _ABIN32
924 * N32 calling convention version
928 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
929 /* First, see if we need to drop onto the stack */
930 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
931 args_onto_stack (info);
933 /* Now, place the argument */
934 if (info->on_stack) {
935 ainfo->storage = ArgOnStack;
936 ainfo->reg = mips_sp; /* in the caller */
937 ainfo->offset = info->stack_size;
938 info->stack_size += SIZEOF_REGISTER;
941 ainfo->storage = ArgInIReg;
942 ainfo->reg = info->gr;
944 info->gr_passed = TRUE;
949 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
950 /* First, see if we need to drop onto the stack */
951 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
952 args_onto_stack (info);
954 /* Now, place the argument */
955 if (info->on_stack) {
956 g_assert (info->stack_size % 4 == 0);
957 info->stack_size += (info->stack_size % 8);
959 ainfo->storage = ArgOnStack;
960 ainfo->reg = mips_sp; /* in the caller */
961 ainfo->offset = info->stack_size;
962 info->stack_size += SIZEOF_REGISTER;
965 g_assert (info->gr <= MIPS_LAST_ARG_REG);
967 ainfo->storage = ArgInIReg;
968 ainfo->reg = info->gr;
970 info->gr_passed = TRUE;
975 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
976 /* First, see if we need to drop onto the stack */
977 if (!info->on_stack) {
978 if (info->gr > MIPS_LAST_ARG_REG)
979 args_onto_stack (info);
980 else if (info->fr > MIPS_LAST_FPARG_REG)
981 args_onto_stack (info);
984 /* Now, place the argument */
985 if (info->on_stack) {
986 ainfo->storage = ArgOnStack;
987 ainfo->reg = mips_sp; /* in the caller */
988 ainfo->offset = info->stack_size;
989 info->stack_size += FREG_SIZE;
992 ainfo->storage = ArgInFReg;
993 ainfo->reg = info->fr;
995 /* FP and GP slots do not overlap */
1001 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1002 /* First, see if we need to drop onto the stack */
1003 if (!info->on_stack) {
1004 if (info->gr > MIPS_LAST_ARG_REG)
1005 args_onto_stack (info);
1006 else if (info->fr > MIPS_LAST_FPARG_REG)
1007 args_onto_stack (info);
1010 /* Now, place the argument */
1011 if (info->on_stack) {
1012 g_assert(info->stack_size % 4 == 0);
1013 info->stack_size += (info->stack_size % 8);
1015 ainfo->storage = ArgOnStack;
1016 ainfo->reg = mips_sp; /* in the caller */
1017 ainfo->offset = info->stack_size;
1018 info->stack_size += FREG_SIZE;
1021 ainfo->storage = ArgInFReg;
1022 ainfo->reg = info->fr;
1024 /* FP and GP slots do not overlap */
1031 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1034 int n = sig->hasthis + sig->param_count;
1036 MonoType* simpletype;
1038 gboolean is_pinvoke = sig->pinvoke;
1041 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1043 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1045 cinfo->fr = MIPS_FIRST_FPARG_REG;
1046 cinfo->gr = MIPS_FIRST_ARG_REG;
1047 cinfo->stack_size = 0;
1049 DEBUG(printf("calculate_sizes\n"));
1051 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1055 /* handle returning a struct */
1056 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1057 cinfo->struct_ret = cinfo->gr;
1058 add_int32_arg (cinfo, &cinfo->ret);
1062 add_int32_arg (cinfo, cinfo->args + n);
1067 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1068 * the first argument, allowing 'this' to be always passed in the first arg reg.
1069 * Also do this if the first argument is a reference type, since virtual calls
1070 * are sometimes made using calli without sig->hasthis set, like in the delegate
1073 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1075 add_int32_arg (cinfo, cinfo->args + n);
1078 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1082 add_int32_arg (cinfo, &cinfo->ret);
1083 cinfo->struct_ret = cinfo->ret.reg;
1087 add_int32_arg (cinfo, cinfo->args + n);
1091 if (cinfo->vtype_retaddr) {
1092 add_int32_arg (cinfo, &cinfo->ret);
1093 cinfo->struct_ret = cinfo->ret.reg;
1098 DEBUG(printf("params: %d\n", sig->param_count));
1099 for (i = pstart; i < sig->param_count; ++i) {
1100 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1101 /* Prevent implicit arguments and sig_cookie from
1102 being passed in registers */
1103 args_onto_stack (cinfo);
1104 /* Emit the signature cookie just before the implicit arguments */
1105 add_int32_arg (cinfo, &cinfo->sig_cookie);
1107 DEBUG(printf("param %d: ", i));
1108 simpletype = mini_get_underlying_type (sig->params [i]);
1109 switch (simpletype->type) {
1110 case MONO_TYPE_BOOLEAN:
1113 DEBUG(printf("1 byte\n"));
1114 cinfo->args [n].size = 1;
1115 add_int32_arg (cinfo, &cinfo->args[n]);
1118 case MONO_TYPE_CHAR:
1121 DEBUG(printf("2 bytes\n"));
1122 cinfo->args [n].size = 2;
1123 add_int32_arg (cinfo, &cinfo->args[n]);
1128 DEBUG(printf("4 bytes\n"));
1129 cinfo->args [n].size = 4;
1130 add_int32_arg (cinfo, &cinfo->args[n]);
1136 case MONO_TYPE_FNPTR:
1137 case MONO_TYPE_CLASS:
1138 case MONO_TYPE_OBJECT:
1139 case MONO_TYPE_STRING:
1140 case MONO_TYPE_SZARRAY:
1141 case MONO_TYPE_ARRAY:
1142 cinfo->args [n].size = sizeof (gpointer);
1143 add_int32_arg (cinfo, &cinfo->args[n]);
1146 case MONO_TYPE_GENERICINST:
1147 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1148 cinfo->args [n].size = sizeof (gpointer);
1149 add_int32_arg (cinfo, &cinfo->args[n]);
1154 case MONO_TYPE_TYPEDBYREF:
1155 case MONO_TYPE_VALUETYPE: {
1158 int has_offset = FALSE;
1160 gint size, alignment;
1163 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1164 size = sizeof (MonoTypedRef);
1165 alignment = sizeof (gpointer);
1167 klass = mono_class_from_mono_type (sig->params [i]);
1169 size = mono_class_native_size (klass, NULL);
1171 size = mono_class_value_size (klass, NULL);
1172 alignment = mono_class_min_align (klass);
1174 #if MIPS_PASS_STRUCTS_BY_VALUE
1175 /* Need to do alignment if struct contains long or double */
1176 if (alignment > 4) {
1177 /* Drop onto stack *before* looking at
1178 stack_size, if required. */
1179 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1180 args_onto_stack (cinfo);
1181 if (cinfo->stack_size & (alignment - 1)) {
1182 add_int32_arg (cinfo, &dummy_arg);
1184 g_assert (!(cinfo->stack_size & (alignment - 1)));
1188 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1189 mono_class_native_size (sig->params [i]->data.klass, NULL),
1190 cinfo->stack_size, alignment);
1192 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1193 g_assert (cinfo->args [n].size == 0);
1194 g_assert (cinfo->args [n].vtsize == 0);
1195 for (j = 0; j < nwords; ++j) {
1197 add_int32_arg (cinfo, &cinfo->args [n]);
1198 if (cinfo->on_stack)
1201 add_int32_arg (cinfo, &dummy_arg);
1202 if (!has_offset && cinfo->on_stack) {
1203 cinfo->args [n].offset = dummy_arg.offset;
1207 if (cinfo->on_stack)
1208 cinfo->args [n].vtsize += 1;
1210 cinfo->args [n].size += 1;
1212 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1213 cinfo->args [n].storage = ArgStructByVal;
1215 add_int32_arg (cinfo, &cinfo->args[n]);
1216 cinfo->args [n].storage = ArgStructByAddr;
1223 DEBUG(printf("8 bytes\n"));
1224 cinfo->args [n].size = 8;
1225 add_int64_arg (cinfo, &cinfo->args[n]);
1229 DEBUG(printf("R4\n"));
1230 cinfo->args [n].size = 4;
1231 add_float32_arg (cinfo, &cinfo->args[n]);
1235 DEBUG(printf("R8\n"));
1236 cinfo->args [n].size = 8;
1237 add_float64_arg (cinfo, &cinfo->args[n]);
1241 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1245 /* Handle the case where there are no implicit arguments */
1246 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1247 /* Prevent implicit arguments and sig_cookie from
1248 being passed in registers */
1249 args_onto_stack (cinfo);
1250 /* Emit the signature cookie just before the implicit arguments */
1251 add_int32_arg (cinfo, &cinfo->sig_cookie);
1255 simpletype = mini_get_underlying_type (sig->ret);
1256 switch (simpletype->type) {
1257 case MONO_TYPE_BOOLEAN:
1262 case MONO_TYPE_CHAR:
1268 case MONO_TYPE_FNPTR:
1269 case MONO_TYPE_CLASS:
1270 case MONO_TYPE_OBJECT:
1271 case MONO_TYPE_SZARRAY:
1272 case MONO_TYPE_ARRAY:
1273 case MONO_TYPE_STRING:
1274 cinfo->ret.reg = mips_v0;
1278 cinfo->ret.reg = mips_v0;
1282 cinfo->ret.reg = mips_f0;
1283 cinfo->ret.storage = ArgInFReg;
1285 case MONO_TYPE_GENERICINST:
1286 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1287 cinfo->ret.reg = mips_v0;
1291 case MONO_TYPE_VALUETYPE:
1292 case MONO_TYPE_TYPEDBYREF:
1294 case MONO_TYPE_VOID:
1297 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1301 /* align stack size to 16 */
1302 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1304 cinfo->stack_usage = cinfo->stack_size;
1309 debug_omit_fp (void)
1312 return mono_debug_count ();
1319 * mono_arch_compute_omit_fp:
1321 * Determine whenever the frame pointer can be eliminated.
1324 mono_arch_compute_omit_fp (MonoCompile *cfg)
1326 MonoMethodSignature *sig;
1327 MonoMethodHeader *header;
1331 if (cfg->arch.omit_fp_computed)
1334 header = cfg->header;
1336 sig = mono_method_signature (cfg->method);
1338 if (!cfg->arch.cinfo)
1339 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1340 cinfo = cfg->arch.cinfo;
1343 * FIXME: Remove some of the restrictions.
1345 cfg->arch.omit_fp = TRUE;
1346 cfg->arch.omit_fp_computed = TRUE;
1348 if (cfg->disable_omit_fp)
1349 cfg->arch.omit_fp = FALSE;
1350 if (!debug_omit_fp ())
1351 cfg->arch.omit_fp = FALSE;
1352 if (cfg->method->save_lmf)
1353 cfg->arch.omit_fp = FALSE;
1354 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1355 cfg->arch.omit_fp = FALSE;
1356 if (header->num_clauses)
1357 cfg->arch.omit_fp = FALSE;
1358 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1359 cfg->arch.omit_fp = FALSE;
1360 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1361 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1362 cfg->arch.omit_fp = FALSE;
1364 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1365 * there are stack arguments.
1368 if (cinfo->stack_usage)
1369 cfg->arch.omit_fp = FALSE;
1373 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1374 MonoInst *ins = cfg->varinfo [i];
1377 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1380 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1384 * Set var information according to the calling convention. mips version.
1385 * The locals var stuff should most likely be split in another method.
1388 mono_arch_allocate_vars (MonoCompile *cfg)
1390 MonoMethodSignature *sig;
1391 MonoMethodHeader *header;
1393 int i, offset, size, align, curinst;
1394 int frame_reg = mips_sp;
1395 guint32 iregs_to_save = 0;
1397 guint32 fregs_to_restore;
1401 sig = mono_method_signature (cfg->method);
1403 if (!cfg->arch.cinfo)
1404 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1405 cinfo = cfg->arch.cinfo;
1407 mono_arch_compute_omit_fp (cfg);
1409 /* spill down, we'll fix it in a separate pass */
1410 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1412 /* allow room for the vararg method args: void* and long/double */
1413 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1414 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1416 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1417 * call convs needs to be handled this way.
1419 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1420 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1422 /* gtk-sharp and other broken code will dllimport vararg functions even with
1423 * non-varargs signatures. Since there is little hope people will get this right
1424 * we assume they won't.
1426 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1427 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1429 /* a0-a3 always present */
1430 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1432 header = cfg->header;
1434 if (cfg->arch.omit_fp)
1435 frame_reg = mips_sp;
1437 frame_reg = mips_fp;
1438 cfg->frame_reg = frame_reg;
1439 if (frame_reg != mips_sp) {
1440 cfg->used_int_regs |= 1 << frame_reg;
1445 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1446 /* FIXME: handle long and FP values */
1447 switch (mini_get_underlying_type (sig->ret)->type) {
1448 case MONO_TYPE_VOID:
1452 cfg->ret->opcode = OP_REGVAR;
1453 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1456 cfg->ret->opcode = OP_REGVAR;
1457 cfg->ret->inst_c0 = mips_v0;
1461 /* Space for outgoing parameters, including a0-a3 */
1462 offset += cfg->param_area;
1464 /* allow room to save the return value (if it's a struct) */
1465 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1468 /* Now handle the local variables */
1470 curinst = cfg->locals_start;
1471 for (i = curinst; i < cfg->num_varinfo; ++i) {
1472 inst = cfg->varinfo [i];
1473 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1476 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1477 * pinvoke wrappers when they call functions returning structure
1479 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1480 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1482 size = mono_type_size (inst->inst_vtype, &align);
1484 offset += align - 1;
1485 offset &= ~(align - 1);
1486 inst->inst_offset = offset;
1487 inst->opcode = OP_REGOFFSET;
1488 inst->inst_basereg = frame_reg;
1490 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1493 /* Space for LMF (if needed) */
1494 if (cfg->method->save_lmf) {
1495 /* align the offset to 16 bytes */
1496 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1497 cfg->arch.lmf_offset = offset;
1498 offset += sizeof (MonoLMF);
1501 if (sig->call_convention == MONO_CALL_VARARG) {
1505 /* Allocate a local slot to hold the sig cookie address */
1506 offset += align - 1;
1507 offset &= ~(align - 1);
1508 cfg->sig_cookie = offset;
1512 offset += SIZEOF_REGISTER - 1;
1513 offset &= ~(SIZEOF_REGISTER - 1);
1515 /* Space for saved registers */
1516 cfg->arch.iregs_offset = offset;
1517 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1518 if (iregs_to_save) {
1519 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1520 if (iregs_to_save & (1 << i)) {
1521 offset += SIZEOF_REGISTER;
1526 /* saved float registers */
1528 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1529 if (fregs_to_restore) {
1530 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1531 if (fregs_to_restore & (1 << i)) {
1532 offset += sizeof(double);
1538 #if _MIPS_SIM == _ABIO32
1539 /* Now add space for saving the ra */
1540 offset += SIZEOF_VOID_P;
1543 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1544 cfg->stack_offset = offset;
1545 cfg->arch.local_alloc_offset = cfg->stack_offset;
1549 * Now allocate stack slots for the int arg regs (a0 - a3)
1550 * On MIPS o32, these are just above the incoming stack pointer
1551 * Even if the arg has been assigned to a regvar, it gets a stack slot
1554 /* Return struct-by-value results in a hidden first argument */
1555 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1556 cfg->vret_addr->opcode = OP_REGOFFSET;
1557 cfg->vret_addr->inst_c0 = mips_a0;
1558 cfg->vret_addr->inst_offset = offset;
1559 cfg->vret_addr->inst_basereg = frame_reg;
1560 offset += SIZEOF_REGISTER;
1563 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1564 inst = cfg->args [i];
1565 if (inst->opcode != OP_REGVAR) {
1568 if (sig->hasthis && (i == 0))
1569 arg_type = &mono_defaults.object_class->byval_arg;
1571 arg_type = sig->params [i - sig->hasthis];
1573 inst->opcode = OP_REGOFFSET;
1574 size = mono_type_size (arg_type, &align);
1576 if (size < SIZEOF_REGISTER) {
1577 size = SIZEOF_REGISTER;
1578 align = SIZEOF_REGISTER;
1580 inst->inst_basereg = frame_reg;
1581 offset = (offset + align - 1) & ~(align - 1);
1582 inst->inst_offset = offset;
1584 if (cfg->verbose_level > 1)
1585 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1588 #if _MIPS_SIM == _ABIO32
1589 /* o32: Even a0-a3 get stack slots */
1590 size = SIZEOF_REGISTER;
1591 align = SIZEOF_REGISTER;
1592 inst->inst_basereg = frame_reg;
1593 offset = (offset + align - 1) & ~(align - 1);
1594 inst->inst_offset = offset;
1596 if (cfg->verbose_level > 1)
1597 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1601 #if _MIPS_SIM == _ABIN32
1602 /* Now add space for saving the ra */
1603 offset += SIZEOF_VOID_P;
1606 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1607 cfg->stack_offset = offset;
1608 cfg->arch.local_alloc_offset = cfg->stack_offset;
1613 mono_arch_create_vars (MonoCompile *cfg)
1615 MonoMethodSignature *sig;
1617 sig = mono_method_signature (cfg->method);
1619 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1620 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1621 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1622 printf ("vret_addr = ");
1623 mono_print_ins (cfg->vret_addr);
1628 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1629 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1633 * take the arguments and generate the arch-specific
1634 * instructions to properly call the function in call.
1635 * This includes pushing, moving arguments to the right register
1637 * Issue: who does the spilling if needed, and when?
1640 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1642 MonoMethodSignature *tmp_sig;
1645 if (call->tail_call)
1648 /* FIXME: Add support for signature tokens to AOT */
1649 cfg->disable_aot = TRUE;
1652 * mono_ArgIterator_Setup assumes the signature cookie is
1653 * passed first and all the arguments which were before it are
1654 * passed on the stack after the signature. So compensate by
1655 * passing a different signature.
1657 tmp_sig = mono_metadata_signature_dup (call->signature);
1658 tmp_sig->param_count -= call->signature->sentinelpos;
1659 tmp_sig->sentinelpos = 0;
1660 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1662 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1663 sig_arg->dreg = mono_alloc_ireg (cfg);
1664 sig_arg->inst_p0 = tmp_sig;
1665 MONO_ADD_INS (cfg->cbb, sig_arg);
1667 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1671 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1674 MonoMethodSignature *sig;
1679 sig = call->signature;
1680 n = sig->param_count + sig->hasthis;
1682 cinfo = get_call_info (cfg->mempool, sig);
1683 if (cinfo->struct_ret)
1684 call->used_iregs |= 1 << cinfo->struct_ret;
1686 for (i = 0; i < n; ++i) {
1687 ArgInfo *ainfo = cinfo->args + i;
1690 if (i >= sig->hasthis)
1691 t = sig->params [i - sig->hasthis];
1693 t = &mono_defaults.int_class->byval_arg;
1694 t = mini_get_underlying_type (t);
1696 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1697 /* Emit the signature cookie just before the implicit arguments */
1698 emit_sig_cookie (cfg, call, cinfo);
1701 if (is_virtual && i == 0) {
1702 /* the argument will be attached to the call instrucion */
1703 in = call->args [i];
1704 call->used_iregs |= 1 << ainfo->reg;
1707 in = call->args [i];
1708 if (ainfo->storage == ArgInIReg) {
1709 #if SIZEOF_REGISTER == 4
1710 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1711 MONO_INST_NEW (cfg, ins, OP_MOVE);
1712 ins->dreg = mono_alloc_ireg (cfg);
1713 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1714 MONO_ADD_INS (cfg->cbb, ins);
1715 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1717 MONO_INST_NEW (cfg, ins, OP_MOVE);
1718 ins->dreg = mono_alloc_ireg (cfg);
1719 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1720 MONO_ADD_INS (cfg->cbb, ins);
1721 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1724 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1727 #if PROMOTE_R4_TO_R8
1728 /* ??? - convert to single first? */
1729 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1730 ins->dreg = mono_alloc_freg (cfg);
1731 ins->sreg1 = in->dreg;
1732 MONO_ADD_INS (cfg->cbb, ins);
1737 /* trying to load float value into int registers */
1738 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1739 ins->dreg = mono_alloc_ireg (cfg);
1741 MONO_ADD_INS (cfg->cbb, ins);
1742 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1743 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1744 /* trying to load float value into int registers */
1745 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1746 ins->dreg = mono_alloc_ireg (cfg);
1747 ins->sreg1 = in->dreg;
1748 MONO_ADD_INS (cfg->cbb, ins);
1749 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1751 MONO_INST_NEW (cfg, ins, OP_MOVE);
1752 ins->dreg = mono_alloc_ireg (cfg);
1753 ins->sreg1 = in->dreg;
1754 MONO_ADD_INS (cfg->cbb, ins);
1755 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1757 } else if (ainfo->storage == ArgStructByAddr) {
1758 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1759 ins->opcode = OP_OUTARG_VT;
1760 ins->sreg1 = in->dreg;
1761 ins->klass = in->klass;
1762 ins->inst_p0 = call;
1763 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1764 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1765 MONO_ADD_INS (cfg->cbb, ins);
1766 } else if (ainfo->storage == ArgStructByVal) {
1767 /* this is further handled in mono_arch_emit_outarg_vt () */
1768 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1769 ins->opcode = OP_OUTARG_VT;
1770 ins->sreg1 = in->dreg;
1771 ins->klass = in->klass;
1772 ins->inst_p0 = call;
1773 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1774 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1775 MONO_ADD_INS (cfg->cbb, ins);
1776 } else if (ainfo->storage == ArgOnStack) {
1777 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1778 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1779 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1780 if (t->type == MONO_TYPE_R8)
1781 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1783 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1785 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1787 } else if (ainfo->storage == ArgInFReg) {
1788 if (t->type == MONO_TYPE_VALUETYPE) {
1789 /* this is further handled in mono_arch_emit_outarg_vt () */
1790 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1791 ins->opcode = OP_OUTARG_VT;
1792 ins->sreg1 = in->dreg;
1793 ins->klass = in->klass;
1794 ins->inst_p0 = call;
1795 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1796 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1797 MONO_ADD_INS (cfg->cbb, ins);
1799 cfg->flags |= MONO_CFG_HAS_FPOUT;
1801 int dreg = mono_alloc_freg (cfg);
1803 if (ainfo->size == 4) {
1804 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1806 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1808 ins->sreg1 = in->dreg;
1809 MONO_ADD_INS (cfg->cbb, ins);
1812 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1813 cfg->flags |= MONO_CFG_HAS_FPOUT;
1816 g_assert_not_reached ();
1820 /* Handle the case where there are no implicit arguments */
1821 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1822 emit_sig_cookie (cfg, call, cinfo);
1824 if (cinfo->struct_ret) {
1827 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1828 vtarg->sreg1 = call->vret_var->dreg;
1829 vtarg->dreg = mono_alloc_preg (cfg);
1830 MONO_ADD_INS (cfg->cbb, vtarg);
1832 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1836 * Reverse the call->out_args list.
1839 MonoInst *prev = NULL, *list = call->out_args, *next;
1846 call->out_args = prev;
1849 call->stack_usage = cinfo->stack_usage;
1850 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1851 #if _MIPS_SIM == _ABIO32
1852 /* a0-a3 always present */
1853 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1855 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1856 cfg->flags |= MONO_CFG_HAS_CALLS;
1858 * should set more info in call, such as the stack space
1859 * used by the args that needs to be added back to esp
1864 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1866 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1867 ArgInfo *ainfo = ins->inst_p1;
1868 int ovf_size = ainfo->vtsize;
1869 int doffset = ainfo->offset;
1870 int i, soffset, dreg;
1872 if (ainfo->storage == ArgStructByVal) {
1874 if (cfg->verbose_level > 0) {
1875 char* nm = mono_method_full_name (cfg->method, TRUE);
1876 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1877 nm, doffset, ainfo->size, ovf_size);
1883 for (i = 0; i < ainfo->size; ++i) {
1884 dreg = mono_alloc_ireg (cfg);
1885 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1886 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1887 soffset += SIZEOF_REGISTER;
1889 if (ovf_size != 0) {
1890 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1892 } else if (ainfo->storage == ArgInFReg) {
1893 int tmpr = mono_alloc_freg (cfg);
1895 if (ainfo->size == 4)
1896 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1898 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1899 dreg = mono_alloc_freg (cfg);
1900 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1901 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1903 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1907 /* FIXME: alignment? */
1908 if (call->signature->pinvoke) {
1909 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1910 vtcopy->backend.is_pinvoke = 1;
1912 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1915 g_assert (ovf_size > 0);
1917 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1918 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1921 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1923 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1928 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1930 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1933 #if (SIZEOF_REGISTER == 4)
1934 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1937 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1938 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1939 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1940 MONO_ADD_INS (cfg->cbb, ins);
1944 if (ret->type == MONO_TYPE_R8) {
1945 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1948 if (ret->type == MONO_TYPE_R4) {
1949 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1953 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1957 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1959 MonoInst *ins, *n, *last_ins = NULL;
1961 if (cfg->verbose_level > 2)
1962 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1965 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1966 if (cfg->verbose_level > 2)
1967 mono_print_ins_index (0, ins);
1969 switch (ins->opcode) {
1971 case OP_LOAD_MEMBASE:
1972 case OP_LOADI4_MEMBASE:
1974 * OP_IADD reg2, reg1, const1
1975 * OP_LOAD_MEMBASE const2(reg2), reg3
1977 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1979 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)){
1980 int const1 = last_ins->inst_imm;
1981 int const2 = ins->inst_offset;
1983 if (mips_is_imm16 (const1 + const2)) {
1984 ins->inst_basereg = last_ins->sreg1;
1985 ins->inst_offset = const1 + const2;
1995 bb->last_ins = last_ins;
1999 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2001 MonoInst *ins, *n, *last_ins = NULL;
2004 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2005 MonoInst *last_ins = ins->prev;
2007 switch (ins->opcode) {
2009 /* remove unnecessary multiplication with 1 */
2010 if (ins->inst_imm == 1) {
2011 if (ins->dreg != ins->sreg1) {
2012 ins->opcode = OP_MOVE;
2014 MONO_DELETE_INS (bb, ins);
2018 int power2 = mono_is_power_of_two (ins->inst_imm);
2020 ins->opcode = OP_SHL_IMM;
2021 ins->inst_imm = power2;
2025 case OP_LOAD_MEMBASE:
2026 case OP_LOADI4_MEMBASE:
2028 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2029 * OP_LOAD_MEMBASE offset(basereg), reg
2031 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2032 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2033 ins->inst_basereg == last_ins->inst_destbasereg &&
2034 ins->inst_offset == last_ins->inst_offset) {
2035 if (ins->dreg == last_ins->sreg1) {
2036 MONO_DELETE_INS (bb, ins);
2039 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2040 ins->opcode = OP_MOVE;
2041 ins->sreg1 = last_ins->sreg1;
2046 * Note: reg1 must be different from the basereg in the second load
2047 * OP_LOAD_MEMBASE offset(basereg), reg1
2048 * OP_LOAD_MEMBASE offset(basereg), reg2
2050 * OP_LOAD_MEMBASE offset(basereg), reg1
2051 * OP_MOVE reg1, reg2
2053 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2054 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2055 ins->inst_basereg != last_ins->dreg &&
2056 ins->inst_basereg == last_ins->inst_basereg &&
2057 ins->inst_offset == last_ins->inst_offset) {
2059 if (ins->dreg == last_ins->dreg) {
2060 MONO_DELETE_INS (bb, ins);
2063 ins->opcode = OP_MOVE;
2064 ins->sreg1 = last_ins->dreg;
2067 //g_assert_not_reached ();
2072 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2073 * OP_LOAD_MEMBASE offset(basereg), reg
2075 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2076 * OP_ICONST reg, imm
2078 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2079 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2080 ins->inst_basereg == last_ins->inst_destbasereg &&
2081 ins->inst_offset == last_ins->inst_offset) {
2082 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2083 ins->opcode = OP_ICONST;
2084 ins->inst_c0 = last_ins->inst_imm;
2085 g_assert_not_reached (); // check this rule
2090 case OP_LOADU1_MEMBASE:
2091 case OP_LOADI1_MEMBASE:
2092 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2093 ins->inst_basereg == last_ins->inst_destbasereg &&
2094 ins->inst_offset == last_ins->inst_offset) {
2095 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2096 ins->sreg1 = last_ins->sreg1;
2099 case OP_LOADU2_MEMBASE:
2100 case OP_LOADI2_MEMBASE:
2101 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2102 ins->inst_basereg == last_ins->inst_destbasereg &&
2103 ins->inst_offset == last_ins->inst_offset) {
2104 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2105 ins->sreg1 = last_ins->sreg1;
2108 case OP_ICONV_TO_I4:
2109 case OP_ICONV_TO_U4:
2111 ins->opcode = OP_MOVE;
2115 if (ins->dreg == ins->sreg1) {
2116 MONO_DELETE_INS (bb, ins);
2120 * OP_MOVE sreg, dreg
2121 * OP_MOVE dreg, sreg
2123 if (last_ins && last_ins->opcode == OP_MOVE &&
2124 ins->sreg1 == last_ins->dreg &&
2125 ins->dreg == last_ins->sreg1) {
2126 MONO_DELETE_INS (bb, ins);
2134 bb->last_ins = last_ins;
2138 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2146 switch (ins->opcode) {
2148 tmp1 = mono_alloc_ireg (cfg);
2149 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2150 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2151 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2152 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2157 tmp1 = mono_alloc_ireg (cfg);
2158 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2159 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2160 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2161 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2166 tmp1 = mono_alloc_ireg (cfg);
2167 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2168 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2169 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2170 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2175 tmp1 = mono_alloc_ireg (cfg);
2176 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2177 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2178 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2179 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2184 tmp1 = mono_alloc_ireg (cfg);
2185 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2186 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2187 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2188 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2193 tmp1 = mono_alloc_ireg (cfg);
2194 tmp2 = mono_alloc_ireg (cfg);
2195 tmp3 = mono_alloc_ireg (cfg);
2196 tmp4 = mono_alloc_ireg (cfg);
2197 tmp5 = mono_alloc_ireg (cfg);
2199 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2201 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2202 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2204 /* add the high 32-bits, and add in the carry from the low 32-bits */
2205 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2206 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2208 /* Overflow happens if
2209 * neg + neg = pos or
2211 * XOR of the high bits returns 0 if the signs match
2212 * XOR of that with the high bit of the result return 1 if overflow.
2215 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2216 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2218 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2219 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2220 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2222 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2223 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2224 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2226 /* Now, if (tmp4 == 0) then overflow */
2227 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2231 case OP_LADD_OVF_UN:
2232 tmp1 = mono_alloc_ireg (cfg);
2233 tmp2 = mono_alloc_ireg (cfg);
2235 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2236 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2237 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2238 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2239 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2240 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2245 tmp1 = mono_alloc_ireg (cfg);
2246 tmp2 = mono_alloc_ireg (cfg);
2247 tmp3 = mono_alloc_ireg (cfg);
2248 tmp4 = mono_alloc_ireg (cfg);
2249 tmp5 = mono_alloc_ireg (cfg);
2251 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2253 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2254 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2255 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2257 /* Overflow happens if
2258 * neg - pos = pos or
2260 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2262 * tmp1 = (lhs ^ rhs)
2263 * tmp2 = (lhs ^ result)
2264 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2267 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2268 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2269 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2270 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2272 /* Now, if (tmp4 == 1) then overflow */
2273 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2277 case OP_LSUB_OVF_UN:
2278 tmp1 = mono_alloc_ireg (cfg);
2279 tmp2 = mono_alloc_ireg (cfg);
2281 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2282 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2283 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2284 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2286 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2287 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2290 case OP_LCONV_TO_OVF_I4_2:
2291 tmp1 = mono_alloc_ireg (cfg);
2293 /* Overflows if reg2 != sign extension of reg1 */
2294 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2295 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2296 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2305 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2313 switch (ins->opcode) {
2315 tmp1 = mono_alloc_ireg (cfg);
2316 tmp2 = mono_alloc_ireg (cfg);
2317 tmp3 = mono_alloc_ireg (cfg);
2318 tmp4 = mono_alloc_ireg (cfg);
2319 tmp5 = mono_alloc_ireg (cfg);
2321 /* add the operands */
2323 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2325 /* Overflow happens if
2326 * neg + neg = pos or
2329 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2330 * XOR of the high bit returns 0 if the signs match
2331 * XOR of that with the high bit of the result return 1 if overflow.
2334 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2335 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2337 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2338 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2339 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2341 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2342 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2344 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2346 /* Now, if (tmp5 == 0) then overflow */
2347 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2348 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2349 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2353 case OP_IADD_OVF_UN:
2354 tmp1 = mono_alloc_ireg (cfg);
2356 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2357 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2358 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2359 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2360 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2365 tmp1 = mono_alloc_ireg (cfg);
2366 tmp2 = mono_alloc_ireg (cfg);
2367 tmp3 = mono_alloc_ireg (cfg);
2368 tmp4 = mono_alloc_ireg (cfg);
2369 tmp5 = mono_alloc_ireg (cfg);
2371 /* add the operands */
2373 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2375 /* Overflow happens if
2376 * neg - pos = pos or
2378 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2380 * tmp1 = (lhs ^ rhs)
2381 * tmp2 = (lhs ^ result)
2382 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2385 /* tmp3 = 1 if the signs of the two inputs differ */
2386 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2387 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2388 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2389 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2390 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2392 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2393 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2394 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2398 case OP_ISUB_OVF_UN:
2399 tmp1 = mono_alloc_ireg (cfg);
2401 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2402 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2403 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2404 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2405 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2412 map_to_reg_reg_op (int op)
2421 case OP_COMPARE_IMM:
2423 case OP_ICOMPARE_IMM:
2425 case OP_LCOMPARE_IMM:
2441 case OP_LOAD_MEMBASE:
2442 return OP_LOAD_MEMINDEX;
2443 case OP_LOADI4_MEMBASE:
2444 return OP_LOADI4_MEMINDEX;
2445 case OP_LOADU4_MEMBASE:
2446 return OP_LOADU4_MEMINDEX;
2447 case OP_LOADU1_MEMBASE:
2448 return OP_LOADU1_MEMINDEX;
2449 case OP_LOADI2_MEMBASE:
2450 return OP_LOADI2_MEMINDEX;
2451 case OP_LOADU2_MEMBASE:
2452 return OP_LOADU2_MEMINDEX;
2453 case OP_LOADI1_MEMBASE:
2454 return OP_LOADI1_MEMINDEX;
2455 case OP_LOADR4_MEMBASE:
2456 return OP_LOADR4_MEMINDEX;
2457 case OP_LOADR8_MEMBASE:
2458 return OP_LOADR8_MEMINDEX;
2459 case OP_STOREI1_MEMBASE_REG:
2460 return OP_STOREI1_MEMINDEX;
2461 case OP_STOREI2_MEMBASE_REG:
2462 return OP_STOREI2_MEMINDEX;
2463 case OP_STOREI4_MEMBASE_REG:
2464 return OP_STOREI4_MEMINDEX;
2465 case OP_STORE_MEMBASE_REG:
2466 return OP_STORE_MEMINDEX;
2467 case OP_STORER4_MEMBASE_REG:
2468 return OP_STORER4_MEMINDEX;
2469 case OP_STORER8_MEMBASE_REG:
2470 return OP_STORER8_MEMINDEX;
2471 case OP_STORE_MEMBASE_IMM:
2472 return OP_STORE_MEMBASE_REG;
2473 case OP_STOREI1_MEMBASE_IMM:
2474 return OP_STOREI1_MEMBASE_REG;
2475 case OP_STOREI2_MEMBASE_IMM:
2476 return OP_STOREI2_MEMBASE_REG;
2477 case OP_STOREI4_MEMBASE_IMM:
2478 return OP_STOREI4_MEMBASE_REG;
2479 case OP_STOREI8_MEMBASE_IMM:
2480 return OP_STOREI8_MEMBASE_REG;
2482 if (mono_op_imm_to_op (op) == -1)
2483 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2484 return mono_op_imm_to_op (op);
2488 map_to_mips_op (int op)
2492 return OP_MIPS_FBEQ;
2494 return OP_MIPS_FBGE;
2496 return OP_MIPS_FBGT;
2498 return OP_MIPS_FBLE;
2500 return OP_MIPS_FBLT;
2502 return OP_MIPS_FBNE;
2504 return OP_MIPS_FBGE_UN;
2506 return OP_MIPS_FBGT_UN;
2508 return OP_MIPS_FBLE_UN;
2510 return OP_MIPS_FBLT_UN;
2518 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2519 g_assert_not_reached ();
2523 #define NEW_INS(cfg,after,dest,op) do { \
2524 MONO_INST_NEW((cfg), (dest), (op)); \
2525 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2528 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2530 MONO_INST_NEW(cfg, temp, (op)); \
2531 mono_bblock_insert_after_ins (bb, (pos), temp); \
2532 temp->dreg = (_dreg); \
2533 temp->sreg1 = (_sreg1); \
2534 temp->sreg2 = (_sreg2); \
2538 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2540 MONO_INST_NEW(cfg, temp, (op)); \
2541 mono_bblock_insert_after_ins (bb, (pos), temp); \
2542 temp->dreg = (_dreg); \
2543 temp->sreg1 = (_sreg1); \
2544 temp->inst_c0 = (_imm); \
2549 * Remove from the instruction list the instructions that can't be
2550 * represented with very simple instructions with no register
2554 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2556 MonoInst *ins, *next, *temp, *last_ins = NULL;
2560 if (cfg->verbose_level > 2) {
2563 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2564 MONO_BB_FOR_EACH_INS (bb, ins) {
2565 mono_print_ins_index (idx++, ins);
2571 MONO_BB_FOR_EACH_INS (bb, ins) {
2573 switch (ins->opcode) {
2578 /* Branch opts can eliminate the branch */
2579 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2585 case OP_COMPARE_IMM:
2586 case OP_ICOMPARE_IMM:
2587 case OP_LCOMPARE_IMM:
2589 /* Branch opts can eliminate the branch */
2590 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2594 if (ins->inst_imm) {
2595 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2596 temp->inst_c0 = ins->inst_imm;
2597 temp->dreg = mono_alloc_ireg (cfg);
2598 ins->sreg2 = temp->dreg;
2602 ins->sreg2 = mips_zero;
2604 if (ins->opcode == OP_COMPARE_IMM)
2605 ins->opcode = OP_COMPARE;
2606 else if (ins->opcode == OP_ICOMPARE_IMM)
2607 ins->opcode = OP_ICOMPARE;
2608 else if (ins->opcode == OP_LCOMPARE_IMM)
2609 ins->opcode = OP_LCOMPARE;
2612 case OP_IDIV_UN_IMM:
2615 case OP_IREM_UN_IMM:
2616 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2617 temp->inst_c0 = ins->inst_imm;
2618 temp->dreg = mono_alloc_ireg (cfg);
2619 ins->sreg2 = temp->dreg;
2620 if (ins->opcode == OP_IDIV_IMM)
2621 ins->opcode = OP_IDIV;
2622 else if (ins->opcode == OP_IREM_IMM)
2623 ins->opcode = OP_IREM;
2624 else if (ins->opcode == OP_IDIV_UN_IMM)
2625 ins->opcode = OP_IDIV_UN;
2626 else if (ins->opcode == OP_IREM_UN_IMM)
2627 ins->opcode = OP_IREM_UN;
2629 /* handle rem separately */
2636 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2637 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2638 temp->inst_c0 = ins->inst_imm;
2639 temp->dreg = mono_alloc_ireg (cfg);
2640 ins->sreg2 = temp->dreg;
2641 ins->opcode = map_to_reg_reg_op (ins->opcode);
2651 /* unsigned 16 bit immediate */
2652 if (ins->inst_imm & 0xffff0000) {
2653 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2654 temp->inst_c0 = ins->inst_imm;
2655 temp->dreg = mono_alloc_ireg (cfg);
2656 ins->sreg2 = temp->dreg;
2657 ins->opcode = map_to_reg_reg_op (ins->opcode);
2664 /* signed 16 bit immediate */
2665 if (!mips_is_imm16 (ins->inst_imm)) {
2666 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2667 temp->inst_c0 = ins->inst_imm;
2668 temp->dreg = mono_alloc_ireg (cfg);
2669 ins->sreg2 = temp->dreg;
2670 ins->opcode = map_to_reg_reg_op (ins->opcode);
2676 if (!mips_is_imm16 (-ins->inst_imm)) {
2677 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2678 temp->inst_c0 = ins->inst_imm;
2679 temp->dreg = mono_alloc_ireg (cfg);
2680 ins->sreg2 = temp->dreg;
2681 ins->opcode = map_to_reg_reg_op (ins->opcode);
2687 if (ins->inst_imm == 1) {
2688 ins->opcode = OP_MOVE;
2691 if (ins->inst_imm == 0) {
2692 ins->opcode = OP_ICONST;
2696 imm = mono_is_power_of_two (ins->inst_imm);
2698 ins->opcode = OP_SHL_IMM;
2699 ins->inst_imm = imm;
2702 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2703 temp->inst_c0 = ins->inst_imm;
2704 temp->dreg = mono_alloc_ireg (cfg);
2705 ins->sreg2 = temp->dreg;
2706 ins->opcode = map_to_reg_reg_op (ins->opcode);
2709 case OP_LOCALLOC_IMM:
2710 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2711 temp->inst_c0 = ins->inst_imm;
2712 temp->dreg = mono_alloc_ireg (cfg);
2713 ins->sreg1 = temp->dreg;
2714 ins->opcode = OP_LOCALLOC;
2717 case OP_LOADR4_MEMBASE:
2718 case OP_STORER4_MEMBASE_REG:
2719 /* we can do two things: load the immed in a register
2720 * and use an indexed load, or see if the immed can be
2721 * represented as an ad_imm + a load with a smaller offset
2722 * that fits. We just do the first for now, optimize later.
2724 if (mips_is_imm16 (ins->inst_offset))
2726 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2727 temp->inst_c0 = ins->inst_offset;
2728 temp->dreg = mono_alloc_ireg (cfg);
2729 ins->sreg2 = temp->dreg;
2730 ins->opcode = map_to_reg_reg_op (ins->opcode);
2733 case OP_STORE_MEMBASE_IMM:
2734 case OP_STOREI1_MEMBASE_IMM:
2735 case OP_STOREI2_MEMBASE_IMM:
2736 case OP_STOREI4_MEMBASE_IMM:
2737 case OP_STOREI8_MEMBASE_IMM:
2738 if (!ins->inst_imm) {
2739 ins->sreg1 = mips_zero;
2740 ins->opcode = map_to_reg_reg_op (ins->opcode);
2743 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2744 temp->inst_c0 = ins->inst_imm;
2745 temp->dreg = mono_alloc_ireg (cfg);
2746 ins->sreg1 = temp->dreg;
2747 ins->opcode = map_to_reg_reg_op (ins->opcode);
2749 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2755 /* Branch opts can eliminate the branch */
2756 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2763 * remap compare/branch and compare/set
2764 * to MIPS specific opcodes.
2766 next->opcode = map_to_mips_op (next->opcode);
2767 next->sreg1 = ins->sreg1;
2768 next->sreg2 = ins->sreg2;
2775 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2776 temp->inst_c0 = (guint32)ins->inst_p0;
2777 temp->dreg = mono_alloc_ireg (cfg);
2778 ins->inst_basereg = temp->dreg;
2779 ins->inst_offset = 0;
2780 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2782 /* make it handle the possibly big ins->inst_offset
2783 * later optimize to use lis + load_membase
2788 g_assert (ins_is_compare(last_ins));
2789 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2790 NULLIFY_INS(last_ins);
2794 g_assert (ins_is_compare(last_ins));
2795 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2796 NULLIFY_INS(last_ins);
2800 g_assert (ins_is_compare(last_ins));
2801 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2802 last_ins->dreg = mono_alloc_ireg (cfg);
2803 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2807 g_assert (ins_is_compare(last_ins));
2808 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2809 last_ins->dreg = mono_alloc_ireg (cfg);
2810 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2814 g_assert (ins_is_compare(last_ins));
2815 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2816 last_ins->dreg = mono_alloc_ireg (cfg);
2817 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2821 g_assert (ins_is_compare(last_ins));
2822 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2823 last_ins->dreg = mono_alloc_ireg (cfg);
2824 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2828 g_assert (ins_is_compare(last_ins));
2829 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2830 last_ins->dreg = mono_alloc_ireg (cfg);
2831 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2835 g_assert (ins_is_compare(last_ins));
2836 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2837 last_ins->dreg = mono_alloc_ireg (cfg);
2838 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2842 g_assert (ins_is_compare(last_ins));
2843 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2844 last_ins->dreg = mono_alloc_ireg (cfg);
2845 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2849 g_assert (ins_is_compare(last_ins));
2850 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2851 last_ins->dreg = mono_alloc_ireg (cfg);
2852 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2857 g_assert (ins_is_compare(last_ins));
2858 last_ins->opcode = OP_IXOR;
2859 last_ins->dreg = mono_alloc_ireg(cfg);
2860 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2865 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2866 NULLIFY_INS(last_ins);
2872 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2873 NULLIFY_INS(last_ins);
2878 g_assert (ins_is_compare(last_ins));
2879 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2880 MONO_DELETE_INS(bb, last_ins);
2885 g_assert (ins_is_compare(last_ins));
2886 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2887 MONO_DELETE_INS(bb, last_ins);
2890 case OP_COND_EXC_EQ:
2891 case OP_COND_EXC_IEQ:
2892 g_assert (ins_is_compare(last_ins));
2893 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2894 MONO_DELETE_INS(bb, last_ins);
2897 case OP_COND_EXC_GE:
2898 case OP_COND_EXC_IGE:
2899 g_assert (ins_is_compare(last_ins));
2900 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2901 MONO_DELETE_INS(bb, last_ins);
2904 case OP_COND_EXC_GT:
2905 case OP_COND_EXC_IGT:
2906 g_assert (ins_is_compare(last_ins));
2907 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2908 MONO_DELETE_INS(bb, last_ins);
2911 case OP_COND_EXC_LE:
2912 case OP_COND_EXC_ILE:
2913 g_assert (ins_is_compare(last_ins));
2914 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2915 MONO_DELETE_INS(bb, last_ins);
2918 case OP_COND_EXC_LT:
2919 case OP_COND_EXC_ILT:
2920 g_assert (ins_is_compare(last_ins));
2921 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2922 MONO_DELETE_INS(bb, last_ins);
2925 case OP_COND_EXC_NE_UN:
2926 case OP_COND_EXC_INE_UN:
2927 g_assert (ins_is_compare(last_ins));
2928 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2929 MONO_DELETE_INS(bb, last_ins);
2932 case OP_COND_EXC_GE_UN:
2933 case OP_COND_EXC_IGE_UN:
2934 g_assert (ins_is_compare(last_ins));
2935 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2936 MONO_DELETE_INS(bb, last_ins);
2939 case OP_COND_EXC_GT_UN:
2940 case OP_COND_EXC_IGT_UN:
2941 g_assert (ins_is_compare(last_ins));
2942 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2943 MONO_DELETE_INS(bb, last_ins);
2946 case OP_COND_EXC_LE_UN:
2947 case OP_COND_EXC_ILE_UN:
2948 g_assert (ins_is_compare(last_ins));
2949 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2950 MONO_DELETE_INS(bb, last_ins);
2953 case OP_COND_EXC_LT_UN:
2954 case OP_COND_EXC_ILT_UN:
2955 g_assert (ins_is_compare(last_ins));
2956 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2957 MONO_DELETE_INS(bb, last_ins);
2960 case OP_COND_EXC_OV:
2961 case OP_COND_EXC_IOV: {
2962 int tmp1, tmp2, tmp3, tmp4, tmp5;
2963 MonoInst *pos = last_ins;
2965 /* Overflow happens if
2966 * neg + neg = pos or
2969 * (bit31s of operands match) AND (bit31 of operand
2970 * != bit31 of result)
2971 * XOR of the high bit returns 0 if the signs match
2972 * XOR of that with the high bit of the result return 1
2975 g_assert (last_ins->opcode == OP_IADC);
2977 tmp1 = mono_alloc_ireg (cfg);
2978 tmp2 = mono_alloc_ireg (cfg);
2979 tmp3 = mono_alloc_ireg (cfg);
2980 tmp4 = mono_alloc_ireg (cfg);
2981 tmp5 = mono_alloc_ireg (cfg);
2983 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2984 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2986 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2987 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2988 INS (pos, OP_INOT, tmp3, tmp2, -1);
2990 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2991 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2992 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2994 /* Now, if (tmp5 == 0) then overflow */
2995 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3000 case OP_COND_EXC_NO:
3001 case OP_COND_EXC_INO:
3002 g_assert_not_reached ();
3006 case OP_COND_EXC_IC:
3007 g_assert_not_reached ();
3010 case OP_COND_EXC_NC:
3011 case OP_COND_EXC_INC:
3012 g_assert_not_reached ();
3018 bb->last_ins = last_ins;
3019 bb->max_vreg = cfg->next_vreg;
3022 if (cfg->verbose_level > 2) {
3025 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3026 MONO_BB_FOR_EACH_INS (bb, ins) {
3027 mono_print_ins_index (idx++, ins);
3036 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3038 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3040 mips_truncwd (code, mips_ftemp, sreg);
3042 mips_cvtwd (code, mips_ftemp, sreg);
3044 mips_mfc1 (code, dreg, mips_ftemp);
3047 mips_andi (code, dreg, dreg, 0xff);
3048 else if (size == 2) {
3049 mips_sll (code, dreg, dreg, 16);
3050 mips_srl (code, dreg, dreg, 16);
3054 mips_sll (code, dreg, dreg, 24);
3055 mips_sra (code, dreg, dreg, 24);
3057 else if (size == 2) {
3058 mips_sll (code, dreg, dreg, 16);
3059 mips_sra (code, dreg, dreg, 16);
3066 * emit_load_volatile_arguments:
3068 * Load volatile arguments from the stack to the original input registers.
3069 * Required before a tail call.
3072 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3074 MonoMethod *method = cfg->method;
3075 MonoMethodSignature *sig;
3080 sig = mono_method_signature (method);
3082 if (!cfg->arch.cinfo)
3083 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3084 cinfo = cfg->arch.cinfo;
3086 if (cinfo->struct_ret) {
3087 ArgInfo *ainfo = &cinfo->ret;
3088 inst = cfg->vret_addr;
3089 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3092 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3093 ArgInfo *ainfo = cinfo->args + i;
3094 inst = cfg->args [i];
3095 if (inst->opcode == OP_REGVAR) {
3096 if (ainfo->storage == ArgInIReg)
3097 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3098 else if (ainfo->storage == ArgInFReg)
3099 g_assert_not_reached();
3100 else if (ainfo->storage == ArgOnStack) {
3103 g_assert_not_reached ();
3105 if (ainfo->storage == ArgInIReg) {
3106 g_assert (mips_is_imm16 (inst->inst_offset));
3107 switch (ainfo->size) {
3109 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3112 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3116 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3119 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3120 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3123 g_assert_not_reached ();
3126 } else if (ainfo->storage == ArgOnStack) {
3128 } else if (ainfo->storage == ArgInFReg) {
3129 g_assert (mips_is_imm16 (inst->inst_offset));
3130 if (ainfo->size == 8) {
3131 #if _MIPS_SIM == _ABIO32
3132 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3133 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3134 #elif _MIPS_SIM == _ABIN32
3135 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3138 else if (ainfo->size == 4)
3139 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3141 g_assert_not_reached ();
3142 } else if (ainfo->storage == ArgStructByVal) {
3144 int doffset = inst->inst_offset;
3146 g_assert (mips_is_imm16 (inst->inst_offset));
3147 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3148 for (i = 0; i < ainfo->size; ++i) {
3149 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3150 doffset += SIZEOF_REGISTER;
3152 } else if (ainfo->storage == ArgStructByAddr) {
3153 g_assert (mips_is_imm16 (inst->inst_offset));
3154 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3156 g_assert_not_reached ();
3164 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3166 int size = cfg->param_area;
3168 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3169 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3174 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3175 if (ppc_is_imm16 (-size)) {
3176 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3178 ppc_load (code, ppc_r12, -size);
3179 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3186 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3188 int size = cfg->param_area;
3190 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3191 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3196 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3197 if (ppc_is_imm16 (size)) {
3198 ppc_stwu (code, ppc_r0, size, ppc_sp);
3200 ppc_load (code, ppc_r12, size);
3201 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3208 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3213 guint8 *code = cfg->native_code + cfg->code_len;
3214 MonoInst *last_ins = NULL;
3215 guint last_offset = 0;
3219 /* we don't align basic blocks of loops on mips */
3221 if (cfg->verbose_level > 2)
3222 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3224 cpos = bb->max_offset;
3227 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3228 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3229 g_assert (!mono_compile_aot);
3232 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3233 /* this is not thread save, but good enough */
3234 /* fixme: howto handle overflows? */
3235 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3236 mips_lw (code, mips_temp, mips_at, 0);
3237 mips_addiu (code, mips_temp, mips_temp, 1);
3238 mips_sw (code, mips_temp, mips_at, 0);
3241 MONO_BB_FOR_EACH_INS (bb, ins) {
3242 offset = code - cfg->native_code;
3244 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3246 if (offset > (cfg->code_size - max_len - 16)) {
3247 cfg->code_size *= 2;
3248 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3249 code = cfg->native_code + offset;
3251 mono_debug_record_line_number (cfg, ins, offset);
3252 if (cfg->verbose_level > 2) {
3253 g_print (" @ 0x%x\t", offset);
3254 mono_print_ins_index (ins_cnt++, ins);
3256 /* Check for virtual regs that snuck by */
3257 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3259 switch (ins->opcode) {
3260 case OP_RELAXED_NOP:
3263 case OP_DUMMY_STORE:
3264 case OP_NOT_REACHED:
3267 case OP_IL_SEQ_POINT:
3268 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3270 case OP_SEQ_POINT: {
3271 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3272 guint32 addr = (guint32)ss_trigger_page;
3274 mips_load_const (code, mips_t9, addr);
3275 mips_lw (code, mips_t9, mips_t9, 0);
3278 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3281 * A placeholder for a possible breakpoint inserted by
3282 * mono_arch_set_breakpoint ().
3284 /* mips_load_const () + mips_lw */
3291 mips_mult (code, ins->sreg1, ins->sreg2);
3292 mips_mflo (code, ins->dreg);
3293 mips_mfhi (code, ins->dreg+1);
3296 mips_multu (code, ins->sreg1, ins->sreg2);
3297 mips_mflo (code, ins->dreg);
3298 mips_mfhi (code, ins->dreg+1);
3300 case OP_MEMORY_BARRIER:
3301 mips_sync (code, 0);
3303 case OP_STOREI1_MEMBASE_IMM:
3304 mips_load_const (code, mips_temp, ins->inst_imm);
3305 if (mips_is_imm16 (ins->inst_offset)) {
3306 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3308 mips_load_const (code, mips_at, ins->inst_offset);
3309 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3312 case OP_STOREI2_MEMBASE_IMM:
3313 mips_load_const (code, mips_temp, ins->inst_imm);
3314 if (mips_is_imm16 (ins->inst_offset)) {
3315 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3317 mips_load_const (code, mips_at, ins->inst_offset);
3318 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3321 case OP_STOREI8_MEMBASE_IMM:
3322 mips_load_const (code, mips_temp, ins->inst_imm);
3323 if (mips_is_imm16 (ins->inst_offset)) {
3324 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3326 mips_load_const (code, mips_at, ins->inst_offset);
3327 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3330 case OP_STORE_MEMBASE_IMM:
3331 case OP_STOREI4_MEMBASE_IMM:
3332 mips_load_const (code, mips_temp, ins->inst_imm);
3333 if (mips_is_imm16 (ins->inst_offset)) {
3334 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3336 mips_load_const (code, mips_at, ins->inst_offset);
3337 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3340 case OP_STOREI1_MEMBASE_REG:
3341 if (mips_is_imm16 (ins->inst_offset)) {
3342 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3344 mips_load_const (code, mips_at, ins->inst_offset);
3345 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3346 mips_sb (code, ins->sreg1, mips_at, 0);
3349 case OP_STOREI2_MEMBASE_REG:
3350 if (mips_is_imm16 (ins->inst_offset)) {
3351 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3353 mips_load_const (code, mips_at, ins->inst_offset);
3354 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3355 mips_sh (code, ins->sreg1, mips_at, 0);
3358 case OP_STORE_MEMBASE_REG:
3359 case OP_STOREI4_MEMBASE_REG:
3360 if (mips_is_imm16 (ins->inst_offset)) {
3361 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3363 mips_load_const (code, mips_at, ins->inst_offset);
3364 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3365 mips_sw (code, ins->sreg1, mips_at, 0);
3368 case OP_STOREI8_MEMBASE_REG:
3369 if (mips_is_imm16 (ins->inst_offset)) {
3370 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3372 mips_load_const (code, mips_at, ins->inst_offset);
3373 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3374 mips_sd (code, ins->sreg1, mips_at, 0);
3378 g_assert_not_reached ();
3379 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3380 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3382 case OP_LOADI8_MEMBASE:
3383 if (mips_is_imm16 (ins->inst_offset)) {
3384 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3386 mips_load_const (code, mips_at, ins->inst_offset);
3387 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3388 mips_ld (code, ins->dreg, mips_at, 0);
3391 case OP_LOAD_MEMBASE:
3392 case OP_LOADI4_MEMBASE:
3393 case OP_LOADU4_MEMBASE:
3394 g_assert (ins->dreg != -1);
3395 if (mips_is_imm16 (ins->inst_offset)) {
3396 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3398 mips_load_const (code, mips_at, ins->inst_offset);
3399 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3400 mips_lw (code, ins->dreg, mips_at, 0);
3403 case OP_LOADI1_MEMBASE:
3404 if (mips_is_imm16 (ins->inst_offset)) {
3405 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3407 mips_load_const (code, mips_at, ins->inst_offset);
3408 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3409 mips_lb (code, ins->dreg, mips_at, 0);
3412 case OP_LOADU1_MEMBASE:
3413 if (mips_is_imm16 (ins->inst_offset)) {
3414 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3416 mips_load_const (code, mips_at, ins->inst_offset);
3417 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3418 mips_lbu (code, ins->dreg, mips_at, 0);
3421 case OP_LOADI2_MEMBASE:
3422 if (mips_is_imm16 (ins->inst_offset)) {
3423 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3425 mips_load_const (code, mips_at, ins->inst_offset);
3426 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3427 mips_lh (code, ins->dreg, mips_at, 0);
3430 case OP_LOADU2_MEMBASE:
3431 if (mips_is_imm16 (ins->inst_offset)) {
3432 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3434 mips_load_const (code, mips_at, ins->inst_offset);
3435 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3436 mips_lhu (code, ins->dreg, mips_at, 0);
3439 case OP_ICONV_TO_I1:
3440 mips_sll (code, mips_at, ins->sreg1, 24);
3441 mips_sra (code, ins->dreg, mips_at, 24);
3443 case OP_ICONV_TO_I2:
3444 mips_sll (code, mips_at, ins->sreg1, 16);
3445 mips_sra (code, ins->dreg, mips_at, 16);
3447 case OP_ICONV_TO_U1:
3448 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3450 case OP_ICONV_TO_U2:
3451 mips_sll (code, mips_at, ins->sreg1, 16);
3452 mips_srl (code, ins->dreg, mips_at, 16);
3455 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3458 g_assert (mips_is_imm16 (ins->inst_imm));
3459 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3462 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3465 g_assert (mips_is_imm16 (ins->inst_imm));
3466 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3470 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3471 * So instead of emitting a trap, we emit a call a C function and place a
3474 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3475 (gpointer)"mono_break");
3476 mips_load (code, mips_t9, 0x1f1f1f1f);
3477 mips_jalr (code, mips_t9, mips_ra);
3481 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3484 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3489 g_assert (mips_is_imm16 (ins->inst_imm));
3490 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3493 g_assert (mips_is_imm16 (ins->inst_imm));
3494 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3498 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3501 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3506 // we add the negated value
3507 g_assert (mips_is_imm16 (-ins->inst_imm));
3508 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3512 // we add the negated value
3513 g_assert (mips_is_imm16 (-ins->inst_imm));
3514 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3519 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3525 g_assert (!(ins->inst_imm & 0xffff0000));
3526 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3531 guint32 *divisor_is_m1;
3532 guint32 *dividend_is_minvalue;
3533 guint32 *divisor_is_zero;
3535 mips_load_const (code, mips_at, -1);
3536 divisor_is_m1 = (guint32 *)(void *)code;
3537 mips_bne (code, ins->sreg2, mips_at, 0);
3538 mips_lui (code, mips_at, mips_zero, 0x8000);
3539 dividend_is_minvalue = (guint32 *)(void *)code;
3540 mips_bne (code, ins->sreg1, mips_at, 0);
3543 /* Divide Int32.MinValue by -1 -- throw exception */
3544 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3546 mips_patch (divisor_is_m1, (guint32)code);
3547 mips_patch (dividend_is_minvalue, (guint32)code);
3549 /* Put divide in branch delay slot (NOT YET) */
3550 divisor_is_zero = (guint32 *)(void *)code;
3551 mips_bne (code, ins->sreg2, mips_zero, 0);
3554 /* Divide by zero -- throw exception */
3555 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3557 mips_patch (divisor_is_zero, (guint32)code);
3558 mips_div (code, ins->sreg1, ins->sreg2);
3559 if (ins->opcode == OP_IDIV)
3560 mips_mflo (code, ins->dreg);
3562 mips_mfhi (code, ins->dreg);
3567 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3569 /* Put divide in branch delay slot (NOT YET) */
3570 mips_bne (code, ins->sreg2, mips_zero, 0);
3573 /* Divide by zero -- throw exception */
3574 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3576 mips_patch (divisor_is_zero, (guint32)code);
3577 mips_divu (code, ins->sreg1, ins->sreg2);
3578 if (ins->opcode == OP_IDIV_UN)
3579 mips_mflo (code, ins->dreg);
3581 mips_mfhi (code, ins->dreg);
3585 g_assert_not_reached ();
3587 ppc_load (code, ppc_r12, ins->inst_imm);
3588 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3589 ppc_mfspr (code, ppc_r0, ppc_xer);
3590 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3591 /* FIXME: use OverflowException for 0x80000000/-1 */
3592 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3594 g_assert_not_reached();
3597 g_assert_not_reached ();
3599 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3603 g_assert (!(ins->inst_imm & 0xffff0000));
3604 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3607 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3611 /* unsigned 16-bit immediate */
3612 g_assert (!(ins->inst_imm & 0xffff0000));
3613 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3616 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3620 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3623 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3626 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3630 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3633 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3636 case OP_ISHR_UN_IMM:
3637 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3639 case OP_LSHR_UN_IMM:
3640 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3643 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3646 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3650 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3653 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3656 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3660 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3662 mips_mult (code, ins->sreg1, ins->sreg2);
3663 mips_mflo (code, ins->dreg);
3668 #if SIZEOF_REGISTER == 8
3670 mips_dmult (code, ins->sreg1, ins->sreg2);
3671 mips_mflo (code, ins->dreg);
3676 mips_mult (code, ins->sreg1, ins->sreg2);
3677 mips_mflo (code, ins->dreg);
3678 mips_mfhi (code, mips_at);
3681 mips_sra (code, mips_temp, ins->dreg, 31);
3682 patch = (guint32 *)(void *)code;
3683 mips_beq (code, mips_temp, mips_at, 0);
3685 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3686 mips_patch (patch, (guint32)code);
3689 case OP_IMUL_OVF_UN: {
3691 mips_mult (code, ins->sreg1, ins->sreg2);
3692 mips_mflo (code, ins->dreg);
3693 mips_mfhi (code, mips_at);
3696 patch = (guint32 *)(void *)code;
3697 mips_beq (code, mips_at, mips_zero, 0);
3699 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3700 mips_patch (patch, (guint32)code);
3704 mips_load_const (code, ins->dreg, ins->inst_c0);
3706 #if SIZEOF_REGISTER == 8
3708 mips_load_const (code, ins->dreg, ins->inst_c0);
3712 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3713 mips_load (code, ins->dreg, 0);
3717 mips_mtc1 (code, ins->dreg, ins->sreg1);
3719 case OP_MIPS_MTC1S_2:
3720 mips_mtc1 (code, ins->dreg, ins->sreg1);
3721 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3724 mips_mfc1 (code, ins->dreg, ins->sreg1);
3727 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3731 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3733 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3734 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3738 case OP_ICONV_TO_I4:
3739 case OP_ICONV_TO_U4:
3741 if (ins->dreg != ins->sreg1)
3742 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3744 #if SIZEOF_REGISTER == 8
3746 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3747 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3750 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3751 mips_dsra (code, ins->dreg, ins->dreg, 32);
3755 int lsreg = mips_v0 + ls_word_idx;
3756 int msreg = mips_v0 + ms_word_idx;
3758 /* Get sreg1 into lsreg, sreg2 into msreg */
3760 if (ins->sreg1 == msreg) {
3761 if (ins->sreg1 != mips_at)
3762 MIPS_MOVE (code, mips_at, ins->sreg1);
3763 if (ins->sreg2 != msreg)
3764 MIPS_MOVE (code, msreg, ins->sreg2);
3765 MIPS_MOVE (code, lsreg, mips_at);
3768 if (ins->sreg2 != msreg)
3769 MIPS_MOVE (code, msreg, ins->sreg2);
3770 if (ins->sreg1 != lsreg)
3771 MIPS_MOVE (code, lsreg, ins->sreg1);
3776 if (ins->dreg != ins->sreg1) {
3777 mips_fmovd (code, ins->dreg, ins->sreg1);
3780 case OP_MOVE_F_TO_I4:
3781 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3782 mips_mfc1 (code, ins->dreg, mips_ftemp);
3784 case OP_MOVE_I4_TO_F:
3785 mips_mtc1 (code, ins->dreg, ins->sreg1);
3786 mips_cvtds (code, ins->dreg, ins->dreg);
3789 /* Convert from double to float and leave it there */
3790 mips_cvtsd (code, ins->dreg, ins->sreg1);
3792 case OP_FCONV_TO_R4:
3794 mips_cvtsd (code, ins->dreg, ins->sreg1);
3796 /* Just a move, no precision change */
3797 if (ins->dreg != ins->sreg1) {
3798 mips_fmovd (code, ins->dreg, ins->sreg1);
3803 code = emit_load_volatile_arguments(cfg, code);
3806 * Pop our stack, then jump to specified method (tail-call)
3807 * Keep in sync with mono_arch_emit_epilog
3809 code = mono_arch_emit_epilog_sub (cfg, code);
3811 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3812 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3813 mips_load (code, mips_t9, 0);
3814 mips_jr (code, mips_t9);
3818 /* ensure ins->sreg1 is not NULL */
3819 mips_lw (code, mips_zero, ins->sreg1, 0);
3822 g_assert (mips_is_imm16 (cfg->sig_cookie));
3823 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3824 mips_sw (code, mips_at, ins->sreg1, 0);
3837 case OP_VOIDCALL_REG:
3839 case OP_FCALL_MEMBASE:
3840 case OP_LCALL_MEMBASE:
3841 case OP_VCALL_MEMBASE:
3842 case OP_VCALL2_MEMBASE:
3843 case OP_VOIDCALL_MEMBASE:
3844 case OP_CALL_MEMBASE:
3845 call = (MonoCallInst*)ins;
3846 switch (ins->opcode) {
3853 if (ins->flags & MONO_INST_HAS_METHOD) {
3854 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3855 mips_load (code, mips_t9, call->method);
3858 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3859 mips_load (code, mips_t9, call->fptr);
3861 mips_jalr (code, mips_t9, mips_ra);
3868 case OP_VOIDCALL_REG:
3870 MIPS_MOVE (code, mips_t9, ins->sreg1);
3871 mips_jalr (code, mips_t9, mips_ra);
3874 case OP_FCALL_MEMBASE:
3875 case OP_LCALL_MEMBASE:
3876 case OP_VCALL_MEMBASE:
3877 case OP_VCALL2_MEMBASE:
3878 case OP_VOIDCALL_MEMBASE:
3879 case OP_CALL_MEMBASE:
3880 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3881 mips_jalr (code, mips_t9, mips_ra);
3885 #if PROMOTE_R4_TO_R8
3886 /* returned an FP R4 (single), promote to R8 (double) in place */
3887 switch (ins->opcode) {
3890 case OP_FCALL_MEMBASE:
3891 if (call->signature->ret->type == MONO_TYPE_R4)
3892 mips_cvtds (code, mips_f0, mips_f0);
3900 int area_offset = cfg->param_area;
3902 /* Round up ins->sreg1, mips_at ends up holding size */
3903 mips_addiu (code, mips_at, ins->sreg1, 31);
3904 mips_addiu (code, mips_temp, mips_zero, ~31);
3905 mips_and (code, mips_at, mips_at, mips_temp);
3907 mips_subu (code, mips_sp, mips_sp, mips_at);
3908 g_assert (mips_is_imm16 (area_offset));
3909 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3911 if (ins->flags & MONO_INST_INIT) {
3914 buf = (guint32*)(void*)code;
3915 mips_beq (code, mips_at, mips_zero, 0);
3918 mips_move (code, mips_temp, ins->dreg);
3919 mips_sb (code, mips_zero, mips_temp, 0);
3920 mips_addiu (code, mips_at, mips_at, -1);
3921 mips_bne (code, mips_at, mips_zero, -3);
3922 mips_addiu (code, mips_temp, mips_temp, 1);
3924 mips_patch (buf, (guint32)code);
3929 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3930 mips_move (code, mips_a0, ins->sreg1);
3931 mips_call (code, mips_t9, addr);
3932 mips_break (code, 0xfc);
3936 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3937 mips_move (code, mips_a0, ins->sreg1);
3938 mips_call (code, mips_t9, addr);
3939 mips_break (code, 0xfb);
3942 case OP_START_HANDLER: {
3944 * The START_HANDLER instruction marks the beginning of
3945 * a handler block. It is called using a call
3946 * instruction, so mips_ra contains the return address.
3947 * Since the handler executes in the same stack frame
3948 * as the method itself, we can't use save/restore to
3949 * save the return address. Instead, we save it into
3950 * a dedicated variable.
3952 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3953 g_assert (spvar->inst_basereg != mips_sp);
3954 code = emit_reserve_param_area (cfg, code);
3956 if (mips_is_imm16 (spvar->inst_offset)) {
3957 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3959 mips_load_const (code, mips_at, spvar->inst_offset);
3960 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3961 mips_sw (code, mips_ra, mips_at, 0);
3965 case OP_ENDFILTER: {
3966 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3967 g_assert (spvar->inst_basereg != mips_sp);
3968 code = emit_unreserve_param_area (cfg, code);
3970 if (ins->sreg1 != mips_v0)
3971 MIPS_MOVE (code, mips_v0, ins->sreg1);
3972 if (mips_is_imm16 (spvar->inst_offset)) {
3973 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3975 mips_load_const (code, mips_at, spvar->inst_offset);
3976 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3977 mips_lw (code, mips_ra, mips_at, 0);
3979 mips_jr (code, mips_ra);
3983 case OP_ENDFINALLY: {
3984 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3985 g_assert (spvar->inst_basereg != mips_sp);
3986 code = emit_unreserve_param_area (cfg, code);
3987 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3988 mips_jalr (code, mips_t9, mips_ra);
3992 case OP_CALL_HANDLER:
3993 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3994 mips_lui (code, mips_t9, mips_zero, 0);
3995 mips_addiu (code, mips_t9, mips_t9, 0);
3996 mips_jalr (code, mips_t9, mips_ra);
3998 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3999 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4002 ins->inst_c0 = code - cfg->native_code;
4005 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4006 if (cfg->arch.long_branch) {
4007 mips_lui (code, mips_at, mips_zero, 0);
4008 mips_addiu (code, mips_at, mips_at, 0);
4009 mips_jr (code, mips_at);
4013 mips_beq (code, mips_zero, mips_zero, 0);
4018 mips_jr (code, ins->sreg1);
4024 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4025 if (offset > (cfg->code_size - max_len - 16)) {
4026 cfg->code_size += max_len;
4027 cfg->code_size *= 2;
4028 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4029 code = cfg->native_code + offset;
4031 g_assert (ins->sreg1 != -1);
4032 mips_sll (code, mips_at, ins->sreg1, 2);
4033 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4034 MIPS_MOVE (code, mips_t8, mips_ra);
4035 mips_bgezal (code, mips_zero, 1); /* bal */
4037 mips_addu (code, mips_t9, mips_ra, mips_at);
4038 /* Table is 16 or 20 bytes from target of bal above */
4039 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4040 MIPS_MOVE (code, mips_ra, mips_t8);
4041 mips_lw (code, mips_t9, mips_t9, 20);
4044 mips_lw (code, mips_t9, mips_t9, 16);
4045 mips_jalr (code, mips_t9, mips_t8);
4047 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4048 mips_emit32 (code, 0xfefefefe);
4053 mips_addiu (code, ins->dreg, mips_zero, 1);
4054 mips_beq (code, mips_at, mips_zero, 2);
4056 MIPS_MOVE (code, ins->dreg, mips_zero);
4062 mips_addiu (code, ins->dreg, mips_zero, 1);
4063 mips_bltz (code, mips_at, 2);
4065 MIPS_MOVE (code, ins->dreg, mips_zero);
4071 mips_addiu (code, ins->dreg, mips_zero, 1);
4072 mips_bgtz (code, mips_at, 2);
4074 MIPS_MOVE (code, ins->dreg, mips_zero);
4077 case OP_MIPS_COND_EXC_EQ:
4078 case OP_MIPS_COND_EXC_GE:
4079 case OP_MIPS_COND_EXC_GT:
4080 case OP_MIPS_COND_EXC_LE:
4081 case OP_MIPS_COND_EXC_LT:
4082 case OP_MIPS_COND_EXC_NE_UN:
4083 case OP_MIPS_COND_EXC_GE_UN:
4084 case OP_MIPS_COND_EXC_GT_UN:
4085 case OP_MIPS_COND_EXC_LE_UN:
4086 case OP_MIPS_COND_EXC_LT_UN:
4088 case OP_MIPS_COND_EXC_OV:
4089 case OP_MIPS_COND_EXC_NO:
4090 case OP_MIPS_COND_EXC_C:
4091 case OP_MIPS_COND_EXC_NC:
4093 case OP_MIPS_COND_EXC_IEQ:
4094 case OP_MIPS_COND_EXC_IGE:
4095 case OP_MIPS_COND_EXC_IGT:
4096 case OP_MIPS_COND_EXC_ILE:
4097 case OP_MIPS_COND_EXC_ILT:
4098 case OP_MIPS_COND_EXC_INE_UN:
4099 case OP_MIPS_COND_EXC_IGE_UN:
4100 case OP_MIPS_COND_EXC_IGT_UN:
4101 case OP_MIPS_COND_EXC_ILE_UN:
4102 case OP_MIPS_COND_EXC_ILT_UN:
4104 case OP_MIPS_COND_EXC_IOV:
4105 case OP_MIPS_COND_EXC_INO:
4106 case OP_MIPS_COND_EXC_IC:
4107 case OP_MIPS_COND_EXC_INC: {
4111 /* If the condition is true, raise the exception */
4113 /* need to reverse test to skip around exception raising */
4115 /* For the moment, branch around a branch to avoid reversing
4118 /* Remember, an unpatched branch to 0 branches to the delay slot */
4119 switch (ins->opcode) {
4120 case OP_MIPS_COND_EXC_EQ:
4121 throw = (guint32 *)(void *)code;
4122 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4126 case OP_MIPS_COND_EXC_NE_UN:
4127 throw = (guint32 *)(void *)code;
4128 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4132 case OP_MIPS_COND_EXC_LE_UN:
4133 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4134 throw = (guint32 *)(void *)code;
4135 mips_beq (code, mips_at, mips_zero, 0);
4139 case OP_MIPS_COND_EXC_GT:
4140 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4141 throw = (guint32 *)(void *)code;
4142 mips_bne (code, mips_at, mips_zero, 0);
4146 case OP_MIPS_COND_EXC_GT_UN:
4147 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4148 throw = (guint32 *)(void *)code;
4149 mips_bne (code, mips_at, mips_zero, 0);
4153 case OP_MIPS_COND_EXC_LT:
4154 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4155 throw = (guint32 *)(void *)code;
4156 mips_bne (code, mips_at, mips_zero, 0);
4160 case OP_MIPS_COND_EXC_LT_UN:
4161 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4162 throw = (guint32 *)(void *)code;
4163 mips_bne (code, mips_at, mips_zero, 0);
4168 /* Not yet implemented */
4169 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4170 g_assert_not_reached ();
4172 skip = (guint32 *)(void *)code;
4173 mips_beq (code, mips_zero, mips_zero, 0);
4175 mips_patch (throw, (guint32)code);
4176 code = mips_emit_exc_by_name (code, ins->inst_p1);
4177 mips_patch (skip, (guint32)code);
4178 cfg->bb_exit->max_offset += 24;
4187 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4190 /* floating point opcodes */
4193 if (((guint32)ins->inst_p0) & (1 << 15))
4194 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4196 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4197 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4199 mips_load_const (code, mips_at, ins->inst_p0);
4200 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4201 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4205 if (((guint32)ins->inst_p0) & (1 << 15))
4206 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4208 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4209 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4210 #if PROMOTE_R4_TO_R8
4211 mips_cvtds (code, ins->dreg, ins->dreg);
4214 case OP_STORER8_MEMBASE_REG:
4215 if (mips_is_imm16 (ins->inst_offset)) {
4216 #if _MIPS_SIM == _ABIO32
4217 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4218 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4219 #elif _MIPS_SIM == _ABIN32
4220 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4223 mips_load_const (code, mips_at, ins->inst_offset);
4224 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4225 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4226 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4229 case OP_LOADR8_MEMBASE:
4230 if (mips_is_imm16 (ins->inst_offset)) {
4231 #if _MIPS_SIM == _ABIO32
4232 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4233 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4234 #elif _MIPS_SIM == _ABIN32
4235 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4238 mips_load_const (code, mips_at, ins->inst_offset);
4239 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4240 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4241 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4244 case OP_STORER4_MEMBASE_REG:
4245 g_assert (mips_is_imm16 (ins->inst_offset));
4246 #if PROMOTE_R4_TO_R8
4247 /* Need to convert ins->sreg1 to single-precision first */
4248 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4249 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4251 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4255 g_assert (mips_is_imm16 (ins->inst_offset));
4256 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4258 case OP_LOADR4_MEMBASE:
4259 g_assert (mips_is_imm16 (ins->inst_offset));
4260 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4261 #if PROMOTE_R4_TO_R8
4262 /* Convert to double precision in place */
4263 mips_cvtds (code, ins->dreg, ins->dreg);
4266 case OP_LOADR4_MEMINDEX:
4267 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4268 mips_lwc1 (code, ins->dreg, mips_at, 0);
4270 case OP_LOADR8_MEMINDEX:
4271 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4272 #if _MIPS_SIM == _ABIO32
4273 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4274 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4275 #elif _MIPS_SIM == _ABIN32
4276 mips_ldc1 (code, ins->dreg, mips_at, 0);
4279 case OP_STORER4_MEMINDEX:
4280 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4281 #if PROMOTE_R4_TO_R8
4282 /* Need to convert ins->sreg1 to single-precision first */
4283 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4284 mips_swc1 (code, mips_ftemp, mips_at, 0);
4286 mips_swc1 (code, ins->sreg1, mips_at, 0);
4289 case OP_STORER8_MEMINDEX:
4290 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4291 #if _MIPS_SIM == _ABIO32
4292 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4293 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4294 #elif _MIPS_SIM == _ABIN32
4295 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4298 case OP_ICONV_TO_R_UN: {
4299 static const guint64 adjust_val = 0x41F0000000000000ULL;
4301 /* convert unsigned int to double */
4302 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4303 mips_bgez (code, ins->sreg1, 5);
4304 mips_cvtdw (code, ins->dreg, mips_ftemp);
4306 mips_load (code, mips_at, (guint32) &adjust_val);
4307 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4308 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4309 /* target is here */
4312 case OP_ICONV_TO_R4:
4313 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4314 mips_cvtsw (code, ins->dreg, mips_ftemp);
4315 mips_cvtds (code, ins->dreg, ins->dreg);
4317 case OP_ICONV_TO_R8:
4318 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4319 mips_cvtdw (code, ins->dreg, mips_ftemp);
4321 case OP_FCONV_TO_I1:
4322 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4324 case OP_FCONV_TO_U1:
4325 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4327 case OP_FCONV_TO_I2:
4328 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4330 case OP_FCONV_TO_U2:
4331 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4333 case OP_FCONV_TO_I4:
4335 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4337 case OP_FCONV_TO_U4:
4339 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4342 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4345 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4348 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4351 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4354 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4357 mips_fnegd (code, ins->dreg, ins->sreg1);
4360 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4361 mips_addiu (code, ins->dreg, mips_zero, 1);
4362 mips_fbtrue (code, 2);
4364 MIPS_MOVE (code, ins->dreg, mips_zero);
4367 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4368 mips_addiu (code, ins->dreg, mips_zero, 1);
4369 mips_fbtrue (code, 2);
4371 MIPS_MOVE (code, ins->dreg, mips_zero);
4374 /* Less than, or Unordered */
4375 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4376 mips_addiu (code, ins->dreg, mips_zero, 1);
4377 mips_fbtrue (code, 2);
4379 MIPS_MOVE (code, ins->dreg, mips_zero);
4382 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4383 MIPS_MOVE (code, ins->dreg, mips_zero);
4384 mips_fbtrue (code, 2);
4386 mips_addiu (code, ins->dreg, mips_zero, 1);
4389 /* Greater than, or Unordered */
4390 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4391 MIPS_MOVE (code, ins->dreg, mips_zero);
4392 mips_fbtrue (code, 2);
4394 mips_addiu (code, ins->dreg, mips_zero, 1);
4399 case OP_MIPS_FBLT_UN:
4401 case OP_MIPS_FBGT_UN:
4403 case OP_MIPS_FBGE_UN:
4405 case OP_MIPS_FBLE_UN: {
4407 gboolean is_true = TRUE, is_ordered = FALSE;
4408 guint32 *buf = NULL;
4410 switch (ins->opcode) {
4424 case OP_MIPS_FBLT_UN:
4425 cond = MIPS_FPU_ULT;
4433 case OP_MIPS_FBGT_UN:
4434 cond = MIPS_FPU_OLE;
4442 case OP_MIPS_FBGE_UN:
4443 cond = MIPS_FPU_OLT;
4447 cond = MIPS_FPU_OLE;
4451 case OP_MIPS_FBLE_UN:
4452 cond = MIPS_FPU_ULE;
4456 g_assert_not_reached ();
4460 /* Skip the check if unordered */
4461 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4463 buf = (guint32*)code;
4464 mips_fbtrue (code, 0);
4468 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4470 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4472 mips_fbtrue (code, 0);
4474 mips_fbfalse (code, 0);
4478 mips_patch (buf, (guint32)code);
4482 guint32 *branch_patch;
4484 mips_mfc1 (code, mips_at, ins->sreg1+1);
4485 mips_srl (code, mips_at, mips_at, 16+4);
4486 mips_andi (code, mips_at, mips_at, 2047);
4487 mips_addiu (code, mips_at, mips_at, -2047);
4489 branch_patch = (guint32 *)(void *)code;
4490 mips_bne (code, mips_at, mips_zero, 0);
4493 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4494 mips_patch (branch_patch, (guint32)code);
4495 mips_fmovd (code, ins->dreg, ins->sreg1);
4499 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4500 mips_load (code, ins->dreg, 0x0f0f0f0f);
4502 case OP_GC_SAFE_POINT:
4507 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4508 g_assert_not_reached ();
4511 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4512 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4513 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4514 g_assert_not_reached ();
4520 last_offset = offset;
4523 cfg->code_len = code - cfg->native_code;
4527 mono_arch_register_lowlevel_calls (void)
4532 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4534 MonoJumpInfo *patch_info;
4536 mono_error_init (error);
4538 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4539 unsigned char *ip = patch_info->ip.i + code;
4540 const unsigned char *target = NULL;
4542 switch (patch_info->type) {
4543 case MONO_PATCH_INFO_IP:
4544 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4546 case MONO_PATCH_INFO_SWITCH: {
4547 gpointer *table = (gpointer *)patch_info->data.table->table;
4550 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4552 for (i = 0; i < patch_info->data.table->table_size; i++) {
4553 table [i] = (int)patch_info->data.table->table [i] + code;
4557 case MONO_PATCH_INFO_METHODCONST:
4558 case MONO_PATCH_INFO_CLASS:
4559 case MONO_PATCH_INFO_IMAGE:
4560 case MONO_PATCH_INFO_FIELD:
4561 case MONO_PATCH_INFO_VTABLE:
4562 case MONO_PATCH_INFO_IID:
4563 case MONO_PATCH_INFO_SFLDA:
4564 case MONO_PATCH_INFO_LDSTR:
4565 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4566 case MONO_PATCH_INFO_LDTOKEN:
4567 case MONO_PATCH_INFO_R4:
4568 case MONO_PATCH_INFO_R8:
4569 /* from OP_AOTCONST : lui + addiu */
4570 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4571 return_if_nok (error);
4573 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4576 case MONO_PATCH_INFO_EXC_NAME:
4577 g_assert_not_reached ();
4578 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4581 case MONO_PATCH_INFO_NONE:
4582 /* everything is dealt with at epilog output time */
4585 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4586 return_if_nok (error);
4588 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4595 * Allow tracing to work with this interface (with an optional argument)
4597 * This code is expected to be inserted just after the 'real' prolog code,
4598 * and before the first basic block. We need to allocate a 2nd, temporary
4599 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4603 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4606 int offset = cfg->arch.tracing_offset;
4612 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4613 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4614 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4615 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4616 #if _MIPS_SIM == _ABIN32
4618 /* FIXME: Need a separate region for these */
4619 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4620 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4621 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4622 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4626 mips_load_const (code, mips_a0, cfg->method);
4627 mips_addiu (code, mips_a1, mips_sp, offset);
4628 mips_call (code, mips_t9, func);
4631 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4632 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4633 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4634 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4635 #if _MIPS_SIM == _ABIN32
4638 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4639 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4640 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4641 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4652 mips_adjust_stackframe(MonoCompile *cfg)
4655 int delta, threshold, i;
4656 MonoMethodSignature *sig;
4659 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4662 /* adjust cfg->stack_offset for account for down-spilling */
4663 cfg->stack_offset += SIZEOF_REGISTER;
4665 /* re-align cfg->stack_offset if needed (due to var spilling) */
4666 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4667 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4668 if (cfg->verbose_level > 2) {
4669 g_print ("mips_adjust_stackframe:\n");
4670 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4672 threshold = cfg->arch.local_alloc_offset;
4673 ra_offset = cfg->stack_offset - sizeof(gpointer);
4674 if (cfg->verbose_level > 2) {
4675 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4678 sig = mono_method_signature (cfg->method);
4679 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4680 cfg->vret_addr->inst_offset += delta;
4682 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4683 MonoInst *inst = cfg->args [i];
4685 inst->inst_offset += delta;
4689 * loads and stores based off the frame reg that (used to) lie
4690 * above the spill var area need to be increased by 'delta'
4691 * to make room for the spill vars.
4693 /* Need to find loads and stores to adjust that
4694 * are above where the spillvars were inserted, but
4695 * which are not the spillvar references themselves.
4697 * Idea - since all offsets from fp are positive, make
4698 * spillvar offsets negative to begin with so we can spot
4703 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4707 if (cfg->verbose_level > 2) {
4708 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4710 MONO_BB_FOR_EACH_INS (bb, ins) {
4714 if (cfg->verbose_level > 2) {
4715 mono_print_ins_index (ins_cnt, ins);
4717 /* The == mips_sp tests catch FP spills */
4718 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4719 (ins->inst_basereg == mips_sp))) {
4720 switch (ins->opcode) {
4721 case OP_LOADI8_MEMBASE:
4722 case OP_LOADR8_MEMBASE:
4729 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4730 (ins->dreg == mips_sp))) {
4731 switch (ins->opcode) {
4732 case OP_STOREI8_MEMBASE_REG:
4733 case OP_STORER8_MEMBASE_REG:
4734 case OP_STOREI8_MEMBASE_IMM:
4742 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4745 if (ins->inst_c0 >= threshold) {
4746 ins->inst_c0 += delta;
4747 if (cfg->verbose_level > 2) {
4749 mono_print_ins_index (ins_cnt, ins);
4752 else if (ins->inst_c0 < 0) {
4753 /* Adj_c0 holds the size of the datatype. */
4754 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4755 if (cfg->verbose_level > 2) {
4757 mono_print_ins_index (ins_cnt, ins);
4760 g_assert (ins->inst_c0 != ra_offset);
4763 if (ins->inst_imm >= threshold) {
4764 ins->inst_imm += delta;
4765 if (cfg->verbose_level > 2) {
4767 mono_print_ins_index (ins_cnt, ins);
4770 g_assert (ins->inst_c0 != ra_offset);
4780 * Stack frame layout:
4782 * ------------------- sp + cfg->stack_usage + cfg->param_area
4783 * param area incoming
4784 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4786 * ------------------- sp + cfg->stack_usage
4788 * ------------------- sp + cfg->stack_usage-4
4790 * ------------------- sp +
4791 * MonoLMF structure optional
4792 * ------------------- sp + cfg->arch.lmf_offset
4793 * saved registers s0-s8
4794 * ------------------- sp + cfg->arch.iregs_offset
4796 * ------------------- sp + cfg->param_area
4797 * param area outgoing
4798 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4800 * ------------------- sp
4804 mono_arch_emit_prolog (MonoCompile *cfg)
4806 MonoMethod *method = cfg->method;
4807 MonoMethodSignature *sig;
4809 int alloc_size, pos, i, max_offset;
4810 int alloc2_size = 0;
4814 guint32 iregs_to_save = 0;
4816 guint32 fregs_to_save = 0;
4818 /* lmf_offset is the offset of the LMF from our stack pointer. */
4819 guint32 lmf_offset = cfg->arch.lmf_offset;
4823 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4827 cfg->flags |= MONO_CFG_HAS_CALLS;
4829 sig = mono_method_signature (method);
4830 cfg->code_size = 768 + sig->param_count * 20;
4831 code = cfg->native_code = g_malloc (cfg->code_size);
4834 * compute max_offset in order to use short forward jumps.
4837 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4838 MonoInst *ins = bb->code;
4839 bb->max_offset = max_offset;
4841 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4844 MONO_BB_FOR_EACH_INS (bb, ins)
4845 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4847 if (max_offset > 0xffff)
4848 cfg->arch.long_branch = TRUE;
4851 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4852 * This means that we have to adjust the offsets inside instructions which reference
4853 * arguments received on the stack, since the initial offset doesn't take into
4854 * account spill slots.
4856 mips_adjust_stackframe (cfg);
4858 /* Offset between current sp and the CFA */
4860 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4862 /* stack_offset should not be changed here. */
4863 alloc_size = cfg->stack_offset;
4864 cfg->stack_usage = alloc_size;
4866 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4869 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4871 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4872 fregs_to_save |= (fregs_to_save << 1);
4875 /* If the stack size is too big, save 1024 bytes to start with
4876 * so the prologue can use imm16(reg) addressing, then allocate
4877 * the rest of the frame.
4879 if (alloc_size > ((1 << 15) - 1024)) {
4880 alloc2_size = alloc_size - 1024;
4884 g_assert (mips_is_imm16 (-alloc_size));
4885 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4886 cfa_offset = alloc_size;
4887 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4890 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4891 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4892 if (mips_is_imm16(offset))
4893 mips_sw (code, mips_ra, mips_sp, offset);
4895 g_assert_not_reached ();
4897 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4898 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4901 /* XXX - optimize this later to not save all regs if LMF constructed */
4902 pos = cfg->arch.iregs_offset - alloc2_size;
4904 if (iregs_to_save) {
4905 /* save used registers in own stack frame (at pos) */
4906 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4907 if (iregs_to_save & (1 << i)) {
4908 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4909 g_assert (mips_is_imm16(pos));
4910 MIPS_SW (code, i, mips_sp, pos);
4911 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4912 pos += SIZEOF_REGISTER;
4917 // FIXME: Don't save registers twice if there is an LMF
4918 // s8 has to be special cased since it is overwritten with the updated value
4920 if (method->save_lmf) {
4921 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4922 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4923 g_assert (mips_is_imm16(offset));
4924 if (MIPS_LMF_IREGMASK & (1 << i))
4925 MIPS_SW (code, i, mips_sp, offset);
4930 /* Save float registers */
4931 if (fregs_to_save) {
4932 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4933 if (fregs_to_save & (1 << i)) {
4934 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4935 g_assert (mips_is_imm16(pos));
4936 mips_swc1 (code, i, mips_sp, pos);
4937 pos += sizeof (gulong);
4942 if (method->save_lmf) {
4943 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4944 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4945 g_assert (mips_is_imm16(offset));
4946 mips_swc1 (code, i, mips_sp, offset);
4951 if (cfg->frame_reg != mips_sp) {
4952 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4953 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4955 if (method->save_lmf) {
4956 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4957 g_assert (mips_is_imm16(offset));
4958 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4962 /* store runtime generic context */
4963 if (cfg->rgctx_var) {
4964 MonoInst *ins = cfg->rgctx_var;
4966 g_assert (ins->opcode == OP_REGOFFSET);
4968 g_assert (mips_is_imm16 (ins->inst_offset));
4969 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4972 /* load arguments allocated to register from the stack */
4975 if (!cfg->arch.cinfo)
4976 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
4977 cinfo = cfg->arch.cinfo;
4979 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4980 ArgInfo *ainfo = &cinfo->ret;
4981 inst = cfg->vret_addr;
4982 if (inst->opcode == OP_REGVAR)
4983 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4984 else if (mips_is_imm16 (inst->inst_offset)) {
4985 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4987 mips_load_const (code, mips_at, inst->inst_offset);
4988 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4989 mips_sw (code, ainfo->reg, mips_at, 0);
4993 if (sig->call_convention == MONO_CALL_VARARG) {
4994 ArgInfo *cookie = &cinfo->sig_cookie;
4995 int offset = alloc_size + cookie->offset;
4997 /* Save the sig cookie address */
4998 g_assert (cookie->storage == ArgOnStack);
5000 g_assert (mips_is_imm16(offset));
5001 mips_addi (code, mips_at, cfg->frame_reg, offset);
5002 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5005 /* Keep this in sync with emit_load_volatile_arguments */
5006 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5007 ArgInfo *ainfo = cinfo->args + i;
5008 inst = cfg->args [pos];
5010 if (cfg->verbose_level > 2)
5011 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5012 if (inst->opcode == OP_REGVAR) {
5013 /* Argument ends up in a register */
5014 if (ainfo->storage == ArgInIReg)
5015 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5016 else if (ainfo->storage == ArgInFReg) {
5017 g_assert_not_reached();
5019 ppc_fmr (code, inst->dreg, ainfo->reg);
5022 else if (ainfo->storage == ArgOnStack) {
5023 int offset = cfg->stack_usage + ainfo->offset;
5024 g_assert (mips_is_imm16(offset));
5025 mips_lw (code, inst->dreg, mips_sp, offset);
5027 g_assert_not_reached ();
5029 if (cfg->verbose_level > 2)
5030 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5032 /* Argument ends up on the stack */
5033 if (ainfo->storage == ArgInIReg) {
5035 /* Incoming parameters should be above this frame */
5036 if (cfg->verbose_level > 2)
5037 g_print ("stack slot at %d of %d+%d\n",
5038 inst->inst_offset, alloc_size, alloc2_size);
5039 /* g_assert (inst->inst_offset >= alloc_size); */
5040 g_assert (inst->inst_basereg == cfg->frame_reg);
5041 basereg_offset = inst->inst_offset - alloc2_size;
5042 g_assert (mips_is_imm16 (basereg_offset));
5043 switch (ainfo->size) {
5045 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5048 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5052 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5055 #if (SIZEOF_REGISTER == 4)
5056 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5057 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5058 #elif (SIZEOF_REGISTER == 8)
5059 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5063 g_assert_not_reached ();
5066 } else if (ainfo->storage == ArgOnStack) {
5068 * Argument comes in on the stack, and ends up on the stack
5069 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5070 * 8 and 16 bit quantities. Shorten them in place.
5072 g_assert (mips_is_imm16 (inst->inst_offset));
5073 switch (ainfo->size) {
5075 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5076 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5079 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5080 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5087 g_assert_not_reached ();
5089 } else if (ainfo->storage == ArgInFReg) {
5090 g_assert (mips_is_imm16 (inst->inst_offset));
5091 g_assert (mips_is_imm16 (inst->inst_offset+4));
5092 if (ainfo->size == 8) {
5093 #if _MIPS_SIM == _ABIO32
5094 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5095 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5096 #elif _MIPS_SIM == _ABIN32
5097 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5100 else if (ainfo->size == 4)
5101 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5103 g_assert_not_reached ();
5104 } else if (ainfo->storage == ArgStructByVal) {
5106 int doffset = inst->inst_offset;
5108 g_assert (mips_is_imm16 (inst->inst_offset));
5109 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5110 /* Push the argument registers into their stack slots */
5111 for (i = 0; i < ainfo->size; ++i) {
5112 g_assert (mips_is_imm16(doffset));
5113 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5114 doffset += SIZEOF_REGISTER;
5116 } else if (ainfo->storage == ArgStructByAddr) {
5117 g_assert (mips_is_imm16 (inst->inst_offset));
5118 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5119 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5121 g_assert_not_reached ();
5126 if (method->save_lmf) {
5127 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5128 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5130 /* This can/will clobber the a0-a3 registers */
5131 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5133 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5134 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5135 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5136 /* new_lmf->previous_lmf = *lmf_addr */
5137 mips_lw (code, mips_at, mips_v0, 0);
5138 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5139 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5140 /* *(lmf_addr) = sp + lmf_offset */
5141 g_assert (mips_is_imm16(lmf_offset));
5142 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5143 mips_sw (code, mips_at, mips_v0, 0);
5145 /* save method info */
5146 mips_load_const (code, mips_at, method);
5147 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5148 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5150 /* save the current IP */
5151 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5152 mips_load_const (code, mips_at, 0x01010101);
5153 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5157 if (mips_is_imm16 (-alloc2_size)) {
5158 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5161 mips_load_const (code, mips_at, -alloc2_size);
5162 mips_addu (code, mips_sp, mips_sp, mips_at);
5164 alloc_size += alloc2_size;
5165 cfa_offset += alloc2_size;
5166 if (cfg->frame_reg != mips_sp)
5167 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5169 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5173 #if _MIPS_SIM == _ABIO32
5174 cfg->arch.tracing_offset = cfg->stack_offset;
5175 #elif _MIPS_SIM == _ABIN32
5176 /* no stack slots by default for argument regs, reserve a special block */
5177 g_assert_not_reached ();
5179 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5182 cfg->code_len = code - cfg->native_code;
5183 g_assert (cfg->code_len < cfg->code_size);
5197 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5200 int save_mode = SAVE_NONE;
5202 MonoMethod *method = cfg->method;
5203 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5204 int save_offset = MIPS_STACK_PARAM_OFFSET;
5206 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5208 offset = code - cfg->native_code;
5209 /* we need about 16 instructions */
5210 if (offset > (cfg->code_size - 16 * 4)) {
5211 cfg->code_size *= 2;
5212 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5213 code = cfg->native_code + offset;
5218 case MONO_TYPE_VOID:
5219 /* special case string .ctor icall */
5220 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5221 save_mode = SAVE_ONE;
5223 save_mode = SAVE_NONE;
5227 save_mode = SAVE_FP;
5229 case MONO_TYPE_VALUETYPE:
5230 save_mode = SAVE_STRUCT;
5234 #if SIZEOF_REGISTER == 4
5235 save_mode = SAVE_TWO;
5236 #elif SIZEOF_REGISTER == 8
5237 save_mode = SAVE_ONE;
5241 save_mode = SAVE_ONE;
5245 mips_addiu (code, mips_sp, mips_sp, -32);
5246 g_assert (mips_is_imm16(save_offset));
5247 switch (save_mode) {
5249 mips_sw (code, mips_v0, mips_sp, save_offset);
5250 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5251 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5252 if (enable_arguments) {
5253 MIPS_MOVE (code, mips_a1, mips_v0);
5254 MIPS_MOVE (code, mips_a2, mips_v1);
5258 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5259 if (enable_arguments) {
5260 MIPS_MOVE (code, mips_a1, mips_v0);
5264 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5265 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5266 mips_lw (code, mips_a0, mips_sp, save_offset);
5267 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5268 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5275 mips_load_const (code, mips_a0, cfg->method);
5276 mips_call (code, mips_t9, func);
5278 switch (save_mode) {
5280 mips_lw (code, mips_v0, mips_sp, save_offset);
5281 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5282 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5285 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5288 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5295 mips_addiu (code, mips_sp, mips_sp, 32);
5302 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5304 MonoMethod *method = cfg->method;
5306 int max_epilog_size = 16 + 20*4;
5307 int alloc2_size = 0;
5308 guint32 iregs_to_restore;
5310 guint32 fregs_to_restore;
5313 if (cfg->method->save_lmf)
5314 max_epilog_size += 128;
5316 if (mono_jit_trace_calls != NULL)
5317 max_epilog_size += 50;
5319 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5320 max_epilog_size += 50;
5323 pos = code - cfg->native_code;
5324 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5325 cfg->code_size *= 2;
5326 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5327 cfg->stat_code_reallocs++;
5331 * Keep in sync with OP_JMP
5334 code = cfg->native_code + pos;
5336 code = cfg->native_code + cfg->code_len;
5338 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5339 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5341 if (cfg->frame_reg != mips_sp) {
5342 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5344 /* If the stack frame is really large, deconstruct it in two steps */
5345 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5346 alloc2_size = cfg->stack_usage - 1024;
5347 /* partially deconstruct the stack */
5348 mips_load_const (code, mips_at, alloc2_size);
5349 mips_addu (code, mips_sp, mips_sp, mips_at);
5351 pos = cfg->arch.iregs_offset - alloc2_size;
5352 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5353 if (iregs_to_restore) {
5354 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5355 if (iregs_to_restore & (1 << i)) {
5356 g_assert (mips_is_imm16(pos));
5357 MIPS_LW (code, i, mips_sp, pos);
5358 pos += SIZEOF_REGISTER;
5365 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5367 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5368 fregs_to_restore |= (fregs_to_restore << 1);
5370 if (fregs_to_restore) {
5371 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5372 if (fregs_to_restore & (1 << i)) {
5373 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5374 g_assert (mips_is_imm16(pos));
5375 mips_lwc1 (code, i, mips_sp, pos);
5382 /* Unlink the LMF if necessary */
5383 if (method->save_lmf) {
5384 int lmf_offset = cfg->arch.lmf_offset;
5386 /* t0 = current_lmf->previous_lmf */
5387 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5388 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5390 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5391 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5392 /* (*lmf_addr) = previous_lmf */
5393 mips_sw (code, mips_temp, mips_t1, 0);
5397 /* Restore the fp */
5398 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5401 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5402 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5403 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5405 /* Restore the stack pointer */
5406 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5407 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5409 /* Caller will emit either return or tail-call sequence */
5411 cfg->code_len = code - cfg->native_code;
5413 g_assert (cfg->code_len < cfg->code_size);
5418 mono_arch_emit_epilog (MonoCompile *cfg)
5422 code = mono_arch_emit_epilog_sub (cfg, NULL);
5424 mips_jr (code, mips_ra);
5427 cfg->code_len = code - cfg->native_code;
5429 g_assert (cfg->code_len < cfg->code_size);
5432 /* remove once throw_exception_by_name is eliminated */
5435 exception_id_by_name (const char *name)
5437 if (strcmp (name, "IndexOutOfRangeException") == 0)
5438 return MONO_EXC_INDEX_OUT_OF_RANGE;
5439 if (strcmp (name, "OverflowException") == 0)
5440 return MONO_EXC_OVERFLOW;
5441 if (strcmp (name, "ArithmeticException") == 0)
5442 return MONO_EXC_ARITHMETIC;
5443 if (strcmp (name, "DivideByZeroException") == 0)
5444 return MONO_EXC_DIVIDE_BY_ZERO;
5445 if (strcmp (name, "InvalidCastException") == 0)
5446 return MONO_EXC_INVALID_CAST;
5447 if (strcmp (name, "NullReferenceException") == 0)
5448 return MONO_EXC_NULL_REF;
5449 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5450 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5451 if (strcmp (name, "ArgumentException") == 0)
5452 return MONO_EXC_ARGUMENT;
5453 g_error ("Unknown intrinsic exception %s\n", name);
5459 mono_arch_emit_exceptions (MonoCompile *cfg)
5462 MonoJumpInfo *patch_info;
5465 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5466 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5467 int max_epilog_size = 50;
5469 /* count the number of exception infos */
5472 * make sure we have enough space for exceptions
5473 * 24 is the simulated call to throw_exception_by_name
5475 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5477 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5478 i = exception_id_by_name (patch_info->data.target);
5479 g_assert (i < MONO_EXC_INTRINS_NUM);
5480 if (!exc_throw_found [i]) {
5481 max_epilog_size += 12;
5482 exc_throw_found [i] = TRUE;
5488 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5489 cfg->code_size *= 2;
5490 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5491 cfg->stat_code_reallocs++;
5494 code = cfg->native_code + cfg->code_len;
5496 /* add code to raise exceptions */
5497 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5498 switch (patch_info->type) {
5499 case MONO_PATCH_INFO_EXC: {
5501 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5503 i = exception_id_by_name (patch_info->data.target);
5504 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5505 if (!exc_throw_pos [i]) {
5508 exc_throw_pos [i] = code;
5509 //g_print ("exc: writing stub at %p\n", code);
5510 mips_load_const (code, mips_a0, patch_info->data.target);
5511 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5512 mips_load_const (code, mips_t9, addr);
5513 mips_jr (code, mips_t9);
5516 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5518 /* Turn into a Relative patch, pointing at code stub */
5519 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5520 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5522 g_assert_not_reached();
5532 cfg->code_len = code - cfg->native_code;
5534 g_assert (cfg->code_len < cfg->code_size);
5539 mono_arch_finish_init (void)
5544 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5549 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5551 int this_dreg = mips_a0;
5554 this_dreg = mips_a1;
5556 /* add the this argument */
5557 if (this_reg != -1) {
5559 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5560 this_ins->type = this_type;
5561 this_ins->sreg1 = this_reg;
5562 this_ins->dreg = mono_alloc_ireg (cfg);
5563 mono_bblock_add_inst (cfg->cbb, this_ins);
5564 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5569 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5570 vtarg->type = STACK_MP;
5571 vtarg->sreg1 = vt_reg;
5572 vtarg->dreg = mono_alloc_ireg (cfg);
5573 mono_bblock_add_inst (cfg->cbb, vtarg);
5574 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5579 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5581 MonoInst *ins = NULL;
5587 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5593 mono_arch_print_tree (MonoInst *tree, int arity)
5599 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5601 return ctx->sc_regs [reg];
5604 #define ENABLE_WRONG_METHOD_CHECK 0
5606 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5607 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5609 #define LOADSTORE_SIZE 4
5610 #define JUMP_IMM_SIZE 16
5611 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5612 #define LOAD_CONST_SIZE 8
5613 #define JUMP_JR_SIZE 8
5616 * LOCKING: called with the domain lock held
5619 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5620 gpointer fail_tramp)
5624 guint8 *code, *start, *patch;
5626 for (i = 0; i < count; ++i) {
5627 MonoIMTCheckItem *item = imt_entries [i];
5629 if (item->is_equals) {
5630 if (item->check_target_idx) {
5631 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5632 if (item->has_target_code)
5633 item->chunk_size += LOAD_CONST_SIZE;
5635 item->chunk_size += LOADSTORE_SIZE;
5638 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5639 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5640 if (!item->has_target_code)
5641 item->chunk_size += LOADSTORE_SIZE;
5643 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5644 #if ENABLE_WRONG_METHOD_CHECK
5645 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5650 item->chunk_size += CMP_SIZE + BR_SIZE;
5651 imt_entries [item->check_target_idx]->compare_done = TRUE;
5653 size += item->chunk_size;
5655 /* the initial load of the vtable address */
5656 size += MIPS_LOAD_SEQUENCE_LENGTH;
5658 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5660 code = mono_domain_code_reserve (domain, size);
5664 /* t7 points to the vtable */
5665 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5667 for (i = 0; i < count; ++i) {
5668 MonoIMTCheckItem *item = imt_entries [i];
5670 item->code_target = code;
5671 if (item->is_equals) {
5672 if (item->check_target_idx) {
5673 mips_load_const (code, mips_temp, (gsize)item->key);
5674 item->jmp_code = code;
5675 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5677 if (item->has_target_code) {
5678 mips_load_const (code, mips_t9,
5679 item->value.target_code);
5682 mips_lw (code, mips_t9, mips_t7,
5683 (sizeof (gpointer) * item->value.vtable_slot));
5685 mips_jr (code, mips_t9);
5689 mips_load_const (code, mips_temp, (gsize)item->key);
5691 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5693 if (item->has_target_code) {
5694 mips_load_const (code, mips_t9,
5695 item->value.target_code);
5698 mips_load_const (code, mips_at,
5699 & (vtable->vtable [item->value.vtable_slot]));
5700 mips_lw (code, mips_t9, mips_at, 0);
5702 mips_jr (code, mips_t9);
5704 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5705 mips_load_const (code, mips_t9, fail_tramp);
5706 mips_jr (code, mips_t9);
5709 /* enable the commented code to assert on wrong method */
5710 #if ENABLE_WRONG_METHOD_CHECK
5711 ppc_load (code, ppc_r0, (guint32)item->key);
5712 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5714 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5716 mips_lw (code, mips_t9, mips_t7,
5717 (sizeof (gpointer) * item->value.vtable_slot));
5718 mips_jr (code, mips_t9);
5721 #if ENABLE_WRONG_METHOD_CHECK
5722 ppc_patch (patch, code);
5728 mips_load_const (code, mips_temp, (gulong)item->key);
5729 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5731 item->jmp_code = code;
5732 mips_beq (code, mips_temp, mips_zero, 0);
5736 /* patch the branches to get to the target items */
5737 for (i = 0; i < count; ++i) {
5738 MonoIMTCheckItem *item = imt_entries [i];
5739 if (item->jmp_code && item->check_target_idx) {
5740 mips_patch ((guint32 *)item->jmp_code,
5741 (guint32)imt_entries [item->check_target_idx]->code_target);
5746 mono_stats.imt_trampolines_size += code - start;
5747 g_assert (code - start <= size);
5748 mono_arch_flush_icache (start, size);
5750 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5756 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5758 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5762 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5764 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5767 /* Soft Debug support */
5768 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5771 * mono_arch_set_breakpoint:
5773 * See mini-amd64.c for docs.
5776 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5779 guint32 addr = (guint32)bp_trigger_page;
5781 mips_load_const (code, mips_t9, addr);
5782 mips_lw (code, mips_t9, mips_t9, 0);
5784 mono_arch_flush_icache (ip, code - ip);
5788 * mono_arch_clear_breakpoint:
5790 * See mini-amd64.c for docs.
5793 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5801 mono_arch_flush_icache (ip, code - ip);
5805 * mono_arch_start_single_stepping:
5807 * See mini-amd64.c for docs.
5810 mono_arch_start_single_stepping (void)
5812 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5816 * mono_arch_stop_single_stepping:
5818 * See mini-amd64.c for docs.
5821 mono_arch_stop_single_stepping (void)
5823 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5827 * mono_arch_is_single_step_event:
5829 * See mini-amd64.c for docs.
5832 mono_arch_is_single_step_event (void *info, void *sigctx)
5834 siginfo_t* sinfo = (siginfo_t*) info;
5835 /* Sometimes the address is off by 4 */
5836 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5843 * mono_arch_is_breakpoint_event:
5845 * See mini-amd64.c for docs.
5848 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5850 siginfo_t* sinfo = (siginfo_t*) info;
5851 /* Sometimes the address is off by 4 */
5852 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5859 * mono_arch_skip_breakpoint:
5861 * See mini-amd64.c for docs.
5864 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5866 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5870 * mono_arch_skip_single_step:
5872 * See mini-amd64.c for docs.
5875 mono_arch_skip_single_step (MonoContext *ctx)
5877 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5881 * mono_arch_get_seq_point_info:
5883 * See mini-amd64.c for docs.
5886 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5893 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5895 ext->lmf.previous_lmf = prev_lmf;
5896 /* Mark that this is a MonoLMFExt */
5897 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5898 ext->lmf.iregs [mips_sp] = (gssize)ext;
5901 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5904 mono_arch_opcode_supported (int opcode)