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>
25 #include <mono/arch/mips/mips-codegen.h>
27 #include "mini-mips.h"
32 #define SAVE_FP_REGS 0
34 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
36 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
37 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
38 remember to update cpu-mips.md if you change this */
40 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
41 #define mips_call(c,D,v) do { \
42 guint32 _target = (guint32)(v); \
43 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
44 mips_load_const (c, D, _target); \
45 mips_jalr (c, D, mips_ra); \
48 mips_jumpl (c, _target >> 2); \
60 /* This mutex protects architecture specific caches */
61 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
62 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
63 static mono_mutex_t mini_arch_mutex;
65 int mono_exc_esp_offset = 0;
67 /* Whenever the host is little-endian */
68 static int little_endian;
69 /* Index of ms word/register */
70 static int ls_word_idx;
71 /* Index of ls word/register */
72 static int ms_word_idx;
73 /* Same for offsets */
74 static int ls_word_offset;
75 static int ms_word_offset;
78 * The code generated for sequence points reads from this location, which is
79 * made read-only when single stepping is enabled.
81 static gpointer ss_trigger_page;
83 /* Enabled breakpoints read from this trigger page */
84 static gpointer bp_trigger_page;
87 #define DEBUG(a) if (cfg->verbose_level > 1) a
93 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
95 code = mips_emit_exc_by_name (code, exc_name); \
96 cfg->bb_exit->max_offset += 16; \
99 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
101 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
102 inst->type = STACK_R8; \
104 inst->inst_p0 = (void*)(addr); \
105 mono_bblock_add_inst (cfg->cbb, inst); \
108 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
109 || ((ins)->opcode == OP_ICOMPARE) \
110 || ((ins)->opcode == OP_LCOMPARE)))
111 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
112 || ((ins)->opcode == OP_ICOMPARE_IMM) \
113 || ((ins)->opcode == OP_LCOMPARE_IMM)))
115 #define INS_REWRITE(ins, op, _s1, _s2) do { \
118 ins->opcode = (op); \
123 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
125 ins->opcode = (op); \
127 ins->inst_imm = (_imm); \
131 typedef struct InstList InstList;
149 guint16 vtsize; /* in param area */
152 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
161 gboolean vtype_retaddr;
170 void patch_lui_addiu(guint32 *ip, guint32 val);
171 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
172 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
173 void mips_adjust_stackframe(MonoCompile *cfg);
174 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
175 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
178 /* Not defined in asm/cachectl.h */
179 int cacheflush(char *addr, int nbytes, int cache);
182 mono_arch_flush_icache (guint8 *code, gint size)
184 /* Linux/MIPS specific */
185 cacheflush ((char*)code, size, BCACHE);
189 mono_arch_flush_register_windows (void)
194 mono_arch_is_inst_imm (gint64 imm)
200 mips_emit_exc_by_name(guint8 *code, const char *name)
203 MonoClass *exc_class;
205 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", name);
207 mips_load_const (code, mips_a0, exc_class->type_token);
208 addr = mono_get_throw_corlib_exception ();
209 mips_call (code, mips_t9, addr);
215 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
217 if (mips_is_imm16 (v))
218 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
220 #if SIZEOF_REGISTER == 8
222 /* v is not a sign-extended 32-bit value */
223 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
224 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
225 mips_dsll (code, dreg, dreg, 16);
226 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
227 mips_dsll (code, dreg, dreg, 16);
228 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
232 if (((guint32)v) & (1 << 15)) {
233 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
236 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
238 if (((guint32)v) & 0xffff)
239 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
245 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
248 if (cfg->arch.long_branch) {
251 /* Invert test and emit branch around jump */
254 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
258 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
262 mips_bltz (code, ins->sreg1, br_offset);
266 mips_blez (code, ins->sreg1, br_offset);
270 mips_bgtz (code, ins->sreg1, br_offset);
274 mips_bgez (code, ins->sreg1, br_offset);
278 g_assert_not_reached ();
280 mono_add_patch_info (cfg, code - cfg->native_code,
281 MONO_PATCH_INFO_BB, ins->inst_true_bb);
282 mips_lui (code, mips_at, mips_zero, 0);
283 mips_addiu (code, mips_at, mips_at, 0);
284 mips_jr (code, mips_at);
288 mono_add_patch_info (cfg, code - cfg->native_code,
289 MONO_PATCH_INFO_BB, ins->inst_true_bb);
292 mips_beq (code, ins->sreg1, ins->sreg2, 0);
296 mips_bne (code, ins->sreg1, ins->sreg2, 0);
300 mips_bgez (code, ins->sreg1, 0);
304 mips_bgtz (code, ins->sreg1, 0);
308 mips_blez (code, ins->sreg1, 0);
312 mips_bltz (code, ins->sreg1, 0);
316 g_assert_not_reached ();
322 /* XXX - big-endian dependent? */
324 patch_lui_addiu(guint32 *ip, guint32 val)
326 guint16 *__lui_addiu = (guint16*)(void *)(ip);
329 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
330 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
333 if (((guint32)(val)) & (1 << 15))
334 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
336 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
337 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
338 mono_arch_flush_icache ((guint8 *)ip, 8);
343 mips_patch (guint32 *code, guint32 target)
346 guint32 op = ins >> 26;
347 guint32 diff, offset;
349 g_assert (trap_target != target);
350 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
352 case 0x00: /* jr ra */
353 if (ins == 0x3e00008)
355 g_assert_not_reached ();
359 g_assert (!(target & 0x03));
360 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
361 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
363 mono_arch_flush_icache ((guint8 *)code, 4);
365 case 0x01: /* BLTZ */
368 case 0x06: /* BLEZ */
369 case 0x07: /* BGTZ */
370 case 0x11: /* bc1t */
371 diff = target - (guint32)(code + 1);
372 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
373 g_assert (!(diff & 0x03));
374 offset = ((gint32)diff) >> 2;
375 if (((int)offset) != ((int)(short)offset))
376 g_assert (((int)offset) == ((int)(short)offset));
377 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
379 mono_arch_flush_icache ((guint8 *)code, 4);
381 case 0x0f: /* LUI / ADDIU pair */
382 g_assert ((code[1] >> 26) == 0x9);
383 patch_lui_addiu (code, target);
384 mono_arch_flush_icache ((guint8 *)code, 8);
388 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
389 g_assert_not_reached ();
393 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
396 mono_arch_regname (int reg) {
397 #if _MIPS_SIM == _ABIO32
398 static const char * rnames[] = {
399 "zero", "at", "v0", "v1",
400 "a0", "a1", "a2", "a3",
401 "t0", "t1", "t2", "t3",
402 "t4", "t5", "t6", "t7",
403 "s0", "s1", "s2", "s3",
404 "s4", "s5", "s6", "s7",
405 "t8", "t9", "k0", "k1",
406 "gp", "sp", "fp", "ra"
408 #elif _MIPS_SIM == _ABIN32
409 static const char * rnames[] = {
410 "zero", "at", "v0", "v1",
411 "a0", "a1", "a2", "a3",
412 "a4", "a5", "a6", "a7",
413 "t0", "t1", "t2", "t3",
414 "s0", "s1", "s2", "s3",
415 "s4", "s5", "s6", "s7",
416 "t8", "t9", "k0", "k1",
417 "gp", "sp", "fp", "ra"
420 if (reg >= 0 && reg < 32)
426 mono_arch_fregname (int reg) {
427 static const char * rnames[] = {
428 "f0", "f1", "f2", "f3",
429 "f4", "f5", "f6", "f7",
430 "f8", "f9", "f10", "f11",
431 "f12", "f13", "f14", "f15",
432 "f16", "f17", "f18", "f19",
433 "f20", "f21", "f22", "f23",
434 "f24", "f25", "f26", "f27",
435 "f28", "f29", "f30", "f31"
437 if (reg >= 0 && reg < 32)
442 /* this function overwrites at */
444 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
446 /* XXX write a loop, not an unrolled loop */
448 mips_lw (code, mips_at, sreg, soffset);
449 mips_sw (code, mips_at, dreg, doffset);
458 * mono_arch_get_argument_info:
459 * @csig: a method signature
460 * @param_count: the number of parameters to consider
461 * @arg_info: an array to store the result infos
463 * Gathers information on parameters such as size, alignment and
464 * padding. arg_info should be large enought to hold param_count + 1 entries.
466 * Returns the size of the activation frame.
469 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
471 int k, frame_size = 0;
472 guint32 size, align, pad;
475 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
476 frame_size += sizeof (gpointer);
480 arg_info [0].offset = offset;
483 frame_size += sizeof (gpointer);
487 arg_info [0].size = frame_size;
489 for (k = 0; k < param_count; k++) {
490 size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
492 /* ignore alignment for now */
495 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
496 arg_info [k].pad = pad;
498 arg_info [k + 1].pad = 0;
499 arg_info [k + 1].size = size;
501 arg_info [k + 1].offset = offset;
505 align = MONO_ARCH_FRAME_ALIGNMENT;
506 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
507 arg_info [k].pad = pad;
512 /* The delegate object plus 3 params */
513 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
516 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
518 guint8 *code, *start;
521 start = code = mono_global_codeman_reserve (16);
523 /* Replace the this argument with the target */
524 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
525 mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
526 mips_jr (code, mips_temp);
529 g_assert ((code - start) <= 16);
531 mono_arch_flush_icache (start, 16);
535 size = 16 + param_count * 4;
536 start = code = mono_global_codeman_reserve (size);
538 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
539 /* slide down the arguments */
540 for (i = 0; i < param_count; ++i) {
541 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
543 mips_jr (code, mips_temp);
546 g_assert ((code - start) <= size);
548 mono_arch_flush_icache (start, size);
552 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
554 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
555 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
563 * mono_arch_get_delegate_invoke_impls:
565 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
569 mono_arch_get_delegate_invoke_impls (void)
575 get_delegate_invoke_impl (&info, TRUE, 0);
576 res = g_slist_prepend (res, info);
578 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
579 get_delegate_invoke_impl (&info, FALSE, i);
580 res = g_slist_prepend (res, info);
587 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
589 guint8 *code, *start;
591 /* FIXME: Support more cases */
592 if (MONO_TYPE_ISSTRUCT (sig->ret))
596 static guint8* cached = NULL;
597 mono_mini_arch_lock ();
599 mono_mini_arch_unlock ();
604 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
607 start = get_delegate_invoke_impl (&info, TRUE, 0);
608 mono_tramp_info_register (info, NULL);
611 mono_mini_arch_unlock ();
614 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
617 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
619 for (i = 0; i < sig->param_count; ++i)
620 if (!mono_is_regsize_var (sig->params [i]))
623 mono_mini_arch_lock ();
624 code = cache [sig->param_count];
626 mono_mini_arch_unlock ();
631 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
632 start = mono_aot_get_trampoline (name);
636 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
637 mono_tramp_info_register (info, NULL);
639 cache [sig->param_count] = start;
640 mono_mini_arch_unlock ();
648 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
654 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
657 return (gpointer)regs [mips_a0];
661 * Initialize the cpu to execute managed code.
664 mono_arch_cpu_init (void)
666 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
675 ls_word_offset = ls_word_idx * 4;
676 ms_word_offset = ms_word_idx * 4;
680 * Initialize architecture specific code.
683 mono_arch_init (void)
685 mono_os_mutex_init_recursive (&mini_arch_mutex);
687 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
688 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
689 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
693 * Cleanup architecture specific code.
696 mono_arch_cleanup (void)
698 mono_os_mutex_destroy (&mini_arch_mutex);
702 mono_arch_have_fast_tls (void)
708 * This function returns the optimizations supported on this cpu.
711 mono_arch_cpu_optimizations (guint32 *exclude_mask)
715 /* no mips-specific optimizations yet */
721 * This function test for all SIMD functions supported.
723 * Returns a bitmask corresponding to all supported versions.
727 mono_arch_cpu_enumerate_simd_versions (void)
729 /* SIMD is currently unimplemented */
734 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
739 for (i = 0; i < cfg->num_varinfo; i++) {
740 MonoInst *ins = cfg->varinfo [i];
741 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
744 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
747 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
750 /* we can only allocate 32 bit values */
751 if (mono_is_regsize_var (ins->inst_vtype)) {
752 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
753 g_assert (i == vmv->idx);
754 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
762 mono_arch_get_global_int_regs (MonoCompile *cfg)
766 regs = g_list_prepend (regs, (gpointer)mips_s0);
767 regs = g_list_prepend (regs, (gpointer)mips_s1);
768 regs = g_list_prepend (regs, (gpointer)mips_s2);
769 regs = g_list_prepend (regs, (gpointer)mips_s3);
770 regs = g_list_prepend (regs, (gpointer)mips_s4);
771 //regs = g_list_prepend (regs, (gpointer)mips_s5);
772 regs = g_list_prepend (regs, (gpointer)mips_s6);
773 regs = g_list_prepend (regs, (gpointer)mips_s7);
779 * mono_arch_regalloc_cost:
781 * Return the cost, in number of memory references, of the action of
782 * allocating the variable VMV into a register during global register
786 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
793 args_onto_stack (CallInfo *info)
795 g_assert (!info->on_stack);
796 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
797 info->on_stack = TRUE;
798 info->stack_size = MIPS_STACK_PARAM_OFFSET;
801 #if _MIPS_SIM == _ABIO32
803 * O32 calling convention version
807 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
808 /* First, see if we need to drop onto the stack */
809 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
810 args_onto_stack (info);
812 /* Now, place the argument */
813 if (info->on_stack) {
814 ainfo->storage = ArgOnStack;
815 ainfo->reg = mips_sp; /* in the caller */
816 ainfo->offset = info->stack_size;
819 ainfo->storage = ArgInIReg;
820 ainfo->reg = info->gr;
822 info->gr_passed = TRUE;
824 info->stack_size += 4;
828 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
829 /* First, see if we need to drop onto the stack */
830 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
831 args_onto_stack (info);
833 /* Now, place the argument */
834 if (info->on_stack) {
835 g_assert (info->stack_size % 4 == 0);
836 info->stack_size += (info->stack_size % 8);
838 ainfo->storage = ArgOnStack;
839 ainfo->reg = mips_sp; /* in the caller */
840 ainfo->offset = info->stack_size;
843 // info->gr must be a0 or a2
844 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
845 g_assert(info->gr <= MIPS_LAST_ARG_REG);
847 ainfo->storage = ArgInIReg;
848 ainfo->reg = info->gr;
850 info->gr_passed = TRUE;
852 info->stack_size += 8;
856 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
857 /* First, see if we need to drop onto the stack */
858 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
859 args_onto_stack (info);
861 /* Now, place the argument */
862 if (info->on_stack) {
863 ainfo->storage = ArgOnStack;
864 ainfo->reg = mips_sp; /* in the caller */
865 ainfo->offset = info->stack_size;
868 /* Only use FP regs for args if no int args passed yet */
869 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
870 ainfo->storage = ArgInFReg;
871 ainfo->reg = info->fr;
872 /* Even though it's a single-precision float, it takes up two FP regs */
874 /* FP and GP slots do not overlap */
878 /* Passing single-precision float arg in a GP register
879 * such as: func (0, 1.0, 2, 3);
880 * In this case, only one 'gr' register is consumed.
882 ainfo->storage = ArgInIReg;
883 ainfo->reg = info->gr;
886 info->gr_passed = TRUE;
889 info->stack_size += 4;
893 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
894 /* First, see if we need to drop onto the stack */
895 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
896 args_onto_stack (info);
898 /* Now, place the argument */
899 if (info->on_stack) {
900 g_assert(info->stack_size % 4 == 0);
901 info->stack_size += (info->stack_size % 8);
903 ainfo->storage = ArgOnStack;
904 ainfo->reg = mips_sp; /* in the caller */
905 ainfo->offset = info->stack_size;
908 /* Only use FP regs for args if no int args passed yet */
909 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
910 ainfo->storage = ArgInFReg;
911 ainfo->reg = info->fr;
913 /* FP and GP slots do not overlap */
917 // info->gr must be a0 or a2
918 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
919 g_assert(info->gr <= MIPS_LAST_ARG_REG);
921 ainfo->storage = ArgInIReg;
922 ainfo->reg = info->gr;
924 info->gr_passed = TRUE;
927 info->stack_size += 8;
929 #elif _MIPS_SIM == _ABIN32
931 * N32 calling convention version
935 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
936 /* First, see if we need to drop onto the stack */
937 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
938 args_onto_stack (info);
940 /* Now, place the argument */
941 if (info->on_stack) {
942 ainfo->storage = ArgOnStack;
943 ainfo->reg = mips_sp; /* in the caller */
944 ainfo->offset = info->stack_size;
945 info->stack_size += SIZEOF_REGISTER;
948 ainfo->storage = ArgInIReg;
949 ainfo->reg = info->gr;
951 info->gr_passed = TRUE;
956 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
957 /* First, see if we need to drop onto the stack */
958 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
959 args_onto_stack (info);
961 /* Now, place the argument */
962 if (info->on_stack) {
963 g_assert (info->stack_size % 4 == 0);
964 info->stack_size += (info->stack_size % 8);
966 ainfo->storage = ArgOnStack;
967 ainfo->reg = mips_sp; /* in the caller */
968 ainfo->offset = info->stack_size;
969 info->stack_size += SIZEOF_REGISTER;
972 g_assert (info->gr <= MIPS_LAST_ARG_REG);
974 ainfo->storage = ArgInIReg;
975 ainfo->reg = info->gr;
977 info->gr_passed = TRUE;
982 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
983 /* First, see if we need to drop onto the stack */
984 if (!info->on_stack) {
985 if (info->gr > MIPS_LAST_ARG_REG)
986 args_onto_stack (info);
987 else if (info->fr > MIPS_LAST_FPARG_REG)
988 args_onto_stack (info);
991 /* Now, place the argument */
992 if (info->on_stack) {
993 ainfo->storage = ArgOnStack;
994 ainfo->reg = mips_sp; /* in the caller */
995 ainfo->offset = info->stack_size;
996 info->stack_size += FREG_SIZE;
999 ainfo->storage = ArgInFReg;
1000 ainfo->reg = info->fr;
1002 /* FP and GP slots do not overlap */
1008 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1009 /* First, see if we need to drop onto the stack */
1010 if (!info->on_stack) {
1011 if (info->gr > MIPS_LAST_ARG_REG)
1012 args_onto_stack (info);
1013 else if (info->fr > MIPS_LAST_FPARG_REG)
1014 args_onto_stack (info);
1017 /* Now, place the argument */
1018 if (info->on_stack) {
1019 g_assert(info->stack_size % 4 == 0);
1020 info->stack_size += (info->stack_size % 8);
1022 ainfo->storage = ArgOnStack;
1023 ainfo->reg = mips_sp; /* in the caller */
1024 ainfo->offset = info->stack_size;
1025 info->stack_size += FREG_SIZE;
1028 ainfo->storage = ArgInFReg;
1029 ainfo->reg = info->fr;
1031 /* FP and GP slots do not overlap */
1038 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1041 int n = sig->hasthis + sig->param_count;
1043 MonoType* simpletype;
1045 gboolean is_pinvoke = sig->pinvoke;
1048 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1050 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1052 cinfo->fr = MIPS_FIRST_FPARG_REG;
1053 cinfo->gr = MIPS_FIRST_ARG_REG;
1054 cinfo->stack_size = 0;
1056 DEBUG(printf("calculate_sizes\n"));
1058 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1062 /* handle returning a struct */
1063 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1064 cinfo->struct_ret = cinfo->gr;
1065 add_int32_arg (cinfo, &cinfo->ret);
1069 add_int32_arg (cinfo, cinfo->args + n);
1074 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1075 * the first argument, allowing 'this' to be always passed in the first arg reg.
1076 * Also do this if the first argument is a reference type, since virtual calls
1077 * are sometimes made using calli without sig->hasthis set, like in the delegate
1080 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1082 add_int32_arg (cinfo, cinfo->args + n);
1085 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1089 add_int32_arg (cinfo, &cinfo->ret);
1090 cinfo->struct_ret = cinfo->ret.reg;
1094 add_int32_arg (cinfo, cinfo->args + n);
1098 if (cinfo->vtype_retaddr) {
1099 add_int32_arg (cinfo, &cinfo->ret);
1100 cinfo->struct_ret = cinfo->ret.reg;
1105 DEBUG(printf("params: %d\n", sig->param_count));
1106 for (i = pstart; i < sig->param_count; ++i) {
1107 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1108 /* Prevent implicit arguments and sig_cookie from
1109 being passed in registers */
1110 args_onto_stack (cinfo);
1111 /* Emit the signature cookie just before the implicit arguments */
1112 add_int32_arg (cinfo, &cinfo->sig_cookie);
1114 DEBUG(printf("param %d: ", i));
1115 simpletype = mini_get_underlying_type (sig->params [i]);
1116 switch (simpletype->type) {
1119 DEBUG(printf("1 byte\n"));
1120 cinfo->args [n].size = 1;
1121 add_int32_arg (cinfo, &cinfo->args[n]);
1126 DEBUG(printf("2 bytes\n"));
1127 cinfo->args [n].size = 2;
1128 add_int32_arg (cinfo, &cinfo->args[n]);
1133 DEBUG(printf("4 bytes\n"));
1134 cinfo->args [n].size = 4;
1135 add_int32_arg (cinfo, &cinfo->args[n]);
1141 case MONO_TYPE_FNPTR:
1142 case MONO_TYPE_OBJECT:
1143 cinfo->args [n].size = sizeof (gpointer);
1144 add_int32_arg (cinfo, &cinfo->args[n]);
1147 case MONO_TYPE_GENERICINST:
1148 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1149 cinfo->args [n].size = sizeof (gpointer);
1150 add_int32_arg (cinfo, &cinfo->args[n]);
1155 case MONO_TYPE_TYPEDBYREF:
1156 case MONO_TYPE_VALUETYPE: {
1159 int has_offset = FALSE;
1161 gint size, alignment;
1164 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1165 size = sizeof (MonoTypedRef);
1166 alignment = sizeof (gpointer);
1168 klass = mono_class_from_mono_type (sig->params [i]);
1170 size = mono_class_native_size (klass, NULL);
1172 size = mono_class_value_size (klass, NULL);
1173 alignment = mono_class_min_align (klass);
1175 #if MIPS_PASS_STRUCTS_BY_VALUE
1176 /* Need to do alignment if struct contains long or double */
1177 if (alignment > 4) {
1178 /* Drop onto stack *before* looking at
1179 stack_size, if required. */
1180 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1181 args_onto_stack (cinfo);
1182 if (cinfo->stack_size & (alignment - 1)) {
1183 add_int32_arg (cinfo, &dummy_arg);
1185 g_assert (!(cinfo->stack_size & (alignment - 1)));
1189 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1190 mono_class_native_size (sig->params [i]->data.klass, NULL),
1191 cinfo->stack_size, alignment);
1193 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1194 g_assert (cinfo->args [n].size == 0);
1195 g_assert (cinfo->args [n].vtsize == 0);
1196 for (j = 0; j < nwords; ++j) {
1198 add_int32_arg (cinfo, &cinfo->args [n]);
1199 if (cinfo->on_stack)
1202 add_int32_arg (cinfo, &dummy_arg);
1203 if (!has_offset && cinfo->on_stack) {
1204 cinfo->args [n].offset = dummy_arg.offset;
1208 if (cinfo->on_stack)
1209 cinfo->args [n].vtsize += 1;
1211 cinfo->args [n].size += 1;
1213 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1214 cinfo->args [n].storage = ArgStructByVal;
1216 add_int32_arg (cinfo, &cinfo->args[n]);
1217 cinfo->args [n].storage = ArgStructByAddr;
1224 DEBUG(printf("8 bytes\n"));
1225 cinfo->args [n].size = 8;
1226 add_int64_arg (cinfo, &cinfo->args[n]);
1230 DEBUG(printf("R4\n"));
1231 cinfo->args [n].size = 4;
1232 add_float32_arg (cinfo, &cinfo->args[n]);
1236 DEBUG(printf("R8\n"));
1237 cinfo->args [n].size = 8;
1238 add_float64_arg (cinfo, &cinfo->args[n]);
1242 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1246 /* Handle the case where there are no implicit arguments */
1247 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1248 /* Prevent implicit arguments and sig_cookie from
1249 being passed in registers */
1250 args_onto_stack (cinfo);
1251 /* Emit the signature cookie just before the implicit arguments */
1252 add_int32_arg (cinfo, &cinfo->sig_cookie);
1256 simpletype = mini_get_underlying_type (sig->ret);
1257 switch (simpletype->type) {
1267 case MONO_TYPE_FNPTR:
1268 case MONO_TYPE_OBJECT:
1269 cinfo->ret.reg = mips_v0;
1273 cinfo->ret.reg = mips_v0;
1277 cinfo->ret.reg = mips_f0;
1278 cinfo->ret.storage = ArgInFReg;
1280 case MONO_TYPE_GENERICINST:
1281 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1282 cinfo->ret.reg = mips_v0;
1286 case MONO_TYPE_VALUETYPE:
1287 case MONO_TYPE_TYPEDBYREF:
1289 case MONO_TYPE_VOID:
1292 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1296 /* align stack size to 16 */
1297 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1299 cinfo->stack_usage = cinfo->stack_size;
1304 debug_omit_fp (void)
1307 return mono_debug_count ();
1314 * mono_arch_compute_omit_fp:
1315 * Determine whether the frame pointer can be eliminated.
1318 mono_arch_compute_omit_fp (MonoCompile *cfg)
1320 MonoMethodSignature *sig;
1321 MonoMethodHeader *header;
1325 if (cfg->arch.omit_fp_computed)
1328 header = cfg->header;
1330 sig = mono_method_signature (cfg->method);
1332 if (!cfg->arch.cinfo)
1333 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1334 cinfo = cfg->arch.cinfo;
1337 * FIXME: Remove some of the restrictions.
1339 cfg->arch.omit_fp = TRUE;
1340 cfg->arch.omit_fp_computed = TRUE;
1342 if (cfg->disable_omit_fp)
1343 cfg->arch.omit_fp = FALSE;
1344 if (!debug_omit_fp ())
1345 cfg->arch.omit_fp = FALSE;
1346 if (cfg->method->save_lmf)
1347 cfg->arch.omit_fp = FALSE;
1348 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1349 cfg->arch.omit_fp = FALSE;
1350 if (header->num_clauses)
1351 cfg->arch.omit_fp = FALSE;
1352 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1353 cfg->arch.omit_fp = FALSE;
1354 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)))
1355 cfg->arch.omit_fp = FALSE;
1357 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1358 * there are stack arguments.
1361 if (cinfo->stack_usage)
1362 cfg->arch.omit_fp = FALSE;
1366 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1367 MonoInst *ins = cfg->varinfo [i];
1370 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1373 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1377 * Set var information according to the calling convention. mips version.
1378 * The locals var stuff should most likely be split in another method.
1381 mono_arch_allocate_vars (MonoCompile *cfg)
1383 MonoMethodSignature *sig;
1384 MonoMethodHeader *header;
1386 int i, offset, size, align, curinst;
1387 int frame_reg = mips_sp;
1388 guint32 iregs_to_save = 0;
1390 guint32 fregs_to_restore;
1394 sig = mono_method_signature (cfg->method);
1396 if (!cfg->arch.cinfo)
1397 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1398 cinfo = cfg->arch.cinfo;
1400 mono_arch_compute_omit_fp (cfg);
1402 /* spill down, we'll fix it in a separate pass */
1403 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1405 /* allow room for the vararg method args: void* and long/double */
1406 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1407 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1409 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1410 * call convs needs to be handled this way.
1412 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1413 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1415 /* gtk-sharp and other broken code will dllimport vararg functions even with
1416 * non-varargs signatures. Since there is little hope people will get this right
1417 * we assume they won't.
1419 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1420 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1422 /* a0-a3 always present */
1423 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1425 header = cfg->header;
1427 if (cfg->arch.omit_fp)
1428 frame_reg = mips_sp;
1430 frame_reg = mips_fp;
1431 cfg->frame_reg = frame_reg;
1432 if (frame_reg != mips_sp) {
1433 cfg->used_int_regs |= 1 << frame_reg;
1438 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1439 /* FIXME: handle long and FP values */
1440 switch (mini_get_underlying_type (sig->ret)->type) {
1441 case MONO_TYPE_VOID:
1445 cfg->ret->opcode = OP_REGVAR;
1446 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1449 cfg->ret->opcode = OP_REGVAR;
1450 cfg->ret->inst_c0 = mips_v0;
1454 /* Space for outgoing parameters, including a0-a3 */
1455 offset += cfg->param_area;
1457 /* allow room to save the return value (if it's a struct) */
1458 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1461 /* Now handle the local variables */
1463 curinst = cfg->locals_start;
1464 for (i = curinst; i < cfg->num_varinfo; ++i) {
1465 inst = cfg->varinfo [i];
1466 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1469 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1470 * pinvoke wrappers when they call functions returning structure
1472 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1473 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1475 size = mono_type_size (inst->inst_vtype, &align);
1477 offset += align - 1;
1478 offset &= ~(align - 1);
1479 inst->inst_offset = offset;
1480 inst->opcode = OP_REGOFFSET;
1481 inst->inst_basereg = frame_reg;
1483 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1486 /* Space for LMF (if needed) */
1487 if (cfg->method->save_lmf) {
1488 /* align the offset to 16 bytes */
1489 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1490 cfg->arch.lmf_offset = offset;
1491 offset += sizeof (MonoLMF);
1494 if (sig->call_convention == MONO_CALL_VARARG) {
1498 /* Allocate a local slot to hold the sig cookie address */
1499 offset += align - 1;
1500 offset &= ~(align - 1);
1501 cfg->sig_cookie = offset;
1505 offset += SIZEOF_REGISTER - 1;
1506 offset &= ~(SIZEOF_REGISTER - 1);
1508 /* Space for saved registers */
1509 cfg->arch.iregs_offset = offset;
1510 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1511 if (iregs_to_save) {
1512 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1513 if (iregs_to_save & (1 << i)) {
1514 offset += SIZEOF_REGISTER;
1519 /* saved float registers */
1521 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1522 if (fregs_to_restore) {
1523 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1524 if (fregs_to_restore & (1 << i)) {
1525 offset += sizeof(double);
1531 #if _MIPS_SIM == _ABIO32
1532 /* Now add space for saving the ra */
1533 offset += SIZEOF_VOID_P;
1536 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1537 cfg->stack_offset = offset;
1538 cfg->arch.local_alloc_offset = cfg->stack_offset;
1542 * Now allocate stack slots for the int arg regs (a0 - a3)
1543 * On MIPS o32, these are just above the incoming stack pointer
1544 * Even if the arg has been assigned to a regvar, it gets a stack slot
1547 /* Return struct-by-value results in a hidden first argument */
1548 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1549 cfg->vret_addr->opcode = OP_REGOFFSET;
1550 cfg->vret_addr->inst_c0 = mips_a0;
1551 cfg->vret_addr->inst_offset = offset;
1552 cfg->vret_addr->inst_basereg = frame_reg;
1553 offset += SIZEOF_REGISTER;
1556 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1557 inst = cfg->args [i];
1558 if (inst->opcode != OP_REGVAR) {
1561 if (sig->hasthis && (i == 0))
1562 arg_type = &mono_defaults.object_class->byval_arg;
1564 arg_type = sig->params [i - sig->hasthis];
1566 inst->opcode = OP_REGOFFSET;
1567 size = mono_type_size (arg_type, &align);
1569 if (size < SIZEOF_REGISTER) {
1570 size = SIZEOF_REGISTER;
1571 align = SIZEOF_REGISTER;
1573 inst->inst_basereg = frame_reg;
1574 offset = (offset + align - 1) & ~(align - 1);
1575 inst->inst_offset = offset;
1577 if (cfg->verbose_level > 1)
1578 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1581 #if _MIPS_SIM == _ABIO32
1582 /* o32: Even a0-a3 get stack slots */
1583 size = SIZEOF_REGISTER;
1584 align = SIZEOF_REGISTER;
1585 inst->inst_basereg = frame_reg;
1586 offset = (offset + align - 1) & ~(align - 1);
1587 inst->inst_offset = offset;
1589 if (cfg->verbose_level > 1)
1590 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1594 #if _MIPS_SIM == _ABIN32
1595 /* Now add space for saving the ra */
1596 offset += SIZEOF_VOID_P;
1599 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1600 cfg->stack_offset = offset;
1601 cfg->arch.local_alloc_offset = cfg->stack_offset;
1606 mono_arch_create_vars (MonoCompile *cfg)
1608 MonoMethodSignature *sig;
1610 sig = mono_method_signature (cfg->method);
1612 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1613 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1614 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1615 printf ("vret_addr = ");
1616 mono_print_ins (cfg->vret_addr);
1621 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1622 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1626 * take the arguments and generate the arch-specific
1627 * instructions to properly call the function in call.
1628 * This includes pushing, moving arguments to the right register
1630 * Issue: who does the spilling if needed, and when?
1633 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1635 MonoMethodSignature *tmp_sig;
1638 if (call->tail_call)
1641 /* FIXME: Add support for signature tokens to AOT */
1642 cfg->disable_aot = TRUE;
1645 * mono_ArgIterator_Setup assumes the signature cookie is
1646 * passed first and all the arguments which were before it are
1647 * passed on the stack after the signature. So compensate by
1648 * passing a different signature.
1650 tmp_sig = mono_metadata_signature_dup (call->signature);
1651 tmp_sig->param_count -= call->signature->sentinelpos;
1652 tmp_sig->sentinelpos = 0;
1653 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1655 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1656 sig_arg->dreg = mono_alloc_ireg (cfg);
1657 sig_arg->inst_p0 = tmp_sig;
1658 MONO_ADD_INS (cfg->cbb, sig_arg);
1660 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1664 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1667 MonoMethodSignature *sig;
1672 sig = call->signature;
1673 n = sig->param_count + sig->hasthis;
1675 cinfo = get_call_info (cfg->mempool, sig);
1676 if (cinfo->struct_ret)
1677 call->used_iregs |= 1 << cinfo->struct_ret;
1679 for (i = 0; i < n; ++i) {
1680 ArgInfo *ainfo = cinfo->args + i;
1683 if (i >= sig->hasthis)
1684 t = sig->params [i - sig->hasthis];
1686 t = &mono_defaults.int_class->byval_arg;
1687 t = mini_get_underlying_type (t);
1689 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1690 /* Emit the signature cookie just before the implicit arguments */
1691 emit_sig_cookie (cfg, call, cinfo);
1694 if (is_virtual && i == 0) {
1695 /* the argument will be attached to the call instrucion */
1696 in = call->args [i];
1697 call->used_iregs |= 1 << ainfo->reg;
1700 in = call->args [i];
1701 if (ainfo->storage == ArgInIReg) {
1702 #if SIZEOF_REGISTER == 4
1703 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1704 MONO_INST_NEW (cfg, ins, OP_MOVE);
1705 ins->dreg = mono_alloc_ireg (cfg);
1706 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1707 MONO_ADD_INS (cfg->cbb, ins);
1708 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1710 MONO_INST_NEW (cfg, ins, OP_MOVE);
1711 ins->dreg = mono_alloc_ireg (cfg);
1712 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1713 MONO_ADD_INS (cfg->cbb, ins);
1714 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1717 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1720 #if PROMOTE_R4_TO_R8
1721 /* ??? - convert to single first? */
1722 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1723 ins->dreg = mono_alloc_freg (cfg);
1724 ins->sreg1 = in->dreg;
1725 MONO_ADD_INS (cfg->cbb, ins);
1730 /* trying to load float value into int registers */
1731 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1732 ins->dreg = mono_alloc_ireg (cfg);
1734 MONO_ADD_INS (cfg->cbb, ins);
1735 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1736 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1737 /* trying to load float value into int registers */
1738 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1739 ins->dreg = mono_alloc_ireg (cfg);
1740 ins->sreg1 = in->dreg;
1741 MONO_ADD_INS (cfg->cbb, ins);
1742 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1744 MONO_INST_NEW (cfg, ins, OP_MOVE);
1745 ins->dreg = mono_alloc_ireg (cfg);
1746 ins->sreg1 = in->dreg;
1747 MONO_ADD_INS (cfg->cbb, ins);
1748 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1750 } else if (ainfo->storage == ArgStructByAddr) {
1751 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1752 ins->opcode = OP_OUTARG_VT;
1753 ins->sreg1 = in->dreg;
1754 ins->klass = in->klass;
1755 ins->inst_p0 = call;
1756 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1757 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1758 MONO_ADD_INS (cfg->cbb, ins);
1759 } else if (ainfo->storage == ArgStructByVal) {
1760 /* this is further handled in mono_arch_emit_outarg_vt () */
1761 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1762 ins->opcode = OP_OUTARG_VT;
1763 ins->sreg1 = in->dreg;
1764 ins->klass = in->klass;
1765 ins->inst_p0 = call;
1766 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1767 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1768 MONO_ADD_INS (cfg->cbb, ins);
1769 } else if (ainfo->storage == ArgOnStack) {
1770 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1771 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1772 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1773 if (t->type == MONO_TYPE_R8)
1774 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1776 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1778 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1780 } else if (ainfo->storage == ArgInFReg) {
1781 if (t->type == MONO_TYPE_VALUETYPE) {
1782 /* this is further handled in mono_arch_emit_outarg_vt () */
1783 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1784 ins->opcode = OP_OUTARG_VT;
1785 ins->sreg1 = in->dreg;
1786 ins->klass = in->klass;
1787 ins->inst_p0 = call;
1788 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1789 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1790 MONO_ADD_INS (cfg->cbb, ins);
1792 cfg->flags |= MONO_CFG_HAS_FPOUT;
1794 int dreg = mono_alloc_freg (cfg);
1796 if (ainfo->size == 4) {
1797 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1799 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1801 ins->sreg1 = in->dreg;
1802 MONO_ADD_INS (cfg->cbb, ins);
1805 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1806 cfg->flags |= MONO_CFG_HAS_FPOUT;
1809 g_assert_not_reached ();
1813 /* Handle the case where there are no implicit arguments */
1814 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1815 emit_sig_cookie (cfg, call, cinfo);
1817 if (cinfo->struct_ret) {
1820 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1821 vtarg->sreg1 = call->vret_var->dreg;
1822 vtarg->dreg = mono_alloc_preg (cfg);
1823 MONO_ADD_INS (cfg->cbb, vtarg);
1825 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1829 * Reverse the call->out_args list.
1832 MonoInst *prev = NULL, *list = call->out_args, *next;
1839 call->out_args = prev;
1842 call->stack_usage = cinfo->stack_usage;
1843 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1844 #if _MIPS_SIM == _ABIO32
1845 /* a0-a3 always present */
1846 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1848 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1849 cfg->flags |= MONO_CFG_HAS_CALLS;
1851 * should set more info in call, such as the stack space
1852 * used by the args that needs to be added back to esp
1857 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1859 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1860 ArgInfo *ainfo = ins->inst_p1;
1861 int ovf_size = ainfo->vtsize;
1862 int doffset = ainfo->offset;
1863 int i, soffset, dreg;
1865 if (ainfo->storage == ArgStructByVal) {
1867 if (cfg->verbose_level > 0) {
1868 char* nm = mono_method_full_name (cfg->method, TRUE);
1869 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1870 nm, doffset, ainfo->size, ovf_size);
1876 for (i = 0; i < ainfo->size; ++i) {
1877 dreg = mono_alloc_ireg (cfg);
1878 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1879 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1880 soffset += SIZEOF_REGISTER;
1882 if (ovf_size != 0) {
1883 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), SIZEOF_VOID_P);
1885 } else if (ainfo->storage == ArgInFReg) {
1886 int tmpr = mono_alloc_freg (cfg);
1888 if (ainfo->size == 4)
1889 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1891 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1892 dreg = mono_alloc_freg (cfg);
1893 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1894 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1896 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1900 /* FIXME: alignment? */
1901 if (call->signature->pinvoke) {
1902 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1903 vtcopy->backend.is_pinvoke = 1;
1905 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1908 g_assert (ovf_size > 0);
1910 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1911 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, SIZEOF_VOID_P);
1914 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1916 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1921 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1923 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1926 #if (SIZEOF_REGISTER == 4)
1927 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1930 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1931 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1932 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1933 MONO_ADD_INS (cfg->cbb, ins);
1937 if (ret->type == MONO_TYPE_R8) {
1938 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1941 if (ret->type == MONO_TYPE_R4) {
1942 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1946 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1950 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1952 MonoInst *ins, *n, *last_ins = NULL;
1954 if (cfg->verbose_level > 2)
1955 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1958 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1959 if (cfg->verbose_level > 2)
1960 mono_print_ins_index (0, ins);
1962 switch (ins->opcode) {
1964 case OP_LOAD_MEMBASE:
1965 case OP_LOADI4_MEMBASE:
1967 * OP_IADD reg2, reg1, const1
1968 * OP_LOAD_MEMBASE const2(reg2), reg3
1970 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1972 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)){
1973 int const1 = last_ins->inst_imm;
1974 int const2 = ins->inst_offset;
1976 if (mips_is_imm16 (const1 + const2)) {
1977 ins->inst_basereg = last_ins->sreg1;
1978 ins->inst_offset = const1 + const2;
1988 bb->last_ins = last_ins;
1992 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1994 MonoInst *ins, *n, *last_ins = NULL;
1997 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1998 MonoInst *last_ins = ins->prev;
2000 switch (ins->opcode) {
2002 /* remove unnecessary multiplication with 1 */
2003 if (ins->inst_imm == 1) {
2004 if (ins->dreg != ins->sreg1) {
2005 ins->opcode = OP_MOVE;
2007 MONO_DELETE_INS (bb, ins);
2011 int power2 = mono_is_power_of_two (ins->inst_imm);
2013 ins->opcode = OP_SHL_IMM;
2014 ins->inst_imm = power2;
2018 case OP_LOAD_MEMBASE:
2019 case OP_LOADI4_MEMBASE:
2021 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2022 * OP_LOAD_MEMBASE offset(basereg), reg
2024 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2025 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2026 ins->inst_basereg == last_ins->inst_destbasereg &&
2027 ins->inst_offset == last_ins->inst_offset) {
2028 if (ins->dreg == last_ins->sreg1) {
2029 MONO_DELETE_INS (bb, ins);
2032 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2033 ins->opcode = OP_MOVE;
2034 ins->sreg1 = last_ins->sreg1;
2039 * Note: reg1 must be different from the basereg in the second load
2040 * OP_LOAD_MEMBASE offset(basereg), reg1
2041 * OP_LOAD_MEMBASE offset(basereg), reg2
2043 * OP_LOAD_MEMBASE offset(basereg), reg1
2044 * OP_MOVE reg1, reg2
2046 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2047 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2048 ins->inst_basereg != last_ins->dreg &&
2049 ins->inst_basereg == last_ins->inst_basereg &&
2050 ins->inst_offset == last_ins->inst_offset) {
2052 if (ins->dreg == last_ins->dreg) {
2053 MONO_DELETE_INS (bb, ins);
2056 ins->opcode = OP_MOVE;
2057 ins->sreg1 = last_ins->dreg;
2060 //g_assert_not_reached ();
2065 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2066 * OP_LOAD_MEMBASE offset(basereg), reg
2068 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2069 * OP_ICONST reg, imm
2071 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2072 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2073 ins->inst_basereg == last_ins->inst_destbasereg &&
2074 ins->inst_offset == last_ins->inst_offset) {
2075 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2076 ins->opcode = OP_ICONST;
2077 ins->inst_c0 = last_ins->inst_imm;
2078 g_assert_not_reached (); // check this rule
2083 case OP_LOADU1_MEMBASE:
2084 case OP_LOADI1_MEMBASE:
2085 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2086 ins->inst_basereg == last_ins->inst_destbasereg &&
2087 ins->inst_offset == last_ins->inst_offset) {
2088 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2089 ins->sreg1 = last_ins->sreg1;
2092 case OP_LOADU2_MEMBASE:
2093 case OP_LOADI2_MEMBASE:
2094 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2095 ins->inst_basereg == last_ins->inst_destbasereg &&
2096 ins->inst_offset == last_ins->inst_offset) {
2097 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2098 ins->sreg1 = last_ins->sreg1;
2101 case OP_ICONV_TO_I4:
2102 case OP_ICONV_TO_U4:
2104 ins->opcode = OP_MOVE;
2108 if (ins->dreg == ins->sreg1) {
2109 MONO_DELETE_INS (bb, ins);
2113 * OP_MOVE sreg, dreg
2114 * OP_MOVE dreg, sreg
2116 if (last_ins && last_ins->opcode == OP_MOVE &&
2117 ins->sreg1 == last_ins->dreg &&
2118 ins->dreg == last_ins->sreg1) {
2119 MONO_DELETE_INS (bb, ins);
2127 bb->last_ins = last_ins;
2131 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2139 switch (ins->opcode) {
2141 tmp1 = mono_alloc_ireg (cfg);
2142 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2143 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2144 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2145 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2150 tmp1 = mono_alloc_ireg (cfg);
2151 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2152 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2153 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2154 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2159 tmp1 = mono_alloc_ireg (cfg);
2160 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2161 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2162 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2163 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2168 tmp1 = mono_alloc_ireg (cfg);
2169 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2170 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2171 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2172 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2177 tmp1 = mono_alloc_ireg (cfg);
2178 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2179 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2180 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2181 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2186 tmp1 = mono_alloc_ireg (cfg);
2187 tmp2 = mono_alloc_ireg (cfg);
2188 tmp3 = mono_alloc_ireg (cfg);
2189 tmp4 = mono_alloc_ireg (cfg);
2190 tmp5 = mono_alloc_ireg (cfg);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2194 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2195 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2197 /* add the high 32-bits, and add in the carry from the low 32-bits */
2198 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2199 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2201 /* Overflow happens if
2202 * neg + neg = pos or
2204 * XOR of the high bits returns 0 if the signs match
2205 * XOR of that with the high bit of the result return 1 if overflow.
2208 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2209 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2211 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2212 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2213 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2215 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2216 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2217 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2219 /* Now, if (tmp4 == 0) then overflow */
2220 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2224 case OP_LADD_OVF_UN:
2225 tmp1 = mono_alloc_ireg (cfg);
2226 tmp2 = mono_alloc_ireg (cfg);
2228 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2229 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2230 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2231 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2232 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2233 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2238 tmp1 = mono_alloc_ireg (cfg);
2239 tmp2 = mono_alloc_ireg (cfg);
2240 tmp3 = mono_alloc_ireg (cfg);
2241 tmp4 = mono_alloc_ireg (cfg);
2242 tmp5 = mono_alloc_ireg (cfg);
2244 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2246 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2247 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2248 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2250 /* Overflow happens if
2251 * neg - pos = pos or
2253 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2255 * tmp1 = (lhs ^ rhs)
2256 * tmp2 = (lhs ^ result)
2257 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2260 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2261 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2262 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2263 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2265 /* Now, if (tmp4 == 1) then overflow */
2266 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2270 case OP_LSUB_OVF_UN:
2271 tmp1 = mono_alloc_ireg (cfg);
2272 tmp2 = mono_alloc_ireg (cfg);
2274 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2275 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2276 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2277 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2279 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2280 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2283 case OP_LCONV_TO_OVF_I4_2:
2284 tmp1 = mono_alloc_ireg (cfg);
2286 /* Overflows if reg2 != sign extension of reg1 */
2287 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2288 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2289 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2298 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2306 switch (ins->opcode) {
2308 tmp1 = mono_alloc_ireg (cfg);
2309 tmp2 = mono_alloc_ireg (cfg);
2310 tmp3 = mono_alloc_ireg (cfg);
2311 tmp4 = mono_alloc_ireg (cfg);
2312 tmp5 = mono_alloc_ireg (cfg);
2314 /* add the operands */
2316 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2318 /* Overflow happens if
2319 * neg + neg = pos or
2322 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2323 * XOR of the high bit returns 0 if the signs match
2324 * XOR of that with the high bit of the result return 1 if overflow.
2327 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2328 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2330 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2331 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2332 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2334 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2335 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2337 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2339 /* Now, if (tmp5 == 0) then overflow */
2340 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2341 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2342 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2346 case OP_IADD_OVF_UN:
2347 tmp1 = mono_alloc_ireg (cfg);
2349 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2350 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2351 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2352 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2353 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2358 tmp1 = mono_alloc_ireg (cfg);
2359 tmp2 = mono_alloc_ireg (cfg);
2360 tmp3 = mono_alloc_ireg (cfg);
2361 tmp4 = mono_alloc_ireg (cfg);
2362 tmp5 = mono_alloc_ireg (cfg);
2364 /* add the operands */
2366 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2368 /* Overflow happens if
2369 * neg - pos = pos or
2371 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2373 * tmp1 = (lhs ^ rhs)
2374 * tmp2 = (lhs ^ result)
2375 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2378 /* tmp3 = 1 if the signs of the two inputs differ */
2379 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2380 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2381 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2382 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2383 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2385 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2386 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2387 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2391 case OP_ISUB_OVF_UN:
2392 tmp1 = mono_alloc_ireg (cfg);
2394 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2395 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2396 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2397 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2398 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2405 map_to_reg_reg_op (int op)
2414 case OP_COMPARE_IMM:
2416 case OP_ICOMPARE_IMM:
2418 case OP_LCOMPARE_IMM:
2434 case OP_LOAD_MEMBASE:
2435 return OP_LOAD_MEMINDEX;
2436 case OP_LOADI4_MEMBASE:
2437 return OP_LOADI4_MEMINDEX;
2438 case OP_LOADU4_MEMBASE:
2439 return OP_LOADU4_MEMINDEX;
2440 case OP_LOADU1_MEMBASE:
2441 return OP_LOADU1_MEMINDEX;
2442 case OP_LOADI2_MEMBASE:
2443 return OP_LOADI2_MEMINDEX;
2444 case OP_LOADU2_MEMBASE:
2445 return OP_LOADU2_MEMINDEX;
2446 case OP_LOADI1_MEMBASE:
2447 return OP_LOADI1_MEMINDEX;
2448 case OP_LOADR4_MEMBASE:
2449 return OP_LOADR4_MEMINDEX;
2450 case OP_LOADR8_MEMBASE:
2451 return OP_LOADR8_MEMINDEX;
2452 case OP_STOREI1_MEMBASE_REG:
2453 return OP_STOREI1_MEMINDEX;
2454 case OP_STOREI2_MEMBASE_REG:
2455 return OP_STOREI2_MEMINDEX;
2456 case OP_STOREI4_MEMBASE_REG:
2457 return OP_STOREI4_MEMINDEX;
2458 case OP_STORE_MEMBASE_REG:
2459 return OP_STORE_MEMINDEX;
2460 case OP_STORER4_MEMBASE_REG:
2461 return OP_STORER4_MEMINDEX;
2462 case OP_STORER8_MEMBASE_REG:
2463 return OP_STORER8_MEMINDEX;
2464 case OP_STORE_MEMBASE_IMM:
2465 return OP_STORE_MEMBASE_REG;
2466 case OP_STOREI1_MEMBASE_IMM:
2467 return OP_STOREI1_MEMBASE_REG;
2468 case OP_STOREI2_MEMBASE_IMM:
2469 return OP_STOREI2_MEMBASE_REG;
2470 case OP_STOREI4_MEMBASE_IMM:
2471 return OP_STOREI4_MEMBASE_REG;
2472 case OP_STOREI8_MEMBASE_IMM:
2473 return OP_STOREI8_MEMBASE_REG;
2475 if (mono_op_imm_to_op (op) == -1)
2476 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2477 return mono_op_imm_to_op (op);
2481 map_to_mips_op (int op)
2485 return OP_MIPS_FBEQ;
2487 return OP_MIPS_FBGE;
2489 return OP_MIPS_FBGT;
2491 return OP_MIPS_FBLE;
2493 return OP_MIPS_FBLT;
2495 return OP_MIPS_FBNE;
2497 return OP_MIPS_FBGE_UN;
2499 return OP_MIPS_FBGT_UN;
2501 return OP_MIPS_FBLE_UN;
2503 return OP_MIPS_FBLT_UN;
2511 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2512 g_assert_not_reached ();
2516 #define NEW_INS(cfg,after,dest,op) do { \
2517 MONO_INST_NEW((cfg), (dest), (op)); \
2518 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2521 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2523 MONO_INST_NEW(cfg, temp, (op)); \
2524 mono_bblock_insert_after_ins (bb, (pos), temp); \
2525 temp->dreg = (_dreg); \
2526 temp->sreg1 = (_sreg1); \
2527 temp->sreg2 = (_sreg2); \
2531 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2533 MONO_INST_NEW(cfg, temp, (op)); \
2534 mono_bblock_insert_after_ins (bb, (pos), temp); \
2535 temp->dreg = (_dreg); \
2536 temp->sreg1 = (_sreg1); \
2537 temp->inst_c0 = (_imm); \
2542 * Remove from the instruction list the instructions that can't be
2543 * represented with very simple instructions with no register
2547 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2549 MonoInst *ins, *next, *temp, *last_ins = NULL;
2553 if (cfg->verbose_level > 2) {
2556 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2557 MONO_BB_FOR_EACH_INS (bb, ins) {
2558 mono_print_ins_index (idx++, ins);
2564 MONO_BB_FOR_EACH_INS (bb, ins) {
2566 switch (ins->opcode) {
2571 /* Branch opts can eliminate the branch */
2572 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2578 case OP_COMPARE_IMM:
2579 case OP_ICOMPARE_IMM:
2580 case OP_LCOMPARE_IMM:
2582 /* Branch opts can eliminate the branch */
2583 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2587 if (ins->inst_imm) {
2588 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2589 temp->inst_c0 = ins->inst_imm;
2590 temp->dreg = mono_alloc_ireg (cfg);
2591 ins->sreg2 = temp->dreg;
2595 ins->sreg2 = mips_zero;
2597 if (ins->opcode == OP_COMPARE_IMM)
2598 ins->opcode = OP_COMPARE;
2599 else if (ins->opcode == OP_ICOMPARE_IMM)
2600 ins->opcode = OP_ICOMPARE;
2601 else if (ins->opcode == OP_LCOMPARE_IMM)
2602 ins->opcode = OP_LCOMPARE;
2605 case OP_IDIV_UN_IMM:
2608 case OP_IREM_UN_IMM:
2609 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2610 temp->inst_c0 = ins->inst_imm;
2611 temp->dreg = mono_alloc_ireg (cfg);
2612 ins->sreg2 = temp->dreg;
2613 if (ins->opcode == OP_IDIV_IMM)
2614 ins->opcode = OP_IDIV;
2615 else if (ins->opcode == OP_IREM_IMM)
2616 ins->opcode = OP_IREM;
2617 else if (ins->opcode == OP_IDIV_UN_IMM)
2618 ins->opcode = OP_IDIV_UN;
2619 else if (ins->opcode == OP_IREM_UN_IMM)
2620 ins->opcode = OP_IREM_UN;
2622 /* handle rem separately */
2629 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2630 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2631 temp->inst_c0 = ins->inst_imm;
2632 temp->dreg = mono_alloc_ireg (cfg);
2633 ins->sreg2 = temp->dreg;
2634 ins->opcode = map_to_reg_reg_op (ins->opcode);
2644 /* unsigned 16 bit immediate */
2645 if (ins->inst_imm & 0xffff0000) {
2646 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2647 temp->inst_c0 = ins->inst_imm;
2648 temp->dreg = mono_alloc_ireg (cfg);
2649 ins->sreg2 = temp->dreg;
2650 ins->opcode = map_to_reg_reg_op (ins->opcode);
2657 /* signed 16 bit immediate */
2658 if (!mips_is_imm16 (ins->inst_imm)) {
2659 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2660 temp->inst_c0 = ins->inst_imm;
2661 temp->dreg = mono_alloc_ireg (cfg);
2662 ins->sreg2 = temp->dreg;
2663 ins->opcode = map_to_reg_reg_op (ins->opcode);
2669 if (!mips_is_imm16 (-ins->inst_imm)) {
2670 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2671 temp->inst_c0 = ins->inst_imm;
2672 temp->dreg = mono_alloc_ireg (cfg);
2673 ins->sreg2 = temp->dreg;
2674 ins->opcode = map_to_reg_reg_op (ins->opcode);
2680 if (ins->inst_imm == 1) {
2681 ins->opcode = OP_MOVE;
2684 if (ins->inst_imm == 0) {
2685 ins->opcode = OP_ICONST;
2689 imm = mono_is_power_of_two (ins->inst_imm);
2691 ins->opcode = OP_SHL_IMM;
2692 ins->inst_imm = imm;
2695 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2696 temp->inst_c0 = ins->inst_imm;
2697 temp->dreg = mono_alloc_ireg (cfg);
2698 ins->sreg2 = temp->dreg;
2699 ins->opcode = map_to_reg_reg_op (ins->opcode);
2702 case OP_LOCALLOC_IMM:
2703 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2704 temp->inst_c0 = ins->inst_imm;
2705 temp->dreg = mono_alloc_ireg (cfg);
2706 ins->sreg1 = temp->dreg;
2707 ins->opcode = OP_LOCALLOC;
2710 case OP_LOADR4_MEMBASE:
2711 case OP_STORER4_MEMBASE_REG:
2712 /* we can do two things: load the immed in a register
2713 * and use an indexed load, or see if the immed can be
2714 * represented as an ad_imm + a load with a smaller offset
2715 * that fits. We just do the first for now, optimize later.
2717 if (mips_is_imm16 (ins->inst_offset))
2719 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2720 temp->inst_c0 = ins->inst_offset;
2721 temp->dreg = mono_alloc_ireg (cfg);
2722 ins->sreg2 = temp->dreg;
2723 ins->opcode = map_to_reg_reg_op (ins->opcode);
2726 case OP_STORE_MEMBASE_IMM:
2727 case OP_STOREI1_MEMBASE_IMM:
2728 case OP_STOREI2_MEMBASE_IMM:
2729 case OP_STOREI4_MEMBASE_IMM:
2730 case OP_STOREI8_MEMBASE_IMM:
2731 if (!ins->inst_imm) {
2732 ins->sreg1 = mips_zero;
2733 ins->opcode = map_to_reg_reg_op (ins->opcode);
2736 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2737 temp->inst_c0 = ins->inst_imm;
2738 temp->dreg = mono_alloc_ireg (cfg);
2739 ins->sreg1 = temp->dreg;
2740 ins->opcode = map_to_reg_reg_op (ins->opcode);
2742 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2748 /* Branch opts can eliminate the branch */
2749 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2756 * remap compare/branch and compare/set
2757 * to MIPS specific opcodes.
2759 next->opcode = map_to_mips_op (next->opcode);
2760 next->sreg1 = ins->sreg1;
2761 next->sreg2 = ins->sreg2;
2768 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2769 temp->inst_c0 = (guint32)ins->inst_p0;
2770 temp->dreg = mono_alloc_ireg (cfg);
2771 ins->inst_basereg = temp->dreg;
2772 ins->inst_offset = 0;
2773 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2775 /* make it handle the possibly big ins->inst_offset
2776 * later optimize to use lis + load_membase
2781 g_assert (ins_is_compare(last_ins));
2782 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2783 NULLIFY_INS(last_ins);
2787 g_assert (ins_is_compare(last_ins));
2788 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2789 NULLIFY_INS(last_ins);
2793 g_assert (ins_is_compare(last_ins));
2794 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2795 last_ins->dreg = mono_alloc_ireg (cfg);
2796 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2800 g_assert (ins_is_compare(last_ins));
2801 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2802 last_ins->dreg = mono_alloc_ireg (cfg);
2803 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2807 g_assert (ins_is_compare(last_ins));
2808 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2809 last_ins->dreg = mono_alloc_ireg (cfg);
2810 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2814 g_assert (ins_is_compare(last_ins));
2815 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2816 last_ins->dreg = mono_alloc_ireg (cfg);
2817 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2821 g_assert (ins_is_compare(last_ins));
2822 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2823 last_ins->dreg = mono_alloc_ireg (cfg);
2824 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2828 g_assert (ins_is_compare(last_ins));
2829 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2830 last_ins->dreg = mono_alloc_ireg (cfg);
2831 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2835 g_assert (ins_is_compare(last_ins));
2836 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2837 last_ins->dreg = mono_alloc_ireg (cfg);
2838 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2842 g_assert (ins_is_compare(last_ins));
2843 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2844 last_ins->dreg = mono_alloc_ireg (cfg);
2845 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2850 g_assert (ins_is_compare(last_ins));
2851 last_ins->opcode = OP_IXOR;
2852 last_ins->dreg = mono_alloc_ireg(cfg);
2853 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2858 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2859 NULLIFY_INS(last_ins);
2865 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2866 NULLIFY_INS(last_ins);
2871 g_assert (ins_is_compare(last_ins));
2872 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2873 MONO_DELETE_INS(bb, last_ins);
2878 g_assert (ins_is_compare(last_ins));
2879 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2880 MONO_DELETE_INS(bb, last_ins);
2883 case OP_COND_EXC_EQ:
2884 case OP_COND_EXC_IEQ:
2885 g_assert (ins_is_compare(last_ins));
2886 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2887 MONO_DELETE_INS(bb, last_ins);
2890 case OP_COND_EXC_GE:
2891 case OP_COND_EXC_IGE:
2892 g_assert (ins_is_compare(last_ins));
2893 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2894 MONO_DELETE_INS(bb, last_ins);
2897 case OP_COND_EXC_GT:
2898 case OP_COND_EXC_IGT:
2899 g_assert (ins_is_compare(last_ins));
2900 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2901 MONO_DELETE_INS(bb, last_ins);
2904 case OP_COND_EXC_LE:
2905 case OP_COND_EXC_ILE:
2906 g_assert (ins_is_compare(last_ins));
2907 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2908 MONO_DELETE_INS(bb, last_ins);
2911 case OP_COND_EXC_LT:
2912 case OP_COND_EXC_ILT:
2913 g_assert (ins_is_compare(last_ins));
2914 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2915 MONO_DELETE_INS(bb, last_ins);
2918 case OP_COND_EXC_NE_UN:
2919 case OP_COND_EXC_INE_UN:
2920 g_assert (ins_is_compare(last_ins));
2921 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2922 MONO_DELETE_INS(bb, last_ins);
2925 case OP_COND_EXC_GE_UN:
2926 case OP_COND_EXC_IGE_UN:
2927 g_assert (ins_is_compare(last_ins));
2928 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2929 MONO_DELETE_INS(bb, last_ins);
2932 case OP_COND_EXC_GT_UN:
2933 case OP_COND_EXC_IGT_UN:
2934 g_assert (ins_is_compare(last_ins));
2935 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2936 MONO_DELETE_INS(bb, last_ins);
2939 case OP_COND_EXC_LE_UN:
2940 case OP_COND_EXC_ILE_UN:
2941 g_assert (ins_is_compare(last_ins));
2942 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2943 MONO_DELETE_INS(bb, last_ins);
2946 case OP_COND_EXC_LT_UN:
2947 case OP_COND_EXC_ILT_UN:
2948 g_assert (ins_is_compare(last_ins));
2949 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2950 MONO_DELETE_INS(bb, last_ins);
2953 case OP_COND_EXC_OV:
2954 case OP_COND_EXC_IOV: {
2955 int tmp1, tmp2, tmp3, tmp4, tmp5;
2956 MonoInst *pos = last_ins;
2958 /* Overflow happens if
2959 * neg + neg = pos or
2962 * (bit31s of operands match) AND (bit31 of operand
2963 * != bit31 of result)
2964 * XOR of the high bit returns 0 if the signs match
2965 * XOR of that with the high bit of the result return 1
2968 g_assert (last_ins->opcode == OP_IADC);
2970 tmp1 = mono_alloc_ireg (cfg);
2971 tmp2 = mono_alloc_ireg (cfg);
2972 tmp3 = mono_alloc_ireg (cfg);
2973 tmp4 = mono_alloc_ireg (cfg);
2974 tmp5 = mono_alloc_ireg (cfg);
2976 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2977 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2979 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2980 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2981 INS (pos, OP_INOT, tmp3, tmp2, -1);
2983 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2984 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2985 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2987 /* Now, if (tmp5 == 0) then overflow */
2988 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2993 case OP_COND_EXC_NO:
2994 case OP_COND_EXC_INO:
2995 g_assert_not_reached ();
2999 case OP_COND_EXC_IC:
3000 g_assert_not_reached ();
3003 case OP_COND_EXC_NC:
3004 case OP_COND_EXC_INC:
3005 g_assert_not_reached ();
3011 bb->last_ins = last_ins;
3012 bb->max_vreg = cfg->next_vreg;
3015 if (cfg->verbose_level > 2) {
3018 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3019 MONO_BB_FOR_EACH_INS (bb, ins) {
3020 mono_print_ins_index (idx++, ins);
3029 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3031 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3033 mips_truncwd (code, mips_ftemp, sreg);
3035 mips_cvtwd (code, mips_ftemp, sreg);
3037 mips_mfc1 (code, dreg, mips_ftemp);
3040 mips_andi (code, dreg, dreg, 0xff);
3041 else if (size == 2) {
3042 mips_sll (code, dreg, dreg, 16);
3043 mips_srl (code, dreg, dreg, 16);
3047 mips_sll (code, dreg, dreg, 24);
3048 mips_sra (code, dreg, dreg, 24);
3050 else if (size == 2) {
3051 mips_sll (code, dreg, dreg, 16);
3052 mips_sra (code, dreg, dreg, 16);
3059 * emit_load_volatile_arguments:
3061 * Load volatile arguments from the stack to the original input registers.
3062 * Required before a tail call.
3065 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3067 MonoMethod *method = cfg->method;
3068 MonoMethodSignature *sig;
3073 sig = mono_method_signature (method);
3075 if (!cfg->arch.cinfo)
3076 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3077 cinfo = cfg->arch.cinfo;
3079 if (cinfo->struct_ret) {
3080 ArgInfo *ainfo = &cinfo->ret;
3081 inst = cfg->vret_addr;
3082 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3085 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3086 ArgInfo *ainfo = cinfo->args + i;
3087 inst = cfg->args [i];
3088 if (inst->opcode == OP_REGVAR) {
3089 if (ainfo->storage == ArgInIReg)
3090 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3091 else if (ainfo->storage == ArgInFReg)
3092 g_assert_not_reached();
3093 else if (ainfo->storage == ArgOnStack) {
3096 g_assert_not_reached ();
3098 if (ainfo->storage == ArgInIReg) {
3099 g_assert (mips_is_imm16 (inst->inst_offset));
3100 switch (ainfo->size) {
3102 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3105 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3109 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3112 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3113 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3116 g_assert_not_reached ();
3119 } else if (ainfo->storage == ArgOnStack) {
3121 } else if (ainfo->storage == ArgInFReg) {
3122 g_assert (mips_is_imm16 (inst->inst_offset));
3123 if (ainfo->size == 8) {
3124 #if _MIPS_SIM == _ABIO32
3125 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3126 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3127 #elif _MIPS_SIM == _ABIN32
3128 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3131 else if (ainfo->size == 4)
3132 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3134 g_assert_not_reached ();
3135 } else if (ainfo->storage == ArgStructByVal) {
3137 int doffset = inst->inst_offset;
3139 g_assert (mips_is_imm16 (inst->inst_offset));
3140 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3141 for (i = 0; i < ainfo->size; ++i) {
3142 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3143 doffset += SIZEOF_REGISTER;
3145 } else if (ainfo->storage == ArgStructByAddr) {
3146 g_assert (mips_is_imm16 (inst->inst_offset));
3147 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3149 g_assert_not_reached ();
3157 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3159 int size = cfg->param_area;
3161 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3162 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3167 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3168 if (ppc_is_imm16 (-size)) {
3169 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3171 ppc_load (code, ppc_r12, -size);
3172 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3179 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3181 int size = cfg->param_area;
3183 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3184 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3189 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3190 if (ppc_is_imm16 (size)) {
3191 ppc_stwu (code, ppc_r0, size, ppc_sp);
3193 ppc_load (code, ppc_r12, size);
3194 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3201 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3206 guint8 *code = cfg->native_code + cfg->code_len;
3207 MonoInst *last_ins = NULL;
3208 guint last_offset = 0;
3212 /* we don't align basic blocks of loops on mips */
3214 if (cfg->verbose_level > 2)
3215 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3217 cpos = bb->max_offset;
3219 MONO_BB_FOR_EACH_INS (bb, ins) {
3220 offset = code - cfg->native_code;
3222 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3224 if (offset > (cfg->code_size - max_len - 16)) {
3225 cfg->code_size *= 2;
3226 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3227 code = cfg->native_code + offset;
3229 mono_debug_record_line_number (cfg, ins, offset);
3230 if (cfg->verbose_level > 2) {
3231 g_print (" @ 0x%x\t", offset);
3232 mono_print_ins_index (ins_cnt++, ins);
3234 /* Check for virtual regs that snuck by */
3235 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3237 switch (ins->opcode) {
3238 case OP_RELAXED_NOP:
3241 case OP_DUMMY_STORE:
3242 case OP_NOT_REACHED:
3245 case OP_IL_SEQ_POINT:
3246 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3248 case OP_SEQ_POINT: {
3249 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3250 guint32 addr = (guint32)ss_trigger_page;
3252 mips_load_const (code, mips_t9, addr);
3253 mips_lw (code, mips_t9, mips_t9, 0);
3256 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3259 * A placeholder for a possible breakpoint inserted by
3260 * mono_arch_set_breakpoint ().
3262 /* mips_load_const () + mips_lw */
3269 mips_mult (code, ins->sreg1, ins->sreg2);
3270 mips_mflo (code, ins->dreg);
3271 mips_mfhi (code, ins->dreg+1);
3274 mips_multu (code, ins->sreg1, ins->sreg2);
3275 mips_mflo (code, ins->dreg);
3276 mips_mfhi (code, ins->dreg+1);
3278 case OP_MEMORY_BARRIER:
3279 mips_sync (code, 0);
3281 case OP_STOREI1_MEMBASE_IMM:
3282 mips_load_const (code, mips_temp, ins->inst_imm);
3283 if (mips_is_imm16 (ins->inst_offset)) {
3284 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3286 mips_load_const (code, mips_at, ins->inst_offset);
3287 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3290 case OP_STOREI2_MEMBASE_IMM:
3291 mips_load_const (code, mips_temp, ins->inst_imm);
3292 if (mips_is_imm16 (ins->inst_offset)) {
3293 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3295 mips_load_const (code, mips_at, ins->inst_offset);
3296 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3299 case OP_STOREI8_MEMBASE_IMM:
3300 mips_load_const (code, mips_temp, ins->inst_imm);
3301 if (mips_is_imm16 (ins->inst_offset)) {
3302 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3304 mips_load_const (code, mips_at, ins->inst_offset);
3305 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3308 case OP_STORE_MEMBASE_IMM:
3309 case OP_STOREI4_MEMBASE_IMM:
3310 mips_load_const (code, mips_temp, ins->inst_imm);
3311 if (mips_is_imm16 (ins->inst_offset)) {
3312 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3314 mips_load_const (code, mips_at, ins->inst_offset);
3315 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3318 case OP_STOREI1_MEMBASE_REG:
3319 if (mips_is_imm16 (ins->inst_offset)) {
3320 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3322 mips_load_const (code, mips_at, ins->inst_offset);
3323 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3324 mips_sb (code, ins->sreg1, mips_at, 0);
3327 case OP_STOREI2_MEMBASE_REG:
3328 if (mips_is_imm16 (ins->inst_offset)) {
3329 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3331 mips_load_const (code, mips_at, ins->inst_offset);
3332 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3333 mips_sh (code, ins->sreg1, mips_at, 0);
3336 case OP_STORE_MEMBASE_REG:
3337 case OP_STOREI4_MEMBASE_REG:
3338 if (mips_is_imm16 (ins->inst_offset)) {
3339 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3341 mips_load_const (code, mips_at, ins->inst_offset);
3342 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3343 mips_sw (code, ins->sreg1, mips_at, 0);
3346 case OP_STOREI8_MEMBASE_REG:
3347 if (mips_is_imm16 (ins->inst_offset)) {
3348 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3350 mips_load_const (code, mips_at, ins->inst_offset);
3351 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3352 mips_sd (code, ins->sreg1, mips_at, 0);
3356 g_assert_not_reached ();
3357 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3358 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3360 case OP_LOADI8_MEMBASE:
3361 if (mips_is_imm16 (ins->inst_offset)) {
3362 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3364 mips_load_const (code, mips_at, ins->inst_offset);
3365 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3366 mips_ld (code, ins->dreg, mips_at, 0);
3369 case OP_LOAD_MEMBASE:
3370 case OP_LOADI4_MEMBASE:
3371 case OP_LOADU4_MEMBASE:
3372 g_assert (ins->dreg != -1);
3373 if (mips_is_imm16 (ins->inst_offset)) {
3374 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3376 mips_load_const (code, mips_at, ins->inst_offset);
3377 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3378 mips_lw (code, ins->dreg, mips_at, 0);
3381 case OP_LOADI1_MEMBASE:
3382 if (mips_is_imm16 (ins->inst_offset)) {
3383 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3385 mips_load_const (code, mips_at, ins->inst_offset);
3386 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3387 mips_lb (code, ins->dreg, mips_at, 0);
3390 case OP_LOADU1_MEMBASE:
3391 if (mips_is_imm16 (ins->inst_offset)) {
3392 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3394 mips_load_const (code, mips_at, ins->inst_offset);
3395 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3396 mips_lbu (code, ins->dreg, mips_at, 0);
3399 case OP_LOADI2_MEMBASE:
3400 if (mips_is_imm16 (ins->inst_offset)) {
3401 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3403 mips_load_const (code, mips_at, ins->inst_offset);
3404 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3405 mips_lh (code, ins->dreg, mips_at, 0);
3408 case OP_LOADU2_MEMBASE:
3409 if (mips_is_imm16 (ins->inst_offset)) {
3410 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3412 mips_load_const (code, mips_at, ins->inst_offset);
3413 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3414 mips_lhu (code, ins->dreg, mips_at, 0);
3417 case OP_ICONV_TO_I1:
3418 mips_sll (code, mips_at, ins->sreg1, 24);
3419 mips_sra (code, ins->dreg, mips_at, 24);
3421 case OP_ICONV_TO_I2:
3422 mips_sll (code, mips_at, ins->sreg1, 16);
3423 mips_sra (code, ins->dreg, mips_at, 16);
3425 case OP_ICONV_TO_U1:
3426 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3428 case OP_ICONV_TO_U2:
3429 mips_sll (code, mips_at, ins->sreg1, 16);
3430 mips_srl (code, ins->dreg, mips_at, 16);
3433 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3436 g_assert (mips_is_imm16 (ins->inst_imm));
3437 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3440 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3443 g_assert (mips_is_imm16 (ins->inst_imm));
3444 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3448 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3449 * So instead of emitting a trap, we emit a call a C function and place a
3452 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3453 (gpointer)"mono_break");
3454 mips_load (code, mips_t9, 0x1f1f1f1f);
3455 mips_jalr (code, mips_t9, mips_ra);
3459 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3462 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3467 g_assert (mips_is_imm16 (ins->inst_imm));
3468 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3471 g_assert (mips_is_imm16 (ins->inst_imm));
3472 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3476 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3479 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3484 // we add the negated value
3485 g_assert (mips_is_imm16 (-ins->inst_imm));
3486 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3490 // we add the negated value
3491 g_assert (mips_is_imm16 (-ins->inst_imm));
3492 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3497 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3503 g_assert (!(ins->inst_imm & 0xffff0000));
3504 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3509 guint32 *divisor_is_m1;
3510 guint32 *dividend_is_minvalue;
3511 guint32 *divisor_is_zero;
3513 mips_load_const (code, mips_at, -1);
3514 divisor_is_m1 = (guint32 *)(void *)code;
3515 mips_bne (code, ins->sreg2, mips_at, 0);
3516 mips_lui (code, mips_at, mips_zero, 0x8000);
3517 dividend_is_minvalue = (guint32 *)(void *)code;
3518 mips_bne (code, ins->sreg1, mips_at, 0);
3521 /* Divide Int32.MinValue by -1 -- throw exception */
3522 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3524 mips_patch (divisor_is_m1, (guint32)code);
3525 mips_patch (dividend_is_minvalue, (guint32)code);
3527 /* Put divide in branch delay slot (NOT YET) */
3528 divisor_is_zero = (guint32 *)(void *)code;
3529 mips_bne (code, ins->sreg2, mips_zero, 0);
3532 /* Divide by zero -- throw exception */
3533 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3535 mips_patch (divisor_is_zero, (guint32)code);
3536 mips_div (code, ins->sreg1, ins->sreg2);
3537 if (ins->opcode == OP_IDIV)
3538 mips_mflo (code, ins->dreg);
3540 mips_mfhi (code, ins->dreg);
3545 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3547 /* Put divide in branch delay slot (NOT YET) */
3548 mips_bne (code, ins->sreg2, mips_zero, 0);
3551 /* Divide by zero -- throw exception */
3552 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3554 mips_patch (divisor_is_zero, (guint32)code);
3555 mips_divu (code, ins->sreg1, ins->sreg2);
3556 if (ins->opcode == OP_IDIV_UN)
3557 mips_mflo (code, ins->dreg);
3559 mips_mfhi (code, ins->dreg);
3563 g_assert_not_reached ();
3565 ppc_load (code, ppc_r12, ins->inst_imm);
3566 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3567 ppc_mfspr (code, ppc_r0, ppc_xer);
3568 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3569 /* FIXME: use OverflowException for 0x80000000/-1 */
3570 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3572 g_assert_not_reached();
3575 g_assert_not_reached ();
3577 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3581 g_assert (!(ins->inst_imm & 0xffff0000));
3582 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3585 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3589 /* unsigned 16-bit immediate */
3590 g_assert (!(ins->inst_imm & 0xffff0000));
3591 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3594 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3598 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3601 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3604 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3608 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3611 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3614 case OP_ISHR_UN_IMM:
3615 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3617 case OP_LSHR_UN_IMM:
3618 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3621 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3624 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3628 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3631 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3634 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3638 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3640 mips_mult (code, ins->sreg1, ins->sreg2);
3641 mips_mflo (code, ins->dreg);
3646 #if SIZEOF_REGISTER == 8
3648 mips_dmult (code, ins->sreg1, ins->sreg2);
3649 mips_mflo (code, ins->dreg);
3654 mips_mult (code, ins->sreg1, ins->sreg2);
3655 mips_mflo (code, ins->dreg);
3656 mips_mfhi (code, mips_at);
3659 mips_sra (code, mips_temp, ins->dreg, 31);
3660 patch = (guint32 *)(void *)code;
3661 mips_beq (code, mips_temp, mips_at, 0);
3663 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3664 mips_patch (patch, (guint32)code);
3667 case OP_IMUL_OVF_UN: {
3669 mips_mult (code, ins->sreg1, ins->sreg2);
3670 mips_mflo (code, ins->dreg);
3671 mips_mfhi (code, mips_at);
3674 patch = (guint32 *)(void *)code;
3675 mips_beq (code, mips_at, mips_zero, 0);
3677 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3678 mips_patch (patch, (guint32)code);
3682 mips_load_const (code, ins->dreg, ins->inst_c0);
3684 #if SIZEOF_REGISTER == 8
3686 mips_load_const (code, ins->dreg, ins->inst_c0);
3690 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3691 mips_load (code, ins->dreg, 0);
3695 mips_mtc1 (code, ins->dreg, ins->sreg1);
3697 case OP_MIPS_MTC1S_2:
3698 mips_mtc1 (code, ins->dreg, ins->sreg1);
3699 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3702 mips_mfc1 (code, ins->dreg, ins->sreg1);
3705 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3709 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3711 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3712 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3716 case OP_ICONV_TO_I4:
3717 case OP_ICONV_TO_U4:
3719 if (ins->dreg != ins->sreg1)
3720 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3722 #if SIZEOF_REGISTER == 8
3724 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3725 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3728 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3729 mips_dsra (code, ins->dreg, ins->dreg, 32);
3733 int lsreg = mips_v0 + ls_word_idx;
3734 int msreg = mips_v0 + ms_word_idx;
3736 /* Get sreg1 into lsreg, sreg2 into msreg */
3738 if (ins->sreg1 == msreg) {
3739 if (ins->sreg1 != mips_at)
3740 MIPS_MOVE (code, mips_at, ins->sreg1);
3741 if (ins->sreg2 != msreg)
3742 MIPS_MOVE (code, msreg, ins->sreg2);
3743 MIPS_MOVE (code, lsreg, mips_at);
3746 if (ins->sreg2 != msreg)
3747 MIPS_MOVE (code, msreg, ins->sreg2);
3748 if (ins->sreg1 != lsreg)
3749 MIPS_MOVE (code, lsreg, ins->sreg1);
3754 if (ins->dreg != ins->sreg1) {
3755 mips_fmovd (code, ins->dreg, ins->sreg1);
3758 case OP_MOVE_F_TO_I4:
3759 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3760 mips_mfc1 (code, ins->dreg, mips_ftemp);
3762 case OP_MOVE_I4_TO_F:
3763 mips_mtc1 (code, ins->dreg, ins->sreg1);
3764 mips_cvtds (code, ins->dreg, ins->dreg);
3767 /* Convert from double to float and leave it there */
3768 mips_cvtsd (code, ins->dreg, ins->sreg1);
3770 case OP_FCONV_TO_R4:
3772 mips_cvtsd (code, ins->dreg, ins->sreg1);
3774 /* Just a move, no precision change */
3775 if (ins->dreg != ins->sreg1) {
3776 mips_fmovd (code, ins->dreg, ins->sreg1);
3781 code = emit_load_volatile_arguments(cfg, code);
3784 * Pop our stack, then jump to specified method (tail-call)
3785 * Keep in sync with mono_arch_emit_epilog
3787 code = mono_arch_emit_epilog_sub (cfg, code);
3789 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3790 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3791 mips_load (code, mips_t9, 0);
3792 mips_jr (code, mips_t9);
3796 /* ensure ins->sreg1 is not NULL */
3797 mips_lw (code, mips_zero, ins->sreg1, 0);
3800 g_assert (mips_is_imm16 (cfg->sig_cookie));
3801 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3802 mips_sw (code, mips_at, ins->sreg1, 0);
3815 case OP_VOIDCALL_REG:
3817 case OP_FCALL_MEMBASE:
3818 case OP_LCALL_MEMBASE:
3819 case OP_VCALL_MEMBASE:
3820 case OP_VCALL2_MEMBASE:
3821 case OP_VOIDCALL_MEMBASE:
3822 case OP_CALL_MEMBASE:
3823 call = (MonoCallInst*)ins;
3824 switch (ins->opcode) {
3831 if (ins->flags & MONO_INST_HAS_METHOD) {
3832 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3833 mips_load (code, mips_t9, call->method);
3836 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3837 mips_load (code, mips_t9, call->fptr);
3839 mips_jalr (code, mips_t9, mips_ra);
3846 case OP_VOIDCALL_REG:
3848 MIPS_MOVE (code, mips_t9, ins->sreg1);
3849 mips_jalr (code, mips_t9, mips_ra);
3852 case OP_FCALL_MEMBASE:
3853 case OP_LCALL_MEMBASE:
3854 case OP_VCALL_MEMBASE:
3855 case OP_VCALL2_MEMBASE:
3856 case OP_VOIDCALL_MEMBASE:
3857 case OP_CALL_MEMBASE:
3858 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3859 mips_jalr (code, mips_t9, mips_ra);
3863 #if PROMOTE_R4_TO_R8
3864 /* returned an FP R4 (single), promote to R8 (double) in place */
3865 switch (ins->opcode) {
3868 case OP_FCALL_MEMBASE:
3869 if (call->signature->ret->type == MONO_TYPE_R4)
3870 mips_cvtds (code, mips_f0, mips_f0);
3878 int area_offset = cfg->param_area;
3880 /* Round up ins->sreg1, mips_at ends up holding size */
3881 mips_addiu (code, mips_at, ins->sreg1, 31);
3882 mips_addiu (code, mips_temp, mips_zero, ~31);
3883 mips_and (code, mips_at, mips_at, mips_temp);
3885 mips_subu (code, mips_sp, mips_sp, mips_at);
3886 g_assert (mips_is_imm16 (area_offset));
3887 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3889 if (ins->flags & MONO_INST_INIT) {
3892 buf = (guint32*)(void*)code;
3893 mips_beq (code, mips_at, mips_zero, 0);
3896 mips_move (code, mips_temp, ins->dreg);
3897 mips_sb (code, mips_zero, mips_temp, 0);
3898 mips_addiu (code, mips_at, mips_at, -1);
3899 mips_bne (code, mips_at, mips_zero, -3);
3900 mips_addiu (code, mips_temp, mips_temp, 1);
3902 mips_patch (buf, (guint32)code);
3907 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3908 mips_move (code, mips_a0, ins->sreg1);
3909 mips_call (code, mips_t9, addr);
3910 mips_break (code, 0xfc);
3914 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3915 mips_move (code, mips_a0, ins->sreg1);
3916 mips_call (code, mips_t9, addr);
3917 mips_break (code, 0xfb);
3920 case OP_START_HANDLER: {
3922 * The START_HANDLER instruction marks the beginning of
3923 * a handler block. It is called using a call
3924 * instruction, so mips_ra contains the return address.
3925 * Since the handler executes in the same stack frame
3926 * as the method itself, we can't use save/restore to
3927 * save the return address. Instead, we save it into
3928 * a dedicated variable.
3930 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3931 g_assert (spvar->inst_basereg != mips_sp);
3932 code = emit_reserve_param_area (cfg, code);
3934 if (mips_is_imm16 (spvar->inst_offset)) {
3935 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3937 mips_load_const (code, mips_at, spvar->inst_offset);
3938 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3939 mips_sw (code, mips_ra, mips_at, 0);
3943 case OP_ENDFILTER: {
3944 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3945 g_assert (spvar->inst_basereg != mips_sp);
3946 code = emit_unreserve_param_area (cfg, code);
3948 if (ins->sreg1 != mips_v0)
3949 MIPS_MOVE (code, mips_v0, ins->sreg1);
3950 if (mips_is_imm16 (spvar->inst_offset)) {
3951 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3953 mips_load_const (code, mips_at, spvar->inst_offset);
3954 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3955 mips_lw (code, mips_ra, mips_at, 0);
3957 mips_jr (code, mips_ra);
3961 case OP_ENDFINALLY: {
3962 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3963 g_assert (spvar->inst_basereg != mips_sp);
3964 code = emit_unreserve_param_area (cfg, code);
3965 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3966 mips_jalr (code, mips_t9, mips_ra);
3970 case OP_CALL_HANDLER:
3971 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3972 mips_lui (code, mips_t9, mips_zero, 0);
3973 mips_addiu (code, mips_t9, mips_t9, 0);
3974 mips_jalr (code, mips_t9, mips_ra);
3976 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3977 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3980 ins->inst_c0 = code - cfg->native_code;
3983 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3984 if (cfg->arch.long_branch) {
3985 mips_lui (code, mips_at, mips_zero, 0);
3986 mips_addiu (code, mips_at, mips_at, 0);
3987 mips_jr (code, mips_at);
3991 mips_beq (code, mips_zero, mips_zero, 0);
3996 mips_jr (code, ins->sreg1);
4002 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4003 if (offset > (cfg->code_size - max_len - 16)) {
4004 cfg->code_size += max_len;
4005 cfg->code_size *= 2;
4006 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4007 code = cfg->native_code + offset;
4009 g_assert (ins->sreg1 != -1);
4010 mips_sll (code, mips_at, ins->sreg1, 2);
4011 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4012 MIPS_MOVE (code, mips_t8, mips_ra);
4013 mips_bgezal (code, mips_zero, 1); /* bal */
4015 mips_addu (code, mips_t9, mips_ra, mips_at);
4016 /* Table is 16 or 20 bytes from target of bal above */
4017 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4018 MIPS_MOVE (code, mips_ra, mips_t8);
4019 mips_lw (code, mips_t9, mips_t9, 20);
4022 mips_lw (code, mips_t9, mips_t9, 16);
4023 mips_jalr (code, mips_t9, mips_t8);
4025 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4026 mips_emit32 (code, 0xfefefefe);
4031 mips_addiu (code, ins->dreg, mips_zero, 1);
4032 mips_beq (code, mips_at, mips_zero, 2);
4034 MIPS_MOVE (code, ins->dreg, mips_zero);
4040 mips_addiu (code, ins->dreg, mips_zero, 1);
4041 mips_bltz (code, mips_at, 2);
4043 MIPS_MOVE (code, ins->dreg, mips_zero);
4049 mips_addiu (code, ins->dreg, mips_zero, 1);
4050 mips_bgtz (code, mips_at, 2);
4052 MIPS_MOVE (code, ins->dreg, mips_zero);
4055 case OP_MIPS_COND_EXC_EQ:
4056 case OP_MIPS_COND_EXC_GE:
4057 case OP_MIPS_COND_EXC_GT:
4058 case OP_MIPS_COND_EXC_LE:
4059 case OP_MIPS_COND_EXC_LT:
4060 case OP_MIPS_COND_EXC_NE_UN:
4061 case OP_MIPS_COND_EXC_GE_UN:
4062 case OP_MIPS_COND_EXC_GT_UN:
4063 case OP_MIPS_COND_EXC_LE_UN:
4064 case OP_MIPS_COND_EXC_LT_UN:
4066 case OP_MIPS_COND_EXC_OV:
4067 case OP_MIPS_COND_EXC_NO:
4068 case OP_MIPS_COND_EXC_C:
4069 case OP_MIPS_COND_EXC_NC:
4071 case OP_MIPS_COND_EXC_IEQ:
4072 case OP_MIPS_COND_EXC_IGE:
4073 case OP_MIPS_COND_EXC_IGT:
4074 case OP_MIPS_COND_EXC_ILE:
4075 case OP_MIPS_COND_EXC_ILT:
4076 case OP_MIPS_COND_EXC_INE_UN:
4077 case OP_MIPS_COND_EXC_IGE_UN:
4078 case OP_MIPS_COND_EXC_IGT_UN:
4079 case OP_MIPS_COND_EXC_ILE_UN:
4080 case OP_MIPS_COND_EXC_ILT_UN:
4082 case OP_MIPS_COND_EXC_IOV:
4083 case OP_MIPS_COND_EXC_INO:
4084 case OP_MIPS_COND_EXC_IC:
4085 case OP_MIPS_COND_EXC_INC: {
4089 /* If the condition is true, raise the exception */
4091 /* need to reverse test to skip around exception raising */
4093 /* For the moment, branch around a branch to avoid reversing
4096 /* Remember, an unpatched branch to 0 branches to the delay slot */
4097 switch (ins->opcode) {
4098 case OP_MIPS_COND_EXC_EQ:
4099 throw = (guint32 *)(void *)code;
4100 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4104 case OP_MIPS_COND_EXC_NE_UN:
4105 throw = (guint32 *)(void *)code;
4106 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4110 case OP_MIPS_COND_EXC_LE_UN:
4111 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4112 throw = (guint32 *)(void *)code;
4113 mips_beq (code, mips_at, mips_zero, 0);
4117 case OP_MIPS_COND_EXC_GT:
4118 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4119 throw = (guint32 *)(void *)code;
4120 mips_bne (code, mips_at, mips_zero, 0);
4124 case OP_MIPS_COND_EXC_GT_UN:
4125 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4126 throw = (guint32 *)(void *)code;
4127 mips_bne (code, mips_at, mips_zero, 0);
4131 case OP_MIPS_COND_EXC_LT:
4132 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4133 throw = (guint32 *)(void *)code;
4134 mips_bne (code, mips_at, mips_zero, 0);
4138 case OP_MIPS_COND_EXC_LT_UN:
4139 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4140 throw = (guint32 *)(void *)code;
4141 mips_bne (code, mips_at, mips_zero, 0);
4146 /* Not yet implemented */
4147 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4148 g_assert_not_reached ();
4150 skip = (guint32 *)(void *)code;
4151 mips_beq (code, mips_zero, mips_zero, 0);
4153 mips_patch (throw, (guint32)code);
4154 code = mips_emit_exc_by_name (code, ins->inst_p1);
4155 mips_patch (skip, (guint32)code);
4156 cfg->bb_exit->max_offset += 24;
4165 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4168 /* floating point opcodes */
4171 if (((guint32)ins->inst_p0) & (1 << 15))
4172 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4174 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4175 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4177 mips_load_const (code, mips_at, ins->inst_p0);
4178 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4179 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4183 if (((guint32)ins->inst_p0) & (1 << 15))
4184 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4186 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4187 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4188 #if PROMOTE_R4_TO_R8
4189 mips_cvtds (code, ins->dreg, ins->dreg);
4192 case OP_STORER8_MEMBASE_REG:
4193 if (mips_is_imm16 (ins->inst_offset)) {
4194 #if _MIPS_SIM == _ABIO32
4195 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4196 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4197 #elif _MIPS_SIM == _ABIN32
4198 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4201 mips_load_const (code, mips_at, ins->inst_offset);
4202 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4203 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4204 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4207 case OP_LOADR8_MEMBASE:
4208 if (mips_is_imm16 (ins->inst_offset)) {
4209 #if _MIPS_SIM == _ABIO32
4210 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4211 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4212 #elif _MIPS_SIM == _ABIN32
4213 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4216 mips_load_const (code, mips_at, ins->inst_offset);
4217 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4218 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4219 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4222 case OP_STORER4_MEMBASE_REG:
4223 g_assert (mips_is_imm16 (ins->inst_offset));
4224 #if PROMOTE_R4_TO_R8
4225 /* Need to convert ins->sreg1 to single-precision first */
4226 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4227 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4229 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4233 g_assert (mips_is_imm16 (ins->inst_offset));
4234 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4236 case OP_LOADR4_MEMBASE:
4237 g_assert (mips_is_imm16 (ins->inst_offset));
4238 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4239 #if PROMOTE_R4_TO_R8
4240 /* Convert to double precision in place */
4241 mips_cvtds (code, ins->dreg, ins->dreg);
4244 case OP_LOADR4_MEMINDEX:
4245 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4246 mips_lwc1 (code, ins->dreg, mips_at, 0);
4248 case OP_LOADR8_MEMINDEX:
4249 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4250 #if _MIPS_SIM == _ABIO32
4251 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4252 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4253 #elif _MIPS_SIM == _ABIN32
4254 mips_ldc1 (code, ins->dreg, mips_at, 0);
4257 case OP_STORER4_MEMINDEX:
4258 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4259 #if PROMOTE_R4_TO_R8
4260 /* Need to convert ins->sreg1 to single-precision first */
4261 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4262 mips_swc1 (code, mips_ftemp, mips_at, 0);
4264 mips_swc1 (code, ins->sreg1, mips_at, 0);
4267 case OP_STORER8_MEMINDEX:
4268 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4269 #if _MIPS_SIM == _ABIO32
4270 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4271 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4272 #elif _MIPS_SIM == _ABIN32
4273 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4276 case OP_ICONV_TO_R_UN: {
4277 static const guint64 adjust_val = 0x41F0000000000000ULL;
4279 /* convert unsigned int to double */
4280 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4281 mips_bgez (code, ins->sreg1, 5);
4282 mips_cvtdw (code, ins->dreg, mips_ftemp);
4284 mips_load (code, mips_at, (guint32) &adjust_val);
4285 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4286 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4287 /* target is here */
4290 case OP_ICONV_TO_R4:
4291 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4292 mips_cvtsw (code, ins->dreg, mips_ftemp);
4293 mips_cvtds (code, ins->dreg, ins->dreg);
4295 case OP_ICONV_TO_R8:
4296 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4297 mips_cvtdw (code, ins->dreg, mips_ftemp);
4299 case OP_FCONV_TO_I1:
4300 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4302 case OP_FCONV_TO_U1:
4303 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4305 case OP_FCONV_TO_I2:
4306 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4308 case OP_FCONV_TO_U2:
4309 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4311 case OP_FCONV_TO_I4:
4313 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4315 case OP_FCONV_TO_U4:
4317 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4320 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4323 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4326 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4329 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4332 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4335 mips_fnegd (code, ins->dreg, ins->sreg1);
4338 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4339 mips_addiu (code, ins->dreg, mips_zero, 1);
4340 mips_fbtrue (code, 2);
4342 MIPS_MOVE (code, ins->dreg, mips_zero);
4345 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4346 mips_addiu (code, ins->dreg, mips_zero, 1);
4347 mips_fbtrue (code, 2);
4349 MIPS_MOVE (code, ins->dreg, mips_zero);
4352 /* Less than, or Unordered */
4353 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4354 mips_addiu (code, ins->dreg, mips_zero, 1);
4355 mips_fbtrue (code, 2);
4357 MIPS_MOVE (code, ins->dreg, mips_zero);
4360 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4361 MIPS_MOVE (code, ins->dreg, mips_zero);
4362 mips_fbtrue (code, 2);
4364 mips_addiu (code, ins->dreg, mips_zero, 1);
4367 /* Greater than, or Unordered */
4368 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4369 MIPS_MOVE (code, ins->dreg, mips_zero);
4370 mips_fbtrue (code, 2);
4372 mips_addiu (code, ins->dreg, mips_zero, 1);
4377 case OP_MIPS_FBLT_UN:
4379 case OP_MIPS_FBGT_UN:
4381 case OP_MIPS_FBGE_UN:
4383 case OP_MIPS_FBLE_UN: {
4385 gboolean is_true = TRUE, is_ordered = FALSE;
4386 guint32 *buf = NULL;
4388 switch (ins->opcode) {
4402 case OP_MIPS_FBLT_UN:
4403 cond = MIPS_FPU_ULT;
4411 case OP_MIPS_FBGT_UN:
4412 cond = MIPS_FPU_OLE;
4420 case OP_MIPS_FBGE_UN:
4421 cond = MIPS_FPU_OLT;
4425 cond = MIPS_FPU_OLE;
4429 case OP_MIPS_FBLE_UN:
4430 cond = MIPS_FPU_ULE;
4434 g_assert_not_reached ();
4438 /* Skip the check if unordered */
4439 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4441 buf = (guint32*)code;
4442 mips_fbtrue (code, 0);
4446 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4448 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4450 mips_fbtrue (code, 0);
4452 mips_fbfalse (code, 0);
4456 mips_patch (buf, (guint32)code);
4460 guint32 *branch_patch;
4462 mips_mfc1 (code, mips_at, ins->sreg1+1);
4463 mips_srl (code, mips_at, mips_at, 16+4);
4464 mips_andi (code, mips_at, mips_at, 2047);
4465 mips_addiu (code, mips_at, mips_at, -2047);
4467 branch_patch = (guint32 *)(void *)code;
4468 mips_bne (code, mips_at, mips_zero, 0);
4471 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4472 mips_patch (branch_patch, (guint32)code);
4473 mips_fmovd (code, ins->dreg, ins->sreg1);
4477 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4478 mips_load (code, ins->dreg, 0x0f0f0f0f);
4480 case OP_GC_SAFE_POINT:
4485 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4486 g_assert_not_reached ();
4489 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4490 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4491 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4492 g_assert_not_reached ();
4498 last_offset = offset;
4501 cfg->code_len = code - cfg->native_code;
4505 mono_arch_register_lowlevel_calls (void)
4510 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4512 MonoJumpInfo *patch_info;
4516 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4517 unsigned char *ip = patch_info->ip.i + code;
4518 const unsigned char *target = NULL;
4520 switch (patch_info->type) {
4521 case MONO_PATCH_INFO_IP:
4522 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4524 case MONO_PATCH_INFO_SWITCH: {
4525 gpointer *table = (gpointer *)patch_info->data.table->table;
4528 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4530 for (i = 0; i < patch_info->data.table->table_size; i++) {
4531 table [i] = (int)patch_info->data.table->table [i] + code;
4535 case MONO_PATCH_INFO_METHODCONST:
4536 case MONO_PATCH_INFO_CLASS:
4537 case MONO_PATCH_INFO_IMAGE:
4538 case MONO_PATCH_INFO_FIELD:
4539 case MONO_PATCH_INFO_VTABLE:
4540 case MONO_PATCH_INFO_IID:
4541 case MONO_PATCH_INFO_SFLDA:
4542 case MONO_PATCH_INFO_LDSTR:
4543 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4544 case MONO_PATCH_INFO_LDTOKEN:
4545 case MONO_PATCH_INFO_R4:
4546 case MONO_PATCH_INFO_R8:
4547 /* from OP_AOTCONST : lui + addiu */
4548 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4549 return_if_nok (error);
4551 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4554 case MONO_PATCH_INFO_EXC_NAME:
4555 g_assert_not_reached ();
4556 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4559 case MONO_PATCH_INFO_NONE:
4560 /* everything is dealt with at epilog output time */
4563 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4564 return_if_nok (error);
4566 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4573 * Allow tracing to work with this interface (with an optional argument)
4575 * This code is expected to be inserted just after the 'real' prolog code,
4576 * and before the first basic block. We need to allocate a 2nd, temporary
4577 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4581 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4584 int offset = cfg->arch.tracing_offset;
4590 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4591 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4592 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4593 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4594 #if _MIPS_SIM == _ABIN32
4596 /* FIXME: Need a separate region for these */
4597 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4598 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4599 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4600 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4604 mips_load_const (code, mips_a0, cfg->method);
4605 mips_addiu (code, mips_a1, mips_sp, offset);
4606 mips_call (code, mips_t9, func);
4609 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4610 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4611 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4612 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4613 #if _MIPS_SIM == _ABIN32
4616 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4617 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4618 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4619 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4630 mips_adjust_stackframe(MonoCompile *cfg)
4633 int delta, threshold, i;
4634 MonoMethodSignature *sig;
4637 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4640 /* adjust cfg->stack_offset for account for down-spilling */
4641 cfg->stack_offset += SIZEOF_REGISTER;
4643 /* re-align cfg->stack_offset if needed (due to var spilling) */
4644 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4645 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4646 if (cfg->verbose_level > 2) {
4647 g_print ("mips_adjust_stackframe:\n");
4648 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4650 threshold = cfg->arch.local_alloc_offset;
4651 ra_offset = cfg->stack_offset - sizeof(gpointer);
4652 if (cfg->verbose_level > 2) {
4653 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4656 sig = mono_method_signature (cfg->method);
4657 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4658 cfg->vret_addr->inst_offset += delta;
4660 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4661 MonoInst *inst = cfg->args [i];
4663 inst->inst_offset += delta;
4667 * loads and stores based off the frame reg that (used to) lie
4668 * above the spill var area need to be increased by 'delta'
4669 * to make room for the spill vars.
4671 /* Need to find loads and stores to adjust that
4672 * are above where the spillvars were inserted, but
4673 * which are not the spillvar references themselves.
4675 * Idea - since all offsets from fp are positive, make
4676 * spillvar offsets negative to begin with so we can spot
4681 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4685 if (cfg->verbose_level > 2) {
4686 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4688 MONO_BB_FOR_EACH_INS (bb, ins) {
4692 if (cfg->verbose_level > 2) {
4693 mono_print_ins_index (ins_cnt, ins);
4695 /* The == mips_sp tests catch FP spills */
4696 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4697 (ins->inst_basereg == mips_sp))) {
4698 switch (ins->opcode) {
4699 case OP_LOADI8_MEMBASE:
4700 case OP_LOADR8_MEMBASE:
4707 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4708 (ins->dreg == mips_sp))) {
4709 switch (ins->opcode) {
4710 case OP_STOREI8_MEMBASE_REG:
4711 case OP_STORER8_MEMBASE_REG:
4712 case OP_STOREI8_MEMBASE_IMM:
4720 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4723 if (ins->inst_c0 >= threshold) {
4724 ins->inst_c0 += delta;
4725 if (cfg->verbose_level > 2) {
4727 mono_print_ins_index (ins_cnt, ins);
4730 else if (ins->inst_c0 < 0) {
4731 /* Adj_c0 holds the size of the datatype. */
4732 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4733 if (cfg->verbose_level > 2) {
4735 mono_print_ins_index (ins_cnt, ins);
4738 g_assert (ins->inst_c0 != ra_offset);
4741 if (ins->inst_imm >= threshold) {
4742 ins->inst_imm += delta;
4743 if (cfg->verbose_level > 2) {
4745 mono_print_ins_index (ins_cnt, ins);
4748 g_assert (ins->inst_c0 != ra_offset);
4758 * Stack frame layout:
4760 * ------------------- sp + cfg->stack_usage + cfg->param_area
4761 * param area incoming
4762 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4764 * ------------------- sp + cfg->stack_usage
4766 * ------------------- sp + cfg->stack_usage-4
4768 * ------------------- sp +
4769 * MonoLMF structure optional
4770 * ------------------- sp + cfg->arch.lmf_offset
4771 * saved registers s0-s8
4772 * ------------------- sp + cfg->arch.iregs_offset
4774 * ------------------- sp + cfg->param_area
4775 * param area outgoing
4776 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4778 * ------------------- sp
4782 mono_arch_emit_prolog (MonoCompile *cfg)
4784 MonoMethod *method = cfg->method;
4785 MonoMethodSignature *sig;
4787 int alloc_size, pos, i, max_offset;
4788 int alloc2_size = 0;
4792 guint32 iregs_to_save = 0;
4794 guint32 fregs_to_save = 0;
4796 /* lmf_offset is the offset of the LMF from our stack pointer. */
4797 guint32 lmf_offset = cfg->arch.lmf_offset;
4801 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4805 cfg->flags |= MONO_CFG_HAS_CALLS;
4807 sig = mono_method_signature (method);
4808 cfg->code_size = 768 + sig->param_count * 20;
4809 code = cfg->native_code = g_malloc (cfg->code_size);
4812 * compute max_offset in order to use short forward jumps.
4815 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4816 MonoInst *ins = bb->code;
4817 bb->max_offset = max_offset;
4819 MONO_BB_FOR_EACH_INS (bb, ins)
4820 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4822 if (max_offset > 0xffff)
4823 cfg->arch.long_branch = TRUE;
4826 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4827 * This means that we have to adjust the offsets inside instructions which reference
4828 * arguments received on the stack, since the initial offset doesn't take into
4829 * account spill slots.
4831 mips_adjust_stackframe (cfg);
4833 /* Offset between current sp and the CFA */
4835 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4837 /* stack_offset should not be changed here. */
4838 alloc_size = cfg->stack_offset;
4839 cfg->stack_usage = alloc_size;
4841 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4844 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4846 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4847 fregs_to_save |= (fregs_to_save << 1);
4850 /* If the stack size is too big, save 1024 bytes to start with
4851 * so the prologue can use imm16(reg) addressing, then allocate
4852 * the rest of the frame.
4854 if (alloc_size > ((1 << 15) - 1024)) {
4855 alloc2_size = alloc_size - 1024;
4859 g_assert (mips_is_imm16 (-alloc_size));
4860 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4861 cfa_offset = alloc_size;
4862 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4865 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4866 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4867 if (mips_is_imm16(offset))
4868 mips_sw (code, mips_ra, mips_sp, offset);
4870 g_assert_not_reached ();
4872 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4873 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4876 /* XXX - optimize this later to not save all regs if LMF constructed */
4877 pos = cfg->arch.iregs_offset - alloc2_size;
4879 if (iregs_to_save) {
4880 /* save used registers in own stack frame (at pos) */
4881 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4882 if (iregs_to_save & (1 << i)) {
4883 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4884 g_assert (mips_is_imm16(pos));
4885 MIPS_SW (code, i, mips_sp, pos);
4886 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4887 pos += SIZEOF_REGISTER;
4892 // FIXME: Don't save registers twice if there is an LMF
4893 // s8 has to be special cased since it is overwritten with the updated value
4895 if (method->save_lmf) {
4896 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4897 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4898 g_assert (mips_is_imm16(offset));
4899 if (MIPS_LMF_IREGMASK & (1 << i))
4900 MIPS_SW (code, i, mips_sp, offset);
4905 /* Save float registers */
4906 if (fregs_to_save) {
4907 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4908 if (fregs_to_save & (1 << i)) {
4909 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4910 g_assert (mips_is_imm16(pos));
4911 mips_swc1 (code, i, mips_sp, pos);
4912 pos += sizeof (gulong);
4917 if (method->save_lmf) {
4918 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4919 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4920 g_assert (mips_is_imm16(offset));
4921 mips_swc1 (code, i, mips_sp, offset);
4926 if (cfg->frame_reg != mips_sp) {
4927 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4928 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4930 if (method->save_lmf) {
4931 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4932 g_assert (mips_is_imm16(offset));
4933 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4937 /* store runtime generic context */
4938 if (cfg->rgctx_var) {
4939 MonoInst *ins = cfg->rgctx_var;
4941 g_assert (ins->opcode == OP_REGOFFSET);
4943 g_assert (mips_is_imm16 (ins->inst_offset));
4944 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4947 /* load arguments allocated to register from the stack */
4950 if (!cfg->arch.cinfo)
4951 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
4952 cinfo = cfg->arch.cinfo;
4954 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4955 ArgInfo *ainfo = &cinfo->ret;
4956 inst = cfg->vret_addr;
4957 if (inst->opcode == OP_REGVAR)
4958 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4959 else if (mips_is_imm16 (inst->inst_offset)) {
4960 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4962 mips_load_const (code, mips_at, inst->inst_offset);
4963 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4964 mips_sw (code, ainfo->reg, mips_at, 0);
4968 if (sig->call_convention == MONO_CALL_VARARG) {
4969 ArgInfo *cookie = &cinfo->sig_cookie;
4970 int offset = alloc_size + cookie->offset;
4972 /* Save the sig cookie address */
4973 g_assert (cookie->storage == ArgOnStack);
4975 g_assert (mips_is_imm16(offset));
4976 mips_addi (code, mips_at, cfg->frame_reg, offset);
4977 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
4980 /* Keep this in sync with emit_load_volatile_arguments */
4981 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4982 ArgInfo *ainfo = cinfo->args + i;
4983 inst = cfg->args [pos];
4985 if (cfg->verbose_level > 2)
4986 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
4987 if (inst->opcode == OP_REGVAR) {
4988 /* Argument ends up in a register */
4989 if (ainfo->storage == ArgInIReg)
4990 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4991 else if (ainfo->storage == ArgInFReg) {
4992 g_assert_not_reached();
4994 ppc_fmr (code, inst->dreg, ainfo->reg);
4997 else if (ainfo->storage == ArgOnStack) {
4998 int offset = cfg->stack_usage + ainfo->offset;
4999 g_assert (mips_is_imm16(offset));
5000 mips_lw (code, inst->dreg, mips_sp, offset);
5002 g_assert_not_reached ();
5004 if (cfg->verbose_level > 2)
5005 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5007 /* Argument ends up on the stack */
5008 if (ainfo->storage == ArgInIReg) {
5010 /* Incoming parameters should be above this frame */
5011 if (cfg->verbose_level > 2)
5012 g_print ("stack slot at %d of %d+%d\n",
5013 inst->inst_offset, alloc_size, alloc2_size);
5014 /* g_assert (inst->inst_offset >= alloc_size); */
5015 g_assert (inst->inst_basereg == cfg->frame_reg);
5016 basereg_offset = inst->inst_offset - alloc2_size;
5017 g_assert (mips_is_imm16 (basereg_offset));
5018 switch (ainfo->size) {
5020 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5023 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5027 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5030 #if (SIZEOF_REGISTER == 4)
5031 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5032 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5033 #elif (SIZEOF_REGISTER == 8)
5034 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5038 g_assert_not_reached ();
5041 } else if (ainfo->storage == ArgOnStack) {
5043 * Argument comes in on the stack, and ends up on the stack
5044 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5045 * 8 and 16 bit quantities. Shorten them in place.
5047 g_assert (mips_is_imm16 (inst->inst_offset));
5048 switch (ainfo->size) {
5050 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5051 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5054 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5055 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5062 g_assert_not_reached ();
5064 } else if (ainfo->storage == ArgInFReg) {
5065 g_assert (mips_is_imm16 (inst->inst_offset));
5066 g_assert (mips_is_imm16 (inst->inst_offset+4));
5067 if (ainfo->size == 8) {
5068 #if _MIPS_SIM == _ABIO32
5069 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5070 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5071 #elif _MIPS_SIM == _ABIN32
5072 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5075 else if (ainfo->size == 4)
5076 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5078 g_assert_not_reached ();
5079 } else if (ainfo->storage == ArgStructByVal) {
5081 int doffset = inst->inst_offset;
5083 g_assert (mips_is_imm16 (inst->inst_offset));
5084 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5085 /* Push the argument registers into their stack slots */
5086 for (i = 0; i < ainfo->size; ++i) {
5087 g_assert (mips_is_imm16(doffset));
5088 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5089 doffset += SIZEOF_REGISTER;
5091 } else if (ainfo->storage == ArgStructByAddr) {
5092 g_assert (mips_is_imm16 (inst->inst_offset));
5093 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5094 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5096 g_assert_not_reached ();
5101 if (method->save_lmf) {
5102 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5103 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5105 /* This can/will clobber the a0-a3 registers */
5106 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5108 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5109 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5110 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5111 /* new_lmf->previous_lmf = *lmf_addr */
5112 mips_lw (code, mips_at, mips_v0, 0);
5113 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5114 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5115 /* *(lmf_addr) = sp + lmf_offset */
5116 g_assert (mips_is_imm16(lmf_offset));
5117 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5118 mips_sw (code, mips_at, mips_v0, 0);
5120 /* save method info */
5121 mips_load_const (code, mips_at, method);
5122 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5123 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5125 /* save the current IP */
5126 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5127 mips_load_const (code, mips_at, 0x01010101);
5128 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5132 if (mips_is_imm16 (-alloc2_size)) {
5133 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5136 mips_load_const (code, mips_at, -alloc2_size);
5137 mips_addu (code, mips_sp, mips_sp, mips_at);
5139 alloc_size += alloc2_size;
5140 cfa_offset += alloc2_size;
5141 if (cfg->frame_reg != mips_sp)
5142 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5144 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5148 #if _MIPS_SIM == _ABIO32
5149 cfg->arch.tracing_offset = cfg->stack_offset;
5150 #elif _MIPS_SIM == _ABIN32
5151 /* no stack slots by default for argument regs, reserve a special block */
5152 g_assert_not_reached ();
5154 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5157 cfg->code_len = code - cfg->native_code;
5158 g_assert (cfg->code_len < cfg->code_size);
5172 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5175 int save_mode = SAVE_NONE;
5177 MonoMethod *method = cfg->method;
5178 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5179 int save_offset = MIPS_STACK_PARAM_OFFSET;
5181 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5183 offset = code - cfg->native_code;
5184 /* we need about 16 instructions */
5185 if (offset > (cfg->code_size - 16 * 4)) {
5186 cfg->code_size *= 2;
5187 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5188 code = cfg->native_code + offset;
5193 case MONO_TYPE_VOID:
5194 /* special case string .ctor icall */
5195 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5196 save_mode = SAVE_ONE;
5198 save_mode = SAVE_NONE;
5202 save_mode = SAVE_FP;
5204 case MONO_TYPE_VALUETYPE:
5205 save_mode = SAVE_STRUCT;
5209 #if SIZEOF_REGISTER == 4
5210 save_mode = SAVE_TWO;
5211 #elif SIZEOF_REGISTER == 8
5212 save_mode = SAVE_ONE;
5216 save_mode = SAVE_ONE;
5220 mips_addiu (code, mips_sp, mips_sp, -32);
5221 g_assert (mips_is_imm16(save_offset));
5222 switch (save_mode) {
5224 mips_sw (code, mips_v0, mips_sp, save_offset);
5225 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5226 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5227 if (enable_arguments) {
5228 MIPS_MOVE (code, mips_a1, mips_v0);
5229 MIPS_MOVE (code, mips_a2, mips_v1);
5233 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5234 if (enable_arguments) {
5235 MIPS_MOVE (code, mips_a1, mips_v0);
5239 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5240 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5241 mips_lw (code, mips_a0, mips_sp, save_offset);
5242 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5243 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5250 mips_load_const (code, mips_a0, cfg->method);
5251 mips_call (code, mips_t9, func);
5253 switch (save_mode) {
5255 mips_lw (code, mips_v0, mips_sp, save_offset);
5256 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5257 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5260 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5263 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5270 mips_addiu (code, mips_sp, mips_sp, 32);
5277 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5279 MonoMethod *method = cfg->method;
5281 int max_epilog_size = 16 + 20*4;
5282 int alloc2_size = 0;
5283 guint32 iregs_to_restore;
5285 guint32 fregs_to_restore;
5288 if (cfg->method->save_lmf)
5289 max_epilog_size += 128;
5291 if (mono_jit_trace_calls != NULL)
5292 max_epilog_size += 50;
5295 pos = code - cfg->native_code;
5296 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5297 cfg->code_size *= 2;
5298 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5299 cfg->stat_code_reallocs++;
5303 * Keep in sync with OP_JMP
5306 code = cfg->native_code + pos;
5308 code = cfg->native_code + cfg->code_len;
5310 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5311 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5313 if (cfg->frame_reg != mips_sp) {
5314 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5316 /* If the stack frame is really large, deconstruct it in two steps */
5317 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5318 alloc2_size = cfg->stack_usage - 1024;
5319 /* partially deconstruct the stack */
5320 mips_load_const (code, mips_at, alloc2_size);
5321 mips_addu (code, mips_sp, mips_sp, mips_at);
5323 pos = cfg->arch.iregs_offset - alloc2_size;
5324 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5325 if (iregs_to_restore) {
5326 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5327 if (iregs_to_restore & (1 << i)) {
5328 g_assert (mips_is_imm16(pos));
5329 MIPS_LW (code, i, mips_sp, pos);
5330 pos += SIZEOF_REGISTER;
5337 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5339 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5340 fregs_to_restore |= (fregs_to_restore << 1);
5342 if (fregs_to_restore) {
5343 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5344 if (fregs_to_restore & (1 << i)) {
5345 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5346 g_assert (mips_is_imm16(pos));
5347 mips_lwc1 (code, i, mips_sp, pos);
5354 /* Unlink the LMF if necessary */
5355 if (method->save_lmf) {
5356 int lmf_offset = cfg->arch.lmf_offset;
5358 /* t0 = current_lmf->previous_lmf */
5359 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5360 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5362 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5363 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5364 /* (*lmf_addr) = previous_lmf */
5365 mips_sw (code, mips_temp, mips_t1, 0);
5369 /* Restore the fp */
5370 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5373 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5374 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5375 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5377 /* Restore the stack pointer */
5378 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5379 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5381 /* Caller will emit either return or tail-call sequence */
5383 cfg->code_len = code - cfg->native_code;
5385 g_assert (cfg->code_len < cfg->code_size);
5390 mono_arch_emit_epilog (MonoCompile *cfg)
5394 code = mono_arch_emit_epilog_sub (cfg, NULL);
5396 mips_jr (code, mips_ra);
5399 cfg->code_len = code - cfg->native_code;
5401 g_assert (cfg->code_len < cfg->code_size);
5404 /* remove once throw_exception_by_name is eliminated */
5407 exception_id_by_name (const char *name)
5409 if (strcmp (name, "IndexOutOfRangeException") == 0)
5410 return MONO_EXC_INDEX_OUT_OF_RANGE;
5411 if (strcmp (name, "OverflowException") == 0)
5412 return MONO_EXC_OVERFLOW;
5413 if (strcmp (name, "ArithmeticException") == 0)
5414 return MONO_EXC_ARITHMETIC;
5415 if (strcmp (name, "DivideByZeroException") == 0)
5416 return MONO_EXC_DIVIDE_BY_ZERO;
5417 if (strcmp (name, "InvalidCastException") == 0)
5418 return MONO_EXC_INVALID_CAST;
5419 if (strcmp (name, "NullReferenceException") == 0)
5420 return MONO_EXC_NULL_REF;
5421 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5422 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5423 if (strcmp (name, "ArgumentException") == 0)
5424 return MONO_EXC_ARGUMENT;
5425 g_error ("Unknown intrinsic exception %s\n", name);
5431 mono_arch_emit_exceptions (MonoCompile *cfg)
5434 MonoJumpInfo *patch_info;
5437 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5438 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5439 int max_epilog_size = 50;
5441 /* count the number of exception infos */
5444 * make sure we have enough space for exceptions
5445 * 24 is the simulated call to throw_exception_by_name
5447 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5449 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5450 i = exception_id_by_name (patch_info->data.target);
5451 g_assert (i < MONO_EXC_INTRINS_NUM);
5452 if (!exc_throw_found [i]) {
5453 max_epilog_size += 12;
5454 exc_throw_found [i] = TRUE;
5460 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5461 cfg->code_size *= 2;
5462 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5463 cfg->stat_code_reallocs++;
5466 code = cfg->native_code + cfg->code_len;
5468 /* add code to raise exceptions */
5469 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5470 switch (patch_info->type) {
5471 case MONO_PATCH_INFO_EXC: {
5473 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5475 i = exception_id_by_name (patch_info->data.target);
5476 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5477 if (!exc_throw_pos [i]) {
5480 exc_throw_pos [i] = code;
5481 //g_print ("exc: writing stub at %p\n", code);
5482 mips_load_const (code, mips_a0, patch_info->data.target);
5483 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5484 mips_load_const (code, mips_t9, addr);
5485 mips_jr (code, mips_t9);
5488 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5490 /* Turn into a Relative patch, pointing at code stub */
5491 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5492 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5494 g_assert_not_reached();
5504 cfg->code_len = code - cfg->native_code;
5506 g_assert (cfg->code_len < cfg->code_size);
5511 mono_arch_finish_init (void)
5516 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5521 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5523 int this_dreg = mips_a0;
5526 this_dreg = mips_a1;
5528 /* add the this argument */
5529 if (this_reg != -1) {
5531 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5532 this_ins->type = this_type;
5533 this_ins->sreg1 = this_reg;
5534 this_ins->dreg = mono_alloc_ireg (cfg);
5535 mono_bblock_add_inst (cfg->cbb, this_ins);
5536 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5541 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5542 vtarg->type = STACK_MP;
5543 vtarg->sreg1 = vt_reg;
5544 vtarg->dreg = mono_alloc_ireg (cfg);
5545 mono_bblock_add_inst (cfg->cbb, vtarg);
5546 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5551 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5553 MonoInst *ins = NULL;
5559 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5565 mono_arch_print_tree (MonoInst *tree, int arity)
5571 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5573 return ctx->sc_regs [reg];
5576 #define ENABLE_WRONG_METHOD_CHECK 0
5578 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5579 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5581 #define LOADSTORE_SIZE 4
5582 #define JUMP_IMM_SIZE 16
5583 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5584 #define LOAD_CONST_SIZE 8
5585 #define JUMP_JR_SIZE 8
5588 * LOCKING: called with the domain lock held
5591 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5592 gpointer fail_tramp)
5596 guint8 *code, *start, *patch;
5598 for (i = 0; i < count; ++i) {
5599 MonoIMTCheckItem *item = imt_entries [i];
5601 if (item->is_equals) {
5602 if (item->check_target_idx) {
5603 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5604 if (item->has_target_code)
5605 item->chunk_size += LOAD_CONST_SIZE;
5607 item->chunk_size += LOADSTORE_SIZE;
5610 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5611 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5612 if (!item->has_target_code)
5613 item->chunk_size += LOADSTORE_SIZE;
5615 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5616 #if ENABLE_WRONG_METHOD_CHECK
5617 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5622 item->chunk_size += CMP_SIZE + BR_SIZE;
5623 imt_entries [item->check_target_idx]->compare_done = TRUE;
5625 size += item->chunk_size;
5627 /* the initial load of the vtable address */
5628 size += MIPS_LOAD_SEQUENCE_LENGTH;
5630 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5632 code = mono_domain_code_reserve (domain, size);
5636 /* t7 points to the vtable */
5637 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5639 for (i = 0; i < count; ++i) {
5640 MonoIMTCheckItem *item = imt_entries [i];
5642 item->code_target = code;
5643 if (item->is_equals) {
5644 if (item->check_target_idx) {
5645 mips_load_const (code, mips_temp, (gsize)item->key);
5646 item->jmp_code = code;
5647 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5649 if (item->has_target_code) {
5650 mips_load_const (code, mips_t9,
5651 item->value.target_code);
5654 mips_lw (code, mips_t9, mips_t7,
5655 (sizeof (gpointer) * item->value.vtable_slot));
5657 mips_jr (code, mips_t9);
5661 mips_load_const (code, mips_temp, (gsize)item->key);
5663 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5665 if (item->has_target_code) {
5666 mips_load_const (code, mips_t9,
5667 item->value.target_code);
5670 mips_load_const (code, mips_at,
5671 & (vtable->vtable [item->value.vtable_slot]));
5672 mips_lw (code, mips_t9, mips_at, 0);
5674 mips_jr (code, mips_t9);
5676 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5677 mips_load_const (code, mips_t9, fail_tramp);
5678 mips_jr (code, mips_t9);
5681 /* enable the commented code to assert on wrong method */
5682 #if ENABLE_WRONG_METHOD_CHECK
5683 ppc_load (code, ppc_r0, (guint32)item->key);
5684 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5686 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5688 mips_lw (code, mips_t9, mips_t7,
5689 (sizeof (gpointer) * item->value.vtable_slot));
5690 mips_jr (code, mips_t9);
5693 #if ENABLE_WRONG_METHOD_CHECK
5694 ppc_patch (patch, code);
5700 mips_load_const (code, mips_temp, (gulong)item->key);
5701 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5703 item->jmp_code = code;
5704 mips_beq (code, mips_temp, mips_zero, 0);
5708 /* patch the branches to get to the target items */
5709 for (i = 0; i < count; ++i) {
5710 MonoIMTCheckItem *item = imt_entries [i];
5711 if (item->jmp_code && item->check_target_idx) {
5712 mips_patch ((guint32 *)item->jmp_code,
5713 (guint32)imt_entries [item->check_target_idx]->code_target);
5718 mono_stats.imt_trampolines_size += code - start;
5719 g_assert (code - start <= size);
5720 mono_arch_flush_icache (start, size);
5722 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5728 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5730 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5734 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5736 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5739 /* Soft Debug support */
5740 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5743 * mono_arch_set_breakpoint:
5745 * See mini-amd64.c for docs.
5748 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5751 guint32 addr = (guint32)bp_trigger_page;
5753 mips_load_const (code, mips_t9, addr);
5754 mips_lw (code, mips_t9, mips_t9, 0);
5756 mono_arch_flush_icache (ip, code - ip);
5760 * mono_arch_clear_breakpoint:
5762 * See mini-amd64.c for docs.
5765 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5773 mono_arch_flush_icache (ip, code - ip);
5777 * mono_arch_start_single_stepping:
5779 * See mini-amd64.c for docs.
5782 mono_arch_start_single_stepping (void)
5784 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5788 * mono_arch_stop_single_stepping:
5790 * See mini-amd64.c for docs.
5793 mono_arch_stop_single_stepping (void)
5795 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5799 * mono_arch_is_single_step_event:
5801 * See mini-amd64.c for docs.
5804 mono_arch_is_single_step_event (void *info, void *sigctx)
5806 siginfo_t* sinfo = (siginfo_t*) info;
5807 /* Sometimes the address is off by 4 */
5808 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5815 * mono_arch_is_breakpoint_event:
5817 * See mini-amd64.c for docs.
5820 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5822 siginfo_t* sinfo = (siginfo_t*) info;
5823 /* Sometimes the address is off by 4 */
5824 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5831 * mono_arch_skip_breakpoint:
5833 * See mini-amd64.c for docs.
5836 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5838 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5842 * mono_arch_skip_single_step:
5844 * See mini-amd64.c for docs.
5847 mono_arch_skip_single_step (MonoContext *ctx)
5849 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5853 * mono_arch_get_seq_point_info:
5855 * See mini-amd64.c for docs.
5858 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5865 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5867 ext->lmf.previous_lmf = prev_lmf;
5868 /* Mark that this is a MonoLMFExt */
5869 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5870 ext->lmf.iregs [mips_sp] = (gssize)ext;
5873 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5876 mono_arch_opcode_supported (int opcode)