3 * MIPS backend for the Mono code generator
6 * Mark Mason (mason@broadcom.com)
8 * Based on mini-ppc.c by
9 * Paolo Molaro (lupus@ximian.com)
10 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2003 Ximian, Inc.
17 #include <asm/cachectl.h>
19 #include <mono/metadata/abi-details.h>
20 #include <mono/metadata/appdomain.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/utils/mono-mmap.h>
23 #include <mono/utils/mono-hwcap.h>
24 #include <mono/utils/unlocked.h>
26 #include <mono/arch/mips/mips-codegen.h>
28 #include "mini-mips.h"
33 #define SAVE_FP_REGS 0
35 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
37 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
38 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
39 remember to update cpu-mips.md if you change this */
41 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
42 #define mips_call(c,D,v) do { \
43 guint32 _target = (guint32)(v); \
44 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
45 mips_load_const (c, D, _target); \
46 mips_jalr (c, D, mips_ra); \
49 mips_jumpl (c, _target >> 2); \
61 /* This mutex protects architecture specific caches */
62 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
63 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
64 static mono_mutex_t mini_arch_mutex;
66 int mono_exc_esp_offset = 0;
68 /* Whenever the host is little-endian */
69 static int little_endian;
70 /* Index of ms word/register */
71 static int ls_word_idx;
72 /* Index of ls word/register */
73 static int ms_word_idx;
74 /* Same for offsets */
75 static int ls_word_offset;
76 static int ms_word_offset;
79 * The code generated for sequence points reads from this location, which is
80 * made read-only when single stepping is enabled.
82 static gpointer ss_trigger_page;
84 /* Enabled breakpoints read from this trigger page */
85 static gpointer bp_trigger_page;
88 #define DEBUG(a) if (cfg->verbose_level > 1) a
94 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
96 code = mips_emit_exc_by_name (code, exc_name); \
97 cfg->bb_exit->max_offset += 16; \
100 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
102 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
103 inst->type = STACK_R8; \
105 inst->inst_p0 = (void*)(addr); \
106 mono_bblock_add_inst (cfg->cbb, inst); \
109 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
110 || ((ins)->opcode == OP_ICOMPARE) \
111 || ((ins)->opcode == OP_LCOMPARE)))
112 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
113 || ((ins)->opcode == OP_ICOMPARE_IMM) \
114 || ((ins)->opcode == OP_LCOMPARE_IMM)))
116 #define INS_REWRITE(ins, op, _s1, _s2) do { \
119 ins->opcode = (op); \
124 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
126 ins->opcode = (op); \
128 ins->inst_imm = (_imm); \
132 typedef struct InstList InstList;
150 guint16 vtsize; /* in param area */
153 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
162 gboolean vtype_retaddr;
171 void patch_lui_addiu(guint32 *ip, guint32 val);
172 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
173 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
174 void mips_adjust_stackframe(MonoCompile *cfg);
175 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
176 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
179 /* Not defined in asm/cachectl.h */
180 int cacheflush(char *addr, int nbytes, int cache);
183 mono_arch_flush_icache (guint8 *code, gint size)
185 /* Linux/MIPS specific */
186 cacheflush ((char*)code, size, BCACHE);
190 mono_arch_flush_register_windows (void)
195 mono_arch_is_inst_imm (gint64 imm)
201 mips_emit_exc_by_name(guint8 *code, const char *name)
204 MonoClass *exc_class;
206 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", name);
208 mips_load_const (code, mips_a0, exc_class->type_token);
209 addr = mono_get_throw_corlib_exception ();
210 mips_call (code, mips_t9, addr);
216 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
218 if (mips_is_imm16 (v))
219 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
221 #if SIZEOF_REGISTER == 8
223 /* v is not a sign-extended 32-bit value */
224 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
225 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
226 mips_dsll (code, dreg, dreg, 16);
227 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
228 mips_dsll (code, dreg, dreg, 16);
229 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
233 if (((guint32)v) & (1 << 15)) {
234 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
237 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
239 if (((guint32)v) & 0xffff)
240 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
246 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
249 if (cfg->arch.long_branch) {
252 /* Invert test and emit branch around jump */
255 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
259 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
263 mips_bltz (code, ins->sreg1, br_offset);
267 mips_blez (code, ins->sreg1, br_offset);
271 mips_bgtz (code, ins->sreg1, br_offset);
275 mips_bgez (code, ins->sreg1, br_offset);
279 g_assert_not_reached ();
281 mono_add_patch_info (cfg, code - cfg->native_code,
282 MONO_PATCH_INFO_BB, ins->inst_true_bb);
283 mips_lui (code, mips_at, mips_zero, 0);
284 mips_addiu (code, mips_at, mips_at, 0);
285 mips_jr (code, mips_at);
289 mono_add_patch_info (cfg, code - cfg->native_code,
290 MONO_PATCH_INFO_BB, ins->inst_true_bb);
293 mips_beq (code, ins->sreg1, ins->sreg2, 0);
297 mips_bne (code, ins->sreg1, ins->sreg2, 0);
301 mips_bgez (code, ins->sreg1, 0);
305 mips_bgtz (code, ins->sreg1, 0);
309 mips_blez (code, ins->sreg1, 0);
313 mips_bltz (code, ins->sreg1, 0);
317 g_assert_not_reached ();
323 /* XXX - big-endian dependent? */
325 patch_lui_addiu(guint32 *ip, guint32 val)
327 guint16 *__lui_addiu = (guint16*)(void *)(ip);
330 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
331 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
334 if (((guint32)(val)) & (1 << 15))
335 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
337 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
338 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
339 mono_arch_flush_icache ((guint8 *)ip, 8);
344 mips_patch (guint32 *code, guint32 target)
347 guint32 op = ins >> 26;
348 guint32 diff, offset;
350 g_assert (trap_target != target);
351 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
353 case 0x00: /* jr ra */
354 if (ins == 0x3e00008)
356 g_assert_not_reached ();
360 g_assert (!(target & 0x03));
361 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
362 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
364 mono_arch_flush_icache ((guint8 *)code, 4);
366 case 0x01: /* BLTZ */
369 case 0x06: /* BLEZ */
370 case 0x07: /* BGTZ */
371 case 0x11: /* bc1t */
372 diff = target - (guint32)(code + 1);
373 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
374 g_assert (!(diff & 0x03));
375 offset = ((gint32)diff) >> 2;
376 if (((int)offset) != ((int)(short)offset))
377 g_assert (((int)offset) == ((int)(short)offset));
378 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
380 mono_arch_flush_icache ((guint8 *)code, 4);
382 case 0x0f: /* LUI / ADDIU pair */
383 g_assert ((code[1] >> 26) == 0x9);
384 patch_lui_addiu (code, target);
385 mono_arch_flush_icache ((guint8 *)code, 8);
389 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
390 g_assert_not_reached ();
394 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
397 mono_arch_regname (int reg) {
398 #if _MIPS_SIM == _ABIO32
399 static const char * rnames[] = {
400 "zero", "at", "v0", "v1",
401 "a0", "a1", "a2", "a3",
402 "t0", "t1", "t2", "t3",
403 "t4", "t5", "t6", "t7",
404 "s0", "s1", "s2", "s3",
405 "s4", "s5", "s6", "s7",
406 "t8", "t9", "k0", "k1",
407 "gp", "sp", "fp", "ra"
409 #elif _MIPS_SIM == _ABIN32
410 static const char * rnames[] = {
411 "zero", "at", "v0", "v1",
412 "a0", "a1", "a2", "a3",
413 "a4", "a5", "a6", "a7",
414 "t0", "t1", "t2", "t3",
415 "s0", "s1", "s2", "s3",
416 "s4", "s5", "s6", "s7",
417 "t8", "t9", "k0", "k1",
418 "gp", "sp", "fp", "ra"
421 if (reg >= 0 && reg < 32)
427 mono_arch_fregname (int reg) {
428 static const char * rnames[] = {
429 "f0", "f1", "f2", "f3",
430 "f4", "f5", "f6", "f7",
431 "f8", "f9", "f10", "f11",
432 "f12", "f13", "f14", "f15",
433 "f16", "f17", "f18", "f19",
434 "f20", "f21", "f22", "f23",
435 "f24", "f25", "f26", "f27",
436 "f28", "f29", "f30", "f31"
438 if (reg >= 0 && reg < 32)
443 /* this function overwrites at */
445 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
447 /* XXX write a loop, not an unrolled loop */
449 mips_lw (code, mips_at, sreg, soffset);
450 mips_sw (code, mips_at, dreg, doffset);
459 * mono_arch_get_argument_info:
460 * @csig: a method signature
461 * @param_count: the number of parameters to consider
462 * @arg_info: an array to store the result infos
464 * Gathers information on parameters such as size, alignment and
465 * padding. arg_info should be large enought to hold param_count + 1 entries.
467 * Returns the size of the activation frame.
470 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
472 int k, frame_size = 0;
473 guint32 size, align, pad;
476 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
477 frame_size += sizeof (gpointer);
481 arg_info [0].offset = offset;
484 frame_size += sizeof (gpointer);
488 arg_info [0].size = frame_size;
490 for (k = 0; k < param_count; k++) {
491 size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
493 /* ignore alignment for now */
496 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
497 arg_info [k].pad = pad;
499 arg_info [k + 1].pad = 0;
500 arg_info [k + 1].size = size;
502 arg_info [k + 1].offset = offset;
506 align = MONO_ARCH_FRAME_ALIGNMENT;
507 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
508 arg_info [k].pad = pad;
513 /* The delegate object plus 3 params */
514 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
517 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
519 guint8 *code, *start;
522 start = code = mono_global_codeman_reserve (16);
524 /* Replace the this argument with the target */
525 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
526 mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
527 mips_jr (code, mips_temp);
530 g_assert ((code - start) <= 16);
532 mono_arch_flush_icache (start, 16);
536 size = 16 + param_count * 4;
537 start = code = mono_global_codeman_reserve (size);
539 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
540 /* slide down the arguments */
541 for (i = 0; i < param_count; ++i) {
542 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
544 mips_jr (code, mips_temp);
547 g_assert ((code - start) <= size);
549 mono_arch_flush_icache (start, size);
553 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
555 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
556 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
564 * mono_arch_get_delegate_invoke_impls:
566 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
570 mono_arch_get_delegate_invoke_impls (void)
576 get_delegate_invoke_impl (&info, TRUE, 0);
577 res = g_slist_prepend (res, info);
579 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
580 get_delegate_invoke_impl (&info, FALSE, i);
581 res = g_slist_prepend (res, info);
588 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
590 guint8 *code, *start;
592 /* FIXME: Support more cases */
593 if (MONO_TYPE_ISSTRUCT (sig->ret))
597 static guint8* cached = NULL;
598 mono_mini_arch_lock ();
600 mono_mini_arch_unlock ();
605 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
608 start = get_delegate_invoke_impl (&info, TRUE, 0);
609 mono_tramp_info_register (info, NULL);
612 mono_mini_arch_unlock ();
615 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
618 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
620 for (i = 0; i < sig->param_count; ++i)
621 if (!mono_is_regsize_var (sig->params [i]))
624 mono_mini_arch_lock ();
625 code = cache [sig->param_count];
627 mono_mini_arch_unlock ();
632 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
633 start = mono_aot_get_trampoline (name);
637 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
638 mono_tramp_info_register (info, NULL);
640 cache [sig->param_count] = start;
641 mono_mini_arch_unlock ();
649 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
655 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
658 return (gpointer)regs [mips_a0];
662 * Initialize the cpu to execute managed code.
665 mono_arch_cpu_init (void)
667 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
676 ls_word_offset = ls_word_idx * 4;
677 ms_word_offset = ms_word_idx * 4;
681 * Initialize architecture specific code.
684 mono_arch_init (void)
686 mono_os_mutex_init_recursive (&mini_arch_mutex);
688 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
689 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
690 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
694 * Cleanup architecture specific code.
697 mono_arch_cleanup (void)
699 mono_os_mutex_destroy (&mini_arch_mutex);
703 mono_arch_have_fast_tls (void)
709 * This function returns the optimizations supported on this cpu.
712 mono_arch_cpu_optimizations (guint32 *exclude_mask)
716 /* no mips-specific optimizations yet */
722 * This function test for all SIMD functions supported.
724 * Returns a bitmask corresponding to all supported versions.
728 mono_arch_cpu_enumerate_simd_versions (void)
730 /* SIMD is currently unimplemented */
735 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
740 for (i = 0; i < cfg->num_varinfo; i++) {
741 MonoInst *ins = cfg->varinfo [i];
742 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
745 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
748 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
751 /* we can only allocate 32 bit values */
752 if (mono_is_regsize_var (ins->inst_vtype)) {
753 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
754 g_assert (i == vmv->idx);
755 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
763 mono_arch_get_global_int_regs (MonoCompile *cfg)
767 regs = g_list_prepend (regs, (gpointer)mips_s0);
768 regs = g_list_prepend (regs, (gpointer)mips_s1);
769 regs = g_list_prepend (regs, (gpointer)mips_s2);
770 regs = g_list_prepend (regs, (gpointer)mips_s3);
771 regs = g_list_prepend (regs, (gpointer)mips_s4);
772 //regs = g_list_prepend (regs, (gpointer)mips_s5);
773 regs = g_list_prepend (regs, (gpointer)mips_s6);
774 regs = g_list_prepend (regs, (gpointer)mips_s7);
780 * mono_arch_regalloc_cost:
782 * Return the cost, in number of memory references, of the action of
783 * allocating the variable VMV into a register during global register
787 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
794 args_onto_stack (CallInfo *info)
796 g_assert (!info->on_stack);
797 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
798 info->on_stack = TRUE;
799 info->stack_size = MIPS_STACK_PARAM_OFFSET;
802 #if _MIPS_SIM == _ABIO32
804 * O32 calling convention version
808 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
809 /* First, see if we need to drop onto the stack */
810 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
811 args_onto_stack (info);
813 /* Now, place the argument */
814 if (info->on_stack) {
815 ainfo->storage = ArgOnStack;
816 ainfo->reg = mips_sp; /* in the caller */
817 ainfo->offset = info->stack_size;
820 ainfo->storage = ArgInIReg;
821 ainfo->reg = info->gr;
823 info->gr_passed = TRUE;
825 info->stack_size += 4;
829 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
830 /* First, see if we need to drop onto the stack */
831 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
832 args_onto_stack (info);
834 /* Now, place the argument */
835 if (info->on_stack) {
836 g_assert (info->stack_size % 4 == 0);
837 info->stack_size += (info->stack_size % 8);
839 ainfo->storage = ArgOnStack;
840 ainfo->reg = mips_sp; /* in the caller */
841 ainfo->offset = info->stack_size;
844 // info->gr must be a0 or a2
845 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
846 g_assert(info->gr <= MIPS_LAST_ARG_REG);
848 ainfo->storage = ArgInIReg;
849 ainfo->reg = info->gr;
851 info->gr_passed = TRUE;
853 info->stack_size += 8;
857 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
858 /* First, see if we need to drop onto the stack */
859 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
860 args_onto_stack (info);
862 /* Now, place the argument */
863 if (info->on_stack) {
864 ainfo->storage = ArgOnStack;
865 ainfo->reg = mips_sp; /* in the caller */
866 ainfo->offset = info->stack_size;
869 /* Only use FP regs for args if no int args passed yet */
870 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
871 ainfo->storage = ArgInFReg;
872 ainfo->reg = info->fr;
873 /* Even though it's a single-precision float, it takes up two FP regs */
875 /* FP and GP slots do not overlap */
879 /* Passing single-precision float arg in a GP register
880 * such as: func (0, 1.0, 2, 3);
881 * In this case, only one 'gr' register is consumed.
883 ainfo->storage = ArgInIReg;
884 ainfo->reg = info->gr;
887 info->gr_passed = TRUE;
890 info->stack_size += 4;
894 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
895 /* First, see if we need to drop onto the stack */
896 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
897 args_onto_stack (info);
899 /* Now, place the argument */
900 if (info->on_stack) {
901 g_assert(info->stack_size % 4 == 0);
902 info->stack_size += (info->stack_size % 8);
904 ainfo->storage = ArgOnStack;
905 ainfo->reg = mips_sp; /* in the caller */
906 ainfo->offset = info->stack_size;
909 /* Only use FP regs for args if no int args passed yet */
910 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
911 ainfo->storage = ArgInFReg;
912 ainfo->reg = info->fr;
914 /* FP and GP slots do not overlap */
918 // info->gr must be a0 or a2
919 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
920 g_assert(info->gr <= MIPS_LAST_ARG_REG);
922 ainfo->storage = ArgInIReg;
923 ainfo->reg = info->gr;
925 info->gr_passed = TRUE;
928 info->stack_size += 8;
930 #elif _MIPS_SIM == _ABIN32
932 * N32 calling convention version
936 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
937 /* First, see if we need to drop onto the stack */
938 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
939 args_onto_stack (info);
941 /* Now, place the argument */
942 if (info->on_stack) {
943 ainfo->storage = ArgOnStack;
944 ainfo->reg = mips_sp; /* in the caller */
945 ainfo->offset = info->stack_size;
946 info->stack_size += SIZEOF_REGISTER;
949 ainfo->storage = ArgInIReg;
950 ainfo->reg = info->gr;
952 info->gr_passed = TRUE;
957 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
958 /* First, see if we need to drop onto the stack */
959 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
960 args_onto_stack (info);
962 /* Now, place the argument */
963 if (info->on_stack) {
964 g_assert (info->stack_size % 4 == 0);
965 info->stack_size += (info->stack_size % 8);
967 ainfo->storage = ArgOnStack;
968 ainfo->reg = mips_sp; /* in the caller */
969 ainfo->offset = info->stack_size;
970 info->stack_size += SIZEOF_REGISTER;
973 g_assert (info->gr <= MIPS_LAST_ARG_REG);
975 ainfo->storage = ArgInIReg;
976 ainfo->reg = info->gr;
978 info->gr_passed = TRUE;
983 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
984 /* First, see if we need to drop onto the stack */
985 if (!info->on_stack) {
986 if (info->gr > MIPS_LAST_ARG_REG)
987 args_onto_stack (info);
988 else if (info->fr > MIPS_LAST_FPARG_REG)
989 args_onto_stack (info);
992 /* Now, place the argument */
993 if (info->on_stack) {
994 ainfo->storage = ArgOnStack;
995 ainfo->reg = mips_sp; /* in the caller */
996 ainfo->offset = info->stack_size;
997 info->stack_size += FREG_SIZE;
1000 ainfo->storage = ArgInFReg;
1001 ainfo->reg = info->fr;
1003 /* FP and GP slots do not overlap */
1009 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1010 /* First, see if we need to drop onto the stack */
1011 if (!info->on_stack) {
1012 if (info->gr > MIPS_LAST_ARG_REG)
1013 args_onto_stack (info);
1014 else if (info->fr > MIPS_LAST_FPARG_REG)
1015 args_onto_stack (info);
1018 /* Now, place the argument */
1019 if (info->on_stack) {
1020 g_assert(info->stack_size % 4 == 0);
1021 info->stack_size += (info->stack_size % 8);
1023 ainfo->storage = ArgOnStack;
1024 ainfo->reg = mips_sp; /* in the caller */
1025 ainfo->offset = info->stack_size;
1026 info->stack_size += FREG_SIZE;
1029 ainfo->storage = ArgInFReg;
1030 ainfo->reg = info->fr;
1032 /* FP and GP slots do not overlap */
1039 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1042 int n = sig->hasthis + sig->param_count;
1044 MonoType* simpletype;
1046 gboolean is_pinvoke = sig->pinvoke;
1049 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1051 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1053 cinfo->fr = MIPS_FIRST_FPARG_REG;
1054 cinfo->gr = MIPS_FIRST_ARG_REG;
1055 cinfo->stack_size = 0;
1057 DEBUG(printf("calculate_sizes\n"));
1059 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1063 /* handle returning a struct */
1064 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1065 cinfo->struct_ret = cinfo->gr;
1066 add_int32_arg (cinfo, &cinfo->ret);
1070 add_int32_arg (cinfo, cinfo->args + n);
1075 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1076 * the first argument, allowing 'this' to be always passed in the first arg reg.
1077 * Also do this if the first argument is a reference type, since virtual calls
1078 * are sometimes made using calli without sig->hasthis set, like in the delegate
1081 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1083 add_int32_arg (cinfo, cinfo->args + n);
1086 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1090 add_int32_arg (cinfo, &cinfo->ret);
1091 cinfo->struct_ret = cinfo->ret.reg;
1095 add_int32_arg (cinfo, cinfo->args + n);
1099 if (cinfo->vtype_retaddr) {
1100 add_int32_arg (cinfo, &cinfo->ret);
1101 cinfo->struct_ret = cinfo->ret.reg;
1106 DEBUG(printf("params: %d\n", sig->param_count));
1107 for (i = pstart; i < sig->param_count; ++i) {
1108 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1109 /* Prevent implicit arguments and sig_cookie from
1110 being passed in registers */
1111 args_onto_stack (cinfo);
1112 /* Emit the signature cookie just before the implicit arguments */
1113 add_int32_arg (cinfo, &cinfo->sig_cookie);
1115 DEBUG(printf("param %d: ", i));
1116 simpletype = mini_get_underlying_type (sig->params [i]);
1117 switch (simpletype->type) {
1120 DEBUG(printf("1 byte\n"));
1121 cinfo->args [n].size = 1;
1122 add_int32_arg (cinfo, &cinfo->args[n]);
1127 DEBUG(printf("2 bytes\n"));
1128 cinfo->args [n].size = 2;
1129 add_int32_arg (cinfo, &cinfo->args[n]);
1134 DEBUG(printf("4 bytes\n"));
1135 cinfo->args [n].size = 4;
1136 add_int32_arg (cinfo, &cinfo->args[n]);
1142 case MONO_TYPE_FNPTR:
1143 case MONO_TYPE_OBJECT:
1144 cinfo->args [n].size = sizeof (gpointer);
1145 add_int32_arg (cinfo, &cinfo->args[n]);
1148 case MONO_TYPE_GENERICINST:
1149 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1150 cinfo->args [n].size = sizeof (gpointer);
1151 add_int32_arg (cinfo, &cinfo->args[n]);
1156 case MONO_TYPE_TYPEDBYREF:
1157 case MONO_TYPE_VALUETYPE: {
1160 int has_offset = FALSE;
1162 gint size, alignment;
1165 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1166 size = sizeof (MonoTypedRef);
1167 alignment = sizeof (gpointer);
1169 klass = mono_class_from_mono_type (sig->params [i]);
1171 size = mono_class_native_size (klass, NULL);
1173 size = mono_class_value_size (klass, NULL);
1174 alignment = mono_class_min_align (klass);
1176 #if MIPS_PASS_STRUCTS_BY_VALUE
1177 /* Need to do alignment if struct contains long or double */
1178 if (alignment > 4) {
1179 /* Drop onto stack *before* looking at
1180 stack_size, if required. */
1181 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1182 args_onto_stack (cinfo);
1183 if (cinfo->stack_size & (alignment - 1)) {
1184 add_int32_arg (cinfo, &dummy_arg);
1186 g_assert (!(cinfo->stack_size & (alignment - 1)));
1190 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1191 mono_class_native_size (sig->params [i]->data.klass, NULL),
1192 cinfo->stack_size, alignment);
1194 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1195 g_assert (cinfo->args [n].size == 0);
1196 g_assert (cinfo->args [n].vtsize == 0);
1197 for (j = 0; j < nwords; ++j) {
1199 add_int32_arg (cinfo, &cinfo->args [n]);
1200 if (cinfo->on_stack)
1203 add_int32_arg (cinfo, &dummy_arg);
1204 if (!has_offset && cinfo->on_stack) {
1205 cinfo->args [n].offset = dummy_arg.offset;
1209 if (cinfo->on_stack)
1210 cinfo->args [n].vtsize += 1;
1212 cinfo->args [n].size += 1;
1214 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1215 cinfo->args [n].storage = ArgStructByVal;
1217 add_int32_arg (cinfo, &cinfo->args[n]);
1218 cinfo->args [n].storage = ArgStructByAddr;
1225 DEBUG(printf("8 bytes\n"));
1226 cinfo->args [n].size = 8;
1227 add_int64_arg (cinfo, &cinfo->args[n]);
1231 DEBUG(printf("R4\n"));
1232 cinfo->args [n].size = 4;
1233 add_float32_arg (cinfo, &cinfo->args[n]);
1237 DEBUG(printf("R8\n"));
1238 cinfo->args [n].size = 8;
1239 add_float64_arg (cinfo, &cinfo->args[n]);
1243 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1247 /* Handle the case where there are no implicit arguments */
1248 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1249 /* Prevent implicit arguments and sig_cookie from
1250 being passed in registers */
1251 args_onto_stack (cinfo);
1252 /* Emit the signature cookie just before the implicit arguments */
1253 add_int32_arg (cinfo, &cinfo->sig_cookie);
1257 simpletype = mini_get_underlying_type (sig->ret);
1258 switch (simpletype->type) {
1268 case MONO_TYPE_FNPTR:
1269 case MONO_TYPE_OBJECT:
1270 cinfo->ret.reg = mips_v0;
1274 cinfo->ret.reg = mips_v0;
1278 cinfo->ret.reg = mips_f0;
1279 cinfo->ret.storage = ArgInFReg;
1281 case MONO_TYPE_GENERICINST:
1282 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1283 cinfo->ret.reg = mips_v0;
1287 case MONO_TYPE_VALUETYPE:
1288 case MONO_TYPE_TYPEDBYREF:
1290 case MONO_TYPE_VOID:
1293 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1297 /* align stack size to 16 */
1298 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1300 cinfo->stack_usage = cinfo->stack_size;
1305 debug_omit_fp (void)
1308 return mono_debug_count ();
1315 * mono_arch_compute_omit_fp:
1316 * Determine whether the frame pointer can be eliminated.
1319 mono_arch_compute_omit_fp (MonoCompile *cfg)
1321 MonoMethodSignature *sig;
1322 MonoMethodHeader *header;
1326 if (cfg->arch.omit_fp_computed)
1329 header = cfg->header;
1331 sig = mono_method_signature (cfg->method);
1333 if (!cfg->arch.cinfo)
1334 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1335 cinfo = cfg->arch.cinfo;
1338 * FIXME: Remove some of the restrictions.
1340 cfg->arch.omit_fp = TRUE;
1341 cfg->arch.omit_fp_computed = TRUE;
1343 if (cfg->disable_omit_fp)
1344 cfg->arch.omit_fp = FALSE;
1345 if (!debug_omit_fp ())
1346 cfg->arch.omit_fp = FALSE;
1347 if (cfg->method->save_lmf)
1348 cfg->arch.omit_fp = FALSE;
1349 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1350 cfg->arch.omit_fp = FALSE;
1351 if (header->num_clauses)
1352 cfg->arch.omit_fp = FALSE;
1353 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1354 cfg->arch.omit_fp = FALSE;
1355 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)))
1356 cfg->arch.omit_fp = FALSE;
1358 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1359 * there are stack arguments.
1362 if (cinfo->stack_usage)
1363 cfg->arch.omit_fp = FALSE;
1367 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1368 MonoInst *ins = cfg->varinfo [i];
1371 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1374 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1378 * Set var information according to the calling convention. mips version.
1379 * The locals var stuff should most likely be split in another method.
1382 mono_arch_allocate_vars (MonoCompile *cfg)
1384 MonoMethodSignature *sig;
1385 MonoMethodHeader *header;
1387 int i, offset, size, align, curinst;
1388 int frame_reg = mips_sp;
1389 guint32 iregs_to_save = 0;
1391 guint32 fregs_to_restore;
1395 sig = mono_method_signature (cfg->method);
1397 if (!cfg->arch.cinfo)
1398 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1399 cinfo = cfg->arch.cinfo;
1401 mono_arch_compute_omit_fp (cfg);
1403 /* spill down, we'll fix it in a separate pass */
1404 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1406 /* allow room for the vararg method args: void* and long/double */
1407 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1408 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1410 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1411 * call convs needs to be handled this way.
1413 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1414 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1416 /* gtk-sharp and other broken code will dllimport vararg functions even with
1417 * non-varargs signatures. Since there is little hope people will get this right
1418 * we assume they won't.
1420 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1421 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1423 /* a0-a3 always present */
1424 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1426 header = cfg->header;
1428 if (cfg->arch.omit_fp)
1429 frame_reg = mips_sp;
1431 frame_reg = mips_fp;
1432 cfg->frame_reg = frame_reg;
1433 if (frame_reg != mips_sp) {
1434 cfg->used_int_regs |= 1 << frame_reg;
1439 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1440 /* FIXME: handle long and FP values */
1441 switch (mini_get_underlying_type (sig->ret)->type) {
1442 case MONO_TYPE_VOID:
1446 cfg->ret->opcode = OP_REGVAR;
1447 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1450 cfg->ret->opcode = OP_REGVAR;
1451 cfg->ret->inst_c0 = mips_v0;
1455 /* Space for outgoing parameters, including a0-a3 */
1456 offset += cfg->param_area;
1458 /* allow room to save the return value (if it's a struct) */
1459 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1462 /* Now handle the local variables */
1464 curinst = cfg->locals_start;
1465 for (i = curinst; i < cfg->num_varinfo; ++i) {
1466 inst = cfg->varinfo [i];
1467 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1470 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1471 * pinvoke wrappers when they call functions returning structure
1473 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1474 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1476 size = mono_type_size (inst->inst_vtype, &align);
1478 offset += align - 1;
1479 offset &= ~(align - 1);
1480 inst->inst_offset = offset;
1481 inst->opcode = OP_REGOFFSET;
1482 inst->inst_basereg = frame_reg;
1484 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1487 /* Space for LMF (if needed) */
1488 if (cfg->method->save_lmf) {
1489 /* align the offset to 16 bytes */
1490 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1491 cfg->arch.lmf_offset = offset;
1492 offset += sizeof (MonoLMF);
1495 if (sig->call_convention == MONO_CALL_VARARG) {
1499 /* Allocate a local slot to hold the sig cookie address */
1500 offset += align - 1;
1501 offset &= ~(align - 1);
1502 cfg->sig_cookie = offset;
1506 offset += SIZEOF_REGISTER - 1;
1507 offset &= ~(SIZEOF_REGISTER - 1);
1509 /* Space for saved registers */
1510 cfg->arch.iregs_offset = offset;
1511 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1512 if (iregs_to_save) {
1513 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1514 if (iregs_to_save & (1 << i)) {
1515 offset += SIZEOF_REGISTER;
1520 /* saved float registers */
1522 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1523 if (fregs_to_restore) {
1524 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1525 if (fregs_to_restore & (1 << i)) {
1526 offset += sizeof(double);
1532 #if _MIPS_SIM == _ABIO32
1533 /* Now add space for saving the ra */
1534 offset += SIZEOF_VOID_P;
1537 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1538 cfg->stack_offset = offset;
1539 cfg->arch.local_alloc_offset = cfg->stack_offset;
1543 * Now allocate stack slots for the int arg regs (a0 - a3)
1544 * On MIPS o32, these are just above the incoming stack pointer
1545 * Even if the arg has been assigned to a regvar, it gets a stack slot
1548 /* Return struct-by-value results in a hidden first argument */
1549 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1550 cfg->vret_addr->opcode = OP_REGOFFSET;
1551 cfg->vret_addr->inst_c0 = mips_a0;
1552 cfg->vret_addr->inst_offset = offset;
1553 cfg->vret_addr->inst_basereg = frame_reg;
1554 offset += SIZEOF_REGISTER;
1557 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1558 inst = cfg->args [i];
1559 if (inst->opcode != OP_REGVAR) {
1562 if (sig->hasthis && (i == 0))
1563 arg_type = &mono_defaults.object_class->byval_arg;
1565 arg_type = sig->params [i - sig->hasthis];
1567 inst->opcode = OP_REGOFFSET;
1568 size = mono_type_size (arg_type, &align);
1570 if (size < SIZEOF_REGISTER) {
1571 size = SIZEOF_REGISTER;
1572 align = SIZEOF_REGISTER;
1574 inst->inst_basereg = frame_reg;
1575 offset = (offset + align - 1) & ~(align - 1);
1576 inst->inst_offset = offset;
1578 if (cfg->verbose_level > 1)
1579 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1582 #if _MIPS_SIM == _ABIO32
1583 /* o32: Even a0-a3 get stack slots */
1584 size = SIZEOF_REGISTER;
1585 align = SIZEOF_REGISTER;
1586 inst->inst_basereg = frame_reg;
1587 offset = (offset + align - 1) & ~(align - 1);
1588 inst->inst_offset = offset;
1590 if (cfg->verbose_level > 1)
1591 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1595 #if _MIPS_SIM == _ABIN32
1596 /* Now add space for saving the ra */
1597 offset += SIZEOF_VOID_P;
1600 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1601 cfg->stack_offset = offset;
1602 cfg->arch.local_alloc_offset = cfg->stack_offset;
1607 mono_arch_create_vars (MonoCompile *cfg)
1609 MonoMethodSignature *sig;
1611 sig = mono_method_signature (cfg->method);
1613 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1614 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1615 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1616 printf ("vret_addr = ");
1617 mono_print_ins (cfg->vret_addr);
1622 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1623 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1627 * take the arguments and generate the arch-specific
1628 * instructions to properly call the function in call.
1629 * This includes pushing, moving arguments to the right register
1631 * Issue: who does the spilling if needed, and when?
1634 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1636 MonoMethodSignature *tmp_sig;
1639 if (call->tail_call)
1642 /* FIXME: Add support for signature tokens to AOT */
1643 cfg->disable_aot = TRUE;
1646 * mono_ArgIterator_Setup assumes the signature cookie is
1647 * passed first and all the arguments which were before it are
1648 * passed on the stack after the signature. So compensate by
1649 * passing a different signature.
1651 tmp_sig = mono_metadata_signature_dup (call->signature);
1652 tmp_sig->param_count -= call->signature->sentinelpos;
1653 tmp_sig->sentinelpos = 0;
1654 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1656 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1657 sig_arg->dreg = mono_alloc_ireg (cfg);
1658 sig_arg->inst_p0 = tmp_sig;
1659 MONO_ADD_INS (cfg->cbb, sig_arg);
1661 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1665 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1668 MonoMethodSignature *sig;
1673 sig = call->signature;
1674 n = sig->param_count + sig->hasthis;
1676 cinfo = get_call_info (cfg->mempool, sig);
1677 if (cinfo->struct_ret)
1678 call->used_iregs |= 1 << cinfo->struct_ret;
1680 for (i = 0; i < n; ++i) {
1681 ArgInfo *ainfo = cinfo->args + i;
1684 if (i >= sig->hasthis)
1685 t = sig->params [i - sig->hasthis];
1687 t = &mono_defaults.int_class->byval_arg;
1688 t = mini_get_underlying_type (t);
1690 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1691 /* Emit the signature cookie just before the implicit arguments */
1692 emit_sig_cookie (cfg, call, cinfo);
1695 if (is_virtual && i == 0) {
1696 /* the argument will be attached to the call instrucion */
1697 in = call->args [i];
1698 call->used_iregs |= 1 << ainfo->reg;
1701 in = call->args [i];
1702 if (ainfo->storage == ArgInIReg) {
1703 #if SIZEOF_REGISTER == 4
1704 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1705 MONO_INST_NEW (cfg, ins, OP_MOVE);
1706 ins->dreg = mono_alloc_ireg (cfg);
1707 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1708 MONO_ADD_INS (cfg->cbb, ins);
1709 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1711 MONO_INST_NEW (cfg, ins, OP_MOVE);
1712 ins->dreg = mono_alloc_ireg (cfg);
1713 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1714 MONO_ADD_INS (cfg->cbb, ins);
1715 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1718 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1721 #if PROMOTE_R4_TO_R8
1722 /* ??? - convert to single first? */
1723 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1724 ins->dreg = mono_alloc_freg (cfg);
1725 ins->sreg1 = in->dreg;
1726 MONO_ADD_INS (cfg->cbb, ins);
1731 /* trying to load float value into int registers */
1732 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1733 ins->dreg = mono_alloc_ireg (cfg);
1735 MONO_ADD_INS (cfg->cbb, ins);
1736 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1737 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1738 /* trying to load float value into int registers */
1739 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1740 ins->dreg = mono_alloc_ireg (cfg);
1741 ins->sreg1 = in->dreg;
1742 MONO_ADD_INS (cfg->cbb, ins);
1743 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1745 MONO_INST_NEW (cfg, ins, OP_MOVE);
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 } else if (ainfo->storage == ArgStructByAddr) {
1752 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1753 ins->opcode = OP_OUTARG_VT;
1754 ins->sreg1 = in->dreg;
1755 ins->klass = in->klass;
1756 ins->inst_p0 = call;
1757 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1758 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1759 MONO_ADD_INS (cfg->cbb, ins);
1760 } else if (ainfo->storage == ArgStructByVal) {
1761 /* this is further handled in mono_arch_emit_outarg_vt () */
1762 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1763 ins->opcode = OP_OUTARG_VT;
1764 ins->sreg1 = in->dreg;
1765 ins->klass = in->klass;
1766 ins->inst_p0 = call;
1767 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1768 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1769 MONO_ADD_INS (cfg->cbb, ins);
1770 } else if (ainfo->storage == ArgOnStack) {
1771 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1772 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1773 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1774 if (t->type == MONO_TYPE_R8)
1775 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1777 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1779 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1781 } else if (ainfo->storage == ArgInFReg) {
1782 if (t->type == MONO_TYPE_VALUETYPE) {
1783 /* this is further handled in mono_arch_emit_outarg_vt () */
1784 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1785 ins->opcode = OP_OUTARG_VT;
1786 ins->sreg1 = in->dreg;
1787 ins->klass = in->klass;
1788 ins->inst_p0 = call;
1789 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1790 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1791 MONO_ADD_INS (cfg->cbb, ins);
1793 cfg->flags |= MONO_CFG_HAS_FPOUT;
1795 int dreg = mono_alloc_freg (cfg);
1797 if (ainfo->size == 4) {
1798 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1800 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1802 ins->sreg1 = in->dreg;
1803 MONO_ADD_INS (cfg->cbb, ins);
1806 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1807 cfg->flags |= MONO_CFG_HAS_FPOUT;
1810 g_assert_not_reached ();
1814 /* Handle the case where there are no implicit arguments */
1815 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1816 emit_sig_cookie (cfg, call, cinfo);
1818 if (cinfo->struct_ret) {
1821 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1822 vtarg->sreg1 = call->vret_var->dreg;
1823 vtarg->dreg = mono_alloc_preg (cfg);
1824 MONO_ADD_INS (cfg->cbb, vtarg);
1826 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1830 * Reverse the call->out_args list.
1833 MonoInst *prev = NULL, *list = call->out_args, *next;
1840 call->out_args = prev;
1843 call->stack_usage = cinfo->stack_usage;
1844 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1845 #if _MIPS_SIM == _ABIO32
1846 /* a0-a3 always present */
1847 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1849 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1850 cfg->flags |= MONO_CFG_HAS_CALLS;
1852 * should set more info in call, such as the stack space
1853 * used by the args that needs to be added back to esp
1858 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1860 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1861 ArgInfo *ainfo = ins->inst_p1;
1862 int ovf_size = ainfo->vtsize;
1863 int doffset = ainfo->offset;
1864 int i, soffset, dreg;
1866 if (ainfo->storage == ArgStructByVal) {
1868 if (cfg->verbose_level > 0) {
1869 char* nm = mono_method_full_name (cfg->method, TRUE);
1870 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1871 nm, doffset, ainfo->size, ovf_size);
1877 for (i = 0; i < ainfo->size; ++i) {
1878 dreg = mono_alloc_ireg (cfg);
1879 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1880 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1881 soffset += SIZEOF_REGISTER;
1883 if (ovf_size != 0) {
1884 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), SIZEOF_VOID_P);
1886 } else if (ainfo->storage == ArgInFReg) {
1887 int tmpr = mono_alloc_freg (cfg);
1889 if (ainfo->size == 4)
1890 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1892 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1893 dreg = mono_alloc_freg (cfg);
1894 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1895 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1897 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1901 /* FIXME: alignment? */
1902 if (call->signature->pinvoke) {
1903 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1904 vtcopy->backend.is_pinvoke = 1;
1906 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1909 g_assert (ovf_size > 0);
1911 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1912 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, SIZEOF_VOID_P);
1915 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1917 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1922 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1924 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1927 #if (SIZEOF_REGISTER == 4)
1928 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1931 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1932 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1933 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1934 MONO_ADD_INS (cfg->cbb, ins);
1938 if (ret->type == MONO_TYPE_R8) {
1939 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1942 if (ret->type == MONO_TYPE_R4) {
1943 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1947 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1951 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1953 MonoInst *ins, *n, *last_ins = NULL;
1955 if (cfg->verbose_level > 2)
1956 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1959 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1960 if (cfg->verbose_level > 2)
1961 mono_print_ins_index (0, ins);
1963 switch (ins->opcode) {
1965 case OP_LOAD_MEMBASE:
1966 case OP_LOADI4_MEMBASE:
1968 * OP_IADD reg2, reg1, const1
1969 * OP_LOAD_MEMBASE const2(reg2), reg3
1971 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1973 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)){
1974 int const1 = last_ins->inst_imm;
1975 int const2 = ins->inst_offset;
1977 if (mips_is_imm16 (const1 + const2)) {
1978 ins->inst_basereg = last_ins->sreg1;
1979 ins->inst_offset = const1 + const2;
1989 bb->last_ins = last_ins;
1993 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1995 MonoInst *ins, *n, *last_ins = NULL;
1998 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1999 MonoInst *last_ins = ins->prev;
2001 switch (ins->opcode) {
2003 /* remove unnecessary multiplication with 1 */
2004 if (ins->inst_imm == 1) {
2005 if (ins->dreg != ins->sreg1) {
2006 ins->opcode = OP_MOVE;
2008 MONO_DELETE_INS (bb, ins);
2012 int power2 = mono_is_power_of_two (ins->inst_imm);
2014 ins->opcode = OP_SHL_IMM;
2015 ins->inst_imm = power2;
2019 case OP_LOAD_MEMBASE:
2020 case OP_LOADI4_MEMBASE:
2022 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2023 * OP_LOAD_MEMBASE offset(basereg), reg
2025 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2026 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2027 ins->inst_basereg == last_ins->inst_destbasereg &&
2028 ins->inst_offset == last_ins->inst_offset) {
2029 if (ins->dreg == last_ins->sreg1) {
2030 MONO_DELETE_INS (bb, ins);
2033 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2034 ins->opcode = OP_MOVE;
2035 ins->sreg1 = last_ins->sreg1;
2040 * Note: reg1 must be different from the basereg in the second load
2041 * OP_LOAD_MEMBASE offset(basereg), reg1
2042 * OP_LOAD_MEMBASE offset(basereg), reg2
2044 * OP_LOAD_MEMBASE offset(basereg), reg1
2045 * OP_MOVE reg1, reg2
2047 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2048 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2049 ins->inst_basereg != last_ins->dreg &&
2050 ins->inst_basereg == last_ins->inst_basereg &&
2051 ins->inst_offset == last_ins->inst_offset) {
2053 if (ins->dreg == last_ins->dreg) {
2054 MONO_DELETE_INS (bb, ins);
2057 ins->opcode = OP_MOVE;
2058 ins->sreg1 = last_ins->dreg;
2061 //g_assert_not_reached ();
2066 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2067 * OP_LOAD_MEMBASE offset(basereg), reg
2069 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2070 * OP_ICONST reg, imm
2072 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2073 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2074 ins->inst_basereg == last_ins->inst_destbasereg &&
2075 ins->inst_offset == last_ins->inst_offset) {
2076 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2077 ins->opcode = OP_ICONST;
2078 ins->inst_c0 = last_ins->inst_imm;
2079 g_assert_not_reached (); // check this rule
2084 case OP_LOADU1_MEMBASE:
2085 case OP_LOADI1_MEMBASE:
2086 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2087 ins->inst_basereg == last_ins->inst_destbasereg &&
2088 ins->inst_offset == last_ins->inst_offset) {
2089 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2090 ins->sreg1 = last_ins->sreg1;
2093 case OP_LOADU2_MEMBASE:
2094 case OP_LOADI2_MEMBASE:
2095 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2096 ins->inst_basereg == last_ins->inst_destbasereg &&
2097 ins->inst_offset == last_ins->inst_offset) {
2098 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2099 ins->sreg1 = last_ins->sreg1;
2102 case OP_ICONV_TO_I4:
2103 case OP_ICONV_TO_U4:
2105 ins->opcode = OP_MOVE;
2109 if (ins->dreg == ins->sreg1) {
2110 MONO_DELETE_INS (bb, ins);
2114 * OP_MOVE sreg, dreg
2115 * OP_MOVE dreg, sreg
2117 if (last_ins && last_ins->opcode == OP_MOVE &&
2118 ins->sreg1 == last_ins->dreg &&
2119 ins->dreg == last_ins->sreg1) {
2120 MONO_DELETE_INS (bb, ins);
2128 bb->last_ins = last_ins;
2132 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2140 switch (ins->opcode) {
2142 tmp1 = mono_alloc_ireg (cfg);
2143 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2144 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2145 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2146 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2151 tmp1 = mono_alloc_ireg (cfg);
2152 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2153 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2154 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2155 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2160 tmp1 = mono_alloc_ireg (cfg);
2161 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2162 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2163 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2164 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2169 tmp1 = mono_alloc_ireg (cfg);
2170 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2171 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2172 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2173 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2178 tmp1 = mono_alloc_ireg (cfg);
2179 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2180 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2181 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2182 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2187 tmp1 = mono_alloc_ireg (cfg);
2188 tmp2 = mono_alloc_ireg (cfg);
2189 tmp3 = mono_alloc_ireg (cfg);
2190 tmp4 = mono_alloc_ireg (cfg);
2191 tmp5 = mono_alloc_ireg (cfg);
2193 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2195 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2196 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2198 /* add the high 32-bits, and add in the carry from the low 32-bits */
2199 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2200 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2202 /* Overflow happens if
2203 * neg + neg = pos or
2205 * XOR of the high bits returns 0 if the signs match
2206 * XOR of that with the high bit of the result return 1 if overflow.
2209 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2210 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2212 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2213 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2214 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2216 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2217 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2218 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2220 /* Now, if (tmp4 == 0) then overflow */
2221 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2225 case OP_LADD_OVF_UN:
2226 tmp1 = mono_alloc_ireg (cfg);
2227 tmp2 = mono_alloc_ireg (cfg);
2229 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2230 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2231 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2232 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2233 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2234 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2239 tmp1 = mono_alloc_ireg (cfg);
2240 tmp2 = mono_alloc_ireg (cfg);
2241 tmp3 = mono_alloc_ireg (cfg);
2242 tmp4 = mono_alloc_ireg (cfg);
2243 tmp5 = mono_alloc_ireg (cfg);
2245 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2247 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2248 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2249 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2251 /* Overflow happens if
2252 * neg - pos = pos or
2254 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2256 * tmp1 = (lhs ^ rhs)
2257 * tmp2 = (lhs ^ result)
2258 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2261 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2262 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2263 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2264 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2266 /* Now, if (tmp4 == 1) then overflow */
2267 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2271 case OP_LSUB_OVF_UN:
2272 tmp1 = mono_alloc_ireg (cfg);
2273 tmp2 = mono_alloc_ireg (cfg);
2275 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2276 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2277 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2278 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2280 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2281 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2284 case OP_LCONV_TO_OVF_I4_2:
2285 tmp1 = mono_alloc_ireg (cfg);
2287 /* Overflows if reg2 != sign extension of reg1 */
2288 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2289 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2290 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2299 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2307 switch (ins->opcode) {
2309 tmp1 = mono_alloc_ireg (cfg);
2310 tmp2 = mono_alloc_ireg (cfg);
2311 tmp3 = mono_alloc_ireg (cfg);
2312 tmp4 = mono_alloc_ireg (cfg);
2313 tmp5 = mono_alloc_ireg (cfg);
2315 /* add the operands */
2317 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2319 /* Overflow happens if
2320 * neg + neg = pos or
2323 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2324 * XOR of the high bit returns 0 if the signs match
2325 * XOR of that with the high bit of the result return 1 if overflow.
2328 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2329 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2331 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2332 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2333 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2335 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2336 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2338 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2340 /* Now, if (tmp5 == 0) then overflow */
2341 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2342 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2343 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2347 case OP_IADD_OVF_UN:
2348 tmp1 = mono_alloc_ireg (cfg);
2350 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2351 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2352 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2353 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2354 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2359 tmp1 = mono_alloc_ireg (cfg);
2360 tmp2 = mono_alloc_ireg (cfg);
2361 tmp3 = mono_alloc_ireg (cfg);
2362 tmp4 = mono_alloc_ireg (cfg);
2363 tmp5 = mono_alloc_ireg (cfg);
2365 /* add the operands */
2367 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2369 /* Overflow happens if
2370 * neg - pos = pos or
2372 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2374 * tmp1 = (lhs ^ rhs)
2375 * tmp2 = (lhs ^ result)
2376 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2379 /* tmp3 = 1 if the signs of the two inputs differ */
2380 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2381 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2382 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2383 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2384 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2386 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2387 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2388 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2392 case OP_ISUB_OVF_UN:
2393 tmp1 = mono_alloc_ireg (cfg);
2395 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2396 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2397 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2398 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2399 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2406 map_to_reg_reg_op (int op)
2415 case OP_COMPARE_IMM:
2417 case OP_ICOMPARE_IMM:
2419 case OP_LCOMPARE_IMM:
2435 case OP_LOAD_MEMBASE:
2436 return OP_LOAD_MEMINDEX;
2437 case OP_LOADI4_MEMBASE:
2438 return OP_LOADI4_MEMINDEX;
2439 case OP_LOADU4_MEMBASE:
2440 return OP_LOADU4_MEMINDEX;
2441 case OP_LOADU1_MEMBASE:
2442 return OP_LOADU1_MEMINDEX;
2443 case OP_LOADI2_MEMBASE:
2444 return OP_LOADI2_MEMINDEX;
2445 case OP_LOADU2_MEMBASE:
2446 return OP_LOADU2_MEMINDEX;
2447 case OP_LOADI1_MEMBASE:
2448 return OP_LOADI1_MEMINDEX;
2449 case OP_LOADR4_MEMBASE:
2450 return OP_LOADR4_MEMINDEX;
2451 case OP_LOADR8_MEMBASE:
2452 return OP_LOADR8_MEMINDEX;
2453 case OP_STOREI1_MEMBASE_REG:
2454 return OP_STOREI1_MEMINDEX;
2455 case OP_STOREI2_MEMBASE_REG:
2456 return OP_STOREI2_MEMINDEX;
2457 case OP_STOREI4_MEMBASE_REG:
2458 return OP_STOREI4_MEMINDEX;
2459 case OP_STORE_MEMBASE_REG:
2460 return OP_STORE_MEMINDEX;
2461 case OP_STORER4_MEMBASE_REG:
2462 return OP_STORER4_MEMINDEX;
2463 case OP_STORER8_MEMBASE_REG:
2464 return OP_STORER8_MEMINDEX;
2465 case OP_STORE_MEMBASE_IMM:
2466 return OP_STORE_MEMBASE_REG;
2467 case OP_STOREI1_MEMBASE_IMM:
2468 return OP_STOREI1_MEMBASE_REG;
2469 case OP_STOREI2_MEMBASE_IMM:
2470 return OP_STOREI2_MEMBASE_REG;
2471 case OP_STOREI4_MEMBASE_IMM:
2472 return OP_STOREI4_MEMBASE_REG;
2473 case OP_STOREI8_MEMBASE_IMM:
2474 return OP_STOREI8_MEMBASE_REG;
2476 if (mono_op_imm_to_op (op) == -1)
2477 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2478 return mono_op_imm_to_op (op);
2482 map_to_mips_op (int op)
2486 return OP_MIPS_FBEQ;
2488 return OP_MIPS_FBGE;
2490 return OP_MIPS_FBGT;
2492 return OP_MIPS_FBLE;
2494 return OP_MIPS_FBLT;
2496 return OP_MIPS_FBNE;
2498 return OP_MIPS_FBGE_UN;
2500 return OP_MIPS_FBGT_UN;
2502 return OP_MIPS_FBLE_UN;
2504 return OP_MIPS_FBLT_UN;
2512 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2513 g_assert_not_reached ();
2517 #define NEW_INS(cfg,after,dest,op) do { \
2518 MONO_INST_NEW((cfg), (dest), (op)); \
2519 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2522 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2524 MONO_INST_NEW(cfg, temp, (op)); \
2525 mono_bblock_insert_after_ins (bb, (pos), temp); \
2526 temp->dreg = (_dreg); \
2527 temp->sreg1 = (_sreg1); \
2528 temp->sreg2 = (_sreg2); \
2532 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2534 MONO_INST_NEW(cfg, temp, (op)); \
2535 mono_bblock_insert_after_ins (bb, (pos), temp); \
2536 temp->dreg = (_dreg); \
2537 temp->sreg1 = (_sreg1); \
2538 temp->inst_c0 = (_imm); \
2543 * Remove from the instruction list the instructions that can't be
2544 * represented with very simple instructions with no register
2548 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2550 MonoInst *ins, *next, *temp, *last_ins = NULL;
2554 if (cfg->verbose_level > 2) {
2557 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2558 MONO_BB_FOR_EACH_INS (bb, ins) {
2559 mono_print_ins_index (idx++, ins);
2565 MONO_BB_FOR_EACH_INS (bb, ins) {
2567 switch (ins->opcode) {
2572 /* Branch opts can eliminate the branch */
2573 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2579 case OP_COMPARE_IMM:
2580 case OP_ICOMPARE_IMM:
2581 case OP_LCOMPARE_IMM:
2583 /* Branch opts can eliminate the branch */
2584 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2588 if (ins->inst_imm) {
2589 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2590 temp->inst_c0 = ins->inst_imm;
2591 temp->dreg = mono_alloc_ireg (cfg);
2592 ins->sreg2 = temp->dreg;
2596 ins->sreg2 = mips_zero;
2598 if (ins->opcode == OP_COMPARE_IMM)
2599 ins->opcode = OP_COMPARE;
2600 else if (ins->opcode == OP_ICOMPARE_IMM)
2601 ins->opcode = OP_ICOMPARE;
2602 else if (ins->opcode == OP_LCOMPARE_IMM)
2603 ins->opcode = OP_LCOMPARE;
2606 case OP_IDIV_UN_IMM:
2609 case OP_IREM_UN_IMM:
2610 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2611 temp->inst_c0 = ins->inst_imm;
2612 temp->dreg = mono_alloc_ireg (cfg);
2613 ins->sreg2 = temp->dreg;
2614 if (ins->opcode == OP_IDIV_IMM)
2615 ins->opcode = OP_IDIV;
2616 else if (ins->opcode == OP_IREM_IMM)
2617 ins->opcode = OP_IREM;
2618 else if (ins->opcode == OP_IDIV_UN_IMM)
2619 ins->opcode = OP_IDIV_UN;
2620 else if (ins->opcode == OP_IREM_UN_IMM)
2621 ins->opcode = OP_IREM_UN;
2623 /* handle rem separately */
2630 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2631 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2632 temp->inst_c0 = ins->inst_imm;
2633 temp->dreg = mono_alloc_ireg (cfg);
2634 ins->sreg2 = temp->dreg;
2635 ins->opcode = map_to_reg_reg_op (ins->opcode);
2645 /* unsigned 16 bit immediate */
2646 if (ins->inst_imm & 0xffff0000) {
2647 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2648 temp->inst_c0 = ins->inst_imm;
2649 temp->dreg = mono_alloc_ireg (cfg);
2650 ins->sreg2 = temp->dreg;
2651 ins->opcode = map_to_reg_reg_op (ins->opcode);
2658 /* signed 16 bit immediate */
2659 if (!mips_is_imm16 (ins->inst_imm)) {
2660 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2661 temp->inst_c0 = ins->inst_imm;
2662 temp->dreg = mono_alloc_ireg (cfg);
2663 ins->sreg2 = temp->dreg;
2664 ins->opcode = map_to_reg_reg_op (ins->opcode);
2670 if (!mips_is_imm16 (-ins->inst_imm)) {
2671 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2672 temp->inst_c0 = ins->inst_imm;
2673 temp->dreg = mono_alloc_ireg (cfg);
2674 ins->sreg2 = temp->dreg;
2675 ins->opcode = map_to_reg_reg_op (ins->opcode);
2681 if (ins->inst_imm == 1) {
2682 ins->opcode = OP_MOVE;
2685 if (ins->inst_imm == 0) {
2686 ins->opcode = OP_ICONST;
2690 imm = mono_is_power_of_two (ins->inst_imm);
2692 ins->opcode = OP_SHL_IMM;
2693 ins->inst_imm = imm;
2696 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2697 temp->inst_c0 = ins->inst_imm;
2698 temp->dreg = mono_alloc_ireg (cfg);
2699 ins->sreg2 = temp->dreg;
2700 ins->opcode = map_to_reg_reg_op (ins->opcode);
2703 case OP_LOCALLOC_IMM:
2704 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2705 temp->inst_c0 = ins->inst_imm;
2706 temp->dreg = mono_alloc_ireg (cfg);
2707 ins->sreg1 = temp->dreg;
2708 ins->opcode = OP_LOCALLOC;
2711 case OP_LOADR4_MEMBASE:
2712 case OP_STORER4_MEMBASE_REG:
2713 /* we can do two things: load the immed in a register
2714 * and use an indexed load, or see if the immed can be
2715 * represented as an ad_imm + a load with a smaller offset
2716 * that fits. We just do the first for now, optimize later.
2718 if (mips_is_imm16 (ins->inst_offset))
2720 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2721 temp->inst_c0 = ins->inst_offset;
2722 temp->dreg = mono_alloc_ireg (cfg);
2723 ins->sreg2 = temp->dreg;
2724 ins->opcode = map_to_reg_reg_op (ins->opcode);
2727 case OP_STORE_MEMBASE_IMM:
2728 case OP_STOREI1_MEMBASE_IMM:
2729 case OP_STOREI2_MEMBASE_IMM:
2730 case OP_STOREI4_MEMBASE_IMM:
2731 case OP_STOREI8_MEMBASE_IMM:
2732 if (!ins->inst_imm) {
2733 ins->sreg1 = mips_zero;
2734 ins->opcode = map_to_reg_reg_op (ins->opcode);
2737 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2738 temp->inst_c0 = ins->inst_imm;
2739 temp->dreg = mono_alloc_ireg (cfg);
2740 ins->sreg1 = temp->dreg;
2741 ins->opcode = map_to_reg_reg_op (ins->opcode);
2743 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2749 /* Branch opts can eliminate the branch */
2750 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2757 * remap compare/branch and compare/set
2758 * to MIPS specific opcodes.
2760 next->opcode = map_to_mips_op (next->opcode);
2761 next->sreg1 = ins->sreg1;
2762 next->sreg2 = ins->sreg2;
2769 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2770 temp->inst_c0 = (guint32)ins->inst_p0;
2771 temp->dreg = mono_alloc_ireg (cfg);
2772 ins->inst_basereg = temp->dreg;
2773 ins->inst_offset = 0;
2774 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2776 /* make it handle the possibly big ins->inst_offset
2777 * later optimize to use lis + load_membase
2782 g_assert (ins_is_compare(last_ins));
2783 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2784 NULLIFY_INS(last_ins);
2788 g_assert (ins_is_compare(last_ins));
2789 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2790 NULLIFY_INS(last_ins);
2794 g_assert (ins_is_compare(last_ins));
2795 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2796 last_ins->dreg = mono_alloc_ireg (cfg);
2797 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2801 g_assert (ins_is_compare(last_ins));
2802 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2803 last_ins->dreg = mono_alloc_ireg (cfg);
2804 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2808 g_assert (ins_is_compare(last_ins));
2809 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2810 last_ins->dreg = mono_alloc_ireg (cfg);
2811 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2815 g_assert (ins_is_compare(last_ins));
2816 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2817 last_ins->dreg = mono_alloc_ireg (cfg);
2818 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2822 g_assert (ins_is_compare(last_ins));
2823 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2824 last_ins->dreg = mono_alloc_ireg (cfg);
2825 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2829 g_assert (ins_is_compare(last_ins));
2830 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2831 last_ins->dreg = mono_alloc_ireg (cfg);
2832 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2836 g_assert (ins_is_compare(last_ins));
2837 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2838 last_ins->dreg = mono_alloc_ireg (cfg);
2839 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2843 g_assert (ins_is_compare(last_ins));
2844 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2845 last_ins->dreg = mono_alloc_ireg (cfg);
2846 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2851 g_assert (ins_is_compare(last_ins));
2852 last_ins->opcode = OP_IXOR;
2853 last_ins->dreg = mono_alloc_ireg(cfg);
2854 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2859 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2860 NULLIFY_INS(last_ins);
2866 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2867 NULLIFY_INS(last_ins);
2872 g_assert (ins_is_compare(last_ins));
2873 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2874 MONO_DELETE_INS(bb, last_ins);
2879 g_assert (ins_is_compare(last_ins));
2880 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2881 MONO_DELETE_INS(bb, last_ins);
2884 case OP_COND_EXC_EQ:
2885 case OP_COND_EXC_IEQ:
2886 g_assert (ins_is_compare(last_ins));
2887 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2888 MONO_DELETE_INS(bb, last_ins);
2891 case OP_COND_EXC_GE:
2892 case OP_COND_EXC_IGE:
2893 g_assert (ins_is_compare(last_ins));
2894 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2895 MONO_DELETE_INS(bb, last_ins);
2898 case OP_COND_EXC_GT:
2899 case OP_COND_EXC_IGT:
2900 g_assert (ins_is_compare(last_ins));
2901 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2902 MONO_DELETE_INS(bb, last_ins);
2905 case OP_COND_EXC_LE:
2906 case OP_COND_EXC_ILE:
2907 g_assert (ins_is_compare(last_ins));
2908 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2909 MONO_DELETE_INS(bb, last_ins);
2912 case OP_COND_EXC_LT:
2913 case OP_COND_EXC_ILT:
2914 g_assert (ins_is_compare(last_ins));
2915 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2916 MONO_DELETE_INS(bb, last_ins);
2919 case OP_COND_EXC_NE_UN:
2920 case OP_COND_EXC_INE_UN:
2921 g_assert (ins_is_compare(last_ins));
2922 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2923 MONO_DELETE_INS(bb, last_ins);
2926 case OP_COND_EXC_GE_UN:
2927 case OP_COND_EXC_IGE_UN:
2928 g_assert (ins_is_compare(last_ins));
2929 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2930 MONO_DELETE_INS(bb, last_ins);
2933 case OP_COND_EXC_GT_UN:
2934 case OP_COND_EXC_IGT_UN:
2935 g_assert (ins_is_compare(last_ins));
2936 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2937 MONO_DELETE_INS(bb, last_ins);
2940 case OP_COND_EXC_LE_UN:
2941 case OP_COND_EXC_ILE_UN:
2942 g_assert (ins_is_compare(last_ins));
2943 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2944 MONO_DELETE_INS(bb, last_ins);
2947 case OP_COND_EXC_LT_UN:
2948 case OP_COND_EXC_ILT_UN:
2949 g_assert (ins_is_compare(last_ins));
2950 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2951 MONO_DELETE_INS(bb, last_ins);
2954 case OP_COND_EXC_OV:
2955 case OP_COND_EXC_IOV: {
2956 int tmp1, tmp2, tmp3, tmp4, tmp5;
2957 MonoInst *pos = last_ins;
2959 /* Overflow happens if
2960 * neg + neg = pos or
2963 * (bit31s of operands match) AND (bit31 of operand
2964 * != bit31 of result)
2965 * XOR of the high bit returns 0 if the signs match
2966 * XOR of that with the high bit of the result return 1
2969 g_assert (last_ins->opcode == OP_IADC);
2971 tmp1 = mono_alloc_ireg (cfg);
2972 tmp2 = mono_alloc_ireg (cfg);
2973 tmp3 = mono_alloc_ireg (cfg);
2974 tmp4 = mono_alloc_ireg (cfg);
2975 tmp5 = mono_alloc_ireg (cfg);
2977 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2978 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2980 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2981 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2982 INS (pos, OP_INOT, tmp3, tmp2, -1);
2984 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2985 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2986 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2988 /* Now, if (tmp5 == 0) then overflow */
2989 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2994 case OP_COND_EXC_NO:
2995 case OP_COND_EXC_INO:
2996 g_assert_not_reached ();
3000 case OP_COND_EXC_IC:
3001 g_assert_not_reached ();
3004 case OP_COND_EXC_NC:
3005 case OP_COND_EXC_INC:
3006 g_assert_not_reached ();
3012 bb->last_ins = last_ins;
3013 bb->max_vreg = cfg->next_vreg;
3016 if (cfg->verbose_level > 2) {
3019 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3020 MONO_BB_FOR_EACH_INS (bb, ins) {
3021 mono_print_ins_index (idx++, ins);
3030 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3032 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3034 mips_truncwd (code, mips_ftemp, sreg);
3036 mips_cvtwd (code, mips_ftemp, sreg);
3038 mips_mfc1 (code, dreg, mips_ftemp);
3041 mips_andi (code, dreg, dreg, 0xff);
3042 else if (size == 2) {
3043 mips_sll (code, dreg, dreg, 16);
3044 mips_srl (code, dreg, dreg, 16);
3048 mips_sll (code, dreg, dreg, 24);
3049 mips_sra (code, dreg, dreg, 24);
3051 else if (size == 2) {
3052 mips_sll (code, dreg, dreg, 16);
3053 mips_sra (code, dreg, dreg, 16);
3060 * emit_load_volatile_arguments:
3062 * Load volatile arguments from the stack to the original input registers.
3063 * Required before a tail call.
3066 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3068 MonoMethod *method = cfg->method;
3069 MonoMethodSignature *sig;
3074 sig = mono_method_signature (method);
3076 if (!cfg->arch.cinfo)
3077 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3078 cinfo = cfg->arch.cinfo;
3080 if (cinfo->struct_ret) {
3081 ArgInfo *ainfo = &cinfo->ret;
3082 inst = cfg->vret_addr;
3083 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3086 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3087 ArgInfo *ainfo = cinfo->args + i;
3088 inst = cfg->args [i];
3089 if (inst->opcode == OP_REGVAR) {
3090 if (ainfo->storage == ArgInIReg)
3091 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3092 else if (ainfo->storage == ArgInFReg)
3093 g_assert_not_reached();
3094 else if (ainfo->storage == ArgOnStack) {
3097 g_assert_not_reached ();
3099 if (ainfo->storage == ArgInIReg) {
3100 g_assert (mips_is_imm16 (inst->inst_offset));
3101 switch (ainfo->size) {
3103 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3106 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3110 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3113 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3114 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3117 g_assert_not_reached ();
3120 } else if (ainfo->storage == ArgOnStack) {
3122 } else if (ainfo->storage == ArgInFReg) {
3123 g_assert (mips_is_imm16 (inst->inst_offset));
3124 if (ainfo->size == 8) {
3125 #if _MIPS_SIM == _ABIO32
3126 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3127 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3128 #elif _MIPS_SIM == _ABIN32
3129 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3132 else if (ainfo->size == 4)
3133 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3135 g_assert_not_reached ();
3136 } else if (ainfo->storage == ArgStructByVal) {
3138 int doffset = inst->inst_offset;
3140 g_assert (mips_is_imm16 (inst->inst_offset));
3141 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3142 for (i = 0; i < ainfo->size; ++i) {
3143 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3144 doffset += SIZEOF_REGISTER;
3146 } else if (ainfo->storage == ArgStructByAddr) {
3147 g_assert (mips_is_imm16 (inst->inst_offset));
3148 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3150 g_assert_not_reached ();
3158 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3160 int size = cfg->param_area;
3162 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3163 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3168 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3169 if (ppc_is_imm16 (-size)) {
3170 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3172 ppc_load (code, ppc_r12, -size);
3173 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3180 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3182 int size = cfg->param_area;
3184 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3185 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3190 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3191 if (ppc_is_imm16 (size)) {
3192 ppc_stwu (code, ppc_r0, size, ppc_sp);
3194 ppc_load (code, ppc_r12, size);
3195 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3202 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3207 guint8 *code = cfg->native_code + cfg->code_len;
3208 MonoInst *last_ins = NULL;
3209 guint last_offset = 0;
3213 /* we don't align basic blocks of loops on mips */
3215 if (cfg->verbose_level > 2)
3216 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3218 cpos = bb->max_offset;
3220 MONO_BB_FOR_EACH_INS (bb, ins) {
3221 offset = code - cfg->native_code;
3223 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3225 if (offset > (cfg->code_size - max_len - 16)) {
3226 cfg->code_size *= 2;
3227 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3228 code = cfg->native_code + offset;
3230 mono_debug_record_line_number (cfg, ins, offset);
3231 if (cfg->verbose_level > 2) {
3232 g_print (" @ 0x%x\t", offset);
3233 mono_print_ins_index (ins_cnt++, ins);
3235 /* Check for virtual regs that snuck by */
3236 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3238 switch (ins->opcode) {
3239 case OP_RELAXED_NOP:
3242 case OP_DUMMY_STORE:
3243 case OP_NOT_REACHED:
3246 case OP_IL_SEQ_POINT:
3247 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3249 case OP_SEQ_POINT: {
3250 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3251 guint32 addr = (guint32)ss_trigger_page;
3253 mips_load_const (code, mips_t9, addr);
3254 mips_lw (code, mips_t9, mips_t9, 0);
3257 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3260 * A placeholder for a possible breakpoint inserted by
3261 * mono_arch_set_breakpoint ().
3263 /* mips_load_const () + mips_lw */
3270 mips_mult (code, ins->sreg1, ins->sreg2);
3271 mips_mflo (code, ins->dreg);
3272 mips_mfhi (code, ins->dreg+1);
3275 mips_multu (code, ins->sreg1, ins->sreg2);
3276 mips_mflo (code, ins->dreg);
3277 mips_mfhi (code, ins->dreg+1);
3279 case OP_MEMORY_BARRIER:
3280 mips_sync (code, 0);
3282 case OP_STOREI1_MEMBASE_IMM:
3283 mips_load_const (code, mips_temp, ins->inst_imm);
3284 if (mips_is_imm16 (ins->inst_offset)) {
3285 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3287 mips_load_const (code, mips_at, ins->inst_offset);
3288 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3291 case OP_STOREI2_MEMBASE_IMM:
3292 mips_load_const (code, mips_temp, ins->inst_imm);
3293 if (mips_is_imm16 (ins->inst_offset)) {
3294 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3296 mips_load_const (code, mips_at, ins->inst_offset);
3297 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3300 case OP_STOREI8_MEMBASE_IMM:
3301 mips_load_const (code, mips_temp, ins->inst_imm);
3302 if (mips_is_imm16 (ins->inst_offset)) {
3303 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3305 mips_load_const (code, mips_at, ins->inst_offset);
3306 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3309 case OP_STORE_MEMBASE_IMM:
3310 case OP_STOREI4_MEMBASE_IMM:
3311 mips_load_const (code, mips_temp, ins->inst_imm);
3312 if (mips_is_imm16 (ins->inst_offset)) {
3313 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3315 mips_load_const (code, mips_at, ins->inst_offset);
3316 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3319 case OP_STOREI1_MEMBASE_REG:
3320 if (mips_is_imm16 (ins->inst_offset)) {
3321 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3323 mips_load_const (code, mips_at, ins->inst_offset);
3324 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3325 mips_sb (code, ins->sreg1, mips_at, 0);
3328 case OP_STOREI2_MEMBASE_REG:
3329 if (mips_is_imm16 (ins->inst_offset)) {
3330 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3332 mips_load_const (code, mips_at, ins->inst_offset);
3333 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3334 mips_sh (code, ins->sreg1, mips_at, 0);
3337 case OP_STORE_MEMBASE_REG:
3338 case OP_STOREI4_MEMBASE_REG:
3339 if (mips_is_imm16 (ins->inst_offset)) {
3340 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3342 mips_load_const (code, mips_at, ins->inst_offset);
3343 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3344 mips_sw (code, ins->sreg1, mips_at, 0);
3347 case OP_STOREI8_MEMBASE_REG:
3348 if (mips_is_imm16 (ins->inst_offset)) {
3349 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3351 mips_load_const (code, mips_at, ins->inst_offset);
3352 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3353 mips_sd (code, ins->sreg1, mips_at, 0);
3357 g_assert_not_reached ();
3358 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3359 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3361 case OP_LOADI8_MEMBASE:
3362 if (mips_is_imm16 (ins->inst_offset)) {
3363 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3365 mips_load_const (code, mips_at, ins->inst_offset);
3366 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3367 mips_ld (code, ins->dreg, mips_at, 0);
3370 case OP_LOAD_MEMBASE:
3371 case OP_LOADI4_MEMBASE:
3372 case OP_LOADU4_MEMBASE:
3373 g_assert (ins->dreg != -1);
3374 if (mips_is_imm16 (ins->inst_offset)) {
3375 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3377 mips_load_const (code, mips_at, ins->inst_offset);
3378 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3379 mips_lw (code, ins->dreg, mips_at, 0);
3382 case OP_LOADI1_MEMBASE:
3383 if (mips_is_imm16 (ins->inst_offset)) {
3384 mips_lb (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_lb (code, ins->dreg, mips_at, 0);
3391 case OP_LOADU1_MEMBASE:
3392 if (mips_is_imm16 (ins->inst_offset)) {
3393 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3395 mips_load_const (code, mips_at, ins->inst_offset);
3396 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3397 mips_lbu (code, ins->dreg, mips_at, 0);
3400 case OP_LOADI2_MEMBASE:
3401 if (mips_is_imm16 (ins->inst_offset)) {
3402 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3404 mips_load_const (code, mips_at, ins->inst_offset);
3405 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3406 mips_lh (code, ins->dreg, mips_at, 0);
3409 case OP_LOADU2_MEMBASE:
3410 if (mips_is_imm16 (ins->inst_offset)) {
3411 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3413 mips_load_const (code, mips_at, ins->inst_offset);
3414 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3415 mips_lhu (code, ins->dreg, mips_at, 0);
3418 case OP_ICONV_TO_I1:
3419 mips_sll (code, mips_at, ins->sreg1, 24);
3420 mips_sra (code, ins->dreg, mips_at, 24);
3422 case OP_ICONV_TO_I2:
3423 mips_sll (code, mips_at, ins->sreg1, 16);
3424 mips_sra (code, ins->dreg, mips_at, 16);
3426 case OP_ICONV_TO_U1:
3427 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3429 case OP_ICONV_TO_U2:
3430 mips_sll (code, mips_at, ins->sreg1, 16);
3431 mips_srl (code, ins->dreg, mips_at, 16);
3434 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3437 g_assert (mips_is_imm16 (ins->inst_imm));
3438 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3441 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3444 g_assert (mips_is_imm16 (ins->inst_imm));
3445 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3449 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3450 * So instead of emitting a trap, we emit a call a C function and place a
3453 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3454 (gpointer)"mono_break");
3455 mips_load (code, mips_t9, 0x1f1f1f1f);
3456 mips_jalr (code, mips_t9, mips_ra);
3460 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3463 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3468 g_assert (mips_is_imm16 (ins->inst_imm));
3469 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3472 g_assert (mips_is_imm16 (ins->inst_imm));
3473 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3477 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3480 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3485 // we add the negated value
3486 g_assert (mips_is_imm16 (-ins->inst_imm));
3487 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3491 // we add the negated value
3492 g_assert (mips_is_imm16 (-ins->inst_imm));
3493 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3498 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3504 g_assert (!(ins->inst_imm & 0xffff0000));
3505 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3510 guint32 *divisor_is_m1;
3511 guint32 *dividend_is_minvalue;
3512 guint32 *divisor_is_zero;
3514 mips_load_const (code, mips_at, -1);
3515 divisor_is_m1 = (guint32 *)(void *)code;
3516 mips_bne (code, ins->sreg2, mips_at, 0);
3517 mips_lui (code, mips_at, mips_zero, 0x8000);
3518 dividend_is_minvalue = (guint32 *)(void *)code;
3519 mips_bne (code, ins->sreg1, mips_at, 0);
3522 /* Divide Int32.MinValue by -1 -- throw exception */
3523 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3525 mips_patch (divisor_is_m1, (guint32)code);
3526 mips_patch (dividend_is_minvalue, (guint32)code);
3528 /* Put divide in branch delay slot (NOT YET) */
3529 divisor_is_zero = (guint32 *)(void *)code;
3530 mips_bne (code, ins->sreg2, mips_zero, 0);
3533 /* Divide by zero -- throw exception */
3534 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3536 mips_patch (divisor_is_zero, (guint32)code);
3537 mips_div (code, ins->sreg1, ins->sreg2);
3538 if (ins->opcode == OP_IDIV)
3539 mips_mflo (code, ins->dreg);
3541 mips_mfhi (code, ins->dreg);
3546 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3548 /* Put divide in branch delay slot (NOT YET) */
3549 mips_bne (code, ins->sreg2, mips_zero, 0);
3552 /* Divide by zero -- throw exception */
3553 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3555 mips_patch (divisor_is_zero, (guint32)code);
3556 mips_divu (code, ins->sreg1, ins->sreg2);
3557 if (ins->opcode == OP_IDIV_UN)
3558 mips_mflo (code, ins->dreg);
3560 mips_mfhi (code, ins->dreg);
3564 g_assert_not_reached ();
3566 ppc_load (code, ppc_r12, ins->inst_imm);
3567 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3568 ppc_mfspr (code, ppc_r0, ppc_xer);
3569 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3570 /* FIXME: use OverflowException for 0x80000000/-1 */
3571 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3573 g_assert_not_reached();
3576 g_assert_not_reached ();
3578 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3582 g_assert (!(ins->inst_imm & 0xffff0000));
3583 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3586 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3590 /* unsigned 16-bit immediate */
3591 g_assert (!(ins->inst_imm & 0xffff0000));
3592 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3595 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3599 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3602 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3605 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3609 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3612 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3615 case OP_ISHR_UN_IMM:
3616 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3618 case OP_LSHR_UN_IMM:
3619 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3622 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3625 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3629 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3632 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3635 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3639 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3641 mips_mult (code, ins->sreg1, ins->sreg2);
3642 mips_mflo (code, ins->dreg);
3647 #if SIZEOF_REGISTER == 8
3649 mips_dmult (code, ins->sreg1, ins->sreg2);
3650 mips_mflo (code, ins->dreg);
3655 mips_mult (code, ins->sreg1, ins->sreg2);
3656 mips_mflo (code, ins->dreg);
3657 mips_mfhi (code, mips_at);
3660 mips_sra (code, mips_temp, ins->dreg, 31);
3661 patch = (guint32 *)(void *)code;
3662 mips_beq (code, mips_temp, mips_at, 0);
3664 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3665 mips_patch (patch, (guint32)code);
3668 case OP_IMUL_OVF_UN: {
3670 mips_mult (code, ins->sreg1, ins->sreg2);
3671 mips_mflo (code, ins->dreg);
3672 mips_mfhi (code, mips_at);
3675 patch = (guint32 *)(void *)code;
3676 mips_beq (code, mips_at, mips_zero, 0);
3678 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3679 mips_patch (patch, (guint32)code);
3683 mips_load_const (code, ins->dreg, ins->inst_c0);
3685 #if SIZEOF_REGISTER == 8
3687 mips_load_const (code, ins->dreg, ins->inst_c0);
3691 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3692 mips_load (code, ins->dreg, 0);
3696 mips_mtc1 (code, ins->dreg, ins->sreg1);
3698 case OP_MIPS_MTC1S_2:
3699 mips_mtc1 (code, ins->dreg, ins->sreg1);
3700 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3703 mips_mfc1 (code, ins->dreg, ins->sreg1);
3706 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3710 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3712 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3713 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3717 case OP_ICONV_TO_I4:
3718 case OP_ICONV_TO_U4:
3720 if (ins->dreg != ins->sreg1)
3721 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3723 #if SIZEOF_REGISTER == 8
3725 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3726 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3729 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3730 mips_dsra (code, ins->dreg, ins->dreg, 32);
3734 int lsreg = mips_v0 + ls_word_idx;
3735 int msreg = mips_v0 + ms_word_idx;
3737 /* Get sreg1 into lsreg, sreg2 into msreg */
3739 if (ins->sreg1 == msreg) {
3740 if (ins->sreg1 != mips_at)
3741 MIPS_MOVE (code, mips_at, ins->sreg1);
3742 if (ins->sreg2 != msreg)
3743 MIPS_MOVE (code, msreg, ins->sreg2);
3744 MIPS_MOVE (code, lsreg, mips_at);
3747 if (ins->sreg2 != msreg)
3748 MIPS_MOVE (code, msreg, ins->sreg2);
3749 if (ins->sreg1 != lsreg)
3750 MIPS_MOVE (code, lsreg, ins->sreg1);
3755 if (ins->dreg != ins->sreg1) {
3756 mips_fmovd (code, ins->dreg, ins->sreg1);
3759 case OP_MOVE_F_TO_I4:
3760 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3761 mips_mfc1 (code, ins->dreg, mips_ftemp);
3763 case OP_MOVE_I4_TO_F:
3764 mips_mtc1 (code, ins->dreg, ins->sreg1);
3765 mips_cvtds (code, ins->dreg, ins->dreg);
3768 /* Convert from double to float and leave it there */
3769 mips_cvtsd (code, ins->dreg, ins->sreg1);
3771 case OP_FCONV_TO_R4:
3773 mips_cvtsd (code, ins->dreg, ins->sreg1);
3775 /* Just a move, no precision change */
3776 if (ins->dreg != ins->sreg1) {
3777 mips_fmovd (code, ins->dreg, ins->sreg1);
3782 code = emit_load_volatile_arguments(cfg, code);
3785 * Pop our stack, then jump to specified method (tail-call)
3786 * Keep in sync with mono_arch_emit_epilog
3788 code = mono_arch_emit_epilog_sub (cfg, code);
3790 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3791 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3792 mips_load (code, mips_t9, 0);
3793 mips_jr (code, mips_t9);
3797 /* ensure ins->sreg1 is not NULL */
3798 mips_lw (code, mips_zero, ins->sreg1, 0);
3801 g_assert (mips_is_imm16 (cfg->sig_cookie));
3802 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3803 mips_sw (code, mips_at, ins->sreg1, 0);
3816 case OP_VOIDCALL_REG:
3818 case OP_FCALL_MEMBASE:
3819 case OP_LCALL_MEMBASE:
3820 case OP_VCALL_MEMBASE:
3821 case OP_VCALL2_MEMBASE:
3822 case OP_VOIDCALL_MEMBASE:
3823 case OP_CALL_MEMBASE:
3824 call = (MonoCallInst*)ins;
3825 switch (ins->opcode) {
3832 if (ins->flags & MONO_INST_HAS_METHOD) {
3833 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3834 mips_load (code, mips_t9, call->method);
3837 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3838 mips_load (code, mips_t9, call->fptr);
3840 mips_jalr (code, mips_t9, mips_ra);
3847 case OP_VOIDCALL_REG:
3849 MIPS_MOVE (code, mips_t9, ins->sreg1);
3850 mips_jalr (code, mips_t9, mips_ra);
3853 case OP_FCALL_MEMBASE:
3854 case OP_LCALL_MEMBASE:
3855 case OP_VCALL_MEMBASE:
3856 case OP_VCALL2_MEMBASE:
3857 case OP_VOIDCALL_MEMBASE:
3858 case OP_CALL_MEMBASE:
3859 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3860 mips_jalr (code, mips_t9, mips_ra);
3864 #if PROMOTE_R4_TO_R8
3865 /* returned an FP R4 (single), promote to R8 (double) in place */
3866 switch (ins->opcode) {
3869 case OP_FCALL_MEMBASE:
3870 if (call->signature->ret->type == MONO_TYPE_R4)
3871 mips_cvtds (code, mips_f0, mips_f0);
3879 int area_offset = cfg->param_area;
3881 /* Round up ins->sreg1, mips_at ends up holding size */
3882 mips_addiu (code, mips_at, ins->sreg1, 31);
3883 mips_addiu (code, mips_temp, mips_zero, ~31);
3884 mips_and (code, mips_at, mips_at, mips_temp);
3886 mips_subu (code, mips_sp, mips_sp, mips_at);
3887 g_assert (mips_is_imm16 (area_offset));
3888 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3890 if (ins->flags & MONO_INST_INIT) {
3893 buf = (guint32*)(void*)code;
3894 mips_beq (code, mips_at, mips_zero, 0);
3897 mips_move (code, mips_temp, ins->dreg);
3898 mips_sb (code, mips_zero, mips_temp, 0);
3899 mips_addiu (code, mips_at, mips_at, -1);
3900 mips_bne (code, mips_at, mips_zero, -3);
3901 mips_addiu (code, mips_temp, mips_temp, 1);
3903 mips_patch (buf, (guint32)code);
3908 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3909 mips_move (code, mips_a0, ins->sreg1);
3910 mips_call (code, mips_t9, addr);
3911 mips_break (code, 0xfc);
3915 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3916 mips_move (code, mips_a0, ins->sreg1);
3917 mips_call (code, mips_t9, addr);
3918 mips_break (code, 0xfb);
3921 case OP_START_HANDLER: {
3923 * The START_HANDLER instruction marks the beginning of
3924 * a handler block. It is called using a call
3925 * instruction, so mips_ra contains the return address.
3926 * Since the handler executes in the same stack frame
3927 * as the method itself, we can't use save/restore to
3928 * save the return address. Instead, we save it into
3929 * a dedicated variable.
3931 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3932 g_assert (spvar->inst_basereg != mips_sp);
3933 code = emit_reserve_param_area (cfg, code);
3935 if (mips_is_imm16 (spvar->inst_offset)) {
3936 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3938 mips_load_const (code, mips_at, spvar->inst_offset);
3939 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3940 mips_sw (code, mips_ra, mips_at, 0);
3944 case OP_ENDFILTER: {
3945 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3946 g_assert (spvar->inst_basereg != mips_sp);
3947 code = emit_unreserve_param_area (cfg, code);
3949 if (ins->sreg1 != mips_v0)
3950 MIPS_MOVE (code, mips_v0, ins->sreg1);
3951 if (mips_is_imm16 (spvar->inst_offset)) {
3952 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3954 mips_load_const (code, mips_at, spvar->inst_offset);
3955 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3956 mips_lw (code, mips_ra, mips_at, 0);
3958 mips_jr (code, mips_ra);
3962 case OP_ENDFINALLY: {
3963 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3964 g_assert (spvar->inst_basereg != mips_sp);
3965 code = emit_unreserve_param_area (cfg, code);
3966 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3967 mips_jalr (code, mips_t9, mips_ra);
3971 case OP_CALL_HANDLER:
3972 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3973 mips_lui (code, mips_t9, mips_zero, 0);
3974 mips_addiu (code, mips_t9, mips_t9, 0);
3975 mips_jalr (code, mips_t9, mips_ra);
3977 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3978 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3981 ins->inst_c0 = code - cfg->native_code;
3984 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3985 if (cfg->arch.long_branch) {
3986 mips_lui (code, mips_at, mips_zero, 0);
3987 mips_addiu (code, mips_at, mips_at, 0);
3988 mips_jr (code, mips_at);
3992 mips_beq (code, mips_zero, mips_zero, 0);
3997 mips_jr (code, ins->sreg1);
4003 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4004 if (offset > (cfg->code_size - max_len - 16)) {
4005 cfg->code_size += max_len;
4006 cfg->code_size *= 2;
4007 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4008 code = cfg->native_code + offset;
4010 g_assert (ins->sreg1 != -1);
4011 mips_sll (code, mips_at, ins->sreg1, 2);
4012 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4013 MIPS_MOVE (code, mips_t8, mips_ra);
4014 mips_bgezal (code, mips_zero, 1); /* bal */
4016 mips_addu (code, mips_t9, mips_ra, mips_at);
4017 /* Table is 16 or 20 bytes from target of bal above */
4018 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4019 MIPS_MOVE (code, mips_ra, mips_t8);
4020 mips_lw (code, mips_t9, mips_t9, 20);
4023 mips_lw (code, mips_t9, mips_t9, 16);
4024 mips_jalr (code, mips_t9, mips_t8);
4026 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4027 mips_emit32 (code, 0xfefefefe);
4032 mips_addiu (code, ins->dreg, mips_zero, 1);
4033 mips_beq (code, mips_at, mips_zero, 2);
4035 MIPS_MOVE (code, ins->dreg, mips_zero);
4041 mips_addiu (code, ins->dreg, mips_zero, 1);
4042 mips_bltz (code, mips_at, 2);
4044 MIPS_MOVE (code, ins->dreg, mips_zero);
4050 mips_addiu (code, ins->dreg, mips_zero, 1);
4051 mips_bgtz (code, mips_at, 2);
4053 MIPS_MOVE (code, ins->dreg, mips_zero);
4056 case OP_MIPS_COND_EXC_EQ:
4057 case OP_MIPS_COND_EXC_GE:
4058 case OP_MIPS_COND_EXC_GT:
4059 case OP_MIPS_COND_EXC_LE:
4060 case OP_MIPS_COND_EXC_LT:
4061 case OP_MIPS_COND_EXC_NE_UN:
4062 case OP_MIPS_COND_EXC_GE_UN:
4063 case OP_MIPS_COND_EXC_GT_UN:
4064 case OP_MIPS_COND_EXC_LE_UN:
4065 case OP_MIPS_COND_EXC_LT_UN:
4067 case OP_MIPS_COND_EXC_OV:
4068 case OP_MIPS_COND_EXC_NO:
4069 case OP_MIPS_COND_EXC_C:
4070 case OP_MIPS_COND_EXC_NC:
4072 case OP_MIPS_COND_EXC_IEQ:
4073 case OP_MIPS_COND_EXC_IGE:
4074 case OP_MIPS_COND_EXC_IGT:
4075 case OP_MIPS_COND_EXC_ILE:
4076 case OP_MIPS_COND_EXC_ILT:
4077 case OP_MIPS_COND_EXC_INE_UN:
4078 case OP_MIPS_COND_EXC_IGE_UN:
4079 case OP_MIPS_COND_EXC_IGT_UN:
4080 case OP_MIPS_COND_EXC_ILE_UN:
4081 case OP_MIPS_COND_EXC_ILT_UN:
4083 case OP_MIPS_COND_EXC_IOV:
4084 case OP_MIPS_COND_EXC_INO:
4085 case OP_MIPS_COND_EXC_IC:
4086 case OP_MIPS_COND_EXC_INC: {
4090 /* If the condition is true, raise the exception */
4092 /* need to reverse test to skip around exception raising */
4094 /* For the moment, branch around a branch to avoid reversing
4097 /* Remember, an unpatched branch to 0 branches to the delay slot */
4098 switch (ins->opcode) {
4099 case OP_MIPS_COND_EXC_EQ:
4100 throw = (guint32 *)(void *)code;
4101 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4105 case OP_MIPS_COND_EXC_NE_UN:
4106 throw = (guint32 *)(void *)code;
4107 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4111 case OP_MIPS_COND_EXC_LE_UN:
4112 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4113 throw = (guint32 *)(void *)code;
4114 mips_beq (code, mips_at, mips_zero, 0);
4118 case OP_MIPS_COND_EXC_GT:
4119 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4120 throw = (guint32 *)(void *)code;
4121 mips_bne (code, mips_at, mips_zero, 0);
4125 case OP_MIPS_COND_EXC_GT_UN:
4126 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4127 throw = (guint32 *)(void *)code;
4128 mips_bne (code, mips_at, mips_zero, 0);
4132 case OP_MIPS_COND_EXC_LT:
4133 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4134 throw = (guint32 *)(void *)code;
4135 mips_bne (code, mips_at, mips_zero, 0);
4139 case OP_MIPS_COND_EXC_LT_UN:
4140 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4141 throw = (guint32 *)(void *)code;
4142 mips_bne (code, mips_at, mips_zero, 0);
4147 /* Not yet implemented */
4148 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4149 g_assert_not_reached ();
4151 skip = (guint32 *)(void *)code;
4152 mips_beq (code, mips_zero, mips_zero, 0);
4154 mips_patch (throw, (guint32)code);
4155 code = mips_emit_exc_by_name (code, ins->inst_p1);
4156 mips_patch (skip, (guint32)code);
4157 cfg->bb_exit->max_offset += 24;
4166 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4169 /* floating point opcodes */
4172 if (((guint32)ins->inst_p0) & (1 << 15))
4173 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4175 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4176 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4178 mips_load_const (code, mips_at, ins->inst_p0);
4179 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4180 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4184 if (((guint32)ins->inst_p0) & (1 << 15))
4185 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4187 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4188 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4189 #if PROMOTE_R4_TO_R8
4190 mips_cvtds (code, ins->dreg, ins->dreg);
4193 case OP_STORER8_MEMBASE_REG:
4194 if (mips_is_imm16 (ins->inst_offset)) {
4195 #if _MIPS_SIM == _ABIO32
4196 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4197 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4198 #elif _MIPS_SIM == _ABIN32
4199 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4202 mips_load_const (code, mips_at, ins->inst_offset);
4203 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4204 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4205 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4208 case OP_LOADR8_MEMBASE:
4209 if (mips_is_imm16 (ins->inst_offset)) {
4210 #if _MIPS_SIM == _ABIO32
4211 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4212 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4213 #elif _MIPS_SIM == _ABIN32
4214 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4217 mips_load_const (code, mips_at, ins->inst_offset);
4218 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4219 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4220 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4223 case OP_STORER4_MEMBASE_REG:
4224 g_assert (mips_is_imm16 (ins->inst_offset));
4225 #if PROMOTE_R4_TO_R8
4226 /* Need to convert ins->sreg1 to single-precision first */
4227 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4228 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4230 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4234 g_assert (mips_is_imm16 (ins->inst_offset));
4235 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4237 case OP_LOADR4_MEMBASE:
4238 g_assert (mips_is_imm16 (ins->inst_offset));
4239 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4240 #if PROMOTE_R4_TO_R8
4241 /* Convert to double precision in place */
4242 mips_cvtds (code, ins->dreg, ins->dreg);
4245 case OP_LOADR4_MEMINDEX:
4246 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4247 mips_lwc1 (code, ins->dreg, mips_at, 0);
4249 case OP_LOADR8_MEMINDEX:
4250 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4251 #if _MIPS_SIM == _ABIO32
4252 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4253 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4254 #elif _MIPS_SIM == _ABIN32
4255 mips_ldc1 (code, ins->dreg, mips_at, 0);
4258 case OP_STORER4_MEMINDEX:
4259 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4260 #if PROMOTE_R4_TO_R8
4261 /* Need to convert ins->sreg1 to single-precision first */
4262 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4263 mips_swc1 (code, mips_ftemp, mips_at, 0);
4265 mips_swc1 (code, ins->sreg1, mips_at, 0);
4268 case OP_STORER8_MEMINDEX:
4269 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4270 #if _MIPS_SIM == _ABIO32
4271 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4272 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4273 #elif _MIPS_SIM == _ABIN32
4274 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4277 case OP_ICONV_TO_R_UN: {
4278 static const guint64 adjust_val = 0x41F0000000000000ULL;
4280 /* convert unsigned int to double */
4281 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4282 mips_bgez (code, ins->sreg1, 5);
4283 mips_cvtdw (code, ins->dreg, mips_ftemp);
4285 mips_load (code, mips_at, (guint32) &adjust_val);
4286 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4287 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4288 /* target is here */
4291 case OP_ICONV_TO_R4:
4292 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4293 mips_cvtsw (code, ins->dreg, mips_ftemp);
4294 mips_cvtds (code, ins->dreg, ins->dreg);
4296 case OP_ICONV_TO_R8:
4297 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4298 mips_cvtdw (code, ins->dreg, mips_ftemp);
4300 case OP_FCONV_TO_I1:
4301 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4303 case OP_FCONV_TO_U1:
4304 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4306 case OP_FCONV_TO_I2:
4307 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4309 case OP_FCONV_TO_U2:
4310 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4312 case OP_FCONV_TO_I4:
4314 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4316 case OP_FCONV_TO_U4:
4318 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4321 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4324 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4327 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4330 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4333 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4336 mips_fnegd (code, ins->dreg, ins->sreg1);
4339 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4340 mips_addiu (code, ins->dreg, mips_zero, 1);
4341 mips_fbtrue (code, 2);
4343 MIPS_MOVE (code, ins->dreg, mips_zero);
4346 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4347 mips_addiu (code, ins->dreg, mips_zero, 1);
4348 mips_fbtrue (code, 2);
4350 MIPS_MOVE (code, ins->dreg, mips_zero);
4353 /* Less than, or Unordered */
4354 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4355 mips_addiu (code, ins->dreg, mips_zero, 1);
4356 mips_fbtrue (code, 2);
4358 MIPS_MOVE (code, ins->dreg, mips_zero);
4361 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4362 MIPS_MOVE (code, ins->dreg, mips_zero);
4363 mips_fbtrue (code, 2);
4365 mips_addiu (code, ins->dreg, mips_zero, 1);
4368 /* Greater than, or Unordered */
4369 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4370 MIPS_MOVE (code, ins->dreg, mips_zero);
4371 mips_fbtrue (code, 2);
4373 mips_addiu (code, ins->dreg, mips_zero, 1);
4378 case OP_MIPS_FBLT_UN:
4380 case OP_MIPS_FBGT_UN:
4382 case OP_MIPS_FBGE_UN:
4384 case OP_MIPS_FBLE_UN: {
4386 gboolean is_true = TRUE, is_ordered = FALSE;
4387 guint32 *buf = NULL;
4389 switch (ins->opcode) {
4403 case OP_MIPS_FBLT_UN:
4404 cond = MIPS_FPU_ULT;
4412 case OP_MIPS_FBGT_UN:
4413 cond = MIPS_FPU_OLE;
4421 case OP_MIPS_FBGE_UN:
4422 cond = MIPS_FPU_OLT;
4426 cond = MIPS_FPU_OLE;
4430 case OP_MIPS_FBLE_UN:
4431 cond = MIPS_FPU_ULE;
4435 g_assert_not_reached ();
4439 /* Skip the check if unordered */
4440 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4442 buf = (guint32*)code;
4443 mips_fbtrue (code, 0);
4447 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4449 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4451 mips_fbtrue (code, 0);
4453 mips_fbfalse (code, 0);
4457 mips_patch (buf, (guint32)code);
4461 guint32 *branch_patch;
4463 mips_mfc1 (code, mips_at, ins->sreg1+1);
4464 mips_srl (code, mips_at, mips_at, 16+4);
4465 mips_andi (code, mips_at, mips_at, 2047);
4466 mips_addiu (code, mips_at, mips_at, -2047);
4468 branch_patch = (guint32 *)(void *)code;
4469 mips_bne (code, mips_at, mips_zero, 0);
4472 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4473 mips_patch (branch_patch, (guint32)code);
4474 mips_fmovd (code, ins->dreg, ins->sreg1);
4478 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4479 mips_load (code, ins->dreg, 0x0f0f0f0f);
4481 case OP_GC_SAFE_POINT:
4486 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4487 g_assert_not_reached ();
4490 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4491 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4492 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4493 g_assert_not_reached ();
4499 last_offset = offset;
4502 cfg->code_len = code - cfg->native_code;
4506 mono_arch_register_lowlevel_calls (void)
4511 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4513 MonoJumpInfo *patch_info;
4517 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4518 unsigned char *ip = patch_info->ip.i + code;
4519 const unsigned char *target = NULL;
4521 switch (patch_info->type) {
4522 case MONO_PATCH_INFO_IP:
4523 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4525 case MONO_PATCH_INFO_SWITCH: {
4526 gpointer *table = (gpointer *)patch_info->data.table->table;
4529 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4531 for (i = 0; i < patch_info->data.table->table_size; i++) {
4532 table [i] = (int)patch_info->data.table->table [i] + code;
4536 case MONO_PATCH_INFO_METHODCONST:
4537 case MONO_PATCH_INFO_CLASS:
4538 case MONO_PATCH_INFO_IMAGE:
4539 case MONO_PATCH_INFO_FIELD:
4540 case MONO_PATCH_INFO_VTABLE:
4541 case MONO_PATCH_INFO_IID:
4542 case MONO_PATCH_INFO_SFLDA:
4543 case MONO_PATCH_INFO_LDSTR:
4544 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4545 case MONO_PATCH_INFO_LDTOKEN:
4546 case MONO_PATCH_INFO_R4:
4547 case MONO_PATCH_INFO_R8:
4548 /* from OP_AOTCONST : lui + addiu */
4549 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4550 return_if_nok (error);
4552 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4555 case MONO_PATCH_INFO_EXC_NAME:
4556 g_assert_not_reached ();
4557 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4560 case MONO_PATCH_INFO_NONE:
4561 /* everything is dealt with at epilog output time */
4564 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4565 return_if_nok (error);
4567 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4574 * Allow tracing to work with this interface (with an optional argument)
4576 * This code is expected to be inserted just after the 'real' prolog code,
4577 * and before the first basic block. We need to allocate a 2nd, temporary
4578 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4582 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4585 int offset = cfg->arch.tracing_offset;
4591 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4592 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4593 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4594 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4595 #if _MIPS_SIM == _ABIN32
4597 /* FIXME: Need a separate region for these */
4598 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4599 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4600 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4601 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4605 mips_load_const (code, mips_a0, cfg->method);
4606 mips_addiu (code, mips_a1, mips_sp, offset);
4607 mips_call (code, mips_t9, func);
4610 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4611 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4612 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4613 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4614 #if _MIPS_SIM == _ABIN32
4617 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4618 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4619 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4620 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4631 mips_adjust_stackframe(MonoCompile *cfg)
4634 int delta, threshold, i;
4635 MonoMethodSignature *sig;
4638 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4641 /* adjust cfg->stack_offset for account for down-spilling */
4642 cfg->stack_offset += SIZEOF_REGISTER;
4644 /* re-align cfg->stack_offset if needed (due to var spilling) */
4645 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4646 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4647 if (cfg->verbose_level > 2) {
4648 g_print ("mips_adjust_stackframe:\n");
4649 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4651 threshold = cfg->arch.local_alloc_offset;
4652 ra_offset = cfg->stack_offset - sizeof(gpointer);
4653 if (cfg->verbose_level > 2) {
4654 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4657 sig = mono_method_signature (cfg->method);
4658 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4659 cfg->vret_addr->inst_offset += delta;
4661 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4662 MonoInst *inst = cfg->args [i];
4664 inst->inst_offset += delta;
4668 * loads and stores based off the frame reg that (used to) lie
4669 * above the spill var area need to be increased by 'delta'
4670 * to make room for the spill vars.
4672 /* Need to find loads and stores to adjust that
4673 * are above where the spillvars were inserted, but
4674 * which are not the spillvar references themselves.
4676 * Idea - since all offsets from fp are positive, make
4677 * spillvar offsets negative to begin with so we can spot
4682 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4686 if (cfg->verbose_level > 2) {
4687 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4689 MONO_BB_FOR_EACH_INS (bb, ins) {
4693 if (cfg->verbose_level > 2) {
4694 mono_print_ins_index (ins_cnt, ins);
4696 /* The == mips_sp tests catch FP spills */
4697 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4698 (ins->inst_basereg == mips_sp))) {
4699 switch (ins->opcode) {
4700 case OP_LOADI8_MEMBASE:
4701 case OP_LOADR8_MEMBASE:
4708 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4709 (ins->dreg == mips_sp))) {
4710 switch (ins->opcode) {
4711 case OP_STOREI8_MEMBASE_REG:
4712 case OP_STORER8_MEMBASE_REG:
4713 case OP_STOREI8_MEMBASE_IMM:
4721 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4724 if (ins->inst_c0 >= threshold) {
4725 ins->inst_c0 += delta;
4726 if (cfg->verbose_level > 2) {
4728 mono_print_ins_index (ins_cnt, ins);
4731 else if (ins->inst_c0 < 0) {
4732 /* Adj_c0 holds the size of the datatype. */
4733 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4734 if (cfg->verbose_level > 2) {
4736 mono_print_ins_index (ins_cnt, ins);
4739 g_assert (ins->inst_c0 != ra_offset);
4742 if (ins->inst_imm >= threshold) {
4743 ins->inst_imm += delta;
4744 if (cfg->verbose_level > 2) {
4746 mono_print_ins_index (ins_cnt, ins);
4749 g_assert (ins->inst_c0 != ra_offset);
4759 * Stack frame layout:
4761 * ------------------- sp + cfg->stack_usage + cfg->param_area
4762 * param area incoming
4763 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4765 * ------------------- sp + cfg->stack_usage
4767 * ------------------- sp + cfg->stack_usage-4
4769 * ------------------- sp +
4770 * MonoLMF structure optional
4771 * ------------------- sp + cfg->arch.lmf_offset
4772 * saved registers s0-s8
4773 * ------------------- sp + cfg->arch.iregs_offset
4775 * ------------------- sp + cfg->param_area
4776 * param area outgoing
4777 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4779 * ------------------- sp
4783 mono_arch_emit_prolog (MonoCompile *cfg)
4785 MonoMethod *method = cfg->method;
4786 MonoMethodSignature *sig;
4788 int alloc_size, pos, i, max_offset;
4789 int alloc2_size = 0;
4793 guint32 iregs_to_save = 0;
4795 guint32 fregs_to_save = 0;
4797 /* lmf_offset is the offset of the LMF from our stack pointer. */
4798 guint32 lmf_offset = cfg->arch.lmf_offset;
4802 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4806 cfg->flags |= MONO_CFG_HAS_CALLS;
4808 sig = mono_method_signature (method);
4809 cfg->code_size = 768 + sig->param_count * 20;
4810 code = cfg->native_code = g_malloc (cfg->code_size);
4813 * compute max_offset in order to use short forward jumps.
4816 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4817 MonoInst *ins = bb->code;
4818 bb->max_offset = max_offset;
4820 MONO_BB_FOR_EACH_INS (bb, ins)
4821 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4823 if (max_offset > 0xffff)
4824 cfg->arch.long_branch = TRUE;
4827 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4828 * This means that we have to adjust the offsets inside instructions which reference
4829 * arguments received on the stack, since the initial offset doesn't take into
4830 * account spill slots.
4832 mips_adjust_stackframe (cfg);
4834 /* Offset between current sp and the CFA */
4836 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4838 /* stack_offset should not be changed here. */
4839 alloc_size = cfg->stack_offset;
4840 cfg->stack_usage = alloc_size;
4842 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4845 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4847 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4848 fregs_to_save |= (fregs_to_save << 1);
4851 /* If the stack size is too big, save 1024 bytes to start with
4852 * so the prologue can use imm16(reg) addressing, then allocate
4853 * the rest of the frame.
4855 if (alloc_size > ((1 << 15) - 1024)) {
4856 alloc2_size = alloc_size - 1024;
4860 g_assert (mips_is_imm16 (-alloc_size));
4861 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4862 cfa_offset = alloc_size;
4863 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4866 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4867 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4868 if (mips_is_imm16(offset))
4869 mips_sw (code, mips_ra, mips_sp, offset);
4871 g_assert_not_reached ();
4873 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4874 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4877 /* XXX - optimize this later to not save all regs if LMF constructed */
4878 pos = cfg->arch.iregs_offset - alloc2_size;
4880 if (iregs_to_save) {
4881 /* save used registers in own stack frame (at pos) */
4882 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4883 if (iregs_to_save & (1 << i)) {
4884 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4885 g_assert (mips_is_imm16(pos));
4886 MIPS_SW (code, i, mips_sp, pos);
4887 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4888 pos += SIZEOF_REGISTER;
4893 // FIXME: Don't save registers twice if there is an LMF
4894 // s8 has to be special cased since it is overwritten with the updated value
4896 if (method->save_lmf) {
4897 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4898 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4899 g_assert (mips_is_imm16(offset));
4900 if (MIPS_LMF_IREGMASK & (1 << i))
4901 MIPS_SW (code, i, mips_sp, offset);
4906 /* Save float registers */
4907 if (fregs_to_save) {
4908 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4909 if (fregs_to_save & (1 << i)) {
4910 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4911 g_assert (mips_is_imm16(pos));
4912 mips_swc1 (code, i, mips_sp, pos);
4913 pos += sizeof (gulong);
4918 if (method->save_lmf) {
4919 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4920 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4921 g_assert (mips_is_imm16(offset));
4922 mips_swc1 (code, i, mips_sp, offset);
4927 if (cfg->frame_reg != mips_sp) {
4928 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4929 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4931 if (method->save_lmf) {
4932 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4933 g_assert (mips_is_imm16(offset));
4934 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4938 /* store runtime generic context */
4939 if (cfg->rgctx_var) {
4940 MonoInst *ins = cfg->rgctx_var;
4942 g_assert (ins->opcode == OP_REGOFFSET);
4944 g_assert (mips_is_imm16 (ins->inst_offset));
4945 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4948 /* load arguments allocated to register from the stack */
4951 if (!cfg->arch.cinfo)
4952 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
4953 cinfo = cfg->arch.cinfo;
4955 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4956 ArgInfo *ainfo = &cinfo->ret;
4957 inst = cfg->vret_addr;
4958 if (inst->opcode == OP_REGVAR)
4959 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4960 else if (mips_is_imm16 (inst->inst_offset)) {
4961 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4963 mips_load_const (code, mips_at, inst->inst_offset);
4964 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4965 mips_sw (code, ainfo->reg, mips_at, 0);
4969 if (sig->call_convention == MONO_CALL_VARARG) {
4970 ArgInfo *cookie = &cinfo->sig_cookie;
4971 int offset = alloc_size + cookie->offset;
4973 /* Save the sig cookie address */
4974 g_assert (cookie->storage == ArgOnStack);
4976 g_assert (mips_is_imm16(offset));
4977 mips_addi (code, mips_at, cfg->frame_reg, offset);
4978 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
4981 /* Keep this in sync with emit_load_volatile_arguments */
4982 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4983 ArgInfo *ainfo = cinfo->args + i;
4984 inst = cfg->args [pos];
4986 if (cfg->verbose_level > 2)
4987 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
4988 if (inst->opcode == OP_REGVAR) {
4989 /* Argument ends up in a register */
4990 if (ainfo->storage == ArgInIReg)
4991 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4992 else if (ainfo->storage == ArgInFReg) {
4993 g_assert_not_reached();
4995 ppc_fmr (code, inst->dreg, ainfo->reg);
4998 else if (ainfo->storage == ArgOnStack) {
4999 int offset = cfg->stack_usage + ainfo->offset;
5000 g_assert (mips_is_imm16(offset));
5001 mips_lw (code, inst->dreg, mips_sp, offset);
5003 g_assert_not_reached ();
5005 if (cfg->verbose_level > 2)
5006 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5008 /* Argument ends up on the stack */
5009 if (ainfo->storage == ArgInIReg) {
5011 /* Incoming parameters should be above this frame */
5012 if (cfg->verbose_level > 2)
5013 g_print ("stack slot at %d of %d+%d\n",
5014 inst->inst_offset, alloc_size, alloc2_size);
5015 /* g_assert (inst->inst_offset >= alloc_size); */
5016 g_assert (inst->inst_basereg == cfg->frame_reg);
5017 basereg_offset = inst->inst_offset - alloc2_size;
5018 g_assert (mips_is_imm16 (basereg_offset));
5019 switch (ainfo->size) {
5021 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5024 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5028 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5031 #if (SIZEOF_REGISTER == 4)
5032 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5033 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5034 #elif (SIZEOF_REGISTER == 8)
5035 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5039 g_assert_not_reached ();
5042 } else if (ainfo->storage == ArgOnStack) {
5044 * Argument comes in on the stack, and ends up on the stack
5045 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5046 * 8 and 16 bit quantities. Shorten them in place.
5048 g_assert (mips_is_imm16 (inst->inst_offset));
5049 switch (ainfo->size) {
5051 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5052 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5055 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5056 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5063 g_assert_not_reached ();
5065 } else if (ainfo->storage == ArgInFReg) {
5066 g_assert (mips_is_imm16 (inst->inst_offset));
5067 g_assert (mips_is_imm16 (inst->inst_offset+4));
5068 if (ainfo->size == 8) {
5069 #if _MIPS_SIM == _ABIO32
5070 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5071 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5072 #elif _MIPS_SIM == _ABIN32
5073 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5076 else if (ainfo->size == 4)
5077 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5079 g_assert_not_reached ();
5080 } else if (ainfo->storage == ArgStructByVal) {
5082 int doffset = inst->inst_offset;
5084 g_assert (mips_is_imm16 (inst->inst_offset));
5085 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5086 /* Push the argument registers into their stack slots */
5087 for (i = 0; i < ainfo->size; ++i) {
5088 g_assert (mips_is_imm16(doffset));
5089 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5090 doffset += SIZEOF_REGISTER;
5092 } else if (ainfo->storage == ArgStructByAddr) {
5093 g_assert (mips_is_imm16 (inst->inst_offset));
5094 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5095 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5097 g_assert_not_reached ();
5102 if (method->save_lmf) {
5103 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5104 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5106 /* This can/will clobber the a0-a3 registers */
5107 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5109 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5110 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5111 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5112 /* new_lmf->previous_lmf = *lmf_addr */
5113 mips_lw (code, mips_at, mips_v0, 0);
5114 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5115 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5116 /* *(lmf_addr) = sp + lmf_offset */
5117 g_assert (mips_is_imm16(lmf_offset));
5118 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5119 mips_sw (code, mips_at, mips_v0, 0);
5121 /* save method info */
5122 mips_load_const (code, mips_at, method);
5123 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5124 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5126 /* save the current IP */
5127 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5128 mips_load_const (code, mips_at, 0x01010101);
5129 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5133 if (mips_is_imm16 (-alloc2_size)) {
5134 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5137 mips_load_const (code, mips_at, -alloc2_size);
5138 mips_addu (code, mips_sp, mips_sp, mips_at);
5140 alloc_size += alloc2_size;
5141 cfa_offset += alloc2_size;
5142 if (cfg->frame_reg != mips_sp)
5143 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5145 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5149 #if _MIPS_SIM == _ABIO32
5150 cfg->arch.tracing_offset = cfg->stack_offset;
5151 #elif _MIPS_SIM == _ABIN32
5152 /* no stack slots by default for argument regs, reserve a special block */
5153 g_assert_not_reached ();
5155 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5158 cfg->code_len = code - cfg->native_code;
5159 g_assert (cfg->code_len < cfg->code_size);
5173 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5176 int save_mode = SAVE_NONE;
5178 MonoMethod *method = cfg->method;
5179 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5180 int save_offset = MIPS_STACK_PARAM_OFFSET;
5182 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5184 offset = code - cfg->native_code;
5185 /* we need about 16 instructions */
5186 if (offset > (cfg->code_size - 16 * 4)) {
5187 cfg->code_size *= 2;
5188 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5189 code = cfg->native_code + offset;
5194 case MONO_TYPE_VOID:
5195 /* special case string .ctor icall */
5196 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5197 save_mode = SAVE_ONE;
5199 save_mode = SAVE_NONE;
5203 save_mode = SAVE_FP;
5205 case MONO_TYPE_VALUETYPE:
5206 save_mode = SAVE_STRUCT;
5210 #if SIZEOF_REGISTER == 4
5211 save_mode = SAVE_TWO;
5212 #elif SIZEOF_REGISTER == 8
5213 save_mode = SAVE_ONE;
5217 save_mode = SAVE_ONE;
5221 mips_addiu (code, mips_sp, mips_sp, -32);
5222 g_assert (mips_is_imm16(save_offset));
5223 switch (save_mode) {
5225 mips_sw (code, mips_v0, mips_sp, save_offset);
5226 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5227 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5228 if (enable_arguments) {
5229 MIPS_MOVE (code, mips_a1, mips_v0);
5230 MIPS_MOVE (code, mips_a2, mips_v1);
5234 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5235 if (enable_arguments) {
5236 MIPS_MOVE (code, mips_a1, mips_v0);
5240 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5241 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5242 mips_lw (code, mips_a0, mips_sp, save_offset);
5243 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5244 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5251 mips_load_const (code, mips_a0, cfg->method);
5252 mips_call (code, mips_t9, func);
5254 switch (save_mode) {
5256 mips_lw (code, mips_v0, mips_sp, save_offset);
5257 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5258 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5261 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5264 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5271 mips_addiu (code, mips_sp, mips_sp, 32);
5278 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5280 MonoMethod *method = cfg->method;
5282 int max_epilog_size = 16 + 20*4;
5283 int alloc2_size = 0;
5284 guint32 iregs_to_restore;
5286 guint32 fregs_to_restore;
5289 if (cfg->method->save_lmf)
5290 max_epilog_size += 128;
5292 if (mono_jit_trace_calls != NULL)
5293 max_epilog_size += 50;
5296 pos = code - cfg->native_code;
5297 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5298 cfg->code_size *= 2;
5299 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5300 cfg->stat_code_reallocs++;
5304 * Keep in sync with OP_JMP
5307 code = cfg->native_code + pos;
5309 code = cfg->native_code + cfg->code_len;
5311 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5312 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5314 if (cfg->frame_reg != mips_sp) {
5315 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5317 /* If the stack frame is really large, deconstruct it in two steps */
5318 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5319 alloc2_size = cfg->stack_usage - 1024;
5320 /* partially deconstruct the stack */
5321 mips_load_const (code, mips_at, alloc2_size);
5322 mips_addu (code, mips_sp, mips_sp, mips_at);
5324 pos = cfg->arch.iregs_offset - alloc2_size;
5325 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5326 if (iregs_to_restore) {
5327 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5328 if (iregs_to_restore & (1 << i)) {
5329 g_assert (mips_is_imm16(pos));
5330 MIPS_LW (code, i, mips_sp, pos);
5331 pos += SIZEOF_REGISTER;
5338 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5340 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5341 fregs_to_restore |= (fregs_to_restore << 1);
5343 if (fregs_to_restore) {
5344 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5345 if (fregs_to_restore & (1 << i)) {
5346 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5347 g_assert (mips_is_imm16(pos));
5348 mips_lwc1 (code, i, mips_sp, pos);
5355 /* Unlink the LMF if necessary */
5356 if (method->save_lmf) {
5357 int lmf_offset = cfg->arch.lmf_offset;
5359 /* t0 = current_lmf->previous_lmf */
5360 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5361 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5363 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5364 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5365 /* (*lmf_addr) = previous_lmf */
5366 mips_sw (code, mips_temp, mips_t1, 0);
5370 /* Restore the fp */
5371 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5374 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5375 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5376 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5378 /* Restore the stack pointer */
5379 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5380 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5382 /* Caller will emit either return or tail-call sequence */
5384 cfg->code_len = code - cfg->native_code;
5386 g_assert (cfg->code_len < cfg->code_size);
5391 mono_arch_emit_epilog (MonoCompile *cfg)
5395 code = mono_arch_emit_epilog_sub (cfg, NULL);
5397 mips_jr (code, mips_ra);
5400 cfg->code_len = code - cfg->native_code;
5402 g_assert (cfg->code_len < cfg->code_size);
5405 /* remove once throw_exception_by_name is eliminated */
5408 exception_id_by_name (const char *name)
5410 if (strcmp (name, "IndexOutOfRangeException") == 0)
5411 return MONO_EXC_INDEX_OUT_OF_RANGE;
5412 if (strcmp (name, "OverflowException") == 0)
5413 return MONO_EXC_OVERFLOW;
5414 if (strcmp (name, "ArithmeticException") == 0)
5415 return MONO_EXC_ARITHMETIC;
5416 if (strcmp (name, "DivideByZeroException") == 0)
5417 return MONO_EXC_DIVIDE_BY_ZERO;
5418 if (strcmp (name, "InvalidCastException") == 0)
5419 return MONO_EXC_INVALID_CAST;
5420 if (strcmp (name, "NullReferenceException") == 0)
5421 return MONO_EXC_NULL_REF;
5422 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5423 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5424 if (strcmp (name, "ArgumentException") == 0)
5425 return MONO_EXC_ARGUMENT;
5426 g_error ("Unknown intrinsic exception %s\n", name);
5432 mono_arch_emit_exceptions (MonoCompile *cfg)
5435 MonoJumpInfo *patch_info;
5438 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5439 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5440 int max_epilog_size = 50;
5442 /* count the number of exception infos */
5445 * make sure we have enough space for exceptions
5446 * 24 is the simulated call to throw_exception_by_name
5448 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5450 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5451 i = exception_id_by_name (patch_info->data.target);
5452 g_assert (i < MONO_EXC_INTRINS_NUM);
5453 if (!exc_throw_found [i]) {
5454 max_epilog_size += 12;
5455 exc_throw_found [i] = TRUE;
5461 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5462 cfg->code_size *= 2;
5463 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5464 cfg->stat_code_reallocs++;
5467 code = cfg->native_code + cfg->code_len;
5469 /* add code to raise exceptions */
5470 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5471 switch (patch_info->type) {
5472 case MONO_PATCH_INFO_EXC: {
5474 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5476 i = exception_id_by_name (patch_info->data.target);
5477 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5478 if (!exc_throw_pos [i]) {
5481 exc_throw_pos [i] = code;
5482 //g_print ("exc: writing stub at %p\n", code);
5483 mips_load_const (code, mips_a0, patch_info->data.target);
5484 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5485 mips_load_const (code, mips_t9, addr);
5486 mips_jr (code, mips_t9);
5489 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5491 /* Turn into a Relative patch, pointing at code stub */
5492 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5493 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5495 g_assert_not_reached();
5505 cfg->code_len = code - cfg->native_code;
5507 g_assert (cfg->code_len < cfg->code_size);
5512 mono_arch_finish_init (void)
5517 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5522 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5524 int this_dreg = mips_a0;
5527 this_dreg = mips_a1;
5529 /* add the this argument */
5530 if (this_reg != -1) {
5532 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5533 this_ins->type = this_type;
5534 this_ins->sreg1 = this_reg;
5535 this_ins->dreg = mono_alloc_ireg (cfg);
5536 mono_bblock_add_inst (cfg->cbb, this_ins);
5537 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5542 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5543 vtarg->type = STACK_MP;
5544 vtarg->sreg1 = vt_reg;
5545 vtarg->dreg = mono_alloc_ireg (cfg);
5546 mono_bblock_add_inst (cfg->cbb, vtarg);
5547 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5552 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5554 MonoInst *ins = NULL;
5560 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5566 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5568 return ctx->sc_regs [reg];
5571 #define ENABLE_WRONG_METHOD_CHECK 0
5573 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5574 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5576 #define LOADSTORE_SIZE 4
5577 #define JUMP_IMM_SIZE 16
5578 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5579 #define LOAD_CONST_SIZE 8
5580 #define JUMP_JR_SIZE 8
5583 * LOCKING: called with the domain lock held
5586 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5587 gpointer fail_tramp)
5591 guint8 *code, *start, *patch;
5593 for (i = 0; i < count; ++i) {
5594 MonoIMTCheckItem *item = imt_entries [i];
5596 if (item->is_equals) {
5597 if (item->check_target_idx) {
5598 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5599 if (item->has_target_code)
5600 item->chunk_size += LOAD_CONST_SIZE;
5602 item->chunk_size += LOADSTORE_SIZE;
5605 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5606 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5607 if (!item->has_target_code)
5608 item->chunk_size += LOADSTORE_SIZE;
5610 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5611 #if ENABLE_WRONG_METHOD_CHECK
5612 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5617 item->chunk_size += CMP_SIZE + BR_SIZE;
5618 imt_entries [item->check_target_idx]->compare_done = TRUE;
5620 size += item->chunk_size;
5622 /* the initial load of the vtable address */
5623 size += MIPS_LOAD_SEQUENCE_LENGTH;
5625 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5627 code = mono_domain_code_reserve (domain, size);
5631 /* t7 points to the vtable */
5632 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5634 for (i = 0; i < count; ++i) {
5635 MonoIMTCheckItem *item = imt_entries [i];
5637 item->code_target = code;
5638 if (item->is_equals) {
5639 if (item->check_target_idx) {
5640 mips_load_const (code, mips_temp, (gsize)item->key);
5641 item->jmp_code = code;
5642 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5644 if (item->has_target_code) {
5645 mips_load_const (code, mips_t9,
5646 item->value.target_code);
5649 mips_lw (code, mips_t9, mips_t7,
5650 (sizeof (gpointer) * item->value.vtable_slot));
5652 mips_jr (code, mips_t9);
5656 mips_load_const (code, mips_temp, (gsize)item->key);
5658 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5660 if (item->has_target_code) {
5661 mips_load_const (code, mips_t9,
5662 item->value.target_code);
5665 mips_load_const (code, mips_at,
5666 & (vtable->vtable [item->value.vtable_slot]));
5667 mips_lw (code, mips_t9, mips_at, 0);
5669 mips_jr (code, mips_t9);
5671 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5672 mips_load_const (code, mips_t9, fail_tramp);
5673 mips_jr (code, mips_t9);
5676 /* enable the commented code to assert on wrong method */
5677 #if ENABLE_WRONG_METHOD_CHECK
5678 ppc_load (code, ppc_r0, (guint32)item->key);
5679 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5681 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5683 mips_lw (code, mips_t9, mips_t7,
5684 (sizeof (gpointer) * item->value.vtable_slot));
5685 mips_jr (code, mips_t9);
5688 #if ENABLE_WRONG_METHOD_CHECK
5689 ppc_patch (patch, code);
5695 mips_load_const (code, mips_temp, (gulong)item->key);
5696 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5698 item->jmp_code = code;
5699 mips_beq (code, mips_temp, mips_zero, 0);
5703 /* patch the branches to get to the target items */
5704 for (i = 0; i < count; ++i) {
5705 MonoIMTCheckItem *item = imt_entries [i];
5706 if (item->jmp_code && item->check_target_idx) {
5707 mips_patch ((guint32 *)item->jmp_code,
5708 (guint32)imt_entries [item->check_target_idx]->code_target);
5713 UnlockedAdd (&mono_stats.imt_trampolines_size, code - start);
5714 g_assert (code - start <= size);
5715 mono_arch_flush_icache (start, size);
5717 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5723 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5725 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5729 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5731 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5734 /* Soft Debug support */
5735 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5738 * mono_arch_set_breakpoint:
5740 * See mini-amd64.c for docs.
5743 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5746 guint32 addr = (guint32)bp_trigger_page;
5748 mips_load_const (code, mips_t9, addr);
5749 mips_lw (code, mips_t9, mips_t9, 0);
5751 mono_arch_flush_icache (ip, code - ip);
5755 * mono_arch_clear_breakpoint:
5757 * See mini-amd64.c for docs.
5760 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5768 mono_arch_flush_icache (ip, code - ip);
5772 * mono_arch_start_single_stepping:
5774 * See mini-amd64.c for docs.
5777 mono_arch_start_single_stepping (void)
5779 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5783 * mono_arch_stop_single_stepping:
5785 * See mini-amd64.c for docs.
5788 mono_arch_stop_single_stepping (void)
5790 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5794 * mono_arch_is_single_step_event:
5796 * See mini-amd64.c for docs.
5799 mono_arch_is_single_step_event (void *info, void *sigctx)
5801 siginfo_t* sinfo = (siginfo_t*) info;
5802 /* Sometimes the address is off by 4 */
5803 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5810 * mono_arch_is_breakpoint_event:
5812 * See mini-amd64.c for docs.
5815 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5817 siginfo_t* sinfo = (siginfo_t*) info;
5818 /* Sometimes the address is off by 4 */
5819 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5826 * mono_arch_skip_breakpoint:
5828 * See mini-amd64.c for docs.
5831 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5833 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5837 * mono_arch_skip_single_step:
5839 * See mini-amd64.c for docs.
5842 mono_arch_skip_single_step (MonoContext *ctx)
5844 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5848 * mono_arch_get_seq_point_info:
5850 * See mini-amd64.c for docs.
5853 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5860 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5862 ext->lmf.previous_lmf = prev_lmf;
5863 /* Mark that this is a MonoLMFExt */
5864 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5865 ext->lmf.iregs [mips_sp] = (gssize)ext;
5868 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5871 mono_arch_opcode_supported (int opcode)