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) {
1117 case MONO_TYPE_BOOLEAN:
1120 DEBUG(printf("1 byte\n"));
1121 cinfo->args [n].size = 1;
1122 add_int32_arg (cinfo, &cinfo->args[n]);
1125 case MONO_TYPE_CHAR:
1128 DEBUG(printf("2 bytes\n"));
1129 cinfo->args [n].size = 2;
1130 add_int32_arg (cinfo, &cinfo->args[n]);
1135 DEBUG(printf("4 bytes\n"));
1136 cinfo->args [n].size = 4;
1137 add_int32_arg (cinfo, &cinfo->args[n]);
1143 case MONO_TYPE_FNPTR:
1144 case MONO_TYPE_CLASS:
1145 case MONO_TYPE_OBJECT:
1146 case MONO_TYPE_STRING:
1147 case MONO_TYPE_SZARRAY:
1148 case MONO_TYPE_ARRAY:
1149 cinfo->args [n].size = sizeof (gpointer);
1150 add_int32_arg (cinfo, &cinfo->args[n]);
1153 case MONO_TYPE_GENERICINST:
1154 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1155 cinfo->args [n].size = sizeof (gpointer);
1156 add_int32_arg (cinfo, &cinfo->args[n]);
1161 case MONO_TYPE_TYPEDBYREF:
1162 case MONO_TYPE_VALUETYPE: {
1165 int has_offset = FALSE;
1167 gint size, alignment;
1170 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1171 size = sizeof (MonoTypedRef);
1172 alignment = sizeof (gpointer);
1174 klass = mono_class_from_mono_type (sig->params [i]);
1176 size = mono_class_native_size (klass, NULL);
1178 size = mono_class_value_size (klass, NULL);
1179 alignment = mono_class_min_align (klass);
1181 #if MIPS_PASS_STRUCTS_BY_VALUE
1182 /* Need to do alignment if struct contains long or double */
1183 if (alignment > 4) {
1184 /* Drop onto stack *before* looking at
1185 stack_size, if required. */
1186 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1187 args_onto_stack (cinfo);
1188 if (cinfo->stack_size & (alignment - 1)) {
1189 add_int32_arg (cinfo, &dummy_arg);
1191 g_assert (!(cinfo->stack_size & (alignment - 1)));
1195 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1196 mono_class_native_size (sig->params [i]->data.klass, NULL),
1197 cinfo->stack_size, alignment);
1199 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1200 g_assert (cinfo->args [n].size == 0);
1201 g_assert (cinfo->args [n].vtsize == 0);
1202 for (j = 0; j < nwords; ++j) {
1204 add_int32_arg (cinfo, &cinfo->args [n]);
1205 if (cinfo->on_stack)
1208 add_int32_arg (cinfo, &dummy_arg);
1209 if (!has_offset && cinfo->on_stack) {
1210 cinfo->args [n].offset = dummy_arg.offset;
1214 if (cinfo->on_stack)
1215 cinfo->args [n].vtsize += 1;
1217 cinfo->args [n].size += 1;
1219 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1220 cinfo->args [n].storage = ArgStructByVal;
1222 add_int32_arg (cinfo, &cinfo->args[n]);
1223 cinfo->args [n].storage = ArgStructByAddr;
1230 DEBUG(printf("8 bytes\n"));
1231 cinfo->args [n].size = 8;
1232 add_int64_arg (cinfo, &cinfo->args[n]);
1236 DEBUG(printf("R4\n"));
1237 cinfo->args [n].size = 4;
1238 add_float32_arg (cinfo, &cinfo->args[n]);
1242 DEBUG(printf("R8\n"));
1243 cinfo->args [n].size = 8;
1244 add_float64_arg (cinfo, &cinfo->args[n]);
1248 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1252 /* Handle the case where there are no implicit arguments */
1253 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1254 /* Prevent implicit arguments and sig_cookie from
1255 being passed in registers */
1256 args_onto_stack (cinfo);
1257 /* Emit the signature cookie just before the implicit arguments */
1258 add_int32_arg (cinfo, &cinfo->sig_cookie);
1262 simpletype = mini_get_underlying_type (sig->ret);
1263 switch (simpletype->type) {
1264 case MONO_TYPE_BOOLEAN:
1269 case MONO_TYPE_CHAR:
1275 case MONO_TYPE_FNPTR:
1276 case MONO_TYPE_CLASS:
1277 case MONO_TYPE_OBJECT:
1278 case MONO_TYPE_SZARRAY:
1279 case MONO_TYPE_ARRAY:
1280 case MONO_TYPE_STRING:
1281 cinfo->ret.reg = mips_v0;
1285 cinfo->ret.reg = mips_v0;
1289 cinfo->ret.reg = mips_f0;
1290 cinfo->ret.storage = ArgInFReg;
1292 case MONO_TYPE_GENERICINST:
1293 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1294 cinfo->ret.reg = mips_v0;
1298 case MONO_TYPE_VALUETYPE:
1299 case MONO_TYPE_TYPEDBYREF:
1301 case MONO_TYPE_VOID:
1304 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1308 /* align stack size to 16 */
1309 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1311 cinfo->stack_usage = cinfo->stack_size;
1316 debug_omit_fp (void)
1319 return mono_debug_count ();
1326 * mono_arch_compute_omit_fp:
1328 * Determine whenever the frame pointer can be eliminated.
1331 mono_arch_compute_omit_fp (MonoCompile *cfg)
1333 MonoMethodSignature *sig;
1334 MonoMethodHeader *header;
1338 if (cfg->arch.omit_fp_computed)
1341 header = cfg->header;
1343 sig = mono_method_signature (cfg->method);
1345 if (!cfg->arch.cinfo)
1346 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1347 cinfo = cfg->arch.cinfo;
1350 * FIXME: Remove some of the restrictions.
1352 cfg->arch.omit_fp = TRUE;
1353 cfg->arch.omit_fp_computed = TRUE;
1355 if (cfg->disable_omit_fp)
1356 cfg->arch.omit_fp = FALSE;
1357 if (!debug_omit_fp ())
1358 cfg->arch.omit_fp = FALSE;
1359 if (cfg->method->save_lmf)
1360 cfg->arch.omit_fp = FALSE;
1361 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1362 cfg->arch.omit_fp = FALSE;
1363 if (header->num_clauses)
1364 cfg->arch.omit_fp = FALSE;
1365 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1366 cfg->arch.omit_fp = FALSE;
1367 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1368 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1369 cfg->arch.omit_fp = FALSE;
1371 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1372 * there are stack arguments.
1375 if (cinfo->stack_usage)
1376 cfg->arch.omit_fp = FALSE;
1380 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1381 MonoInst *ins = cfg->varinfo [i];
1384 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1387 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1391 * Set var information according to the calling convention. mips version.
1392 * The locals var stuff should most likely be split in another method.
1395 mono_arch_allocate_vars (MonoCompile *cfg)
1397 MonoMethodSignature *sig;
1398 MonoMethodHeader *header;
1400 int i, offset, size, align, curinst;
1401 int frame_reg = mips_sp;
1402 guint32 iregs_to_save = 0;
1404 guint32 fregs_to_restore;
1408 sig = mono_method_signature (cfg->method);
1410 if (!cfg->arch.cinfo)
1411 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1412 cinfo = cfg->arch.cinfo;
1414 mono_arch_compute_omit_fp (cfg);
1416 /* spill down, we'll fix it in a separate pass */
1417 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1419 /* allow room for the vararg method args: void* and long/double */
1420 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1421 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1423 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1424 * call convs needs to be handled this way.
1426 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1427 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1429 /* gtk-sharp and other broken code will dllimport vararg functions even with
1430 * non-varargs signatures. Since there is little hope people will get this right
1431 * we assume they won't.
1433 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1434 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1436 /* a0-a3 always present */
1437 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1439 header = cfg->header;
1441 if (cfg->arch.omit_fp)
1442 frame_reg = mips_sp;
1444 frame_reg = mips_fp;
1445 cfg->frame_reg = frame_reg;
1446 if (frame_reg != mips_sp) {
1447 cfg->used_int_regs |= 1 << frame_reg;
1452 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1453 /* FIXME: handle long and FP values */
1454 switch (mini_get_underlying_type (sig->ret)->type) {
1455 case MONO_TYPE_VOID:
1459 cfg->ret->opcode = OP_REGVAR;
1460 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1463 cfg->ret->opcode = OP_REGVAR;
1464 cfg->ret->inst_c0 = mips_v0;
1468 /* Space for outgoing parameters, including a0-a3 */
1469 offset += cfg->param_area;
1471 /* allow room to save the return value (if it's a struct) */
1472 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1475 /* Now handle the local variables */
1477 curinst = cfg->locals_start;
1478 for (i = curinst; i < cfg->num_varinfo; ++i) {
1479 inst = cfg->varinfo [i];
1480 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1483 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1484 * pinvoke wrappers when they call functions returning structure
1486 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1487 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1489 size = mono_type_size (inst->inst_vtype, &align);
1491 offset += align - 1;
1492 offset &= ~(align - 1);
1493 inst->inst_offset = offset;
1494 inst->opcode = OP_REGOFFSET;
1495 inst->inst_basereg = frame_reg;
1497 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1500 /* Space for LMF (if needed) */
1501 if (cfg->method->save_lmf) {
1502 /* align the offset to 16 bytes */
1503 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1504 cfg->arch.lmf_offset = offset;
1505 offset += sizeof (MonoLMF);
1508 if (sig->call_convention == MONO_CALL_VARARG) {
1512 /* Allocate a local slot to hold the sig cookie address */
1513 offset += align - 1;
1514 offset &= ~(align - 1);
1515 cfg->sig_cookie = offset;
1519 offset += SIZEOF_REGISTER - 1;
1520 offset &= ~(SIZEOF_REGISTER - 1);
1522 /* Space for saved registers */
1523 cfg->arch.iregs_offset = offset;
1524 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1525 if (iregs_to_save) {
1526 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1527 if (iregs_to_save & (1 << i)) {
1528 offset += SIZEOF_REGISTER;
1533 /* saved float registers */
1535 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1536 if (fregs_to_restore) {
1537 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1538 if (fregs_to_restore & (1 << i)) {
1539 offset += sizeof(double);
1545 #if _MIPS_SIM == _ABIO32
1546 /* Now add space for saving the ra */
1547 offset += SIZEOF_VOID_P;
1550 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1551 cfg->stack_offset = offset;
1552 cfg->arch.local_alloc_offset = cfg->stack_offset;
1556 * Now allocate stack slots for the int arg regs (a0 - a3)
1557 * On MIPS o32, these are just above the incoming stack pointer
1558 * Even if the arg has been assigned to a regvar, it gets a stack slot
1561 /* Return struct-by-value results in a hidden first argument */
1562 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1563 cfg->vret_addr->opcode = OP_REGOFFSET;
1564 cfg->vret_addr->inst_c0 = mips_a0;
1565 cfg->vret_addr->inst_offset = offset;
1566 cfg->vret_addr->inst_basereg = frame_reg;
1567 offset += SIZEOF_REGISTER;
1570 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1571 inst = cfg->args [i];
1572 if (inst->opcode != OP_REGVAR) {
1575 if (sig->hasthis && (i == 0))
1576 arg_type = &mono_defaults.object_class->byval_arg;
1578 arg_type = sig->params [i - sig->hasthis];
1580 inst->opcode = OP_REGOFFSET;
1581 size = mono_type_size (arg_type, &align);
1583 if (size < SIZEOF_REGISTER) {
1584 size = SIZEOF_REGISTER;
1585 align = SIZEOF_REGISTER;
1587 inst->inst_basereg = frame_reg;
1588 offset = (offset + align - 1) & ~(align - 1);
1589 inst->inst_offset = offset;
1591 if (cfg->verbose_level > 1)
1592 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1595 #if _MIPS_SIM == _ABIO32
1596 /* o32: Even a0-a3 get stack slots */
1597 size = SIZEOF_REGISTER;
1598 align = SIZEOF_REGISTER;
1599 inst->inst_basereg = frame_reg;
1600 offset = (offset + align - 1) & ~(align - 1);
1601 inst->inst_offset = offset;
1603 if (cfg->verbose_level > 1)
1604 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1608 #if _MIPS_SIM == _ABIN32
1609 /* Now add space for saving the ra */
1610 offset += SIZEOF_VOID_P;
1613 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1614 cfg->stack_offset = offset;
1615 cfg->arch.local_alloc_offset = cfg->stack_offset;
1620 mono_arch_create_vars (MonoCompile *cfg)
1622 MonoMethodSignature *sig;
1624 sig = mono_method_signature (cfg->method);
1626 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1627 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1628 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1629 printf ("vret_addr = ");
1630 mono_print_ins (cfg->vret_addr);
1635 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1636 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1640 * take the arguments and generate the arch-specific
1641 * instructions to properly call the function in call.
1642 * This includes pushing, moving arguments to the right register
1644 * Issue: who does the spilling if needed, and when?
1647 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1649 MonoMethodSignature *tmp_sig;
1652 if (call->tail_call)
1655 /* FIXME: Add support for signature tokens to AOT */
1656 cfg->disable_aot = TRUE;
1659 * mono_ArgIterator_Setup assumes the signature cookie is
1660 * passed first and all the arguments which were before it are
1661 * passed on the stack after the signature. So compensate by
1662 * passing a different signature.
1664 tmp_sig = mono_metadata_signature_dup (call->signature);
1665 tmp_sig->param_count -= call->signature->sentinelpos;
1666 tmp_sig->sentinelpos = 0;
1667 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1669 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1670 sig_arg->dreg = mono_alloc_ireg (cfg);
1671 sig_arg->inst_p0 = tmp_sig;
1672 MONO_ADD_INS (cfg->cbb, sig_arg);
1674 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1678 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1681 MonoMethodSignature *sig;
1686 sig = call->signature;
1687 n = sig->param_count + sig->hasthis;
1689 cinfo = get_call_info (cfg->mempool, sig);
1690 if (cinfo->struct_ret)
1691 call->used_iregs |= 1 << cinfo->struct_ret;
1693 for (i = 0; i < n; ++i) {
1694 ArgInfo *ainfo = cinfo->args + i;
1697 if (i >= sig->hasthis)
1698 t = sig->params [i - sig->hasthis];
1700 t = &mono_defaults.int_class->byval_arg;
1701 t = mini_get_underlying_type (t);
1703 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1704 /* Emit the signature cookie just before the implicit arguments */
1705 emit_sig_cookie (cfg, call, cinfo);
1708 if (is_virtual && i == 0) {
1709 /* the argument will be attached to the call instrucion */
1710 in = call->args [i];
1711 call->used_iregs |= 1 << ainfo->reg;
1714 in = call->args [i];
1715 if (ainfo->storage == ArgInIReg) {
1716 #if SIZEOF_REGISTER == 4
1717 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1718 MONO_INST_NEW (cfg, ins, OP_MOVE);
1719 ins->dreg = mono_alloc_ireg (cfg);
1720 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1721 MONO_ADD_INS (cfg->cbb, ins);
1722 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1724 MONO_INST_NEW (cfg, ins, OP_MOVE);
1725 ins->dreg = mono_alloc_ireg (cfg);
1726 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1727 MONO_ADD_INS (cfg->cbb, ins);
1728 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1731 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1734 #if PROMOTE_R4_TO_R8
1735 /* ??? - convert to single first? */
1736 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1737 ins->dreg = mono_alloc_freg (cfg);
1738 ins->sreg1 = in->dreg;
1739 MONO_ADD_INS (cfg->cbb, ins);
1744 /* trying to load float value into int registers */
1745 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1746 ins->dreg = mono_alloc_ireg (cfg);
1748 MONO_ADD_INS (cfg->cbb, ins);
1749 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1750 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1751 /* trying to load float value into int registers */
1752 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1753 ins->dreg = mono_alloc_ireg (cfg);
1754 ins->sreg1 = in->dreg;
1755 MONO_ADD_INS (cfg->cbb, ins);
1756 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1758 MONO_INST_NEW (cfg, ins, OP_MOVE);
1759 ins->dreg = mono_alloc_ireg (cfg);
1760 ins->sreg1 = in->dreg;
1761 MONO_ADD_INS (cfg->cbb, ins);
1762 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1764 } else if (ainfo->storage == ArgStructByAddr) {
1765 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1766 ins->opcode = OP_OUTARG_VT;
1767 ins->sreg1 = in->dreg;
1768 ins->klass = in->klass;
1769 ins->inst_p0 = call;
1770 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1771 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1772 MONO_ADD_INS (cfg->cbb, ins);
1773 } else if (ainfo->storage == ArgStructByVal) {
1774 /* this is further handled in mono_arch_emit_outarg_vt () */
1775 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1776 ins->opcode = OP_OUTARG_VT;
1777 ins->sreg1 = in->dreg;
1778 ins->klass = in->klass;
1779 ins->inst_p0 = call;
1780 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1781 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1782 MONO_ADD_INS (cfg->cbb, ins);
1783 } else if (ainfo->storage == ArgOnStack) {
1784 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1785 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1786 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1787 if (t->type == MONO_TYPE_R8)
1788 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1790 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1792 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1794 } else if (ainfo->storage == ArgInFReg) {
1795 if (t->type == MONO_TYPE_VALUETYPE) {
1796 /* this is further handled in mono_arch_emit_outarg_vt () */
1797 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1798 ins->opcode = OP_OUTARG_VT;
1799 ins->sreg1 = in->dreg;
1800 ins->klass = in->klass;
1801 ins->inst_p0 = call;
1802 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1803 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1804 MONO_ADD_INS (cfg->cbb, ins);
1806 cfg->flags |= MONO_CFG_HAS_FPOUT;
1808 int dreg = mono_alloc_freg (cfg);
1810 if (ainfo->size == 4) {
1811 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1813 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1815 ins->sreg1 = in->dreg;
1816 MONO_ADD_INS (cfg->cbb, ins);
1819 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1820 cfg->flags |= MONO_CFG_HAS_FPOUT;
1823 g_assert_not_reached ();
1827 /* Handle the case where there are no implicit arguments */
1828 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1829 emit_sig_cookie (cfg, call, cinfo);
1831 if (cinfo->struct_ret) {
1834 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1835 vtarg->sreg1 = call->vret_var->dreg;
1836 vtarg->dreg = mono_alloc_preg (cfg);
1837 MONO_ADD_INS (cfg->cbb, vtarg);
1839 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1843 * Reverse the call->out_args list.
1846 MonoInst *prev = NULL, *list = call->out_args, *next;
1853 call->out_args = prev;
1856 call->stack_usage = cinfo->stack_usage;
1857 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1858 #if _MIPS_SIM == _ABIO32
1859 /* a0-a3 always present */
1860 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1862 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1863 cfg->flags |= MONO_CFG_HAS_CALLS;
1865 * should set more info in call, such as the stack space
1866 * used by the args that needs to be added back to esp
1871 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1873 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1874 ArgInfo *ainfo = ins->inst_p1;
1875 int ovf_size = ainfo->vtsize;
1876 int doffset = ainfo->offset;
1877 int i, soffset, dreg;
1879 if (ainfo->storage == ArgStructByVal) {
1881 if (cfg->verbose_level > 0) {
1882 char* nm = mono_method_full_name (cfg->method, TRUE);
1883 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1884 nm, doffset, ainfo->size, ovf_size);
1890 for (i = 0; i < ainfo->size; ++i) {
1891 dreg = mono_alloc_ireg (cfg);
1892 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1893 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1894 soffset += SIZEOF_REGISTER;
1896 if (ovf_size != 0) {
1897 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1899 } else if (ainfo->storage == ArgInFReg) {
1900 int tmpr = mono_alloc_freg (cfg);
1902 if (ainfo->size == 4)
1903 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1905 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1906 dreg = mono_alloc_freg (cfg);
1907 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1908 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1910 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1914 /* FIXME: alignment? */
1915 if (call->signature->pinvoke) {
1916 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1917 vtcopy->backend.is_pinvoke = 1;
1919 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1922 g_assert (ovf_size > 0);
1924 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1925 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1928 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1930 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1935 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1937 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1940 #if (SIZEOF_REGISTER == 4)
1941 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1944 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1945 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1946 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1947 MONO_ADD_INS (cfg->cbb, ins);
1951 if (ret->type == MONO_TYPE_R8) {
1952 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1955 if (ret->type == MONO_TYPE_R4) {
1956 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1960 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1964 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1966 MonoInst *ins, *n, *last_ins = NULL;
1968 if (cfg->verbose_level > 2)
1969 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1972 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1973 if (cfg->verbose_level > 2)
1974 mono_print_ins_index (0, ins);
1976 switch (ins->opcode) {
1978 case OP_LOAD_MEMBASE:
1979 case OP_LOADI4_MEMBASE:
1981 * OP_IADD reg2, reg1, const1
1982 * OP_LOAD_MEMBASE const2(reg2), reg3
1984 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1986 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)){
1987 int const1 = last_ins->inst_imm;
1988 int const2 = ins->inst_offset;
1990 if (mips_is_imm16 (const1 + const2)) {
1991 ins->inst_basereg = last_ins->sreg1;
1992 ins->inst_offset = const1 + const2;
2002 bb->last_ins = last_ins;
2006 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2008 MonoInst *ins, *n, *last_ins = NULL;
2011 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2012 MonoInst *last_ins = ins->prev;
2014 switch (ins->opcode) {
2016 /* remove unnecessary multiplication with 1 */
2017 if (ins->inst_imm == 1) {
2018 if (ins->dreg != ins->sreg1) {
2019 ins->opcode = OP_MOVE;
2021 MONO_DELETE_INS (bb, ins);
2025 int power2 = mono_is_power_of_two (ins->inst_imm);
2027 ins->opcode = OP_SHL_IMM;
2028 ins->inst_imm = power2;
2032 case OP_LOAD_MEMBASE:
2033 case OP_LOADI4_MEMBASE:
2035 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2036 * OP_LOAD_MEMBASE offset(basereg), reg
2038 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2039 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2040 ins->inst_basereg == last_ins->inst_destbasereg &&
2041 ins->inst_offset == last_ins->inst_offset) {
2042 if (ins->dreg == last_ins->sreg1) {
2043 MONO_DELETE_INS (bb, ins);
2046 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2047 ins->opcode = OP_MOVE;
2048 ins->sreg1 = last_ins->sreg1;
2053 * Note: reg1 must be different from the basereg in the second load
2054 * OP_LOAD_MEMBASE offset(basereg), reg1
2055 * OP_LOAD_MEMBASE offset(basereg), reg2
2057 * OP_LOAD_MEMBASE offset(basereg), reg1
2058 * OP_MOVE reg1, reg2
2060 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2061 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2062 ins->inst_basereg != last_ins->dreg &&
2063 ins->inst_basereg == last_ins->inst_basereg &&
2064 ins->inst_offset == last_ins->inst_offset) {
2066 if (ins->dreg == last_ins->dreg) {
2067 MONO_DELETE_INS (bb, ins);
2070 ins->opcode = OP_MOVE;
2071 ins->sreg1 = last_ins->dreg;
2074 //g_assert_not_reached ();
2079 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2080 * OP_LOAD_MEMBASE offset(basereg), reg
2082 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2083 * OP_ICONST reg, imm
2085 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2086 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2087 ins->inst_basereg == last_ins->inst_destbasereg &&
2088 ins->inst_offset == last_ins->inst_offset) {
2089 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2090 ins->opcode = OP_ICONST;
2091 ins->inst_c0 = last_ins->inst_imm;
2092 g_assert_not_reached (); // check this rule
2097 case OP_LOADU1_MEMBASE:
2098 case OP_LOADI1_MEMBASE:
2099 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2100 ins->inst_basereg == last_ins->inst_destbasereg &&
2101 ins->inst_offset == last_ins->inst_offset) {
2102 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2103 ins->sreg1 = last_ins->sreg1;
2106 case OP_LOADU2_MEMBASE:
2107 case OP_LOADI2_MEMBASE:
2108 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2109 ins->inst_basereg == last_ins->inst_destbasereg &&
2110 ins->inst_offset == last_ins->inst_offset) {
2111 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2112 ins->sreg1 = last_ins->sreg1;
2115 case OP_ICONV_TO_I4:
2116 case OP_ICONV_TO_U4:
2118 ins->opcode = OP_MOVE;
2122 if (ins->dreg == ins->sreg1) {
2123 MONO_DELETE_INS (bb, ins);
2127 * OP_MOVE sreg, dreg
2128 * OP_MOVE dreg, sreg
2130 if (last_ins && last_ins->opcode == OP_MOVE &&
2131 ins->sreg1 == last_ins->dreg &&
2132 ins->dreg == last_ins->sreg1) {
2133 MONO_DELETE_INS (bb, ins);
2141 bb->last_ins = last_ins;
2145 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2153 switch (ins->opcode) {
2155 tmp1 = mono_alloc_ireg (cfg);
2156 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2157 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2158 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2159 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2164 tmp1 = mono_alloc_ireg (cfg);
2165 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2166 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2167 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2168 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2173 tmp1 = mono_alloc_ireg (cfg);
2174 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2175 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2176 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2177 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2182 tmp1 = mono_alloc_ireg (cfg);
2183 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2184 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2185 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2186 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2191 tmp1 = mono_alloc_ireg (cfg);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2193 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2194 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2195 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2200 tmp1 = mono_alloc_ireg (cfg);
2201 tmp2 = mono_alloc_ireg (cfg);
2202 tmp3 = mono_alloc_ireg (cfg);
2203 tmp4 = mono_alloc_ireg (cfg);
2204 tmp5 = mono_alloc_ireg (cfg);
2206 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2208 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2209 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2211 /* add the high 32-bits, and add in the carry from the low 32-bits */
2212 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2213 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2215 /* Overflow happens if
2216 * neg + neg = pos or
2218 * XOR of the high bits returns 0 if the signs match
2219 * XOR of that with the high bit of the result return 1 if overflow.
2222 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2223 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2225 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2226 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2227 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2229 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2230 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2231 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2233 /* Now, if (tmp4 == 0) then overflow */
2234 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2238 case OP_LADD_OVF_UN:
2239 tmp1 = mono_alloc_ireg (cfg);
2240 tmp2 = mono_alloc_ireg (cfg);
2242 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2243 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2244 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2245 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2246 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2247 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2252 tmp1 = mono_alloc_ireg (cfg);
2253 tmp2 = mono_alloc_ireg (cfg);
2254 tmp3 = mono_alloc_ireg (cfg);
2255 tmp4 = mono_alloc_ireg (cfg);
2256 tmp5 = mono_alloc_ireg (cfg);
2258 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2260 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2261 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2262 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2264 /* Overflow happens if
2265 * neg - pos = pos or
2267 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2269 * tmp1 = (lhs ^ rhs)
2270 * tmp2 = (lhs ^ result)
2271 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2274 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2275 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2276 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2277 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2279 /* Now, if (tmp4 == 1) then overflow */
2280 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2284 case OP_LSUB_OVF_UN:
2285 tmp1 = mono_alloc_ireg (cfg);
2286 tmp2 = mono_alloc_ireg (cfg);
2288 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2289 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2290 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2291 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2293 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2294 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2297 case OP_LCONV_TO_OVF_I4_2:
2298 tmp1 = mono_alloc_ireg (cfg);
2300 /* Overflows if reg2 != sign extension of reg1 */
2301 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2302 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2303 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2312 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2320 switch (ins->opcode) {
2322 tmp1 = mono_alloc_ireg (cfg);
2323 tmp2 = mono_alloc_ireg (cfg);
2324 tmp3 = mono_alloc_ireg (cfg);
2325 tmp4 = mono_alloc_ireg (cfg);
2326 tmp5 = mono_alloc_ireg (cfg);
2328 /* add the operands */
2330 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2332 /* Overflow happens if
2333 * neg + neg = pos or
2336 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2337 * XOR of the high bit returns 0 if the signs match
2338 * XOR of that with the high bit of the result return 1 if overflow.
2341 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2342 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2344 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2345 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2346 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2348 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2349 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2351 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2353 /* Now, if (tmp5 == 0) then overflow */
2354 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2355 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2356 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2360 case OP_IADD_OVF_UN:
2361 tmp1 = mono_alloc_ireg (cfg);
2363 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2364 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2365 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2366 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2367 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2372 tmp1 = mono_alloc_ireg (cfg);
2373 tmp2 = mono_alloc_ireg (cfg);
2374 tmp3 = mono_alloc_ireg (cfg);
2375 tmp4 = mono_alloc_ireg (cfg);
2376 tmp5 = mono_alloc_ireg (cfg);
2378 /* add the operands */
2380 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2382 /* Overflow happens if
2383 * neg - pos = pos or
2385 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2387 * tmp1 = (lhs ^ rhs)
2388 * tmp2 = (lhs ^ result)
2389 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2392 /* tmp3 = 1 if the signs of the two inputs differ */
2393 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2394 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2395 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2396 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2397 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2399 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2400 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2401 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2405 case OP_ISUB_OVF_UN:
2406 tmp1 = mono_alloc_ireg (cfg);
2408 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2409 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2410 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2411 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2412 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2419 map_to_reg_reg_op (int op)
2428 case OP_COMPARE_IMM:
2430 case OP_ICOMPARE_IMM:
2432 case OP_LCOMPARE_IMM:
2448 case OP_LOAD_MEMBASE:
2449 return OP_LOAD_MEMINDEX;
2450 case OP_LOADI4_MEMBASE:
2451 return OP_LOADI4_MEMINDEX;
2452 case OP_LOADU4_MEMBASE:
2453 return OP_LOADU4_MEMINDEX;
2454 case OP_LOADU1_MEMBASE:
2455 return OP_LOADU1_MEMINDEX;
2456 case OP_LOADI2_MEMBASE:
2457 return OP_LOADI2_MEMINDEX;
2458 case OP_LOADU2_MEMBASE:
2459 return OP_LOADU2_MEMINDEX;
2460 case OP_LOADI1_MEMBASE:
2461 return OP_LOADI1_MEMINDEX;
2462 case OP_LOADR4_MEMBASE:
2463 return OP_LOADR4_MEMINDEX;
2464 case OP_LOADR8_MEMBASE:
2465 return OP_LOADR8_MEMINDEX;
2466 case OP_STOREI1_MEMBASE_REG:
2467 return OP_STOREI1_MEMINDEX;
2468 case OP_STOREI2_MEMBASE_REG:
2469 return OP_STOREI2_MEMINDEX;
2470 case OP_STOREI4_MEMBASE_REG:
2471 return OP_STOREI4_MEMINDEX;
2472 case OP_STORE_MEMBASE_REG:
2473 return OP_STORE_MEMINDEX;
2474 case OP_STORER4_MEMBASE_REG:
2475 return OP_STORER4_MEMINDEX;
2476 case OP_STORER8_MEMBASE_REG:
2477 return OP_STORER8_MEMINDEX;
2478 case OP_STORE_MEMBASE_IMM:
2479 return OP_STORE_MEMBASE_REG;
2480 case OP_STOREI1_MEMBASE_IMM:
2481 return OP_STOREI1_MEMBASE_REG;
2482 case OP_STOREI2_MEMBASE_IMM:
2483 return OP_STOREI2_MEMBASE_REG;
2484 case OP_STOREI4_MEMBASE_IMM:
2485 return OP_STOREI4_MEMBASE_REG;
2486 case OP_STOREI8_MEMBASE_IMM:
2487 return OP_STOREI8_MEMBASE_REG;
2489 if (mono_op_imm_to_op (op) == -1)
2490 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2491 return mono_op_imm_to_op (op);
2495 map_to_mips_op (int op)
2499 return OP_MIPS_FBEQ;
2501 return OP_MIPS_FBGE;
2503 return OP_MIPS_FBGT;
2505 return OP_MIPS_FBLE;
2507 return OP_MIPS_FBLT;
2509 return OP_MIPS_FBNE;
2511 return OP_MIPS_FBGE_UN;
2513 return OP_MIPS_FBGT_UN;
2515 return OP_MIPS_FBLE_UN;
2517 return OP_MIPS_FBLT_UN;
2525 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2526 g_assert_not_reached ();
2530 #define NEW_INS(cfg,after,dest,op) do { \
2531 MONO_INST_NEW((cfg), (dest), (op)); \
2532 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2535 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2537 MONO_INST_NEW(cfg, temp, (op)); \
2538 mono_bblock_insert_after_ins (bb, (pos), temp); \
2539 temp->dreg = (_dreg); \
2540 temp->sreg1 = (_sreg1); \
2541 temp->sreg2 = (_sreg2); \
2545 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2547 MONO_INST_NEW(cfg, temp, (op)); \
2548 mono_bblock_insert_after_ins (bb, (pos), temp); \
2549 temp->dreg = (_dreg); \
2550 temp->sreg1 = (_sreg1); \
2551 temp->inst_c0 = (_imm); \
2556 * Remove from the instruction list the instructions that can't be
2557 * represented with very simple instructions with no register
2561 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2563 MonoInst *ins, *next, *temp, *last_ins = NULL;
2567 if (cfg->verbose_level > 2) {
2570 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2571 MONO_BB_FOR_EACH_INS (bb, ins) {
2572 mono_print_ins_index (idx++, ins);
2578 MONO_BB_FOR_EACH_INS (bb, ins) {
2580 switch (ins->opcode) {
2585 /* Branch opts can eliminate the branch */
2586 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2592 case OP_COMPARE_IMM:
2593 case OP_ICOMPARE_IMM:
2594 case OP_LCOMPARE_IMM:
2596 /* Branch opts can eliminate the branch */
2597 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2601 if (ins->inst_imm) {
2602 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2603 temp->inst_c0 = ins->inst_imm;
2604 temp->dreg = mono_alloc_ireg (cfg);
2605 ins->sreg2 = temp->dreg;
2609 ins->sreg2 = mips_zero;
2611 if (ins->opcode == OP_COMPARE_IMM)
2612 ins->opcode = OP_COMPARE;
2613 else if (ins->opcode == OP_ICOMPARE_IMM)
2614 ins->opcode = OP_ICOMPARE;
2615 else if (ins->opcode == OP_LCOMPARE_IMM)
2616 ins->opcode = OP_LCOMPARE;
2619 case OP_IDIV_UN_IMM:
2622 case OP_IREM_UN_IMM:
2623 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2624 temp->inst_c0 = ins->inst_imm;
2625 temp->dreg = mono_alloc_ireg (cfg);
2626 ins->sreg2 = temp->dreg;
2627 if (ins->opcode == OP_IDIV_IMM)
2628 ins->opcode = OP_IDIV;
2629 else if (ins->opcode == OP_IREM_IMM)
2630 ins->opcode = OP_IREM;
2631 else if (ins->opcode == OP_IDIV_UN_IMM)
2632 ins->opcode = OP_IDIV_UN;
2633 else if (ins->opcode == OP_IREM_UN_IMM)
2634 ins->opcode = OP_IREM_UN;
2636 /* handle rem separately */
2643 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2644 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2645 temp->inst_c0 = ins->inst_imm;
2646 temp->dreg = mono_alloc_ireg (cfg);
2647 ins->sreg2 = temp->dreg;
2648 ins->opcode = map_to_reg_reg_op (ins->opcode);
2658 /* unsigned 16 bit immediate */
2659 if (ins->inst_imm & 0xffff0000) {
2660 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2661 temp->inst_c0 = ins->inst_imm;
2662 temp->dreg = mono_alloc_ireg (cfg);
2663 ins->sreg2 = temp->dreg;
2664 ins->opcode = map_to_reg_reg_op (ins->opcode);
2671 /* signed 16 bit immediate */
2672 if (!mips_is_imm16 (ins->inst_imm)) {
2673 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2674 temp->inst_c0 = ins->inst_imm;
2675 temp->dreg = mono_alloc_ireg (cfg);
2676 ins->sreg2 = temp->dreg;
2677 ins->opcode = map_to_reg_reg_op (ins->opcode);
2683 if (!mips_is_imm16 (-ins->inst_imm)) {
2684 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2685 temp->inst_c0 = ins->inst_imm;
2686 temp->dreg = mono_alloc_ireg (cfg);
2687 ins->sreg2 = temp->dreg;
2688 ins->opcode = map_to_reg_reg_op (ins->opcode);
2694 if (ins->inst_imm == 1) {
2695 ins->opcode = OP_MOVE;
2698 if (ins->inst_imm == 0) {
2699 ins->opcode = OP_ICONST;
2703 imm = mono_is_power_of_two (ins->inst_imm);
2705 ins->opcode = OP_SHL_IMM;
2706 ins->inst_imm = imm;
2709 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2710 temp->inst_c0 = ins->inst_imm;
2711 temp->dreg = mono_alloc_ireg (cfg);
2712 ins->sreg2 = temp->dreg;
2713 ins->opcode = map_to_reg_reg_op (ins->opcode);
2716 case OP_LOCALLOC_IMM:
2717 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2718 temp->inst_c0 = ins->inst_imm;
2719 temp->dreg = mono_alloc_ireg (cfg);
2720 ins->sreg1 = temp->dreg;
2721 ins->opcode = OP_LOCALLOC;
2724 case OP_LOADR4_MEMBASE:
2725 case OP_STORER4_MEMBASE_REG:
2726 /* we can do two things: load the immed in a register
2727 * and use an indexed load, or see if the immed can be
2728 * represented as an ad_imm + a load with a smaller offset
2729 * that fits. We just do the first for now, optimize later.
2731 if (mips_is_imm16 (ins->inst_offset))
2733 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2734 temp->inst_c0 = ins->inst_offset;
2735 temp->dreg = mono_alloc_ireg (cfg);
2736 ins->sreg2 = temp->dreg;
2737 ins->opcode = map_to_reg_reg_op (ins->opcode);
2740 case OP_STORE_MEMBASE_IMM:
2741 case OP_STOREI1_MEMBASE_IMM:
2742 case OP_STOREI2_MEMBASE_IMM:
2743 case OP_STOREI4_MEMBASE_IMM:
2744 case OP_STOREI8_MEMBASE_IMM:
2745 if (!ins->inst_imm) {
2746 ins->sreg1 = mips_zero;
2747 ins->opcode = map_to_reg_reg_op (ins->opcode);
2750 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2751 temp->inst_c0 = ins->inst_imm;
2752 temp->dreg = mono_alloc_ireg (cfg);
2753 ins->sreg1 = temp->dreg;
2754 ins->opcode = map_to_reg_reg_op (ins->opcode);
2756 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2762 /* Branch opts can eliminate the branch */
2763 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2770 * remap compare/branch and compare/set
2771 * to MIPS specific opcodes.
2773 next->opcode = map_to_mips_op (next->opcode);
2774 next->sreg1 = ins->sreg1;
2775 next->sreg2 = ins->sreg2;
2782 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2783 temp->inst_c0 = (guint32)ins->inst_p0;
2784 temp->dreg = mono_alloc_ireg (cfg);
2785 ins->inst_basereg = temp->dreg;
2786 ins->inst_offset = 0;
2787 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2789 /* make it handle the possibly big ins->inst_offset
2790 * later optimize to use lis + load_membase
2795 g_assert (ins_is_compare(last_ins));
2796 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2797 NULLIFY_INS(last_ins);
2801 g_assert (ins_is_compare(last_ins));
2802 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2803 NULLIFY_INS(last_ins);
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_BEQ, 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_BEQ, last_ins->dreg, mips_zero);
2821 g_assert (ins_is_compare(last_ins));
2822 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2823 last_ins->dreg = mono_alloc_ireg (cfg);
2824 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2828 g_assert (ins_is_compare(last_ins));
2829 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2830 last_ins->dreg = mono_alloc_ireg (cfg);
2831 INS_REWRITE(ins, OP_MIPS_BNE, 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_BEQ, 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_BEQ, last_ins->dreg, mips_zero);
2849 g_assert (ins_is_compare(last_ins));
2850 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2851 last_ins->dreg = mono_alloc_ireg (cfg);
2852 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2856 g_assert (ins_is_compare(last_ins));
2857 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2858 last_ins->dreg = mono_alloc_ireg (cfg);
2859 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2864 g_assert (ins_is_compare(last_ins));
2865 last_ins->opcode = OP_IXOR;
2866 last_ins->dreg = mono_alloc_ireg(cfg);
2867 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2872 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2873 NULLIFY_INS(last_ins);
2879 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2880 NULLIFY_INS(last_ins);
2885 g_assert (ins_is_compare(last_ins));
2886 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2887 MONO_DELETE_INS(bb, last_ins);
2892 g_assert (ins_is_compare(last_ins));
2893 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2894 MONO_DELETE_INS(bb, last_ins);
2897 case OP_COND_EXC_EQ:
2898 case OP_COND_EXC_IEQ:
2899 g_assert (ins_is_compare(last_ins));
2900 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2901 MONO_DELETE_INS(bb, last_ins);
2904 case OP_COND_EXC_GE:
2905 case OP_COND_EXC_IGE:
2906 g_assert (ins_is_compare(last_ins));
2907 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2908 MONO_DELETE_INS(bb, last_ins);
2911 case OP_COND_EXC_GT:
2912 case OP_COND_EXC_IGT:
2913 g_assert (ins_is_compare(last_ins));
2914 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2915 MONO_DELETE_INS(bb, last_ins);
2918 case OP_COND_EXC_LE:
2919 case OP_COND_EXC_ILE:
2920 g_assert (ins_is_compare(last_ins));
2921 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2922 MONO_DELETE_INS(bb, last_ins);
2925 case OP_COND_EXC_LT:
2926 case OP_COND_EXC_ILT:
2927 g_assert (ins_is_compare(last_ins));
2928 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2929 MONO_DELETE_INS(bb, last_ins);
2932 case OP_COND_EXC_NE_UN:
2933 case OP_COND_EXC_INE_UN:
2934 g_assert (ins_is_compare(last_ins));
2935 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2936 MONO_DELETE_INS(bb, last_ins);
2939 case OP_COND_EXC_GE_UN:
2940 case OP_COND_EXC_IGE_UN:
2941 g_assert (ins_is_compare(last_ins));
2942 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2943 MONO_DELETE_INS(bb, last_ins);
2946 case OP_COND_EXC_GT_UN:
2947 case OP_COND_EXC_IGT_UN:
2948 g_assert (ins_is_compare(last_ins));
2949 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2950 MONO_DELETE_INS(bb, last_ins);
2953 case OP_COND_EXC_LE_UN:
2954 case OP_COND_EXC_ILE_UN:
2955 g_assert (ins_is_compare(last_ins));
2956 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2957 MONO_DELETE_INS(bb, last_ins);
2960 case OP_COND_EXC_LT_UN:
2961 case OP_COND_EXC_ILT_UN:
2962 g_assert (ins_is_compare(last_ins));
2963 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2964 MONO_DELETE_INS(bb, last_ins);
2967 case OP_COND_EXC_OV:
2968 case OP_COND_EXC_IOV: {
2969 int tmp1, tmp2, tmp3, tmp4, tmp5;
2970 MonoInst *pos = last_ins;
2972 /* Overflow happens if
2973 * neg + neg = pos or
2976 * (bit31s of operands match) AND (bit31 of operand
2977 * != bit31 of result)
2978 * XOR of the high bit returns 0 if the signs match
2979 * XOR of that with the high bit of the result return 1
2982 g_assert (last_ins->opcode == OP_IADC);
2984 tmp1 = mono_alloc_ireg (cfg);
2985 tmp2 = mono_alloc_ireg (cfg);
2986 tmp3 = mono_alloc_ireg (cfg);
2987 tmp4 = mono_alloc_ireg (cfg);
2988 tmp5 = mono_alloc_ireg (cfg);
2990 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2991 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2993 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2994 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2995 INS (pos, OP_INOT, tmp3, tmp2, -1);
2997 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2998 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2999 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3001 /* Now, if (tmp5 == 0) then overflow */
3002 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3007 case OP_COND_EXC_NO:
3008 case OP_COND_EXC_INO:
3009 g_assert_not_reached ();
3013 case OP_COND_EXC_IC:
3014 g_assert_not_reached ();
3017 case OP_COND_EXC_NC:
3018 case OP_COND_EXC_INC:
3019 g_assert_not_reached ();
3025 bb->last_ins = last_ins;
3026 bb->max_vreg = cfg->next_vreg;
3029 if (cfg->verbose_level > 2) {
3032 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3033 MONO_BB_FOR_EACH_INS (bb, ins) {
3034 mono_print_ins_index (idx++, ins);
3043 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3045 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3047 mips_truncwd (code, mips_ftemp, sreg);
3049 mips_cvtwd (code, mips_ftemp, sreg);
3051 mips_mfc1 (code, dreg, mips_ftemp);
3054 mips_andi (code, dreg, dreg, 0xff);
3055 else if (size == 2) {
3056 mips_sll (code, dreg, dreg, 16);
3057 mips_srl (code, dreg, dreg, 16);
3061 mips_sll (code, dreg, dreg, 24);
3062 mips_sra (code, dreg, dreg, 24);
3064 else if (size == 2) {
3065 mips_sll (code, dreg, dreg, 16);
3066 mips_sra (code, dreg, dreg, 16);
3073 * emit_load_volatile_arguments:
3075 * Load volatile arguments from the stack to the original input registers.
3076 * Required before a tail call.
3079 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3081 MonoMethod *method = cfg->method;
3082 MonoMethodSignature *sig;
3087 sig = mono_method_signature (method);
3089 if (!cfg->arch.cinfo)
3090 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3091 cinfo = cfg->arch.cinfo;
3093 if (cinfo->struct_ret) {
3094 ArgInfo *ainfo = &cinfo->ret;
3095 inst = cfg->vret_addr;
3096 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3099 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3100 ArgInfo *ainfo = cinfo->args + i;
3101 inst = cfg->args [i];
3102 if (inst->opcode == OP_REGVAR) {
3103 if (ainfo->storage == ArgInIReg)
3104 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3105 else if (ainfo->storage == ArgInFReg)
3106 g_assert_not_reached();
3107 else if (ainfo->storage == ArgOnStack) {
3110 g_assert_not_reached ();
3112 if (ainfo->storage == ArgInIReg) {
3113 g_assert (mips_is_imm16 (inst->inst_offset));
3114 switch (ainfo->size) {
3116 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3119 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3123 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3126 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3127 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3130 g_assert_not_reached ();
3133 } else if (ainfo->storage == ArgOnStack) {
3135 } else if (ainfo->storage == ArgInFReg) {
3136 g_assert (mips_is_imm16 (inst->inst_offset));
3137 if (ainfo->size == 8) {
3138 #if _MIPS_SIM == _ABIO32
3139 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3140 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3141 #elif _MIPS_SIM == _ABIN32
3142 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3145 else if (ainfo->size == 4)
3146 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3148 g_assert_not_reached ();
3149 } else if (ainfo->storage == ArgStructByVal) {
3151 int doffset = inst->inst_offset;
3153 g_assert (mips_is_imm16 (inst->inst_offset));
3154 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3155 for (i = 0; i < ainfo->size; ++i) {
3156 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3157 doffset += SIZEOF_REGISTER;
3159 } else if (ainfo->storage == ArgStructByAddr) {
3160 g_assert (mips_is_imm16 (inst->inst_offset));
3161 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3163 g_assert_not_reached ();
3171 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3173 int size = cfg->param_area;
3175 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3176 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3181 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3182 if (ppc_is_imm16 (-size)) {
3183 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3185 ppc_load (code, ppc_r12, -size);
3186 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3193 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3195 int size = cfg->param_area;
3197 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3198 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3203 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3204 if (ppc_is_imm16 (size)) {
3205 ppc_stwu (code, ppc_r0, size, ppc_sp);
3207 ppc_load (code, ppc_r12, size);
3208 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3215 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3220 guint8 *code = cfg->native_code + cfg->code_len;
3221 MonoInst *last_ins = NULL;
3222 guint last_offset = 0;
3226 /* we don't align basic blocks of loops on mips */
3228 if (cfg->verbose_level > 2)
3229 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3231 cpos = bb->max_offset;
3234 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3235 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3236 g_assert (!mono_compile_aot);
3239 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3240 /* this is not thread save, but good enough */
3241 /* fixme: howto handle overflows? */
3242 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3243 mips_lw (code, mips_temp, mips_at, 0);
3244 mips_addiu (code, mips_temp, mips_temp, 1);
3245 mips_sw (code, mips_temp, mips_at, 0);
3248 MONO_BB_FOR_EACH_INS (bb, ins) {
3249 offset = code - cfg->native_code;
3251 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3253 if (offset > (cfg->code_size - max_len - 16)) {
3254 cfg->code_size *= 2;
3255 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3256 code = cfg->native_code + offset;
3258 mono_debug_record_line_number (cfg, ins, offset);
3259 if (cfg->verbose_level > 2) {
3260 g_print (" @ 0x%x\t", offset);
3261 mono_print_ins_index (ins_cnt++, ins);
3263 /* Check for virtual regs that snuck by */
3264 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3266 switch (ins->opcode) {
3267 case OP_RELAXED_NOP:
3270 case OP_DUMMY_STORE:
3271 case OP_NOT_REACHED:
3274 case OP_IL_SEQ_POINT:
3275 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3277 case OP_SEQ_POINT: {
3278 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3279 guint32 addr = (guint32)ss_trigger_page;
3281 mips_load_const (code, mips_t9, addr);
3282 mips_lw (code, mips_t9, mips_t9, 0);
3285 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3288 * A placeholder for a possible breakpoint inserted by
3289 * mono_arch_set_breakpoint ().
3291 /* mips_load_const () + mips_lw */
3298 mips_mult (code, ins->sreg1, ins->sreg2);
3299 mips_mflo (code, ins->dreg);
3300 mips_mfhi (code, ins->dreg+1);
3303 mips_multu (code, ins->sreg1, ins->sreg2);
3304 mips_mflo (code, ins->dreg);
3305 mips_mfhi (code, ins->dreg+1);
3307 case OP_MEMORY_BARRIER:
3308 mips_sync (code, 0);
3310 case OP_STOREI1_MEMBASE_IMM:
3311 mips_load_const (code, mips_temp, ins->inst_imm);
3312 if (mips_is_imm16 (ins->inst_offset)) {
3313 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3315 mips_load_const (code, mips_at, ins->inst_offset);
3316 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3319 case OP_STOREI2_MEMBASE_IMM:
3320 mips_load_const (code, mips_temp, ins->inst_imm);
3321 if (mips_is_imm16 (ins->inst_offset)) {
3322 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3324 mips_load_const (code, mips_at, ins->inst_offset);
3325 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3328 case OP_STOREI8_MEMBASE_IMM:
3329 mips_load_const (code, mips_temp, ins->inst_imm);
3330 if (mips_is_imm16 (ins->inst_offset)) {
3331 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3333 mips_load_const (code, mips_at, ins->inst_offset);
3334 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3337 case OP_STORE_MEMBASE_IMM:
3338 case OP_STOREI4_MEMBASE_IMM:
3339 mips_load_const (code, mips_temp, ins->inst_imm);
3340 if (mips_is_imm16 (ins->inst_offset)) {
3341 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3343 mips_load_const (code, mips_at, ins->inst_offset);
3344 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3347 case OP_STOREI1_MEMBASE_REG:
3348 if (mips_is_imm16 (ins->inst_offset)) {
3349 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3351 mips_load_const (code, mips_at, ins->inst_offset);
3352 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3353 mips_sb (code, ins->sreg1, mips_at, 0);
3356 case OP_STOREI2_MEMBASE_REG:
3357 if (mips_is_imm16 (ins->inst_offset)) {
3358 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3360 mips_load_const (code, mips_at, ins->inst_offset);
3361 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3362 mips_sh (code, ins->sreg1, mips_at, 0);
3365 case OP_STORE_MEMBASE_REG:
3366 case OP_STOREI4_MEMBASE_REG:
3367 if (mips_is_imm16 (ins->inst_offset)) {
3368 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3370 mips_load_const (code, mips_at, ins->inst_offset);
3371 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3372 mips_sw (code, ins->sreg1, mips_at, 0);
3375 case OP_STOREI8_MEMBASE_REG:
3376 if (mips_is_imm16 (ins->inst_offset)) {
3377 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3379 mips_load_const (code, mips_at, ins->inst_offset);
3380 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3381 mips_sd (code, ins->sreg1, mips_at, 0);
3385 g_assert_not_reached ();
3386 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3387 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3389 case OP_LOADI8_MEMBASE:
3390 if (mips_is_imm16 (ins->inst_offset)) {
3391 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3393 mips_load_const (code, mips_at, ins->inst_offset);
3394 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3395 mips_ld (code, ins->dreg, mips_at, 0);
3398 case OP_LOAD_MEMBASE:
3399 case OP_LOADI4_MEMBASE:
3400 case OP_LOADU4_MEMBASE:
3401 g_assert (ins->dreg != -1);
3402 if (mips_is_imm16 (ins->inst_offset)) {
3403 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3405 mips_load_const (code, mips_at, ins->inst_offset);
3406 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3407 mips_lw (code, ins->dreg, mips_at, 0);
3410 case OP_LOADI1_MEMBASE:
3411 if (mips_is_imm16 (ins->inst_offset)) {
3412 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3414 mips_load_const (code, mips_at, ins->inst_offset);
3415 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3416 mips_lb (code, ins->dreg, mips_at, 0);
3419 case OP_LOADU1_MEMBASE:
3420 if (mips_is_imm16 (ins->inst_offset)) {
3421 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3423 mips_load_const (code, mips_at, ins->inst_offset);
3424 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3425 mips_lbu (code, ins->dreg, mips_at, 0);
3428 case OP_LOADI2_MEMBASE:
3429 if (mips_is_imm16 (ins->inst_offset)) {
3430 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3432 mips_load_const (code, mips_at, ins->inst_offset);
3433 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3434 mips_lh (code, ins->dreg, mips_at, 0);
3437 case OP_LOADU2_MEMBASE:
3438 if (mips_is_imm16 (ins->inst_offset)) {
3439 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3441 mips_load_const (code, mips_at, ins->inst_offset);
3442 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3443 mips_lhu (code, ins->dreg, mips_at, 0);
3446 case OP_ICONV_TO_I1:
3447 mips_sll (code, mips_at, ins->sreg1, 24);
3448 mips_sra (code, ins->dreg, mips_at, 24);
3450 case OP_ICONV_TO_I2:
3451 mips_sll (code, mips_at, ins->sreg1, 16);
3452 mips_sra (code, ins->dreg, mips_at, 16);
3454 case OP_ICONV_TO_U1:
3455 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3457 case OP_ICONV_TO_U2:
3458 mips_sll (code, mips_at, ins->sreg1, 16);
3459 mips_srl (code, ins->dreg, mips_at, 16);
3462 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3465 g_assert (mips_is_imm16 (ins->inst_imm));
3466 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3469 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3472 g_assert (mips_is_imm16 (ins->inst_imm));
3473 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3477 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3478 * So instead of emitting a trap, we emit a call a C function and place a
3481 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3482 (gpointer)"mono_break");
3483 mips_load (code, mips_t9, 0x1f1f1f1f);
3484 mips_jalr (code, mips_t9, mips_ra);
3488 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3491 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3496 g_assert (mips_is_imm16 (ins->inst_imm));
3497 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3500 g_assert (mips_is_imm16 (ins->inst_imm));
3501 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3505 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3508 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3513 // we add the negated value
3514 g_assert (mips_is_imm16 (-ins->inst_imm));
3515 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3519 // we add the negated value
3520 g_assert (mips_is_imm16 (-ins->inst_imm));
3521 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3526 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3532 g_assert (!(ins->inst_imm & 0xffff0000));
3533 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3538 guint32 *divisor_is_m1;
3539 guint32 *dividend_is_minvalue;
3540 guint32 *divisor_is_zero;
3542 mips_load_const (code, mips_at, -1);
3543 divisor_is_m1 = (guint32 *)(void *)code;
3544 mips_bne (code, ins->sreg2, mips_at, 0);
3545 mips_lui (code, mips_at, mips_zero, 0x8000);
3546 dividend_is_minvalue = (guint32 *)(void *)code;
3547 mips_bne (code, ins->sreg1, mips_at, 0);
3550 /* Divide Int32.MinValue by -1 -- throw exception */
3551 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3553 mips_patch (divisor_is_m1, (guint32)code);
3554 mips_patch (dividend_is_minvalue, (guint32)code);
3556 /* Put divide in branch delay slot (NOT YET) */
3557 divisor_is_zero = (guint32 *)(void *)code;
3558 mips_bne (code, ins->sreg2, mips_zero, 0);
3561 /* Divide by zero -- throw exception */
3562 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3564 mips_patch (divisor_is_zero, (guint32)code);
3565 mips_div (code, ins->sreg1, ins->sreg2);
3566 if (ins->opcode == OP_IDIV)
3567 mips_mflo (code, ins->dreg);
3569 mips_mfhi (code, ins->dreg);
3574 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3576 /* Put divide in branch delay slot (NOT YET) */
3577 mips_bne (code, ins->sreg2, mips_zero, 0);
3580 /* Divide by zero -- throw exception */
3581 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3583 mips_patch (divisor_is_zero, (guint32)code);
3584 mips_divu (code, ins->sreg1, ins->sreg2);
3585 if (ins->opcode == OP_IDIV_UN)
3586 mips_mflo (code, ins->dreg);
3588 mips_mfhi (code, ins->dreg);
3592 g_assert_not_reached ();
3594 ppc_load (code, ppc_r12, ins->inst_imm);
3595 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3596 ppc_mfspr (code, ppc_r0, ppc_xer);
3597 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3598 /* FIXME: use OverflowException for 0x80000000/-1 */
3599 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3601 g_assert_not_reached();
3604 g_assert_not_reached ();
3606 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3610 g_assert (!(ins->inst_imm & 0xffff0000));
3611 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3614 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3618 /* unsigned 16-bit immediate */
3619 g_assert (!(ins->inst_imm & 0xffff0000));
3620 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3623 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3627 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3630 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3633 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3637 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3640 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3643 case OP_ISHR_UN_IMM:
3644 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3646 case OP_LSHR_UN_IMM:
3647 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3650 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3653 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3657 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3660 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3663 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3667 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3669 mips_mult (code, ins->sreg1, ins->sreg2);
3670 mips_mflo (code, ins->dreg);
3675 #if SIZEOF_REGISTER == 8
3677 mips_dmult (code, ins->sreg1, ins->sreg2);
3678 mips_mflo (code, ins->dreg);
3683 mips_mult (code, ins->sreg1, ins->sreg2);
3684 mips_mflo (code, ins->dreg);
3685 mips_mfhi (code, mips_at);
3688 mips_sra (code, mips_temp, ins->dreg, 31);
3689 patch = (guint32 *)(void *)code;
3690 mips_beq (code, mips_temp, mips_at, 0);
3692 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3693 mips_patch (patch, (guint32)code);
3696 case OP_IMUL_OVF_UN: {
3698 mips_mult (code, ins->sreg1, ins->sreg2);
3699 mips_mflo (code, ins->dreg);
3700 mips_mfhi (code, mips_at);
3703 patch = (guint32 *)(void *)code;
3704 mips_beq (code, mips_at, mips_zero, 0);
3706 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3707 mips_patch (patch, (guint32)code);
3711 mips_load_const (code, ins->dreg, ins->inst_c0);
3713 #if SIZEOF_REGISTER == 8
3715 mips_load_const (code, ins->dreg, ins->inst_c0);
3719 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3720 mips_load (code, ins->dreg, 0);
3724 mips_mtc1 (code, ins->dreg, ins->sreg1);
3726 case OP_MIPS_MTC1S_2:
3727 mips_mtc1 (code, ins->dreg, ins->sreg1);
3728 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3731 mips_mfc1 (code, ins->dreg, ins->sreg1);
3734 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3738 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3740 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3741 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3745 case OP_ICONV_TO_I4:
3746 case OP_ICONV_TO_U4:
3748 if (ins->dreg != ins->sreg1)
3749 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3751 #if SIZEOF_REGISTER == 8
3753 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3754 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3757 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3758 mips_dsra (code, ins->dreg, ins->dreg, 32);
3762 int lsreg = mips_v0 + ls_word_idx;
3763 int msreg = mips_v0 + ms_word_idx;
3765 /* Get sreg1 into lsreg, sreg2 into msreg */
3767 if (ins->sreg1 == msreg) {
3768 if (ins->sreg1 != mips_at)
3769 MIPS_MOVE (code, mips_at, ins->sreg1);
3770 if (ins->sreg2 != msreg)
3771 MIPS_MOVE (code, msreg, ins->sreg2);
3772 MIPS_MOVE (code, lsreg, mips_at);
3775 if (ins->sreg2 != msreg)
3776 MIPS_MOVE (code, msreg, ins->sreg2);
3777 if (ins->sreg1 != lsreg)
3778 MIPS_MOVE (code, lsreg, ins->sreg1);
3783 if (ins->dreg != ins->sreg1) {
3784 mips_fmovd (code, ins->dreg, ins->sreg1);
3787 case OP_MOVE_F_TO_I4:
3788 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3789 mips_mfc1 (code, ins->dreg, mips_ftemp);
3791 case OP_MOVE_I4_TO_F:
3792 mips_mtc1 (code, ins->dreg, ins->sreg1);
3793 mips_cvtds (code, ins->dreg, ins->dreg);
3796 /* Convert from double to float and leave it there */
3797 mips_cvtsd (code, ins->dreg, ins->sreg1);
3799 case OP_FCONV_TO_R4:
3801 mips_cvtsd (code, ins->dreg, ins->sreg1);
3803 /* Just a move, no precision change */
3804 if (ins->dreg != ins->sreg1) {
3805 mips_fmovd (code, ins->dreg, ins->sreg1);
3810 code = emit_load_volatile_arguments(cfg, code);
3813 * Pop our stack, then jump to specified method (tail-call)
3814 * Keep in sync with mono_arch_emit_epilog
3816 code = mono_arch_emit_epilog_sub (cfg, code);
3818 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3819 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3820 mips_load (code, mips_t9, 0);
3821 mips_jr (code, mips_t9);
3825 /* ensure ins->sreg1 is not NULL */
3826 mips_lw (code, mips_zero, ins->sreg1, 0);
3829 g_assert (mips_is_imm16 (cfg->sig_cookie));
3830 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3831 mips_sw (code, mips_at, ins->sreg1, 0);
3844 case OP_VOIDCALL_REG:
3846 case OP_FCALL_MEMBASE:
3847 case OP_LCALL_MEMBASE:
3848 case OP_VCALL_MEMBASE:
3849 case OP_VCALL2_MEMBASE:
3850 case OP_VOIDCALL_MEMBASE:
3851 case OP_CALL_MEMBASE:
3852 call = (MonoCallInst*)ins;
3853 switch (ins->opcode) {
3860 if (ins->flags & MONO_INST_HAS_METHOD) {
3861 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3862 mips_load (code, mips_t9, call->method);
3865 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3866 mips_load (code, mips_t9, call->fptr);
3868 mips_jalr (code, mips_t9, mips_ra);
3875 case OP_VOIDCALL_REG:
3877 MIPS_MOVE (code, mips_t9, ins->sreg1);
3878 mips_jalr (code, mips_t9, mips_ra);
3881 case OP_FCALL_MEMBASE:
3882 case OP_LCALL_MEMBASE:
3883 case OP_VCALL_MEMBASE:
3884 case OP_VCALL2_MEMBASE:
3885 case OP_VOIDCALL_MEMBASE:
3886 case OP_CALL_MEMBASE:
3887 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3888 mips_jalr (code, mips_t9, mips_ra);
3892 #if PROMOTE_R4_TO_R8
3893 /* returned an FP R4 (single), promote to R8 (double) in place */
3894 switch (ins->opcode) {
3897 case OP_FCALL_MEMBASE:
3898 if (call->signature->ret->type == MONO_TYPE_R4)
3899 mips_cvtds (code, mips_f0, mips_f0);
3907 int area_offset = cfg->param_area;
3909 /* Round up ins->sreg1, mips_at ends up holding size */
3910 mips_addiu (code, mips_at, ins->sreg1, 31);
3911 mips_addiu (code, mips_temp, mips_zero, ~31);
3912 mips_and (code, mips_at, mips_at, mips_temp);
3914 mips_subu (code, mips_sp, mips_sp, mips_at);
3915 g_assert (mips_is_imm16 (area_offset));
3916 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3918 if (ins->flags & MONO_INST_INIT) {
3921 buf = (guint32*)(void*)code;
3922 mips_beq (code, mips_at, mips_zero, 0);
3925 mips_move (code, mips_temp, ins->dreg);
3926 mips_sb (code, mips_zero, mips_temp, 0);
3927 mips_addiu (code, mips_at, mips_at, -1);
3928 mips_bne (code, mips_at, mips_zero, -3);
3929 mips_addiu (code, mips_temp, mips_temp, 1);
3931 mips_patch (buf, (guint32)code);
3936 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3937 mips_move (code, mips_a0, ins->sreg1);
3938 mips_call (code, mips_t9, addr);
3939 mips_break (code, 0xfc);
3943 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3944 mips_move (code, mips_a0, ins->sreg1);
3945 mips_call (code, mips_t9, addr);
3946 mips_break (code, 0xfb);
3949 case OP_START_HANDLER: {
3951 * The START_HANDLER instruction marks the beginning of
3952 * a handler block. It is called using a call
3953 * instruction, so mips_ra contains the return address.
3954 * Since the handler executes in the same stack frame
3955 * as the method itself, we can't use save/restore to
3956 * save the return address. Instead, we save it into
3957 * a dedicated variable.
3959 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3960 g_assert (spvar->inst_basereg != mips_sp);
3961 code = emit_reserve_param_area (cfg, code);
3963 if (mips_is_imm16 (spvar->inst_offset)) {
3964 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3966 mips_load_const (code, mips_at, spvar->inst_offset);
3967 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3968 mips_sw (code, mips_ra, mips_at, 0);
3972 case OP_ENDFILTER: {
3973 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3974 g_assert (spvar->inst_basereg != mips_sp);
3975 code = emit_unreserve_param_area (cfg, code);
3977 if (ins->sreg1 != mips_v0)
3978 MIPS_MOVE (code, mips_v0, ins->sreg1);
3979 if (mips_is_imm16 (spvar->inst_offset)) {
3980 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3982 mips_load_const (code, mips_at, spvar->inst_offset);
3983 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3984 mips_lw (code, mips_ra, mips_at, 0);
3986 mips_jr (code, mips_ra);
3990 case OP_ENDFINALLY: {
3991 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3992 g_assert (spvar->inst_basereg != mips_sp);
3993 code = emit_unreserve_param_area (cfg, code);
3994 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3995 mips_jalr (code, mips_t9, mips_ra);
3999 case OP_CALL_HANDLER:
4000 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4001 mips_lui (code, mips_t9, mips_zero, 0);
4002 mips_addiu (code, mips_t9, mips_t9, 0);
4003 mips_jalr (code, mips_t9, mips_ra);
4005 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4006 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4009 ins->inst_c0 = code - cfg->native_code;
4012 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4013 if (cfg->arch.long_branch) {
4014 mips_lui (code, mips_at, mips_zero, 0);
4015 mips_addiu (code, mips_at, mips_at, 0);
4016 mips_jr (code, mips_at);
4020 mips_beq (code, mips_zero, mips_zero, 0);
4025 mips_jr (code, ins->sreg1);
4031 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4032 if (offset > (cfg->code_size - max_len - 16)) {
4033 cfg->code_size += max_len;
4034 cfg->code_size *= 2;
4035 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4036 code = cfg->native_code + offset;
4038 g_assert (ins->sreg1 != -1);
4039 mips_sll (code, mips_at, ins->sreg1, 2);
4040 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4041 MIPS_MOVE (code, mips_t8, mips_ra);
4042 mips_bgezal (code, mips_zero, 1); /* bal */
4044 mips_addu (code, mips_t9, mips_ra, mips_at);
4045 /* Table is 16 or 20 bytes from target of bal above */
4046 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4047 MIPS_MOVE (code, mips_ra, mips_t8);
4048 mips_lw (code, mips_t9, mips_t9, 20);
4051 mips_lw (code, mips_t9, mips_t9, 16);
4052 mips_jalr (code, mips_t9, mips_t8);
4054 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4055 mips_emit32 (code, 0xfefefefe);
4060 mips_addiu (code, ins->dreg, mips_zero, 1);
4061 mips_beq (code, mips_at, mips_zero, 2);
4063 MIPS_MOVE (code, ins->dreg, mips_zero);
4069 mips_addiu (code, ins->dreg, mips_zero, 1);
4070 mips_bltz (code, mips_at, 2);
4072 MIPS_MOVE (code, ins->dreg, mips_zero);
4078 mips_addiu (code, ins->dreg, mips_zero, 1);
4079 mips_bgtz (code, mips_at, 2);
4081 MIPS_MOVE (code, ins->dreg, mips_zero);
4084 case OP_MIPS_COND_EXC_EQ:
4085 case OP_MIPS_COND_EXC_GE:
4086 case OP_MIPS_COND_EXC_GT:
4087 case OP_MIPS_COND_EXC_LE:
4088 case OP_MIPS_COND_EXC_LT:
4089 case OP_MIPS_COND_EXC_NE_UN:
4090 case OP_MIPS_COND_EXC_GE_UN:
4091 case OP_MIPS_COND_EXC_GT_UN:
4092 case OP_MIPS_COND_EXC_LE_UN:
4093 case OP_MIPS_COND_EXC_LT_UN:
4095 case OP_MIPS_COND_EXC_OV:
4096 case OP_MIPS_COND_EXC_NO:
4097 case OP_MIPS_COND_EXC_C:
4098 case OP_MIPS_COND_EXC_NC:
4100 case OP_MIPS_COND_EXC_IEQ:
4101 case OP_MIPS_COND_EXC_IGE:
4102 case OP_MIPS_COND_EXC_IGT:
4103 case OP_MIPS_COND_EXC_ILE:
4104 case OP_MIPS_COND_EXC_ILT:
4105 case OP_MIPS_COND_EXC_INE_UN:
4106 case OP_MIPS_COND_EXC_IGE_UN:
4107 case OP_MIPS_COND_EXC_IGT_UN:
4108 case OP_MIPS_COND_EXC_ILE_UN:
4109 case OP_MIPS_COND_EXC_ILT_UN:
4111 case OP_MIPS_COND_EXC_IOV:
4112 case OP_MIPS_COND_EXC_INO:
4113 case OP_MIPS_COND_EXC_IC:
4114 case OP_MIPS_COND_EXC_INC: {
4118 /* If the condition is true, raise the exception */
4120 /* need to reverse test to skip around exception raising */
4122 /* For the moment, branch around a branch to avoid reversing
4125 /* Remember, an unpatched branch to 0 branches to the delay slot */
4126 switch (ins->opcode) {
4127 case OP_MIPS_COND_EXC_EQ:
4128 throw = (guint32 *)(void *)code;
4129 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4133 case OP_MIPS_COND_EXC_NE_UN:
4134 throw = (guint32 *)(void *)code;
4135 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4139 case OP_MIPS_COND_EXC_LE_UN:
4140 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4141 throw = (guint32 *)(void *)code;
4142 mips_beq (code, mips_at, mips_zero, 0);
4146 case OP_MIPS_COND_EXC_GT:
4147 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4148 throw = (guint32 *)(void *)code;
4149 mips_bne (code, mips_at, mips_zero, 0);
4153 case OP_MIPS_COND_EXC_GT_UN:
4154 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4155 throw = (guint32 *)(void *)code;
4156 mips_bne (code, mips_at, mips_zero, 0);
4160 case OP_MIPS_COND_EXC_LT:
4161 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4162 throw = (guint32 *)(void *)code;
4163 mips_bne (code, mips_at, mips_zero, 0);
4167 case OP_MIPS_COND_EXC_LT_UN:
4168 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4169 throw = (guint32 *)(void *)code;
4170 mips_bne (code, mips_at, mips_zero, 0);
4175 /* Not yet implemented */
4176 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4177 g_assert_not_reached ();
4179 skip = (guint32 *)(void *)code;
4180 mips_beq (code, mips_zero, mips_zero, 0);
4182 mips_patch (throw, (guint32)code);
4183 code = mips_emit_exc_by_name (code, ins->inst_p1);
4184 mips_patch (skip, (guint32)code);
4185 cfg->bb_exit->max_offset += 24;
4194 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4197 /* floating point opcodes */
4200 if (((guint32)ins->inst_p0) & (1 << 15))
4201 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4203 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4204 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4206 mips_load_const (code, mips_at, ins->inst_p0);
4207 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4208 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4212 if (((guint32)ins->inst_p0) & (1 << 15))
4213 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4215 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4216 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4217 #if PROMOTE_R4_TO_R8
4218 mips_cvtds (code, ins->dreg, ins->dreg);
4221 case OP_STORER8_MEMBASE_REG:
4222 if (mips_is_imm16 (ins->inst_offset)) {
4223 #if _MIPS_SIM == _ABIO32
4224 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4225 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4226 #elif _MIPS_SIM == _ABIN32
4227 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4230 mips_load_const (code, mips_at, ins->inst_offset);
4231 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4232 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4233 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4236 case OP_LOADR8_MEMBASE:
4237 if (mips_is_imm16 (ins->inst_offset)) {
4238 #if _MIPS_SIM == _ABIO32
4239 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4240 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4241 #elif _MIPS_SIM == _ABIN32
4242 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4245 mips_load_const (code, mips_at, ins->inst_offset);
4246 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4247 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4248 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4251 case OP_STORER4_MEMBASE_REG:
4252 g_assert (mips_is_imm16 (ins->inst_offset));
4253 #if PROMOTE_R4_TO_R8
4254 /* Need to convert ins->sreg1 to single-precision first */
4255 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4256 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4258 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4262 g_assert (mips_is_imm16 (ins->inst_offset));
4263 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4265 case OP_LOADR4_MEMBASE:
4266 g_assert (mips_is_imm16 (ins->inst_offset));
4267 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4268 #if PROMOTE_R4_TO_R8
4269 /* Convert to double precision in place */
4270 mips_cvtds (code, ins->dreg, ins->dreg);
4273 case OP_LOADR4_MEMINDEX:
4274 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4275 mips_lwc1 (code, ins->dreg, mips_at, 0);
4277 case OP_LOADR8_MEMINDEX:
4278 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4279 #if _MIPS_SIM == _ABIO32
4280 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4281 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4282 #elif _MIPS_SIM == _ABIN32
4283 mips_ldc1 (code, ins->dreg, mips_at, 0);
4286 case OP_STORER4_MEMINDEX:
4287 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4288 #if PROMOTE_R4_TO_R8
4289 /* Need to convert ins->sreg1 to single-precision first */
4290 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4291 mips_swc1 (code, mips_ftemp, mips_at, 0);
4293 mips_swc1 (code, ins->sreg1, mips_at, 0);
4296 case OP_STORER8_MEMINDEX:
4297 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4298 #if _MIPS_SIM == _ABIO32
4299 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4300 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4301 #elif _MIPS_SIM == _ABIN32
4302 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4305 case OP_ICONV_TO_R_UN: {
4306 static const guint64 adjust_val = 0x41F0000000000000ULL;
4308 /* convert unsigned int to double */
4309 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4310 mips_bgez (code, ins->sreg1, 5);
4311 mips_cvtdw (code, ins->dreg, mips_ftemp);
4313 mips_load (code, mips_at, (guint32) &adjust_val);
4314 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4315 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4316 /* target is here */
4319 case OP_ICONV_TO_R4:
4320 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4321 mips_cvtsw (code, ins->dreg, mips_ftemp);
4322 mips_cvtds (code, ins->dreg, ins->dreg);
4324 case OP_ICONV_TO_R8:
4325 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4326 mips_cvtdw (code, ins->dreg, mips_ftemp);
4328 case OP_FCONV_TO_I1:
4329 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4331 case OP_FCONV_TO_U1:
4332 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4334 case OP_FCONV_TO_I2:
4335 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4337 case OP_FCONV_TO_U2:
4338 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4340 case OP_FCONV_TO_I4:
4342 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4344 case OP_FCONV_TO_U4:
4346 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4349 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4352 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4355 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4358 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4361 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4364 mips_fnegd (code, ins->dreg, ins->sreg1);
4367 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4368 mips_addiu (code, ins->dreg, mips_zero, 1);
4369 mips_fbtrue (code, 2);
4371 MIPS_MOVE (code, ins->dreg, mips_zero);
4374 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4375 mips_addiu (code, ins->dreg, mips_zero, 1);
4376 mips_fbtrue (code, 2);
4378 MIPS_MOVE (code, ins->dreg, mips_zero);
4381 /* Less than, or Unordered */
4382 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4383 mips_addiu (code, ins->dreg, mips_zero, 1);
4384 mips_fbtrue (code, 2);
4386 MIPS_MOVE (code, ins->dreg, mips_zero);
4389 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4390 MIPS_MOVE (code, ins->dreg, mips_zero);
4391 mips_fbtrue (code, 2);
4393 mips_addiu (code, ins->dreg, mips_zero, 1);
4396 /* Greater than, or Unordered */
4397 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4398 MIPS_MOVE (code, ins->dreg, mips_zero);
4399 mips_fbtrue (code, 2);
4401 mips_addiu (code, ins->dreg, mips_zero, 1);
4406 case OP_MIPS_FBLT_UN:
4408 case OP_MIPS_FBGT_UN:
4410 case OP_MIPS_FBGE_UN:
4412 case OP_MIPS_FBLE_UN: {
4414 gboolean is_true = TRUE, is_ordered = FALSE;
4415 guint32 *buf = NULL;
4417 switch (ins->opcode) {
4431 case OP_MIPS_FBLT_UN:
4432 cond = MIPS_FPU_ULT;
4440 case OP_MIPS_FBGT_UN:
4441 cond = MIPS_FPU_OLE;
4449 case OP_MIPS_FBGE_UN:
4450 cond = MIPS_FPU_OLT;
4454 cond = MIPS_FPU_OLE;
4458 case OP_MIPS_FBLE_UN:
4459 cond = MIPS_FPU_ULE;
4463 g_assert_not_reached ();
4467 /* Skip the check if unordered */
4468 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4470 buf = (guint32*)code;
4471 mips_fbtrue (code, 0);
4475 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4477 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4479 mips_fbtrue (code, 0);
4481 mips_fbfalse (code, 0);
4485 mips_patch (buf, (guint32)code);
4489 guint32 *branch_patch;
4491 mips_mfc1 (code, mips_at, ins->sreg1+1);
4492 mips_srl (code, mips_at, mips_at, 16+4);
4493 mips_andi (code, mips_at, mips_at, 2047);
4494 mips_addiu (code, mips_at, mips_at, -2047);
4496 branch_patch = (guint32 *)(void *)code;
4497 mips_bne (code, mips_at, mips_zero, 0);
4500 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4501 mips_patch (branch_patch, (guint32)code);
4502 mips_fmovd (code, ins->dreg, ins->sreg1);
4506 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4507 mips_load (code, ins->dreg, 0x0f0f0f0f);
4509 case OP_GC_SAFE_POINT:
4514 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4515 g_assert_not_reached ();
4518 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4519 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4520 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4521 g_assert_not_reached ();
4527 last_offset = offset;
4530 cfg->code_len = code - cfg->native_code;
4534 mono_arch_register_lowlevel_calls (void)
4539 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4541 MonoJumpInfo *patch_info;
4545 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4546 unsigned char *ip = patch_info->ip.i + code;
4547 const unsigned char *target = NULL;
4549 switch (patch_info->type) {
4550 case MONO_PATCH_INFO_IP:
4551 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4553 case MONO_PATCH_INFO_SWITCH: {
4554 gpointer *table = (gpointer *)patch_info->data.table->table;
4557 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4559 for (i = 0; i < patch_info->data.table->table_size; i++) {
4560 table [i] = (int)patch_info->data.table->table [i] + code;
4564 case MONO_PATCH_INFO_METHODCONST:
4565 case MONO_PATCH_INFO_CLASS:
4566 case MONO_PATCH_INFO_IMAGE:
4567 case MONO_PATCH_INFO_FIELD:
4568 case MONO_PATCH_INFO_VTABLE:
4569 case MONO_PATCH_INFO_IID:
4570 case MONO_PATCH_INFO_SFLDA:
4571 case MONO_PATCH_INFO_LDSTR:
4572 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4573 case MONO_PATCH_INFO_LDTOKEN:
4574 case MONO_PATCH_INFO_R4:
4575 case MONO_PATCH_INFO_R8:
4576 /* from OP_AOTCONST : lui + addiu */
4577 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4578 return_if_nok (error);
4580 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4583 case MONO_PATCH_INFO_EXC_NAME:
4584 g_assert_not_reached ();
4585 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4588 case MONO_PATCH_INFO_NONE:
4589 /* everything is dealt with at epilog output time */
4592 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4593 return_if_nok (error);
4595 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4602 * Allow tracing to work with this interface (with an optional argument)
4604 * This code is expected to be inserted just after the 'real' prolog code,
4605 * and before the first basic block. We need to allocate a 2nd, temporary
4606 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4610 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4613 int offset = cfg->arch.tracing_offset;
4619 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4620 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4621 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4622 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4623 #if _MIPS_SIM == _ABIN32
4625 /* FIXME: Need a separate region for these */
4626 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4627 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4628 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4629 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4633 mips_load_const (code, mips_a0, cfg->method);
4634 mips_addiu (code, mips_a1, mips_sp, offset);
4635 mips_call (code, mips_t9, func);
4638 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4639 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4640 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4641 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4642 #if _MIPS_SIM == _ABIN32
4645 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4646 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4647 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4648 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4659 mips_adjust_stackframe(MonoCompile *cfg)
4662 int delta, threshold, i;
4663 MonoMethodSignature *sig;
4666 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4669 /* adjust cfg->stack_offset for account for down-spilling */
4670 cfg->stack_offset += SIZEOF_REGISTER;
4672 /* re-align cfg->stack_offset if needed (due to var spilling) */
4673 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4674 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4675 if (cfg->verbose_level > 2) {
4676 g_print ("mips_adjust_stackframe:\n");
4677 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4679 threshold = cfg->arch.local_alloc_offset;
4680 ra_offset = cfg->stack_offset - sizeof(gpointer);
4681 if (cfg->verbose_level > 2) {
4682 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4685 sig = mono_method_signature (cfg->method);
4686 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4687 cfg->vret_addr->inst_offset += delta;
4689 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4690 MonoInst *inst = cfg->args [i];
4692 inst->inst_offset += delta;
4696 * loads and stores based off the frame reg that (used to) lie
4697 * above the spill var area need to be increased by 'delta'
4698 * to make room for the spill vars.
4700 /* Need to find loads and stores to adjust that
4701 * are above where the spillvars were inserted, but
4702 * which are not the spillvar references themselves.
4704 * Idea - since all offsets from fp are positive, make
4705 * spillvar offsets negative to begin with so we can spot
4710 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4714 if (cfg->verbose_level > 2) {
4715 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4717 MONO_BB_FOR_EACH_INS (bb, ins) {
4721 if (cfg->verbose_level > 2) {
4722 mono_print_ins_index (ins_cnt, ins);
4724 /* The == mips_sp tests catch FP spills */
4725 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4726 (ins->inst_basereg == mips_sp))) {
4727 switch (ins->opcode) {
4728 case OP_LOADI8_MEMBASE:
4729 case OP_LOADR8_MEMBASE:
4736 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4737 (ins->dreg == mips_sp))) {
4738 switch (ins->opcode) {
4739 case OP_STOREI8_MEMBASE_REG:
4740 case OP_STORER8_MEMBASE_REG:
4741 case OP_STOREI8_MEMBASE_IMM:
4749 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4752 if (ins->inst_c0 >= threshold) {
4753 ins->inst_c0 += delta;
4754 if (cfg->verbose_level > 2) {
4756 mono_print_ins_index (ins_cnt, ins);
4759 else if (ins->inst_c0 < 0) {
4760 /* Adj_c0 holds the size of the datatype. */
4761 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4762 if (cfg->verbose_level > 2) {
4764 mono_print_ins_index (ins_cnt, ins);
4767 g_assert (ins->inst_c0 != ra_offset);
4770 if (ins->inst_imm >= threshold) {
4771 ins->inst_imm += delta;
4772 if (cfg->verbose_level > 2) {
4774 mono_print_ins_index (ins_cnt, ins);
4777 g_assert (ins->inst_c0 != ra_offset);
4787 * Stack frame layout:
4789 * ------------------- sp + cfg->stack_usage + cfg->param_area
4790 * param area incoming
4791 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4793 * ------------------- sp + cfg->stack_usage
4795 * ------------------- sp + cfg->stack_usage-4
4797 * ------------------- sp +
4798 * MonoLMF structure optional
4799 * ------------------- sp + cfg->arch.lmf_offset
4800 * saved registers s0-s8
4801 * ------------------- sp + cfg->arch.iregs_offset
4803 * ------------------- sp + cfg->param_area
4804 * param area outgoing
4805 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4807 * ------------------- sp
4811 mono_arch_emit_prolog (MonoCompile *cfg)
4813 MonoMethod *method = cfg->method;
4814 MonoMethodSignature *sig;
4816 int alloc_size, pos, i, max_offset;
4817 int alloc2_size = 0;
4821 guint32 iregs_to_save = 0;
4823 guint32 fregs_to_save = 0;
4825 /* lmf_offset is the offset of the LMF from our stack pointer. */
4826 guint32 lmf_offset = cfg->arch.lmf_offset;
4830 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4834 cfg->flags |= MONO_CFG_HAS_CALLS;
4836 sig = mono_method_signature (method);
4837 cfg->code_size = 768 + sig->param_count * 20;
4838 code = cfg->native_code = g_malloc (cfg->code_size);
4841 * compute max_offset in order to use short forward jumps.
4844 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4845 MonoInst *ins = bb->code;
4846 bb->max_offset = max_offset;
4848 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4851 MONO_BB_FOR_EACH_INS (bb, ins)
4852 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4854 if (max_offset > 0xffff)
4855 cfg->arch.long_branch = TRUE;
4858 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4859 * This means that we have to adjust the offsets inside instructions which reference
4860 * arguments received on the stack, since the initial offset doesn't take into
4861 * account spill slots.
4863 mips_adjust_stackframe (cfg);
4865 /* Offset between current sp and the CFA */
4867 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4869 /* stack_offset should not be changed here. */
4870 alloc_size = cfg->stack_offset;
4871 cfg->stack_usage = alloc_size;
4873 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4876 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4878 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4879 fregs_to_save |= (fregs_to_save << 1);
4882 /* If the stack size is too big, save 1024 bytes to start with
4883 * so the prologue can use imm16(reg) addressing, then allocate
4884 * the rest of the frame.
4886 if (alloc_size > ((1 << 15) - 1024)) {
4887 alloc2_size = alloc_size - 1024;
4891 g_assert (mips_is_imm16 (-alloc_size));
4892 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4893 cfa_offset = alloc_size;
4894 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4897 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4898 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4899 if (mips_is_imm16(offset))
4900 mips_sw (code, mips_ra, mips_sp, offset);
4902 g_assert_not_reached ();
4904 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4905 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4908 /* XXX - optimize this later to not save all regs if LMF constructed */
4909 pos = cfg->arch.iregs_offset - alloc2_size;
4911 if (iregs_to_save) {
4912 /* save used registers in own stack frame (at pos) */
4913 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4914 if (iregs_to_save & (1 << i)) {
4915 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4916 g_assert (mips_is_imm16(pos));
4917 MIPS_SW (code, i, mips_sp, pos);
4918 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4919 pos += SIZEOF_REGISTER;
4924 // FIXME: Don't save registers twice if there is an LMF
4925 // s8 has to be special cased since it is overwritten with the updated value
4927 if (method->save_lmf) {
4928 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4929 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4930 g_assert (mips_is_imm16(offset));
4931 if (MIPS_LMF_IREGMASK & (1 << i))
4932 MIPS_SW (code, i, mips_sp, offset);
4937 /* Save float registers */
4938 if (fregs_to_save) {
4939 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4940 if (fregs_to_save & (1 << i)) {
4941 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4942 g_assert (mips_is_imm16(pos));
4943 mips_swc1 (code, i, mips_sp, pos);
4944 pos += sizeof (gulong);
4949 if (method->save_lmf) {
4950 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4951 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4952 g_assert (mips_is_imm16(offset));
4953 mips_swc1 (code, i, mips_sp, offset);
4958 if (cfg->frame_reg != mips_sp) {
4959 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4960 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4962 if (method->save_lmf) {
4963 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4964 g_assert (mips_is_imm16(offset));
4965 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4969 /* store runtime generic context */
4970 if (cfg->rgctx_var) {
4971 MonoInst *ins = cfg->rgctx_var;
4973 g_assert (ins->opcode == OP_REGOFFSET);
4975 g_assert (mips_is_imm16 (ins->inst_offset));
4976 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4979 /* load arguments allocated to register from the stack */
4982 if (!cfg->arch.cinfo)
4983 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
4984 cinfo = cfg->arch.cinfo;
4986 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4987 ArgInfo *ainfo = &cinfo->ret;
4988 inst = cfg->vret_addr;
4989 if (inst->opcode == OP_REGVAR)
4990 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4991 else if (mips_is_imm16 (inst->inst_offset)) {
4992 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4994 mips_load_const (code, mips_at, inst->inst_offset);
4995 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4996 mips_sw (code, ainfo->reg, mips_at, 0);
5000 if (sig->call_convention == MONO_CALL_VARARG) {
5001 ArgInfo *cookie = &cinfo->sig_cookie;
5002 int offset = alloc_size + cookie->offset;
5004 /* Save the sig cookie address */
5005 g_assert (cookie->storage == ArgOnStack);
5007 g_assert (mips_is_imm16(offset));
5008 mips_addi (code, mips_at, cfg->frame_reg, offset);
5009 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5012 /* Keep this in sync with emit_load_volatile_arguments */
5013 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5014 ArgInfo *ainfo = cinfo->args + i;
5015 inst = cfg->args [pos];
5017 if (cfg->verbose_level > 2)
5018 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5019 if (inst->opcode == OP_REGVAR) {
5020 /* Argument ends up in a register */
5021 if (ainfo->storage == ArgInIReg)
5022 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5023 else if (ainfo->storage == ArgInFReg) {
5024 g_assert_not_reached();
5026 ppc_fmr (code, inst->dreg, ainfo->reg);
5029 else if (ainfo->storage == ArgOnStack) {
5030 int offset = cfg->stack_usage + ainfo->offset;
5031 g_assert (mips_is_imm16(offset));
5032 mips_lw (code, inst->dreg, mips_sp, offset);
5034 g_assert_not_reached ();
5036 if (cfg->verbose_level > 2)
5037 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5039 /* Argument ends up on the stack */
5040 if (ainfo->storage == ArgInIReg) {
5042 /* Incoming parameters should be above this frame */
5043 if (cfg->verbose_level > 2)
5044 g_print ("stack slot at %d of %d+%d\n",
5045 inst->inst_offset, alloc_size, alloc2_size);
5046 /* g_assert (inst->inst_offset >= alloc_size); */
5047 g_assert (inst->inst_basereg == cfg->frame_reg);
5048 basereg_offset = inst->inst_offset - alloc2_size;
5049 g_assert (mips_is_imm16 (basereg_offset));
5050 switch (ainfo->size) {
5052 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5055 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5059 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5062 #if (SIZEOF_REGISTER == 4)
5063 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5064 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5065 #elif (SIZEOF_REGISTER == 8)
5066 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5070 g_assert_not_reached ();
5073 } else if (ainfo->storage == ArgOnStack) {
5075 * Argument comes in on the stack, and ends up on the stack
5076 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5077 * 8 and 16 bit quantities. Shorten them in place.
5079 g_assert (mips_is_imm16 (inst->inst_offset));
5080 switch (ainfo->size) {
5082 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5083 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5086 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5087 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5094 g_assert_not_reached ();
5096 } else if (ainfo->storage == ArgInFReg) {
5097 g_assert (mips_is_imm16 (inst->inst_offset));
5098 g_assert (mips_is_imm16 (inst->inst_offset+4));
5099 if (ainfo->size == 8) {
5100 #if _MIPS_SIM == _ABIO32
5101 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5102 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5103 #elif _MIPS_SIM == _ABIN32
5104 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5107 else if (ainfo->size == 4)
5108 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5110 g_assert_not_reached ();
5111 } else if (ainfo->storage == ArgStructByVal) {
5113 int doffset = inst->inst_offset;
5115 g_assert (mips_is_imm16 (inst->inst_offset));
5116 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5117 /* Push the argument registers into their stack slots */
5118 for (i = 0; i < ainfo->size; ++i) {
5119 g_assert (mips_is_imm16(doffset));
5120 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5121 doffset += SIZEOF_REGISTER;
5123 } else if (ainfo->storage == ArgStructByAddr) {
5124 g_assert (mips_is_imm16 (inst->inst_offset));
5125 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5126 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5128 g_assert_not_reached ();
5133 if (method->save_lmf) {
5134 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5135 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5137 /* This can/will clobber the a0-a3 registers */
5138 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5140 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5141 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5142 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5143 /* new_lmf->previous_lmf = *lmf_addr */
5144 mips_lw (code, mips_at, mips_v0, 0);
5145 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5146 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5147 /* *(lmf_addr) = sp + lmf_offset */
5148 g_assert (mips_is_imm16(lmf_offset));
5149 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5150 mips_sw (code, mips_at, mips_v0, 0);
5152 /* save method info */
5153 mips_load_const (code, mips_at, method);
5154 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5155 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5157 /* save the current IP */
5158 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5159 mips_load_const (code, mips_at, 0x01010101);
5160 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5164 if (mips_is_imm16 (-alloc2_size)) {
5165 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5168 mips_load_const (code, mips_at, -alloc2_size);
5169 mips_addu (code, mips_sp, mips_sp, mips_at);
5171 alloc_size += alloc2_size;
5172 cfa_offset += alloc2_size;
5173 if (cfg->frame_reg != mips_sp)
5174 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5176 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5180 #if _MIPS_SIM == _ABIO32
5181 cfg->arch.tracing_offset = cfg->stack_offset;
5182 #elif _MIPS_SIM == _ABIN32
5183 /* no stack slots by default for argument regs, reserve a special block */
5184 g_assert_not_reached ();
5186 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5189 cfg->code_len = code - cfg->native_code;
5190 g_assert (cfg->code_len < cfg->code_size);
5204 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5207 int save_mode = SAVE_NONE;
5209 MonoMethod *method = cfg->method;
5210 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5211 int save_offset = MIPS_STACK_PARAM_OFFSET;
5213 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5215 offset = code - cfg->native_code;
5216 /* we need about 16 instructions */
5217 if (offset > (cfg->code_size - 16 * 4)) {
5218 cfg->code_size *= 2;
5219 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5220 code = cfg->native_code + offset;
5225 case MONO_TYPE_VOID:
5226 /* special case string .ctor icall */
5227 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5228 save_mode = SAVE_ONE;
5230 save_mode = SAVE_NONE;
5234 save_mode = SAVE_FP;
5236 case MONO_TYPE_VALUETYPE:
5237 save_mode = SAVE_STRUCT;
5241 #if SIZEOF_REGISTER == 4
5242 save_mode = SAVE_TWO;
5243 #elif SIZEOF_REGISTER == 8
5244 save_mode = SAVE_ONE;
5248 save_mode = SAVE_ONE;
5252 mips_addiu (code, mips_sp, mips_sp, -32);
5253 g_assert (mips_is_imm16(save_offset));
5254 switch (save_mode) {
5256 mips_sw (code, mips_v0, mips_sp, save_offset);
5257 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5258 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5259 if (enable_arguments) {
5260 MIPS_MOVE (code, mips_a1, mips_v0);
5261 MIPS_MOVE (code, mips_a2, mips_v1);
5265 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5266 if (enable_arguments) {
5267 MIPS_MOVE (code, mips_a1, mips_v0);
5271 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5272 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5273 mips_lw (code, mips_a0, mips_sp, save_offset);
5274 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5275 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5282 mips_load_const (code, mips_a0, cfg->method);
5283 mips_call (code, mips_t9, func);
5285 switch (save_mode) {
5287 mips_lw (code, mips_v0, mips_sp, save_offset);
5288 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5289 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5292 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5295 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5302 mips_addiu (code, mips_sp, mips_sp, 32);
5309 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5311 MonoMethod *method = cfg->method;
5313 int max_epilog_size = 16 + 20*4;
5314 int alloc2_size = 0;
5315 guint32 iregs_to_restore;
5317 guint32 fregs_to_restore;
5320 if (cfg->method->save_lmf)
5321 max_epilog_size += 128;
5323 if (mono_jit_trace_calls != NULL)
5324 max_epilog_size += 50;
5326 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5327 max_epilog_size += 50;
5330 pos = code - cfg->native_code;
5331 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5332 cfg->code_size *= 2;
5333 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5334 cfg->stat_code_reallocs++;
5338 * Keep in sync with OP_JMP
5341 code = cfg->native_code + pos;
5343 code = cfg->native_code + cfg->code_len;
5345 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5346 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5348 if (cfg->frame_reg != mips_sp) {
5349 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5351 /* If the stack frame is really large, deconstruct it in two steps */
5352 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5353 alloc2_size = cfg->stack_usage - 1024;
5354 /* partially deconstruct the stack */
5355 mips_load_const (code, mips_at, alloc2_size);
5356 mips_addu (code, mips_sp, mips_sp, mips_at);
5358 pos = cfg->arch.iregs_offset - alloc2_size;
5359 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5360 if (iregs_to_restore) {
5361 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5362 if (iregs_to_restore & (1 << i)) {
5363 g_assert (mips_is_imm16(pos));
5364 MIPS_LW (code, i, mips_sp, pos);
5365 pos += SIZEOF_REGISTER;
5372 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5374 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5375 fregs_to_restore |= (fregs_to_restore << 1);
5377 if (fregs_to_restore) {
5378 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5379 if (fregs_to_restore & (1 << i)) {
5380 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5381 g_assert (mips_is_imm16(pos));
5382 mips_lwc1 (code, i, mips_sp, pos);
5389 /* Unlink the LMF if necessary */
5390 if (method->save_lmf) {
5391 int lmf_offset = cfg->arch.lmf_offset;
5393 /* t0 = current_lmf->previous_lmf */
5394 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5395 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5397 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5398 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5399 /* (*lmf_addr) = previous_lmf */
5400 mips_sw (code, mips_temp, mips_t1, 0);
5404 /* Restore the fp */
5405 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5408 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5409 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5410 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5412 /* Restore the stack pointer */
5413 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5414 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5416 /* Caller will emit either return or tail-call sequence */
5418 cfg->code_len = code - cfg->native_code;
5420 g_assert (cfg->code_len < cfg->code_size);
5425 mono_arch_emit_epilog (MonoCompile *cfg)
5429 code = mono_arch_emit_epilog_sub (cfg, NULL);
5431 mips_jr (code, mips_ra);
5434 cfg->code_len = code - cfg->native_code;
5436 g_assert (cfg->code_len < cfg->code_size);
5439 /* remove once throw_exception_by_name is eliminated */
5442 exception_id_by_name (const char *name)
5444 if (strcmp (name, "IndexOutOfRangeException") == 0)
5445 return MONO_EXC_INDEX_OUT_OF_RANGE;
5446 if (strcmp (name, "OverflowException") == 0)
5447 return MONO_EXC_OVERFLOW;
5448 if (strcmp (name, "ArithmeticException") == 0)
5449 return MONO_EXC_ARITHMETIC;
5450 if (strcmp (name, "DivideByZeroException") == 0)
5451 return MONO_EXC_DIVIDE_BY_ZERO;
5452 if (strcmp (name, "InvalidCastException") == 0)
5453 return MONO_EXC_INVALID_CAST;
5454 if (strcmp (name, "NullReferenceException") == 0)
5455 return MONO_EXC_NULL_REF;
5456 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5457 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5458 if (strcmp (name, "ArgumentException") == 0)
5459 return MONO_EXC_ARGUMENT;
5460 g_error ("Unknown intrinsic exception %s\n", name);
5466 mono_arch_emit_exceptions (MonoCompile *cfg)
5469 MonoJumpInfo *patch_info;
5472 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5473 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5474 int max_epilog_size = 50;
5476 /* count the number of exception infos */
5479 * make sure we have enough space for exceptions
5480 * 24 is the simulated call to throw_exception_by_name
5482 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5484 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5485 i = exception_id_by_name (patch_info->data.target);
5486 g_assert (i < MONO_EXC_INTRINS_NUM);
5487 if (!exc_throw_found [i]) {
5488 max_epilog_size += 12;
5489 exc_throw_found [i] = TRUE;
5495 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5496 cfg->code_size *= 2;
5497 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5498 cfg->stat_code_reallocs++;
5501 code = cfg->native_code + cfg->code_len;
5503 /* add code to raise exceptions */
5504 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5505 switch (patch_info->type) {
5506 case MONO_PATCH_INFO_EXC: {
5508 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5510 i = exception_id_by_name (patch_info->data.target);
5511 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5512 if (!exc_throw_pos [i]) {
5515 exc_throw_pos [i] = code;
5516 //g_print ("exc: writing stub at %p\n", code);
5517 mips_load_const (code, mips_a0, patch_info->data.target);
5518 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5519 mips_load_const (code, mips_t9, addr);
5520 mips_jr (code, mips_t9);
5523 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5525 /* Turn into a Relative patch, pointing at code stub */
5526 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5527 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5529 g_assert_not_reached();
5539 cfg->code_len = code - cfg->native_code;
5541 g_assert (cfg->code_len < cfg->code_size);
5546 mono_arch_finish_init (void)
5551 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5556 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5558 int this_dreg = mips_a0;
5561 this_dreg = mips_a1;
5563 /* add the this argument */
5564 if (this_reg != -1) {
5566 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5567 this_ins->type = this_type;
5568 this_ins->sreg1 = this_reg;
5569 this_ins->dreg = mono_alloc_ireg (cfg);
5570 mono_bblock_add_inst (cfg->cbb, this_ins);
5571 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5576 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5577 vtarg->type = STACK_MP;
5578 vtarg->sreg1 = vt_reg;
5579 vtarg->dreg = mono_alloc_ireg (cfg);
5580 mono_bblock_add_inst (cfg->cbb, vtarg);
5581 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5586 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5588 MonoInst *ins = NULL;
5594 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5600 mono_arch_print_tree (MonoInst *tree, int arity)
5606 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5608 return ctx->sc_regs [reg];
5611 #define ENABLE_WRONG_METHOD_CHECK 0
5613 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5614 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5616 #define LOADSTORE_SIZE 4
5617 #define JUMP_IMM_SIZE 16
5618 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5619 #define LOAD_CONST_SIZE 8
5620 #define JUMP_JR_SIZE 8
5623 * LOCKING: called with the domain lock held
5626 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5627 gpointer fail_tramp)
5631 guint8 *code, *start, *patch;
5633 for (i = 0; i < count; ++i) {
5634 MonoIMTCheckItem *item = imt_entries [i];
5636 if (item->is_equals) {
5637 if (item->check_target_idx) {
5638 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5639 if (item->has_target_code)
5640 item->chunk_size += LOAD_CONST_SIZE;
5642 item->chunk_size += LOADSTORE_SIZE;
5645 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5646 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5647 if (!item->has_target_code)
5648 item->chunk_size += LOADSTORE_SIZE;
5650 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5651 #if ENABLE_WRONG_METHOD_CHECK
5652 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5657 item->chunk_size += CMP_SIZE + BR_SIZE;
5658 imt_entries [item->check_target_idx]->compare_done = TRUE;
5660 size += item->chunk_size;
5662 /* the initial load of the vtable address */
5663 size += MIPS_LOAD_SEQUENCE_LENGTH;
5665 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5667 code = mono_domain_code_reserve (domain, size);
5671 /* t7 points to the vtable */
5672 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5674 for (i = 0; i < count; ++i) {
5675 MonoIMTCheckItem *item = imt_entries [i];
5677 item->code_target = code;
5678 if (item->is_equals) {
5679 if (item->check_target_idx) {
5680 mips_load_const (code, mips_temp, (gsize)item->key);
5681 item->jmp_code = code;
5682 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5684 if (item->has_target_code) {
5685 mips_load_const (code, mips_t9,
5686 item->value.target_code);
5689 mips_lw (code, mips_t9, mips_t7,
5690 (sizeof (gpointer) * item->value.vtable_slot));
5692 mips_jr (code, mips_t9);
5696 mips_load_const (code, mips_temp, (gsize)item->key);
5698 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5700 if (item->has_target_code) {
5701 mips_load_const (code, mips_t9,
5702 item->value.target_code);
5705 mips_load_const (code, mips_at,
5706 & (vtable->vtable [item->value.vtable_slot]));
5707 mips_lw (code, mips_t9, mips_at, 0);
5709 mips_jr (code, mips_t9);
5711 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5712 mips_load_const (code, mips_t9, fail_tramp);
5713 mips_jr (code, mips_t9);
5716 /* enable the commented code to assert on wrong method */
5717 #if ENABLE_WRONG_METHOD_CHECK
5718 ppc_load (code, ppc_r0, (guint32)item->key);
5719 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5721 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5723 mips_lw (code, mips_t9, mips_t7,
5724 (sizeof (gpointer) * item->value.vtable_slot));
5725 mips_jr (code, mips_t9);
5728 #if ENABLE_WRONG_METHOD_CHECK
5729 ppc_patch (patch, code);
5735 mips_load_const (code, mips_temp, (gulong)item->key);
5736 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5738 item->jmp_code = code;
5739 mips_beq (code, mips_temp, mips_zero, 0);
5743 /* patch the branches to get to the target items */
5744 for (i = 0; i < count; ++i) {
5745 MonoIMTCheckItem *item = imt_entries [i];
5746 if (item->jmp_code && item->check_target_idx) {
5747 mips_patch ((guint32 *)item->jmp_code,
5748 (guint32)imt_entries [item->check_target_idx]->code_target);
5753 mono_stats.imt_trampolines_size += code - start;
5754 g_assert (code - start <= size);
5755 mono_arch_flush_icache (start, size);
5757 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5763 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5765 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5769 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5771 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5774 /* Soft Debug support */
5775 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5778 * mono_arch_set_breakpoint:
5780 * See mini-amd64.c for docs.
5783 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5786 guint32 addr = (guint32)bp_trigger_page;
5788 mips_load_const (code, mips_t9, addr);
5789 mips_lw (code, mips_t9, mips_t9, 0);
5791 mono_arch_flush_icache (ip, code - ip);
5795 * mono_arch_clear_breakpoint:
5797 * See mini-amd64.c for docs.
5800 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5808 mono_arch_flush_icache (ip, code - ip);
5812 * mono_arch_start_single_stepping:
5814 * See mini-amd64.c for docs.
5817 mono_arch_start_single_stepping (void)
5819 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5823 * mono_arch_stop_single_stepping:
5825 * See mini-amd64.c for docs.
5828 mono_arch_stop_single_stepping (void)
5830 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5834 * mono_arch_is_single_step_event:
5836 * See mini-amd64.c for docs.
5839 mono_arch_is_single_step_event (void *info, void *sigctx)
5841 siginfo_t* sinfo = (siginfo_t*) info;
5842 /* Sometimes the address is off by 4 */
5843 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5850 * mono_arch_is_breakpoint_event:
5852 * See mini-amd64.c for docs.
5855 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5857 siginfo_t* sinfo = (siginfo_t*) info;
5858 /* Sometimes the address is off by 4 */
5859 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5866 * mono_arch_skip_breakpoint:
5868 * See mini-amd64.c for docs.
5871 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5873 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5877 * mono_arch_skip_single_step:
5879 * See mini-amd64.c for docs.
5882 mono_arch_skip_single_step (MonoContext *ctx)
5884 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5888 * mono_arch_get_seq_point_info:
5890 * See mini-amd64.c for docs.
5893 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5900 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5902 ext->lmf.previous_lmf = prev_lmf;
5903 /* Mark that this is a MonoLMFExt */
5904 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5905 ext->lmf.iregs [mips_sp] = (gssize)ext;
5908 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5911 mono_arch_opcode_supported (int opcode)