3 * MIPS backend for the Mono code generator
6 * Mark Mason (mason@broadcom.com)
8 * Based on mini-ppc.c by
9 * Paolo Molaro (lupus@ximian.com)
10 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2003 Ximian, Inc.
17 #include <asm/cachectl.h>
19 #include <mono/metadata/abi-details.h>
20 #include <mono/metadata/appdomain.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/utils/mono-mmap.h>
23 #include <mono/utils/mono-hwcap.h>
25 #include <mono/arch/mips/mips-codegen.h>
27 #include "mini-mips.h"
32 #define SAVE_FP_REGS 0
34 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
36 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
37 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
38 remember to update cpu-mips.md if you change this */
40 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
41 #define mips_call(c,D,v) do { \
42 guint32 _target = (guint32)(v); \
43 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
44 mips_load_const (c, D, _target); \
45 mips_jalr (c, D, mips_ra); \
48 mips_jumpl (c, _target >> 2); \
60 /* This mutex protects architecture specific caches */
61 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
62 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
63 static mono_mutex_t mini_arch_mutex;
65 int mono_exc_esp_offset = 0;
67 /* Whenever the host is little-endian */
68 static int little_endian;
69 /* Index of ms word/register */
70 static int ls_word_idx;
71 /* Index of ls word/register */
72 static int ms_word_idx;
73 /* Same for offsets */
74 static int ls_word_offset;
75 static int ms_word_offset;
78 * The code generated for sequence points reads from this location, which is
79 * made read-only when single stepping is enabled.
81 static gpointer ss_trigger_page;
83 /* Enabled breakpoints read from this trigger page */
84 static gpointer bp_trigger_page;
87 #define DEBUG(a) if (cfg->verbose_level > 1) a
93 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
95 code = mips_emit_exc_by_name (code, exc_name); \
96 cfg->bb_exit->max_offset += 16; \
99 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
101 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
102 inst->type = STACK_R8; \
104 inst->inst_p0 = (void*)(addr); \
105 mono_bblock_add_inst (cfg->cbb, inst); \
108 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
109 || ((ins)->opcode == OP_ICOMPARE) \
110 || ((ins)->opcode == OP_LCOMPARE)))
111 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
112 || ((ins)->opcode == OP_ICOMPARE_IMM) \
113 || ((ins)->opcode == OP_LCOMPARE_IMM)))
115 #define INS_REWRITE(ins, op, _s1, _s2) do { \
118 ins->opcode = (op); \
123 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
125 ins->opcode = (op); \
127 ins->inst_imm = (_imm); \
131 typedef struct InstList InstList;
149 guint16 vtsize; /* in param area */
152 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
161 gboolean vtype_retaddr;
170 void patch_lui_addiu(guint32 *ip, guint32 val);
171 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
172 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
173 void mips_adjust_stackframe(MonoCompile *cfg);
174 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
175 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
178 /* Not defined in asm/cachectl.h */
179 int cacheflush(char *addr, int nbytes, int cache);
182 mono_arch_flush_icache (guint8 *code, gint size)
184 /* Linux/MIPS specific */
185 cacheflush ((char*)code, size, BCACHE);
189 mono_arch_flush_register_windows (void)
194 mono_arch_is_inst_imm (gint64 imm)
200 mips_emit_exc_by_name(guint8 *code, const char *name)
203 MonoClass *exc_class;
205 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", name);
207 mips_load_const (code, mips_a0, exc_class->type_token);
208 addr = mono_get_throw_corlib_exception ();
209 mips_call (code, mips_t9, addr);
215 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
217 if (mips_is_imm16 (v))
218 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
220 #if SIZEOF_REGISTER == 8
222 /* v is not a sign-extended 32-bit value */
223 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
224 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
225 mips_dsll (code, dreg, dreg, 16);
226 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
227 mips_dsll (code, dreg, dreg, 16);
228 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
232 if (((guint32)v) & (1 << 15)) {
233 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
236 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
238 if (((guint32)v) & 0xffff)
239 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
245 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
248 if (cfg->arch.long_branch) {
251 /* Invert test and emit branch around jump */
254 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
258 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
262 mips_bltz (code, ins->sreg1, br_offset);
266 mips_blez (code, ins->sreg1, br_offset);
270 mips_bgtz (code, ins->sreg1, br_offset);
274 mips_bgez (code, ins->sreg1, br_offset);
278 g_assert_not_reached ();
280 mono_add_patch_info (cfg, code - cfg->native_code,
281 MONO_PATCH_INFO_BB, ins->inst_true_bb);
282 mips_lui (code, mips_at, mips_zero, 0);
283 mips_addiu (code, mips_at, mips_at, 0);
284 mips_jr (code, mips_at);
288 mono_add_patch_info (cfg, code - cfg->native_code,
289 MONO_PATCH_INFO_BB, ins->inst_true_bb);
292 mips_beq (code, ins->sreg1, ins->sreg2, 0);
296 mips_bne (code, ins->sreg1, ins->sreg2, 0);
300 mips_bgez (code, ins->sreg1, 0);
304 mips_bgtz (code, ins->sreg1, 0);
308 mips_blez (code, ins->sreg1, 0);
312 mips_bltz (code, ins->sreg1, 0);
316 g_assert_not_reached ();
322 /* XXX - big-endian dependent? */
324 patch_lui_addiu(guint32 *ip, guint32 val)
326 guint16 *__lui_addiu = (guint16*)(void *)(ip);
329 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
330 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
333 if (((guint32)(val)) & (1 << 15))
334 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
336 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
337 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
338 mono_arch_flush_icache ((guint8 *)ip, 8);
343 mips_patch (guint32 *code, guint32 target)
346 guint32 op = ins >> 26;
347 guint32 diff, offset;
349 g_assert (trap_target != target);
350 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
352 case 0x00: /* jr ra */
353 if (ins == 0x3e00008)
355 g_assert_not_reached ();
359 g_assert (!(target & 0x03));
360 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
361 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
363 mono_arch_flush_icache ((guint8 *)code, 4);
365 case 0x01: /* BLTZ */
368 case 0x06: /* BLEZ */
369 case 0x07: /* BGTZ */
370 case 0x11: /* bc1t */
371 diff = target - (guint32)(code + 1);
372 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
373 g_assert (!(diff & 0x03));
374 offset = ((gint32)diff) >> 2;
375 if (((int)offset) != ((int)(short)offset))
376 g_assert (((int)offset) == ((int)(short)offset));
377 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
379 mono_arch_flush_icache ((guint8 *)code, 4);
381 case 0x0f: /* LUI / ADDIU pair */
382 g_assert ((code[1] >> 26) == 0x9);
383 patch_lui_addiu (code, target);
384 mono_arch_flush_icache ((guint8 *)code, 8);
388 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
389 g_assert_not_reached ();
393 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
396 mono_arch_regname (int reg) {
397 #if _MIPS_SIM == _ABIO32
398 static const char * rnames[] = {
399 "zero", "at", "v0", "v1",
400 "a0", "a1", "a2", "a3",
401 "t0", "t1", "t2", "t3",
402 "t4", "t5", "t6", "t7",
403 "s0", "s1", "s2", "s3",
404 "s4", "s5", "s6", "s7",
405 "t8", "t9", "k0", "k1",
406 "gp", "sp", "fp", "ra"
408 #elif _MIPS_SIM == _ABIN32
409 static const char * rnames[] = {
410 "zero", "at", "v0", "v1",
411 "a0", "a1", "a2", "a3",
412 "a4", "a5", "a6", "a7",
413 "t0", "t1", "t2", "t3",
414 "s0", "s1", "s2", "s3",
415 "s4", "s5", "s6", "s7",
416 "t8", "t9", "k0", "k1",
417 "gp", "sp", "fp", "ra"
420 if (reg >= 0 && reg < 32)
426 mono_arch_fregname (int reg) {
427 static const char * rnames[] = {
428 "f0", "f1", "f2", "f3",
429 "f4", "f5", "f6", "f7",
430 "f8", "f9", "f10", "f11",
431 "f12", "f13", "f14", "f15",
432 "f16", "f17", "f18", "f19",
433 "f20", "f21", "f22", "f23",
434 "f24", "f25", "f26", "f27",
435 "f28", "f29", "f30", "f31"
437 if (reg >= 0 && reg < 32)
442 /* this function overwrites at */
444 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
446 /* XXX write a loop, not an unrolled loop */
448 mips_lw (code, mips_at, sreg, soffset);
449 mips_sw (code, mips_at, dreg, doffset);
458 * mono_arch_get_argument_info:
459 * @csig: a method signature
460 * @param_count: the number of parameters to consider
461 * @arg_info: an array to store the result infos
463 * Gathers information on parameters such as size, alignment and
464 * padding. arg_info should be large enought to hold param_count + 1 entries.
466 * Returns the size of the activation frame.
469 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
471 int k, frame_size = 0;
472 guint32 size, align, pad;
475 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
476 frame_size += sizeof (gpointer);
480 arg_info [0].offset = offset;
483 frame_size += sizeof (gpointer);
487 arg_info [0].size = frame_size;
489 for (k = 0; k < param_count; k++) {
490 size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
492 /* ignore alignment for now */
495 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
496 arg_info [k].pad = pad;
498 arg_info [k + 1].pad = 0;
499 arg_info [k + 1].size = size;
501 arg_info [k + 1].offset = offset;
505 align = MONO_ARCH_FRAME_ALIGNMENT;
506 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
507 arg_info [k].pad = pad;
512 /* The delegate object plus 3 params */
513 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
516 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
518 guint8 *code, *start;
521 start = code = mono_global_codeman_reserve (16);
523 /* Replace the this argument with the target */
524 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
525 mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
526 mips_jr (code, mips_temp);
529 g_assert ((code - start) <= 16);
531 mono_arch_flush_icache (start, 16);
535 size = 16 + param_count * 4;
536 start = code = mono_global_codeman_reserve (size);
538 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
539 /* slide down the arguments */
540 for (i = 0; i < param_count; ++i) {
541 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
543 mips_jr (code, mips_temp);
546 g_assert ((code - start) <= size);
548 mono_arch_flush_icache (start, size);
552 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
554 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
555 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
563 * mono_arch_get_delegate_invoke_impls:
565 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
569 mono_arch_get_delegate_invoke_impls (void)
575 get_delegate_invoke_impl (&info, TRUE, 0);
576 res = g_slist_prepend (res, info);
578 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
579 get_delegate_invoke_impl (&info, FALSE, i);
580 res = g_slist_prepend (res, info);
587 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
589 guint8 *code, *start;
591 /* FIXME: Support more cases */
592 if (MONO_TYPE_ISSTRUCT (sig->ret))
596 static guint8* cached = NULL;
597 mono_mini_arch_lock ();
599 mono_mini_arch_unlock ();
604 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
607 start = get_delegate_invoke_impl (&info, TRUE, 0);
608 mono_tramp_info_register (info, NULL);
611 mono_mini_arch_unlock ();
614 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
617 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
619 for (i = 0; i < sig->param_count; ++i)
620 if (!mono_is_regsize_var (sig->params [i]))
623 mono_mini_arch_lock ();
624 code = cache [sig->param_count];
626 mono_mini_arch_unlock ();
631 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
632 start = mono_aot_get_trampoline (name);
636 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
637 mono_tramp_info_register (info, NULL);
639 cache [sig->param_count] = start;
640 mono_mini_arch_unlock ();
648 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
654 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
657 return (gpointer)regs [mips_a0];
661 * Initialize the cpu to execute managed code.
664 mono_arch_cpu_init (void)
666 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
675 ls_word_offset = ls_word_idx * 4;
676 ms_word_offset = ms_word_idx * 4;
680 * Initialize architecture specific code.
683 mono_arch_init (void)
685 mono_os_mutex_init_recursive (&mini_arch_mutex);
687 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
688 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
689 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
693 * Cleanup architecture specific code.
696 mono_arch_cleanup (void)
698 mono_os_mutex_destroy (&mini_arch_mutex);
702 mono_arch_have_fast_tls (void)
708 * This function returns the optimizations supported on this cpu.
711 mono_arch_cpu_optimizations (guint32 *exclude_mask)
715 /* no mips-specific optimizations yet */
721 * This function test for all SIMD functions supported.
723 * Returns a bitmask corresponding to all supported versions.
727 mono_arch_cpu_enumerate_simd_versions (void)
729 /* SIMD is currently unimplemented */
734 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
739 for (i = 0; i < cfg->num_varinfo; i++) {
740 MonoInst *ins = cfg->varinfo [i];
741 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
744 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
747 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
750 /* we can only allocate 32 bit values */
751 if (mono_is_regsize_var (ins->inst_vtype)) {
752 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
753 g_assert (i == vmv->idx);
754 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
762 mono_arch_get_global_int_regs (MonoCompile *cfg)
766 regs = g_list_prepend (regs, (gpointer)mips_s0);
767 regs = g_list_prepend (regs, (gpointer)mips_s1);
768 regs = g_list_prepend (regs, (gpointer)mips_s2);
769 regs = g_list_prepend (regs, (gpointer)mips_s3);
770 regs = g_list_prepend (regs, (gpointer)mips_s4);
771 //regs = g_list_prepend (regs, (gpointer)mips_s5);
772 regs = g_list_prepend (regs, (gpointer)mips_s6);
773 regs = g_list_prepend (regs, (gpointer)mips_s7);
779 * mono_arch_regalloc_cost:
781 * Return the cost, in number of memory references, of the action of
782 * allocating the variable VMV into a register during global register
786 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
793 args_onto_stack (CallInfo *info)
795 g_assert (!info->on_stack);
796 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
797 info->on_stack = TRUE;
798 info->stack_size = MIPS_STACK_PARAM_OFFSET;
801 #if _MIPS_SIM == _ABIO32
803 * O32 calling convention version
807 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
808 /* First, see if we need to drop onto the stack */
809 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
810 args_onto_stack (info);
812 /* Now, place the argument */
813 if (info->on_stack) {
814 ainfo->storage = ArgOnStack;
815 ainfo->reg = mips_sp; /* in the caller */
816 ainfo->offset = info->stack_size;
819 ainfo->storage = ArgInIReg;
820 ainfo->reg = info->gr;
822 info->gr_passed = TRUE;
824 info->stack_size += 4;
828 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
829 /* First, see if we need to drop onto the stack */
830 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
831 args_onto_stack (info);
833 /* Now, place the argument */
834 if (info->on_stack) {
835 g_assert (info->stack_size % 4 == 0);
836 info->stack_size += (info->stack_size % 8);
838 ainfo->storage = ArgOnStack;
839 ainfo->reg = mips_sp; /* in the caller */
840 ainfo->offset = info->stack_size;
843 // info->gr must be a0 or a2
844 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
845 g_assert(info->gr <= MIPS_LAST_ARG_REG);
847 ainfo->storage = ArgInIReg;
848 ainfo->reg = info->gr;
850 info->gr_passed = TRUE;
852 info->stack_size += 8;
856 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
857 /* First, see if we need to drop onto the stack */
858 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
859 args_onto_stack (info);
861 /* Now, place the argument */
862 if (info->on_stack) {
863 ainfo->storage = ArgOnStack;
864 ainfo->reg = mips_sp; /* in the caller */
865 ainfo->offset = info->stack_size;
868 /* Only use FP regs for args if no int args passed yet */
869 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
870 ainfo->storage = ArgInFReg;
871 ainfo->reg = info->fr;
872 /* Even though it's a single-precision float, it takes up two FP regs */
874 /* FP and GP slots do not overlap */
878 /* Passing single-precision float arg in a GP register
879 * such as: func (0, 1.0, 2, 3);
880 * In this case, only one 'gr' register is consumed.
882 ainfo->storage = ArgInIReg;
883 ainfo->reg = info->gr;
886 info->gr_passed = TRUE;
889 info->stack_size += 4;
893 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
894 /* First, see if we need to drop onto the stack */
895 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
896 args_onto_stack (info);
898 /* Now, place the argument */
899 if (info->on_stack) {
900 g_assert(info->stack_size % 4 == 0);
901 info->stack_size += (info->stack_size % 8);
903 ainfo->storage = ArgOnStack;
904 ainfo->reg = mips_sp; /* in the caller */
905 ainfo->offset = info->stack_size;
908 /* Only use FP regs for args if no int args passed yet */
909 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
910 ainfo->storage = ArgInFReg;
911 ainfo->reg = info->fr;
913 /* FP and GP slots do not overlap */
917 // info->gr must be a0 or a2
918 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
919 g_assert(info->gr <= MIPS_LAST_ARG_REG);
921 ainfo->storage = ArgInIReg;
922 ainfo->reg = info->gr;
924 info->gr_passed = TRUE;
927 info->stack_size += 8;
929 #elif _MIPS_SIM == _ABIN32
931 * N32 calling convention version
935 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
936 /* First, see if we need to drop onto the stack */
937 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
938 args_onto_stack (info);
940 /* Now, place the argument */
941 if (info->on_stack) {
942 ainfo->storage = ArgOnStack;
943 ainfo->reg = mips_sp; /* in the caller */
944 ainfo->offset = info->stack_size;
945 info->stack_size += SIZEOF_REGISTER;
948 ainfo->storage = ArgInIReg;
949 ainfo->reg = info->gr;
951 info->gr_passed = TRUE;
956 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
957 /* First, see if we need to drop onto the stack */
958 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
959 args_onto_stack (info);
961 /* Now, place the argument */
962 if (info->on_stack) {
963 g_assert (info->stack_size % 4 == 0);
964 info->stack_size += (info->stack_size % 8);
966 ainfo->storage = ArgOnStack;
967 ainfo->reg = mips_sp; /* in the caller */
968 ainfo->offset = info->stack_size;
969 info->stack_size += SIZEOF_REGISTER;
972 g_assert (info->gr <= MIPS_LAST_ARG_REG);
974 ainfo->storage = ArgInIReg;
975 ainfo->reg = info->gr;
977 info->gr_passed = TRUE;
982 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
983 /* First, see if we need to drop onto the stack */
984 if (!info->on_stack) {
985 if (info->gr > MIPS_LAST_ARG_REG)
986 args_onto_stack (info);
987 else if (info->fr > MIPS_LAST_FPARG_REG)
988 args_onto_stack (info);
991 /* Now, place the argument */
992 if (info->on_stack) {
993 ainfo->storage = ArgOnStack;
994 ainfo->reg = mips_sp; /* in the caller */
995 ainfo->offset = info->stack_size;
996 info->stack_size += FREG_SIZE;
999 ainfo->storage = ArgInFReg;
1000 ainfo->reg = info->fr;
1002 /* FP and GP slots do not overlap */
1008 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1009 /* First, see if we need to drop onto the stack */
1010 if (!info->on_stack) {
1011 if (info->gr > MIPS_LAST_ARG_REG)
1012 args_onto_stack (info);
1013 else if (info->fr > MIPS_LAST_FPARG_REG)
1014 args_onto_stack (info);
1017 /* Now, place the argument */
1018 if (info->on_stack) {
1019 g_assert(info->stack_size % 4 == 0);
1020 info->stack_size += (info->stack_size % 8);
1022 ainfo->storage = ArgOnStack;
1023 ainfo->reg = mips_sp; /* in the caller */
1024 ainfo->offset = info->stack_size;
1025 info->stack_size += FREG_SIZE;
1028 ainfo->storage = ArgInFReg;
1029 ainfo->reg = info->fr;
1031 /* FP and GP slots do not overlap */
1038 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1041 int n = sig->hasthis + sig->param_count;
1043 MonoType* simpletype;
1045 gboolean is_pinvoke = sig->pinvoke;
1048 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1050 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1052 cinfo->fr = MIPS_FIRST_FPARG_REG;
1053 cinfo->gr = MIPS_FIRST_ARG_REG;
1054 cinfo->stack_size = 0;
1056 DEBUG(printf("calculate_sizes\n"));
1058 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1062 /* handle returning a struct */
1063 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1064 cinfo->struct_ret = cinfo->gr;
1065 add_int32_arg (cinfo, &cinfo->ret);
1069 add_int32_arg (cinfo, cinfo->args + n);
1074 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1075 * the first argument, allowing 'this' to be always passed in the first arg reg.
1076 * Also do this if the first argument is a reference type, since virtual calls
1077 * are sometimes made using calli without sig->hasthis set, like in the delegate
1080 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1082 add_int32_arg (cinfo, cinfo->args + n);
1085 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1089 add_int32_arg (cinfo, &cinfo->ret);
1090 cinfo->struct_ret = cinfo->ret.reg;
1094 add_int32_arg (cinfo, cinfo->args + n);
1098 if (cinfo->vtype_retaddr) {
1099 add_int32_arg (cinfo, &cinfo->ret);
1100 cinfo->struct_ret = cinfo->ret.reg;
1105 DEBUG(printf("params: %d\n", sig->param_count));
1106 for (i = pstart; i < sig->param_count; ++i) {
1107 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1108 /* Prevent implicit arguments and sig_cookie from
1109 being passed in registers */
1110 args_onto_stack (cinfo);
1111 /* Emit the signature cookie just before the implicit arguments */
1112 add_int32_arg (cinfo, &cinfo->sig_cookie);
1114 DEBUG(printf("param %d: ", i));
1115 simpletype = mini_get_underlying_type (sig->params [i]);
1116 switch (simpletype->type) {
1119 DEBUG(printf("1 byte\n"));
1120 cinfo->args [n].size = 1;
1121 add_int32_arg (cinfo, &cinfo->args[n]);
1126 DEBUG(printf("2 bytes\n"));
1127 cinfo->args [n].size = 2;
1128 add_int32_arg (cinfo, &cinfo->args[n]);
1133 DEBUG(printf("4 bytes\n"));
1134 cinfo->args [n].size = 4;
1135 add_int32_arg (cinfo, &cinfo->args[n]);
1141 case MONO_TYPE_FNPTR:
1142 case MONO_TYPE_OBJECT:
1143 cinfo->args [n].size = sizeof (gpointer);
1144 add_int32_arg (cinfo, &cinfo->args[n]);
1147 case MONO_TYPE_GENERICINST:
1148 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1149 cinfo->args [n].size = sizeof (gpointer);
1150 add_int32_arg (cinfo, &cinfo->args[n]);
1155 case MONO_TYPE_TYPEDBYREF:
1156 case MONO_TYPE_VALUETYPE: {
1159 int has_offset = FALSE;
1161 gint size, alignment;
1164 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1165 size = sizeof (MonoTypedRef);
1166 alignment = sizeof (gpointer);
1168 klass = mono_class_from_mono_type (sig->params [i]);
1170 size = mono_class_native_size (klass, NULL);
1172 size = mono_class_value_size (klass, NULL);
1173 alignment = mono_class_min_align (klass);
1175 #if MIPS_PASS_STRUCTS_BY_VALUE
1176 /* Need to do alignment if struct contains long or double */
1177 if (alignment > 4) {
1178 /* Drop onto stack *before* looking at
1179 stack_size, if required. */
1180 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1181 args_onto_stack (cinfo);
1182 if (cinfo->stack_size & (alignment - 1)) {
1183 add_int32_arg (cinfo, &dummy_arg);
1185 g_assert (!(cinfo->stack_size & (alignment - 1)));
1189 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1190 mono_class_native_size (sig->params [i]->data.klass, NULL),
1191 cinfo->stack_size, alignment);
1193 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1194 g_assert (cinfo->args [n].size == 0);
1195 g_assert (cinfo->args [n].vtsize == 0);
1196 for (j = 0; j < nwords; ++j) {
1198 add_int32_arg (cinfo, &cinfo->args [n]);
1199 if (cinfo->on_stack)
1202 add_int32_arg (cinfo, &dummy_arg);
1203 if (!has_offset && cinfo->on_stack) {
1204 cinfo->args [n].offset = dummy_arg.offset;
1208 if (cinfo->on_stack)
1209 cinfo->args [n].vtsize += 1;
1211 cinfo->args [n].size += 1;
1213 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1214 cinfo->args [n].storage = ArgStructByVal;
1216 add_int32_arg (cinfo, &cinfo->args[n]);
1217 cinfo->args [n].storage = ArgStructByAddr;
1224 DEBUG(printf("8 bytes\n"));
1225 cinfo->args [n].size = 8;
1226 add_int64_arg (cinfo, &cinfo->args[n]);
1230 DEBUG(printf("R4\n"));
1231 cinfo->args [n].size = 4;
1232 add_float32_arg (cinfo, &cinfo->args[n]);
1236 DEBUG(printf("R8\n"));
1237 cinfo->args [n].size = 8;
1238 add_float64_arg (cinfo, &cinfo->args[n]);
1242 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1246 /* Handle the case where there are no implicit arguments */
1247 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1248 /* Prevent implicit arguments and sig_cookie from
1249 being passed in registers */
1250 args_onto_stack (cinfo);
1251 /* Emit the signature cookie just before the implicit arguments */
1252 add_int32_arg (cinfo, &cinfo->sig_cookie);
1256 simpletype = mini_get_underlying_type (sig->ret);
1257 switch (simpletype->type) {
1267 case MONO_TYPE_FNPTR:
1268 case MONO_TYPE_OBJECT:
1269 cinfo->ret.reg = mips_v0;
1273 cinfo->ret.reg = mips_v0;
1277 cinfo->ret.reg = mips_f0;
1278 cinfo->ret.storage = ArgInFReg;
1280 case MONO_TYPE_GENERICINST:
1281 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1282 cinfo->ret.reg = mips_v0;
1286 case MONO_TYPE_VALUETYPE:
1287 case MONO_TYPE_TYPEDBYREF:
1289 case MONO_TYPE_VOID:
1292 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1296 /* align stack size to 16 */
1297 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1299 cinfo->stack_usage = cinfo->stack_size;
1304 debug_omit_fp (void)
1307 return mono_debug_count ();
1314 * mono_arch_compute_omit_fp:
1315 * Determine whether the frame pointer can be eliminated.
1318 mono_arch_compute_omit_fp (MonoCompile *cfg)
1320 MonoMethodSignature *sig;
1321 MonoMethodHeader *header;
1325 if (cfg->arch.omit_fp_computed)
1328 header = cfg->header;
1330 sig = mono_method_signature (cfg->method);
1332 if (!cfg->arch.cinfo)
1333 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1334 cinfo = cfg->arch.cinfo;
1337 * FIXME: Remove some of the restrictions.
1339 cfg->arch.omit_fp = TRUE;
1340 cfg->arch.omit_fp_computed = TRUE;
1342 if (cfg->disable_omit_fp)
1343 cfg->arch.omit_fp = FALSE;
1344 if (!debug_omit_fp ())
1345 cfg->arch.omit_fp = FALSE;
1346 if (cfg->method->save_lmf)
1347 cfg->arch.omit_fp = FALSE;
1348 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1349 cfg->arch.omit_fp = FALSE;
1350 if (header->num_clauses)
1351 cfg->arch.omit_fp = FALSE;
1352 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1353 cfg->arch.omit_fp = FALSE;
1354 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)))
1355 cfg->arch.omit_fp = FALSE;
1357 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1358 * there are stack arguments.
1361 if (cinfo->stack_usage)
1362 cfg->arch.omit_fp = FALSE;
1366 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1367 MonoInst *ins = cfg->varinfo [i];
1370 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1373 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1377 * Set var information according to the calling convention. mips version.
1378 * The locals var stuff should most likely be split in another method.
1381 mono_arch_allocate_vars (MonoCompile *cfg)
1383 MonoMethodSignature *sig;
1384 MonoMethodHeader *header;
1386 int i, offset, size, align, curinst;
1387 int frame_reg = mips_sp;
1388 guint32 iregs_to_save = 0;
1390 guint32 fregs_to_restore;
1394 sig = mono_method_signature (cfg->method);
1396 if (!cfg->arch.cinfo)
1397 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1398 cinfo = cfg->arch.cinfo;
1400 mono_arch_compute_omit_fp (cfg);
1402 /* spill down, we'll fix it in a separate pass */
1403 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1405 /* allow room for the vararg method args: void* and long/double */
1406 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1407 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1409 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1410 * call convs needs to be handled this way.
1412 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1413 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1415 /* gtk-sharp and other broken code will dllimport vararg functions even with
1416 * non-varargs signatures. Since there is little hope people will get this right
1417 * we assume they won't.
1419 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1420 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1422 /* a0-a3 always present */
1423 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1425 header = cfg->header;
1427 if (cfg->arch.omit_fp)
1428 frame_reg = mips_sp;
1430 frame_reg = mips_fp;
1431 cfg->frame_reg = frame_reg;
1432 if (frame_reg != mips_sp) {
1433 cfg->used_int_regs |= 1 << frame_reg;
1438 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1439 /* FIXME: handle long and FP values */
1440 switch (mini_get_underlying_type (sig->ret)->type) {
1441 case MONO_TYPE_VOID:
1445 cfg->ret->opcode = OP_REGVAR;
1446 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1449 cfg->ret->opcode = OP_REGVAR;
1450 cfg->ret->inst_c0 = mips_v0;
1454 /* Space for outgoing parameters, including a0-a3 */
1455 offset += cfg->param_area;
1457 /* allow room to save the return value (if it's a struct) */
1458 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1461 /* Now handle the local variables */
1463 curinst = cfg->locals_start;
1464 for (i = curinst; i < cfg->num_varinfo; ++i) {
1465 inst = cfg->varinfo [i];
1466 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1469 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1470 * pinvoke wrappers when they call functions returning structure
1472 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1473 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1475 size = mono_type_size (inst->inst_vtype, &align);
1477 offset += align - 1;
1478 offset &= ~(align - 1);
1479 inst->inst_offset = offset;
1480 inst->opcode = OP_REGOFFSET;
1481 inst->inst_basereg = frame_reg;
1483 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1486 /* Space for LMF (if needed) */
1487 if (cfg->method->save_lmf) {
1488 /* align the offset to 16 bytes */
1489 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1490 cfg->arch.lmf_offset = offset;
1491 offset += sizeof (MonoLMF);
1494 if (sig->call_convention == MONO_CALL_VARARG) {
1498 /* Allocate a local slot to hold the sig cookie address */
1499 offset += align - 1;
1500 offset &= ~(align - 1);
1501 cfg->sig_cookie = offset;
1505 offset += SIZEOF_REGISTER - 1;
1506 offset &= ~(SIZEOF_REGISTER - 1);
1508 /* Space for saved registers */
1509 cfg->arch.iregs_offset = offset;
1510 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1511 if (iregs_to_save) {
1512 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1513 if (iregs_to_save & (1 << i)) {
1514 offset += SIZEOF_REGISTER;
1519 /* saved float registers */
1521 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1522 if (fregs_to_restore) {
1523 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1524 if (fregs_to_restore & (1 << i)) {
1525 offset += sizeof(double);
1531 #if _MIPS_SIM == _ABIO32
1532 /* Now add space for saving the ra */
1533 offset += SIZEOF_VOID_P;
1536 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1537 cfg->stack_offset = offset;
1538 cfg->arch.local_alloc_offset = cfg->stack_offset;
1542 * Now allocate stack slots for the int arg regs (a0 - a3)
1543 * On MIPS o32, these are just above the incoming stack pointer
1544 * Even if the arg has been assigned to a regvar, it gets a stack slot
1547 /* Return struct-by-value results in a hidden first argument */
1548 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1549 cfg->vret_addr->opcode = OP_REGOFFSET;
1550 cfg->vret_addr->inst_c0 = mips_a0;
1551 cfg->vret_addr->inst_offset = offset;
1552 cfg->vret_addr->inst_basereg = frame_reg;
1553 offset += SIZEOF_REGISTER;
1556 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1557 inst = cfg->args [i];
1558 if (inst->opcode != OP_REGVAR) {
1561 if (sig->hasthis && (i == 0))
1562 arg_type = &mono_defaults.object_class->byval_arg;
1564 arg_type = sig->params [i - sig->hasthis];
1566 inst->opcode = OP_REGOFFSET;
1567 size = mono_type_size (arg_type, &align);
1569 if (size < SIZEOF_REGISTER) {
1570 size = SIZEOF_REGISTER;
1571 align = SIZEOF_REGISTER;
1573 inst->inst_basereg = frame_reg;
1574 offset = (offset + align - 1) & ~(align - 1);
1575 inst->inst_offset = offset;
1577 if (cfg->verbose_level > 1)
1578 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1581 #if _MIPS_SIM == _ABIO32
1582 /* o32: Even a0-a3 get stack slots */
1583 size = SIZEOF_REGISTER;
1584 align = SIZEOF_REGISTER;
1585 inst->inst_basereg = frame_reg;
1586 offset = (offset + align - 1) & ~(align - 1);
1587 inst->inst_offset = offset;
1589 if (cfg->verbose_level > 1)
1590 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1594 #if _MIPS_SIM == _ABIN32
1595 /* Now add space for saving the ra */
1596 offset += SIZEOF_VOID_P;
1599 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1600 cfg->stack_offset = offset;
1601 cfg->arch.local_alloc_offset = cfg->stack_offset;
1606 mono_arch_create_vars (MonoCompile *cfg)
1608 MonoMethodSignature *sig;
1610 sig = mono_method_signature (cfg->method);
1612 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1613 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1614 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1615 printf ("vret_addr = ");
1616 mono_print_ins (cfg->vret_addr);
1621 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1622 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1626 * take the arguments and generate the arch-specific
1627 * instructions to properly call the function in call.
1628 * This includes pushing, moving arguments to the right register
1630 * Issue: who does the spilling if needed, and when?
1633 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1635 MonoMethodSignature *tmp_sig;
1638 if (call->tail_call)
1641 /* FIXME: Add support for signature tokens to AOT */
1642 cfg->disable_aot = TRUE;
1645 * mono_ArgIterator_Setup assumes the signature cookie is
1646 * passed first and all the arguments which were before it are
1647 * passed on the stack after the signature. So compensate by
1648 * passing a different signature.
1650 tmp_sig = mono_metadata_signature_dup (call->signature);
1651 tmp_sig->param_count -= call->signature->sentinelpos;
1652 tmp_sig->sentinelpos = 0;
1653 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1655 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1656 sig_arg->dreg = mono_alloc_ireg (cfg);
1657 sig_arg->inst_p0 = tmp_sig;
1658 MONO_ADD_INS (cfg->cbb, sig_arg);
1660 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1664 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1667 MonoMethodSignature *sig;
1672 sig = call->signature;
1673 n = sig->param_count + sig->hasthis;
1675 cinfo = get_call_info (cfg->mempool, sig);
1676 if (cinfo->struct_ret)
1677 call->used_iregs |= 1 << cinfo->struct_ret;
1679 for (i = 0; i < n; ++i) {
1680 ArgInfo *ainfo = cinfo->args + i;
1683 if (i >= sig->hasthis)
1684 t = sig->params [i - sig->hasthis];
1686 t = &mono_defaults.int_class->byval_arg;
1687 t = mini_get_underlying_type (t);
1689 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1690 /* Emit the signature cookie just before the implicit arguments */
1691 emit_sig_cookie (cfg, call, cinfo);
1694 if (is_virtual && i == 0) {
1695 /* the argument will be attached to the call instrucion */
1696 in = call->args [i];
1697 call->used_iregs |= 1 << ainfo->reg;
1700 in = call->args [i];
1701 if (ainfo->storage == ArgInIReg) {
1702 #if SIZEOF_REGISTER == 4
1703 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1704 MONO_INST_NEW (cfg, ins, OP_MOVE);
1705 ins->dreg = mono_alloc_ireg (cfg);
1706 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1707 MONO_ADD_INS (cfg->cbb, ins);
1708 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1710 MONO_INST_NEW (cfg, ins, OP_MOVE);
1711 ins->dreg = mono_alloc_ireg (cfg);
1712 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1713 MONO_ADD_INS (cfg->cbb, ins);
1714 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1717 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1720 #if PROMOTE_R4_TO_R8
1721 /* ??? - convert to single first? */
1722 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1723 ins->dreg = mono_alloc_freg (cfg);
1724 ins->sreg1 = in->dreg;
1725 MONO_ADD_INS (cfg->cbb, ins);
1730 /* trying to load float value into int registers */
1731 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1732 ins->dreg = mono_alloc_ireg (cfg);
1734 MONO_ADD_INS (cfg->cbb, ins);
1735 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1736 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1737 /* trying to load float value into int registers */
1738 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1739 ins->dreg = mono_alloc_ireg (cfg);
1740 ins->sreg1 = in->dreg;
1741 MONO_ADD_INS (cfg->cbb, ins);
1742 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1744 MONO_INST_NEW (cfg, ins, OP_MOVE);
1745 ins->dreg = mono_alloc_ireg (cfg);
1746 ins->sreg1 = in->dreg;
1747 MONO_ADD_INS (cfg->cbb, ins);
1748 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1750 } else if (ainfo->storage == ArgStructByAddr) {
1751 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1752 ins->opcode = OP_OUTARG_VT;
1753 ins->sreg1 = in->dreg;
1754 ins->klass = in->klass;
1755 ins->inst_p0 = call;
1756 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1757 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1758 MONO_ADD_INS (cfg->cbb, ins);
1759 } else if (ainfo->storage == ArgStructByVal) {
1760 /* this is further handled in mono_arch_emit_outarg_vt () */
1761 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1762 ins->opcode = OP_OUTARG_VT;
1763 ins->sreg1 = in->dreg;
1764 ins->klass = in->klass;
1765 ins->inst_p0 = call;
1766 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1767 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1768 MONO_ADD_INS (cfg->cbb, ins);
1769 } else if (ainfo->storage == ArgOnStack) {
1770 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1771 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1772 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1773 if (t->type == MONO_TYPE_R8)
1774 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1776 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1778 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1780 } else if (ainfo->storage == ArgInFReg) {
1781 if (t->type == MONO_TYPE_VALUETYPE) {
1782 /* this is further handled in mono_arch_emit_outarg_vt () */
1783 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1784 ins->opcode = OP_OUTARG_VT;
1785 ins->sreg1 = in->dreg;
1786 ins->klass = in->klass;
1787 ins->inst_p0 = call;
1788 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1789 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1790 MONO_ADD_INS (cfg->cbb, ins);
1792 cfg->flags |= MONO_CFG_HAS_FPOUT;
1794 int dreg = mono_alloc_freg (cfg);
1796 if (ainfo->size == 4) {
1797 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1799 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1801 ins->sreg1 = in->dreg;
1802 MONO_ADD_INS (cfg->cbb, ins);
1805 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1806 cfg->flags |= MONO_CFG_HAS_FPOUT;
1809 g_assert_not_reached ();
1813 /* Handle the case where there are no implicit arguments */
1814 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1815 emit_sig_cookie (cfg, call, cinfo);
1817 if (cinfo->struct_ret) {
1820 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1821 vtarg->sreg1 = call->vret_var->dreg;
1822 vtarg->dreg = mono_alloc_preg (cfg);
1823 MONO_ADD_INS (cfg->cbb, vtarg);
1825 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1829 * Reverse the call->out_args list.
1832 MonoInst *prev = NULL, *list = call->out_args, *next;
1839 call->out_args = prev;
1842 call->stack_usage = cinfo->stack_usage;
1843 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1844 #if _MIPS_SIM == _ABIO32
1845 /* a0-a3 always present */
1846 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1848 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1849 cfg->flags |= MONO_CFG_HAS_CALLS;
1851 * should set more info in call, such as the stack space
1852 * used by the args that needs to be added back to esp
1857 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1859 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1860 ArgInfo *ainfo = ins->inst_p1;
1861 int ovf_size = ainfo->vtsize;
1862 int doffset = ainfo->offset;
1863 int i, soffset, dreg;
1865 if (ainfo->storage == ArgStructByVal) {
1867 if (cfg->verbose_level > 0) {
1868 char* nm = mono_method_full_name (cfg->method, TRUE);
1869 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1870 nm, doffset, ainfo->size, ovf_size);
1876 for (i = 0; i < ainfo->size; ++i) {
1877 dreg = mono_alloc_ireg (cfg);
1878 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1879 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1880 soffset += SIZEOF_REGISTER;
1882 if (ovf_size != 0) {
1883 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), SIZEOF_VOID_P);
1885 } else if (ainfo->storage == ArgInFReg) {
1886 int tmpr = mono_alloc_freg (cfg);
1888 if (ainfo->size == 4)
1889 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1891 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1892 dreg = mono_alloc_freg (cfg);
1893 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1894 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1896 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1900 /* FIXME: alignment? */
1901 if (call->signature->pinvoke) {
1902 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1903 vtcopy->backend.is_pinvoke = 1;
1905 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1908 g_assert (ovf_size > 0);
1910 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1911 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, SIZEOF_VOID_P);
1914 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1916 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1921 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1923 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1926 #if (SIZEOF_REGISTER == 4)
1927 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1930 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1931 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1932 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1933 MONO_ADD_INS (cfg->cbb, ins);
1937 if (ret->type == MONO_TYPE_R8) {
1938 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1941 if (ret->type == MONO_TYPE_R4) {
1942 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1946 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1950 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1952 MonoInst *ins, *n, *last_ins = NULL;
1954 if (cfg->verbose_level > 2)
1955 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1958 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1959 if (cfg->verbose_level > 2)
1960 mono_print_ins_index (0, ins);
1962 switch (ins->opcode) {
1964 case OP_LOAD_MEMBASE:
1965 case OP_LOADI4_MEMBASE:
1967 * OP_IADD reg2, reg1, const1
1968 * OP_LOAD_MEMBASE const2(reg2), reg3
1970 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1972 if (last_ins && (last_ins->opcode == OP_IADD_IMM || last_ins->opcode == OP_ADD_IMM) && (last_ins->dreg == ins->inst_basereg) && (last_ins->sreg1 != last_ins->dreg)){
1973 int const1 = last_ins->inst_imm;
1974 int const2 = ins->inst_offset;
1976 if (mips_is_imm16 (const1 + const2)) {
1977 ins->inst_basereg = last_ins->sreg1;
1978 ins->inst_offset = const1 + const2;
1988 bb->last_ins = last_ins;
1992 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1994 MonoInst *ins, *n, *last_ins = NULL;
1997 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1998 MonoInst *last_ins = ins->prev;
2000 switch (ins->opcode) {
2002 /* remove unnecessary multiplication with 1 */
2003 if (ins->inst_imm == 1) {
2004 if (ins->dreg != ins->sreg1) {
2005 ins->opcode = OP_MOVE;
2007 MONO_DELETE_INS (bb, ins);
2011 int power2 = mono_is_power_of_two (ins->inst_imm);
2013 ins->opcode = OP_SHL_IMM;
2014 ins->inst_imm = power2;
2018 case OP_LOAD_MEMBASE:
2019 case OP_LOADI4_MEMBASE:
2021 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2022 * OP_LOAD_MEMBASE offset(basereg), reg
2024 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2025 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2026 ins->inst_basereg == last_ins->inst_destbasereg &&
2027 ins->inst_offset == last_ins->inst_offset) {
2028 if (ins->dreg == last_ins->sreg1) {
2029 MONO_DELETE_INS (bb, ins);
2032 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2033 ins->opcode = OP_MOVE;
2034 ins->sreg1 = last_ins->sreg1;
2039 * Note: reg1 must be different from the basereg in the second load
2040 * OP_LOAD_MEMBASE offset(basereg), reg1
2041 * OP_LOAD_MEMBASE offset(basereg), reg2
2043 * OP_LOAD_MEMBASE offset(basereg), reg1
2044 * OP_MOVE reg1, reg2
2046 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2047 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2048 ins->inst_basereg != last_ins->dreg &&
2049 ins->inst_basereg == last_ins->inst_basereg &&
2050 ins->inst_offset == last_ins->inst_offset) {
2052 if (ins->dreg == last_ins->dreg) {
2053 MONO_DELETE_INS (bb, ins);
2056 ins->opcode = OP_MOVE;
2057 ins->sreg1 = last_ins->dreg;
2060 //g_assert_not_reached ();
2065 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2066 * OP_LOAD_MEMBASE offset(basereg), reg
2068 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2069 * OP_ICONST reg, imm
2071 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2072 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2073 ins->inst_basereg == last_ins->inst_destbasereg &&
2074 ins->inst_offset == last_ins->inst_offset) {
2075 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2076 ins->opcode = OP_ICONST;
2077 ins->inst_c0 = last_ins->inst_imm;
2078 g_assert_not_reached (); // check this rule
2083 case OP_LOADU1_MEMBASE:
2084 case OP_LOADI1_MEMBASE:
2085 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2086 ins->inst_basereg == last_ins->inst_destbasereg &&
2087 ins->inst_offset == last_ins->inst_offset) {
2088 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2089 ins->sreg1 = last_ins->sreg1;
2092 case OP_LOADU2_MEMBASE:
2093 case OP_LOADI2_MEMBASE:
2094 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2095 ins->inst_basereg == last_ins->inst_destbasereg &&
2096 ins->inst_offset == last_ins->inst_offset) {
2097 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2098 ins->sreg1 = last_ins->sreg1;
2101 case OP_ICONV_TO_I4:
2102 case OP_ICONV_TO_U4:
2104 ins->opcode = OP_MOVE;
2108 if (ins->dreg == ins->sreg1) {
2109 MONO_DELETE_INS (bb, ins);
2113 * OP_MOVE sreg, dreg
2114 * OP_MOVE dreg, sreg
2116 if (last_ins && last_ins->opcode == OP_MOVE &&
2117 ins->sreg1 == last_ins->dreg &&
2118 ins->dreg == last_ins->sreg1) {
2119 MONO_DELETE_INS (bb, ins);
2127 bb->last_ins = last_ins;
2131 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2139 switch (ins->opcode) {
2141 tmp1 = mono_alloc_ireg (cfg);
2142 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2143 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2144 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2145 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2150 tmp1 = mono_alloc_ireg (cfg);
2151 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2152 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2153 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2154 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2159 tmp1 = mono_alloc_ireg (cfg);
2160 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2161 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2162 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2163 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2168 tmp1 = mono_alloc_ireg (cfg);
2169 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2170 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2171 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2172 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2177 tmp1 = mono_alloc_ireg (cfg);
2178 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2179 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2180 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2181 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2186 tmp1 = mono_alloc_ireg (cfg);
2187 tmp2 = mono_alloc_ireg (cfg);
2188 tmp3 = mono_alloc_ireg (cfg);
2189 tmp4 = mono_alloc_ireg (cfg);
2190 tmp5 = mono_alloc_ireg (cfg);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2194 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2195 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2197 /* add the high 32-bits, and add in the carry from the low 32-bits */
2198 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2199 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2201 /* Overflow happens if
2202 * neg + neg = pos or
2204 * XOR of the high bits returns 0 if the signs match
2205 * XOR of that with the high bit of the result return 1 if overflow.
2208 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2209 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2211 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2212 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2213 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2215 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2216 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2217 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2219 /* Now, if (tmp4 == 0) then overflow */
2220 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2224 case OP_LADD_OVF_UN:
2225 tmp1 = mono_alloc_ireg (cfg);
2226 tmp2 = mono_alloc_ireg (cfg);
2228 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2229 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2230 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2231 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2232 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2233 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2238 tmp1 = mono_alloc_ireg (cfg);
2239 tmp2 = mono_alloc_ireg (cfg);
2240 tmp3 = mono_alloc_ireg (cfg);
2241 tmp4 = mono_alloc_ireg (cfg);
2242 tmp5 = mono_alloc_ireg (cfg);
2244 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2246 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2247 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2248 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2250 /* Overflow happens if
2251 * neg - pos = pos or
2253 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2255 * tmp1 = (lhs ^ rhs)
2256 * tmp2 = (lhs ^ result)
2257 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2260 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2261 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2262 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2263 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2265 /* Now, if (tmp4 == 1) then overflow */
2266 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2270 case OP_LSUB_OVF_UN:
2271 tmp1 = mono_alloc_ireg (cfg);
2272 tmp2 = mono_alloc_ireg (cfg);
2274 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2275 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2276 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2277 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2279 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2280 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2283 case OP_LCONV_TO_OVF_I4_2:
2284 tmp1 = mono_alloc_ireg (cfg);
2286 /* Overflows if reg2 != sign extension of reg1 */
2287 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2288 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2289 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2298 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2306 switch (ins->opcode) {
2308 tmp1 = mono_alloc_ireg (cfg);
2309 tmp2 = mono_alloc_ireg (cfg);
2310 tmp3 = mono_alloc_ireg (cfg);
2311 tmp4 = mono_alloc_ireg (cfg);
2312 tmp5 = mono_alloc_ireg (cfg);
2314 /* add the operands */
2316 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2318 /* Overflow happens if
2319 * neg + neg = pos or
2322 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2323 * XOR of the high bit returns 0 if the signs match
2324 * XOR of that with the high bit of the result return 1 if overflow.
2327 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2328 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2330 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2331 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2332 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2334 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2335 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2337 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2339 /* Now, if (tmp5 == 0) then overflow */
2340 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2341 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2342 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2346 case OP_IADD_OVF_UN:
2347 tmp1 = mono_alloc_ireg (cfg);
2349 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2350 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2351 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2352 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2353 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2358 tmp1 = mono_alloc_ireg (cfg);
2359 tmp2 = mono_alloc_ireg (cfg);
2360 tmp3 = mono_alloc_ireg (cfg);
2361 tmp4 = mono_alloc_ireg (cfg);
2362 tmp5 = mono_alloc_ireg (cfg);
2364 /* add the operands */
2366 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2368 /* Overflow happens if
2369 * neg - pos = pos or
2371 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2373 * tmp1 = (lhs ^ rhs)
2374 * tmp2 = (lhs ^ result)
2375 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2378 /* tmp3 = 1 if the signs of the two inputs differ */
2379 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2380 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2381 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2382 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2383 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2385 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2386 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2387 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2391 case OP_ISUB_OVF_UN:
2392 tmp1 = mono_alloc_ireg (cfg);
2394 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2395 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2396 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2397 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2398 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2405 map_to_reg_reg_op (int op)
2414 case OP_COMPARE_IMM:
2416 case OP_ICOMPARE_IMM:
2418 case OP_LCOMPARE_IMM:
2434 case OP_LOAD_MEMBASE:
2435 return OP_LOAD_MEMINDEX;
2436 case OP_LOADI4_MEMBASE:
2437 return OP_LOADI4_MEMINDEX;
2438 case OP_LOADU4_MEMBASE:
2439 return OP_LOADU4_MEMINDEX;
2440 case OP_LOADU1_MEMBASE:
2441 return OP_LOADU1_MEMINDEX;
2442 case OP_LOADI2_MEMBASE:
2443 return OP_LOADI2_MEMINDEX;
2444 case OP_LOADU2_MEMBASE:
2445 return OP_LOADU2_MEMINDEX;
2446 case OP_LOADI1_MEMBASE:
2447 return OP_LOADI1_MEMINDEX;
2448 case OP_LOADR4_MEMBASE:
2449 return OP_LOADR4_MEMINDEX;
2450 case OP_LOADR8_MEMBASE:
2451 return OP_LOADR8_MEMINDEX;
2452 case OP_STOREI1_MEMBASE_REG:
2453 return OP_STOREI1_MEMINDEX;
2454 case OP_STOREI2_MEMBASE_REG:
2455 return OP_STOREI2_MEMINDEX;
2456 case OP_STOREI4_MEMBASE_REG:
2457 return OP_STOREI4_MEMINDEX;
2458 case OP_STORE_MEMBASE_REG:
2459 return OP_STORE_MEMINDEX;
2460 case OP_STORER4_MEMBASE_REG:
2461 return OP_STORER4_MEMINDEX;
2462 case OP_STORER8_MEMBASE_REG:
2463 return OP_STORER8_MEMINDEX;
2464 case OP_STORE_MEMBASE_IMM:
2465 return OP_STORE_MEMBASE_REG;
2466 case OP_STOREI1_MEMBASE_IMM:
2467 return OP_STOREI1_MEMBASE_REG;
2468 case OP_STOREI2_MEMBASE_IMM:
2469 return OP_STOREI2_MEMBASE_REG;
2470 case OP_STOREI4_MEMBASE_IMM:
2471 return OP_STOREI4_MEMBASE_REG;
2472 case OP_STOREI8_MEMBASE_IMM:
2473 return OP_STOREI8_MEMBASE_REG;
2475 if (mono_op_imm_to_op (op) == -1)
2476 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2477 return mono_op_imm_to_op (op);
2481 map_to_mips_op (int op)
2485 return OP_MIPS_FBEQ;
2487 return OP_MIPS_FBGE;
2489 return OP_MIPS_FBGT;
2491 return OP_MIPS_FBLE;
2493 return OP_MIPS_FBLT;
2495 return OP_MIPS_FBNE;
2497 return OP_MIPS_FBGE_UN;
2499 return OP_MIPS_FBGT_UN;
2501 return OP_MIPS_FBLE_UN;
2503 return OP_MIPS_FBLT_UN;
2511 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2512 g_assert_not_reached ();
2516 #define NEW_INS(cfg,after,dest,op) do { \
2517 MONO_INST_NEW((cfg), (dest), (op)); \
2518 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2521 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2523 MONO_INST_NEW(cfg, temp, (op)); \
2524 mono_bblock_insert_after_ins (bb, (pos), temp); \
2525 temp->dreg = (_dreg); \
2526 temp->sreg1 = (_sreg1); \
2527 temp->sreg2 = (_sreg2); \
2531 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2533 MONO_INST_NEW(cfg, temp, (op)); \
2534 mono_bblock_insert_after_ins (bb, (pos), temp); \
2535 temp->dreg = (_dreg); \
2536 temp->sreg1 = (_sreg1); \
2537 temp->inst_c0 = (_imm); \
2542 * Remove from the instruction list the instructions that can't be
2543 * represented with very simple instructions with no register
2547 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2549 MonoInst *ins, *next, *temp, *last_ins = NULL;
2553 if (cfg->verbose_level > 2) {
2556 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2557 MONO_BB_FOR_EACH_INS (bb, ins) {
2558 mono_print_ins_index (idx++, ins);
2564 MONO_BB_FOR_EACH_INS (bb, ins) {
2566 switch (ins->opcode) {
2571 /* Branch opts can eliminate the branch */
2572 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2578 case OP_COMPARE_IMM:
2579 case OP_ICOMPARE_IMM:
2580 case OP_LCOMPARE_IMM:
2582 /* Branch opts can eliminate the branch */
2583 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2587 if (ins->inst_imm) {
2588 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2589 temp->inst_c0 = ins->inst_imm;
2590 temp->dreg = mono_alloc_ireg (cfg);
2591 ins->sreg2 = temp->dreg;
2595 ins->sreg2 = mips_zero;
2597 if (ins->opcode == OP_COMPARE_IMM)
2598 ins->opcode = OP_COMPARE;
2599 else if (ins->opcode == OP_ICOMPARE_IMM)
2600 ins->opcode = OP_ICOMPARE;
2601 else if (ins->opcode == OP_LCOMPARE_IMM)
2602 ins->opcode = OP_LCOMPARE;
2605 case OP_IDIV_UN_IMM:
2608 case OP_IREM_UN_IMM:
2609 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2610 temp->inst_c0 = ins->inst_imm;
2611 temp->dreg = mono_alloc_ireg (cfg);
2612 ins->sreg2 = temp->dreg;
2613 if (ins->opcode == OP_IDIV_IMM)
2614 ins->opcode = OP_IDIV;
2615 else if (ins->opcode == OP_IREM_IMM)
2616 ins->opcode = OP_IREM;
2617 else if (ins->opcode == OP_IDIV_UN_IMM)
2618 ins->opcode = OP_IDIV_UN;
2619 else if (ins->opcode == OP_IREM_UN_IMM)
2620 ins->opcode = OP_IREM_UN;
2622 /* handle rem separately */
2629 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2630 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2631 temp->inst_c0 = ins->inst_imm;
2632 temp->dreg = mono_alloc_ireg (cfg);
2633 ins->sreg2 = temp->dreg;
2634 ins->opcode = map_to_reg_reg_op (ins->opcode);
2644 /* unsigned 16 bit immediate */
2645 if (ins->inst_imm & 0xffff0000) {
2646 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2647 temp->inst_c0 = ins->inst_imm;
2648 temp->dreg = mono_alloc_ireg (cfg);
2649 ins->sreg2 = temp->dreg;
2650 ins->opcode = map_to_reg_reg_op (ins->opcode);
2657 /* signed 16 bit immediate */
2658 if (!mips_is_imm16 (ins->inst_imm)) {
2659 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2660 temp->inst_c0 = ins->inst_imm;
2661 temp->dreg = mono_alloc_ireg (cfg);
2662 ins->sreg2 = temp->dreg;
2663 ins->opcode = map_to_reg_reg_op (ins->opcode);
2669 if (!mips_is_imm16 (-ins->inst_imm)) {
2670 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2671 temp->inst_c0 = ins->inst_imm;
2672 temp->dreg = mono_alloc_ireg (cfg);
2673 ins->sreg2 = temp->dreg;
2674 ins->opcode = map_to_reg_reg_op (ins->opcode);
2680 if (ins->inst_imm == 1) {
2681 ins->opcode = OP_MOVE;
2684 if (ins->inst_imm == 0) {
2685 ins->opcode = OP_ICONST;
2689 imm = mono_is_power_of_two (ins->inst_imm);
2691 ins->opcode = OP_SHL_IMM;
2692 ins->inst_imm = imm;
2695 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2696 temp->inst_c0 = ins->inst_imm;
2697 temp->dreg = mono_alloc_ireg (cfg);
2698 ins->sreg2 = temp->dreg;
2699 ins->opcode = map_to_reg_reg_op (ins->opcode);
2702 case OP_LOCALLOC_IMM:
2703 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2704 temp->inst_c0 = ins->inst_imm;
2705 temp->dreg = mono_alloc_ireg (cfg);
2706 ins->sreg1 = temp->dreg;
2707 ins->opcode = OP_LOCALLOC;
2710 case OP_LOADR4_MEMBASE:
2711 case OP_STORER4_MEMBASE_REG:
2712 /* we can do two things: load the immed in a register
2713 * and use an indexed load, or see if the immed can be
2714 * represented as an ad_imm + a load with a smaller offset
2715 * that fits. We just do the first for now, optimize later.
2717 if (mips_is_imm16 (ins->inst_offset))
2719 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2720 temp->inst_c0 = ins->inst_offset;
2721 temp->dreg = mono_alloc_ireg (cfg);
2722 ins->sreg2 = temp->dreg;
2723 ins->opcode = map_to_reg_reg_op (ins->opcode);
2726 case OP_STORE_MEMBASE_IMM:
2727 case OP_STOREI1_MEMBASE_IMM:
2728 case OP_STOREI2_MEMBASE_IMM:
2729 case OP_STOREI4_MEMBASE_IMM:
2730 case OP_STOREI8_MEMBASE_IMM:
2731 if (!ins->inst_imm) {
2732 ins->sreg1 = mips_zero;
2733 ins->opcode = map_to_reg_reg_op (ins->opcode);
2736 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2737 temp->inst_c0 = ins->inst_imm;
2738 temp->dreg = mono_alloc_ireg (cfg);
2739 ins->sreg1 = temp->dreg;
2740 ins->opcode = map_to_reg_reg_op (ins->opcode);
2742 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2748 /* Branch opts can eliminate the branch */
2749 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2756 * remap compare/branch and compare/set
2757 * to MIPS specific opcodes.
2759 next->opcode = map_to_mips_op (next->opcode);
2760 next->sreg1 = ins->sreg1;
2761 next->sreg2 = ins->sreg2;
2768 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2769 temp->inst_c0 = (guint32)ins->inst_p0;
2770 temp->dreg = mono_alloc_ireg (cfg);
2771 ins->inst_basereg = temp->dreg;
2772 ins->inst_offset = 0;
2773 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2775 /* make it handle the possibly big ins->inst_offset
2776 * later optimize to use lis + load_membase
2781 g_assert (ins_is_compare(last_ins));
2782 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2783 NULLIFY_INS(last_ins);
2787 g_assert (ins_is_compare(last_ins));
2788 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2789 NULLIFY_INS(last_ins);
2793 g_assert (ins_is_compare(last_ins));
2794 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2795 last_ins->dreg = mono_alloc_ireg (cfg);
2796 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2800 g_assert (ins_is_compare(last_ins));
2801 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2802 last_ins->dreg = mono_alloc_ireg (cfg);
2803 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2807 g_assert (ins_is_compare(last_ins));
2808 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2809 last_ins->dreg = mono_alloc_ireg (cfg);
2810 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2814 g_assert (ins_is_compare(last_ins));
2815 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2816 last_ins->dreg = mono_alloc_ireg (cfg);
2817 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2821 g_assert (ins_is_compare(last_ins));
2822 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2823 last_ins->dreg = mono_alloc_ireg (cfg);
2824 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2828 g_assert (ins_is_compare(last_ins));
2829 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2830 last_ins->dreg = mono_alloc_ireg (cfg);
2831 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2835 g_assert (ins_is_compare(last_ins));
2836 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2837 last_ins->dreg = mono_alloc_ireg (cfg);
2838 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2842 g_assert (ins_is_compare(last_ins));
2843 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2844 last_ins->dreg = mono_alloc_ireg (cfg);
2845 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2850 g_assert (ins_is_compare(last_ins));
2851 last_ins->opcode = OP_IXOR;
2852 last_ins->dreg = mono_alloc_ireg(cfg);
2853 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2858 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2859 NULLIFY_INS(last_ins);
2865 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2866 NULLIFY_INS(last_ins);
2871 g_assert (ins_is_compare(last_ins));
2872 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2873 MONO_DELETE_INS(bb, last_ins);
2878 g_assert (ins_is_compare(last_ins));
2879 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2880 MONO_DELETE_INS(bb, last_ins);
2883 case OP_COND_EXC_EQ:
2884 case OP_COND_EXC_IEQ:
2885 g_assert (ins_is_compare(last_ins));
2886 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2887 MONO_DELETE_INS(bb, last_ins);
2890 case OP_COND_EXC_GE:
2891 case OP_COND_EXC_IGE:
2892 g_assert (ins_is_compare(last_ins));
2893 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2894 MONO_DELETE_INS(bb, last_ins);
2897 case OP_COND_EXC_GT:
2898 case OP_COND_EXC_IGT:
2899 g_assert (ins_is_compare(last_ins));
2900 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2901 MONO_DELETE_INS(bb, last_ins);
2904 case OP_COND_EXC_LE:
2905 case OP_COND_EXC_ILE:
2906 g_assert (ins_is_compare(last_ins));
2907 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2908 MONO_DELETE_INS(bb, last_ins);
2911 case OP_COND_EXC_LT:
2912 case OP_COND_EXC_ILT:
2913 g_assert (ins_is_compare(last_ins));
2914 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2915 MONO_DELETE_INS(bb, last_ins);
2918 case OP_COND_EXC_NE_UN:
2919 case OP_COND_EXC_INE_UN:
2920 g_assert (ins_is_compare(last_ins));
2921 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2922 MONO_DELETE_INS(bb, last_ins);
2925 case OP_COND_EXC_GE_UN:
2926 case OP_COND_EXC_IGE_UN:
2927 g_assert (ins_is_compare(last_ins));
2928 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2929 MONO_DELETE_INS(bb, last_ins);
2932 case OP_COND_EXC_GT_UN:
2933 case OP_COND_EXC_IGT_UN:
2934 g_assert (ins_is_compare(last_ins));
2935 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2936 MONO_DELETE_INS(bb, last_ins);
2939 case OP_COND_EXC_LE_UN:
2940 case OP_COND_EXC_ILE_UN:
2941 g_assert (ins_is_compare(last_ins));
2942 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2943 MONO_DELETE_INS(bb, last_ins);
2946 case OP_COND_EXC_LT_UN:
2947 case OP_COND_EXC_ILT_UN:
2948 g_assert (ins_is_compare(last_ins));
2949 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2950 MONO_DELETE_INS(bb, last_ins);
2953 case OP_COND_EXC_OV:
2954 case OP_COND_EXC_IOV: {
2955 int tmp1, tmp2, tmp3, tmp4, tmp5;
2956 MonoInst *pos = last_ins;
2958 /* Overflow happens if
2959 * neg + neg = pos or
2962 * (bit31s of operands match) AND (bit31 of operand
2963 * != bit31 of result)
2964 * XOR of the high bit returns 0 if the signs match
2965 * XOR of that with the high bit of the result return 1
2968 g_assert (last_ins->opcode == OP_IADC);
2970 tmp1 = mono_alloc_ireg (cfg);
2971 tmp2 = mono_alloc_ireg (cfg);
2972 tmp3 = mono_alloc_ireg (cfg);
2973 tmp4 = mono_alloc_ireg (cfg);
2974 tmp5 = mono_alloc_ireg (cfg);
2976 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2977 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2979 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2980 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2981 INS (pos, OP_INOT, tmp3, tmp2, -1);
2983 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2984 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2985 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2987 /* Now, if (tmp5 == 0) then overflow */
2988 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2993 case OP_COND_EXC_NO:
2994 case OP_COND_EXC_INO:
2995 g_assert_not_reached ();
2999 case OP_COND_EXC_IC:
3000 g_assert_not_reached ();
3003 case OP_COND_EXC_NC:
3004 case OP_COND_EXC_INC:
3005 g_assert_not_reached ();
3011 bb->last_ins = last_ins;
3012 bb->max_vreg = cfg->next_vreg;
3015 if (cfg->verbose_level > 2) {
3018 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3019 MONO_BB_FOR_EACH_INS (bb, ins) {
3020 mono_print_ins_index (idx++, ins);
3029 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3031 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3033 mips_truncwd (code, mips_ftemp, sreg);
3035 mips_cvtwd (code, mips_ftemp, sreg);
3037 mips_mfc1 (code, dreg, mips_ftemp);
3040 mips_andi (code, dreg, dreg, 0xff);
3041 else if (size == 2) {
3042 mips_sll (code, dreg, dreg, 16);
3043 mips_srl (code, dreg, dreg, 16);
3047 mips_sll (code, dreg, dreg, 24);
3048 mips_sra (code, dreg, dreg, 24);
3050 else if (size == 2) {
3051 mips_sll (code, dreg, dreg, 16);
3052 mips_sra (code, dreg, dreg, 16);
3059 * emit_load_volatile_arguments:
3061 * Load volatile arguments from the stack to the original input registers.
3062 * Required before a tail call.
3065 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3067 MonoMethod *method = cfg->method;
3068 MonoMethodSignature *sig;
3073 sig = mono_method_signature (method);
3075 if (!cfg->arch.cinfo)
3076 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3077 cinfo = cfg->arch.cinfo;
3079 if (cinfo->struct_ret) {
3080 ArgInfo *ainfo = &cinfo->ret;
3081 inst = cfg->vret_addr;
3082 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3085 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3086 ArgInfo *ainfo = cinfo->args + i;
3087 inst = cfg->args [i];
3088 if (inst->opcode == OP_REGVAR) {
3089 if (ainfo->storage == ArgInIReg)
3090 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3091 else if (ainfo->storage == ArgInFReg)
3092 g_assert_not_reached();
3093 else if (ainfo->storage == ArgOnStack) {
3096 g_assert_not_reached ();
3098 if (ainfo->storage == ArgInIReg) {
3099 g_assert (mips_is_imm16 (inst->inst_offset));
3100 switch (ainfo->size) {
3102 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3105 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3109 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3112 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3113 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3116 g_assert_not_reached ();
3119 } else if (ainfo->storage == ArgOnStack) {
3121 } else if (ainfo->storage == ArgInFReg) {
3122 g_assert (mips_is_imm16 (inst->inst_offset));
3123 if (ainfo->size == 8) {
3124 #if _MIPS_SIM == _ABIO32
3125 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3126 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3127 #elif _MIPS_SIM == _ABIN32
3128 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3131 else if (ainfo->size == 4)
3132 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3134 g_assert_not_reached ();
3135 } else if (ainfo->storage == ArgStructByVal) {
3137 int doffset = inst->inst_offset;
3139 g_assert (mips_is_imm16 (inst->inst_offset));
3140 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3141 for (i = 0; i < ainfo->size; ++i) {
3142 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3143 doffset += SIZEOF_REGISTER;
3145 } else if (ainfo->storage == ArgStructByAddr) {
3146 g_assert (mips_is_imm16 (inst->inst_offset));
3147 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3149 g_assert_not_reached ();
3157 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3159 int size = cfg->param_area;
3161 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3162 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3167 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3168 if (ppc_is_imm16 (-size)) {
3169 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3171 ppc_load (code, ppc_r12, -size);
3172 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3179 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3181 int size = cfg->param_area;
3183 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3184 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3189 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3190 if (ppc_is_imm16 (size)) {
3191 ppc_stwu (code, ppc_r0, size, ppc_sp);
3193 ppc_load (code, ppc_r12, size);
3194 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3201 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3206 guint8 *code = cfg->native_code + cfg->code_len;
3207 MonoInst *last_ins = NULL;
3208 guint last_offset = 0;
3212 /* we don't align basic blocks of loops on mips */
3214 if (cfg->verbose_level > 2)
3215 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3217 cpos = bb->max_offset;
3220 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3221 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3222 g_assert (!mono_compile_aot);
3225 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3226 /* this is not thread save, but good enough */
3227 /* fixme: howto handle overflows? */
3228 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3229 mips_lw (code, mips_temp, mips_at, 0);
3230 mips_addiu (code, mips_temp, mips_temp, 1);
3231 mips_sw (code, mips_temp, mips_at, 0);
3234 MONO_BB_FOR_EACH_INS (bb, ins) {
3235 offset = code - cfg->native_code;
3237 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3239 if (offset > (cfg->code_size - max_len - 16)) {
3240 cfg->code_size *= 2;
3241 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3242 code = cfg->native_code + offset;
3244 mono_debug_record_line_number (cfg, ins, offset);
3245 if (cfg->verbose_level > 2) {
3246 g_print (" @ 0x%x\t", offset);
3247 mono_print_ins_index (ins_cnt++, ins);
3249 /* Check for virtual regs that snuck by */
3250 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3252 switch (ins->opcode) {
3253 case OP_RELAXED_NOP:
3256 case OP_DUMMY_STORE:
3257 case OP_NOT_REACHED:
3260 case OP_IL_SEQ_POINT:
3261 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3263 case OP_SEQ_POINT: {
3264 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3265 guint32 addr = (guint32)ss_trigger_page;
3267 mips_load_const (code, mips_t9, addr);
3268 mips_lw (code, mips_t9, mips_t9, 0);
3271 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3274 * A placeholder for a possible breakpoint inserted by
3275 * mono_arch_set_breakpoint ().
3277 /* mips_load_const () + mips_lw */
3284 mips_mult (code, ins->sreg1, ins->sreg2);
3285 mips_mflo (code, ins->dreg);
3286 mips_mfhi (code, ins->dreg+1);
3289 mips_multu (code, ins->sreg1, ins->sreg2);
3290 mips_mflo (code, ins->dreg);
3291 mips_mfhi (code, ins->dreg+1);
3293 case OP_MEMORY_BARRIER:
3294 mips_sync (code, 0);
3296 case OP_STOREI1_MEMBASE_IMM:
3297 mips_load_const (code, mips_temp, ins->inst_imm);
3298 if (mips_is_imm16 (ins->inst_offset)) {
3299 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3301 mips_load_const (code, mips_at, ins->inst_offset);
3302 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3305 case OP_STOREI2_MEMBASE_IMM:
3306 mips_load_const (code, mips_temp, ins->inst_imm);
3307 if (mips_is_imm16 (ins->inst_offset)) {
3308 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3310 mips_load_const (code, mips_at, ins->inst_offset);
3311 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3314 case OP_STOREI8_MEMBASE_IMM:
3315 mips_load_const (code, mips_temp, ins->inst_imm);
3316 if (mips_is_imm16 (ins->inst_offset)) {
3317 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3319 mips_load_const (code, mips_at, ins->inst_offset);
3320 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3323 case OP_STORE_MEMBASE_IMM:
3324 case OP_STOREI4_MEMBASE_IMM:
3325 mips_load_const (code, mips_temp, ins->inst_imm);
3326 if (mips_is_imm16 (ins->inst_offset)) {
3327 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3329 mips_load_const (code, mips_at, ins->inst_offset);
3330 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3333 case OP_STOREI1_MEMBASE_REG:
3334 if (mips_is_imm16 (ins->inst_offset)) {
3335 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3337 mips_load_const (code, mips_at, ins->inst_offset);
3338 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3339 mips_sb (code, ins->sreg1, mips_at, 0);
3342 case OP_STOREI2_MEMBASE_REG:
3343 if (mips_is_imm16 (ins->inst_offset)) {
3344 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3346 mips_load_const (code, mips_at, ins->inst_offset);
3347 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3348 mips_sh (code, ins->sreg1, mips_at, 0);
3351 case OP_STORE_MEMBASE_REG:
3352 case OP_STOREI4_MEMBASE_REG:
3353 if (mips_is_imm16 (ins->inst_offset)) {
3354 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3356 mips_load_const (code, mips_at, ins->inst_offset);
3357 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3358 mips_sw (code, ins->sreg1, mips_at, 0);
3361 case OP_STOREI8_MEMBASE_REG:
3362 if (mips_is_imm16 (ins->inst_offset)) {
3363 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3365 mips_load_const (code, mips_at, ins->inst_offset);
3366 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3367 mips_sd (code, ins->sreg1, mips_at, 0);
3371 g_assert_not_reached ();
3372 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3373 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3375 case OP_LOADI8_MEMBASE:
3376 if (mips_is_imm16 (ins->inst_offset)) {
3377 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3379 mips_load_const (code, mips_at, ins->inst_offset);
3380 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3381 mips_ld (code, ins->dreg, mips_at, 0);
3384 case OP_LOAD_MEMBASE:
3385 case OP_LOADI4_MEMBASE:
3386 case OP_LOADU4_MEMBASE:
3387 g_assert (ins->dreg != -1);
3388 if (mips_is_imm16 (ins->inst_offset)) {
3389 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3391 mips_load_const (code, mips_at, ins->inst_offset);
3392 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3393 mips_lw (code, ins->dreg, mips_at, 0);
3396 case OP_LOADI1_MEMBASE:
3397 if (mips_is_imm16 (ins->inst_offset)) {
3398 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3400 mips_load_const (code, mips_at, ins->inst_offset);
3401 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3402 mips_lb (code, ins->dreg, mips_at, 0);
3405 case OP_LOADU1_MEMBASE:
3406 if (mips_is_imm16 (ins->inst_offset)) {
3407 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3409 mips_load_const (code, mips_at, ins->inst_offset);
3410 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3411 mips_lbu (code, ins->dreg, mips_at, 0);
3414 case OP_LOADI2_MEMBASE:
3415 if (mips_is_imm16 (ins->inst_offset)) {
3416 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3418 mips_load_const (code, mips_at, ins->inst_offset);
3419 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3420 mips_lh (code, ins->dreg, mips_at, 0);
3423 case OP_LOADU2_MEMBASE:
3424 if (mips_is_imm16 (ins->inst_offset)) {
3425 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3427 mips_load_const (code, mips_at, ins->inst_offset);
3428 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3429 mips_lhu (code, ins->dreg, mips_at, 0);
3432 case OP_ICONV_TO_I1:
3433 mips_sll (code, mips_at, ins->sreg1, 24);
3434 mips_sra (code, ins->dreg, mips_at, 24);
3436 case OP_ICONV_TO_I2:
3437 mips_sll (code, mips_at, ins->sreg1, 16);
3438 mips_sra (code, ins->dreg, mips_at, 16);
3440 case OP_ICONV_TO_U1:
3441 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3443 case OP_ICONV_TO_U2:
3444 mips_sll (code, mips_at, ins->sreg1, 16);
3445 mips_srl (code, ins->dreg, mips_at, 16);
3448 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3451 g_assert (mips_is_imm16 (ins->inst_imm));
3452 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3455 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3458 g_assert (mips_is_imm16 (ins->inst_imm));
3459 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3463 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3464 * So instead of emitting a trap, we emit a call a C function and place a
3467 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3468 (gpointer)"mono_break");
3469 mips_load (code, mips_t9, 0x1f1f1f1f);
3470 mips_jalr (code, mips_t9, mips_ra);
3474 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3477 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3482 g_assert (mips_is_imm16 (ins->inst_imm));
3483 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3486 g_assert (mips_is_imm16 (ins->inst_imm));
3487 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3491 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3494 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3499 // we add the negated value
3500 g_assert (mips_is_imm16 (-ins->inst_imm));
3501 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3505 // we add the negated value
3506 g_assert (mips_is_imm16 (-ins->inst_imm));
3507 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3512 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3518 g_assert (!(ins->inst_imm & 0xffff0000));
3519 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3524 guint32 *divisor_is_m1;
3525 guint32 *dividend_is_minvalue;
3526 guint32 *divisor_is_zero;
3528 mips_load_const (code, mips_at, -1);
3529 divisor_is_m1 = (guint32 *)(void *)code;
3530 mips_bne (code, ins->sreg2, mips_at, 0);
3531 mips_lui (code, mips_at, mips_zero, 0x8000);
3532 dividend_is_minvalue = (guint32 *)(void *)code;
3533 mips_bne (code, ins->sreg1, mips_at, 0);
3536 /* Divide Int32.MinValue by -1 -- throw exception */
3537 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3539 mips_patch (divisor_is_m1, (guint32)code);
3540 mips_patch (dividend_is_minvalue, (guint32)code);
3542 /* Put divide in branch delay slot (NOT YET) */
3543 divisor_is_zero = (guint32 *)(void *)code;
3544 mips_bne (code, ins->sreg2, mips_zero, 0);
3547 /* Divide by zero -- throw exception */
3548 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3550 mips_patch (divisor_is_zero, (guint32)code);
3551 mips_div (code, ins->sreg1, ins->sreg2);
3552 if (ins->opcode == OP_IDIV)
3553 mips_mflo (code, ins->dreg);
3555 mips_mfhi (code, ins->dreg);
3560 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3562 /* Put divide in branch delay slot (NOT YET) */
3563 mips_bne (code, ins->sreg2, mips_zero, 0);
3566 /* Divide by zero -- throw exception */
3567 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3569 mips_patch (divisor_is_zero, (guint32)code);
3570 mips_divu (code, ins->sreg1, ins->sreg2);
3571 if (ins->opcode == OP_IDIV_UN)
3572 mips_mflo (code, ins->dreg);
3574 mips_mfhi (code, ins->dreg);
3578 g_assert_not_reached ();
3580 ppc_load (code, ppc_r12, ins->inst_imm);
3581 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3582 ppc_mfspr (code, ppc_r0, ppc_xer);
3583 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3584 /* FIXME: use OverflowException for 0x80000000/-1 */
3585 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3587 g_assert_not_reached();
3590 g_assert_not_reached ();
3592 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3596 g_assert (!(ins->inst_imm & 0xffff0000));
3597 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3600 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3604 /* unsigned 16-bit immediate */
3605 g_assert (!(ins->inst_imm & 0xffff0000));
3606 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3609 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3613 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3616 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3619 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3623 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3626 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3629 case OP_ISHR_UN_IMM:
3630 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3632 case OP_LSHR_UN_IMM:
3633 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3636 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3639 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3643 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3646 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3649 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3653 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3655 mips_mult (code, ins->sreg1, ins->sreg2);
3656 mips_mflo (code, ins->dreg);
3661 #if SIZEOF_REGISTER == 8
3663 mips_dmult (code, ins->sreg1, ins->sreg2);
3664 mips_mflo (code, ins->dreg);
3669 mips_mult (code, ins->sreg1, ins->sreg2);
3670 mips_mflo (code, ins->dreg);
3671 mips_mfhi (code, mips_at);
3674 mips_sra (code, mips_temp, ins->dreg, 31);
3675 patch = (guint32 *)(void *)code;
3676 mips_beq (code, mips_temp, mips_at, 0);
3678 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3679 mips_patch (patch, (guint32)code);
3682 case OP_IMUL_OVF_UN: {
3684 mips_mult (code, ins->sreg1, ins->sreg2);
3685 mips_mflo (code, ins->dreg);
3686 mips_mfhi (code, mips_at);
3689 patch = (guint32 *)(void *)code;
3690 mips_beq (code, mips_at, mips_zero, 0);
3692 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3693 mips_patch (patch, (guint32)code);
3697 mips_load_const (code, ins->dreg, ins->inst_c0);
3699 #if SIZEOF_REGISTER == 8
3701 mips_load_const (code, ins->dreg, ins->inst_c0);
3705 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3706 mips_load (code, ins->dreg, 0);
3710 mips_mtc1 (code, ins->dreg, ins->sreg1);
3712 case OP_MIPS_MTC1S_2:
3713 mips_mtc1 (code, ins->dreg, ins->sreg1);
3714 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3717 mips_mfc1 (code, ins->dreg, ins->sreg1);
3720 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3724 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3726 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3727 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3731 case OP_ICONV_TO_I4:
3732 case OP_ICONV_TO_U4:
3734 if (ins->dreg != ins->sreg1)
3735 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3737 #if SIZEOF_REGISTER == 8
3739 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3740 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3743 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3744 mips_dsra (code, ins->dreg, ins->dreg, 32);
3748 int lsreg = mips_v0 + ls_word_idx;
3749 int msreg = mips_v0 + ms_word_idx;
3751 /* Get sreg1 into lsreg, sreg2 into msreg */
3753 if (ins->sreg1 == msreg) {
3754 if (ins->sreg1 != mips_at)
3755 MIPS_MOVE (code, mips_at, ins->sreg1);
3756 if (ins->sreg2 != msreg)
3757 MIPS_MOVE (code, msreg, ins->sreg2);
3758 MIPS_MOVE (code, lsreg, mips_at);
3761 if (ins->sreg2 != msreg)
3762 MIPS_MOVE (code, msreg, ins->sreg2);
3763 if (ins->sreg1 != lsreg)
3764 MIPS_MOVE (code, lsreg, ins->sreg1);
3769 if (ins->dreg != ins->sreg1) {
3770 mips_fmovd (code, ins->dreg, ins->sreg1);
3773 case OP_MOVE_F_TO_I4:
3774 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3775 mips_mfc1 (code, ins->dreg, mips_ftemp);
3777 case OP_MOVE_I4_TO_F:
3778 mips_mtc1 (code, ins->dreg, ins->sreg1);
3779 mips_cvtds (code, ins->dreg, ins->dreg);
3782 /* Convert from double to float and leave it there */
3783 mips_cvtsd (code, ins->dreg, ins->sreg1);
3785 case OP_FCONV_TO_R4:
3787 mips_cvtsd (code, ins->dreg, ins->sreg1);
3789 /* Just a move, no precision change */
3790 if (ins->dreg != ins->sreg1) {
3791 mips_fmovd (code, ins->dreg, ins->sreg1);
3796 code = emit_load_volatile_arguments(cfg, code);
3799 * Pop our stack, then jump to specified method (tail-call)
3800 * Keep in sync with mono_arch_emit_epilog
3802 code = mono_arch_emit_epilog_sub (cfg, code);
3804 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3805 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3806 mips_load (code, mips_t9, 0);
3807 mips_jr (code, mips_t9);
3811 /* ensure ins->sreg1 is not NULL */
3812 mips_lw (code, mips_zero, ins->sreg1, 0);
3815 g_assert (mips_is_imm16 (cfg->sig_cookie));
3816 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3817 mips_sw (code, mips_at, ins->sreg1, 0);
3830 case OP_VOIDCALL_REG:
3832 case OP_FCALL_MEMBASE:
3833 case OP_LCALL_MEMBASE:
3834 case OP_VCALL_MEMBASE:
3835 case OP_VCALL2_MEMBASE:
3836 case OP_VOIDCALL_MEMBASE:
3837 case OP_CALL_MEMBASE:
3838 call = (MonoCallInst*)ins;
3839 switch (ins->opcode) {
3846 if (ins->flags & MONO_INST_HAS_METHOD) {
3847 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3848 mips_load (code, mips_t9, call->method);
3851 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3852 mips_load (code, mips_t9, call->fptr);
3854 mips_jalr (code, mips_t9, mips_ra);
3861 case OP_VOIDCALL_REG:
3863 MIPS_MOVE (code, mips_t9, ins->sreg1);
3864 mips_jalr (code, mips_t9, mips_ra);
3867 case OP_FCALL_MEMBASE:
3868 case OP_LCALL_MEMBASE:
3869 case OP_VCALL_MEMBASE:
3870 case OP_VCALL2_MEMBASE:
3871 case OP_VOIDCALL_MEMBASE:
3872 case OP_CALL_MEMBASE:
3873 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3874 mips_jalr (code, mips_t9, mips_ra);
3878 #if PROMOTE_R4_TO_R8
3879 /* returned an FP R4 (single), promote to R8 (double) in place */
3880 switch (ins->opcode) {
3883 case OP_FCALL_MEMBASE:
3884 if (call->signature->ret->type == MONO_TYPE_R4)
3885 mips_cvtds (code, mips_f0, mips_f0);
3893 int area_offset = cfg->param_area;
3895 /* Round up ins->sreg1, mips_at ends up holding size */
3896 mips_addiu (code, mips_at, ins->sreg1, 31);
3897 mips_addiu (code, mips_temp, mips_zero, ~31);
3898 mips_and (code, mips_at, mips_at, mips_temp);
3900 mips_subu (code, mips_sp, mips_sp, mips_at);
3901 g_assert (mips_is_imm16 (area_offset));
3902 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3904 if (ins->flags & MONO_INST_INIT) {
3907 buf = (guint32*)(void*)code;
3908 mips_beq (code, mips_at, mips_zero, 0);
3911 mips_move (code, mips_temp, ins->dreg);
3912 mips_sb (code, mips_zero, mips_temp, 0);
3913 mips_addiu (code, mips_at, mips_at, -1);
3914 mips_bne (code, mips_at, mips_zero, -3);
3915 mips_addiu (code, mips_temp, mips_temp, 1);
3917 mips_patch (buf, (guint32)code);
3922 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3923 mips_move (code, mips_a0, ins->sreg1);
3924 mips_call (code, mips_t9, addr);
3925 mips_break (code, 0xfc);
3929 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3930 mips_move (code, mips_a0, ins->sreg1);
3931 mips_call (code, mips_t9, addr);
3932 mips_break (code, 0xfb);
3935 case OP_START_HANDLER: {
3937 * The START_HANDLER instruction marks the beginning of
3938 * a handler block. It is called using a call
3939 * instruction, so mips_ra contains the return address.
3940 * Since the handler executes in the same stack frame
3941 * as the method itself, we can't use save/restore to
3942 * save the return address. Instead, we save it into
3943 * a dedicated variable.
3945 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3946 g_assert (spvar->inst_basereg != mips_sp);
3947 code = emit_reserve_param_area (cfg, code);
3949 if (mips_is_imm16 (spvar->inst_offset)) {
3950 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3952 mips_load_const (code, mips_at, spvar->inst_offset);
3953 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3954 mips_sw (code, mips_ra, mips_at, 0);
3958 case OP_ENDFILTER: {
3959 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3960 g_assert (spvar->inst_basereg != mips_sp);
3961 code = emit_unreserve_param_area (cfg, code);
3963 if (ins->sreg1 != mips_v0)
3964 MIPS_MOVE (code, mips_v0, ins->sreg1);
3965 if (mips_is_imm16 (spvar->inst_offset)) {
3966 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3968 mips_load_const (code, mips_at, spvar->inst_offset);
3969 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3970 mips_lw (code, mips_ra, mips_at, 0);
3972 mips_jr (code, mips_ra);
3976 case OP_ENDFINALLY: {
3977 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3978 g_assert (spvar->inst_basereg != mips_sp);
3979 code = emit_unreserve_param_area (cfg, code);
3980 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3981 mips_jalr (code, mips_t9, mips_ra);
3985 case OP_CALL_HANDLER:
3986 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3987 mips_lui (code, mips_t9, mips_zero, 0);
3988 mips_addiu (code, mips_t9, mips_t9, 0);
3989 mips_jalr (code, mips_t9, mips_ra);
3991 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3992 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3995 ins->inst_c0 = code - cfg->native_code;
3998 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3999 if (cfg->arch.long_branch) {
4000 mips_lui (code, mips_at, mips_zero, 0);
4001 mips_addiu (code, mips_at, mips_at, 0);
4002 mips_jr (code, mips_at);
4006 mips_beq (code, mips_zero, mips_zero, 0);
4011 mips_jr (code, ins->sreg1);
4017 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4018 if (offset > (cfg->code_size - max_len - 16)) {
4019 cfg->code_size += max_len;
4020 cfg->code_size *= 2;
4021 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4022 code = cfg->native_code + offset;
4024 g_assert (ins->sreg1 != -1);
4025 mips_sll (code, mips_at, ins->sreg1, 2);
4026 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4027 MIPS_MOVE (code, mips_t8, mips_ra);
4028 mips_bgezal (code, mips_zero, 1); /* bal */
4030 mips_addu (code, mips_t9, mips_ra, mips_at);
4031 /* Table is 16 or 20 bytes from target of bal above */
4032 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4033 MIPS_MOVE (code, mips_ra, mips_t8);
4034 mips_lw (code, mips_t9, mips_t9, 20);
4037 mips_lw (code, mips_t9, mips_t9, 16);
4038 mips_jalr (code, mips_t9, mips_t8);
4040 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4041 mips_emit32 (code, 0xfefefefe);
4046 mips_addiu (code, ins->dreg, mips_zero, 1);
4047 mips_beq (code, mips_at, mips_zero, 2);
4049 MIPS_MOVE (code, ins->dreg, mips_zero);
4055 mips_addiu (code, ins->dreg, mips_zero, 1);
4056 mips_bltz (code, mips_at, 2);
4058 MIPS_MOVE (code, ins->dreg, mips_zero);
4064 mips_addiu (code, ins->dreg, mips_zero, 1);
4065 mips_bgtz (code, mips_at, 2);
4067 MIPS_MOVE (code, ins->dreg, mips_zero);
4070 case OP_MIPS_COND_EXC_EQ:
4071 case OP_MIPS_COND_EXC_GE:
4072 case OP_MIPS_COND_EXC_GT:
4073 case OP_MIPS_COND_EXC_LE:
4074 case OP_MIPS_COND_EXC_LT:
4075 case OP_MIPS_COND_EXC_NE_UN:
4076 case OP_MIPS_COND_EXC_GE_UN:
4077 case OP_MIPS_COND_EXC_GT_UN:
4078 case OP_MIPS_COND_EXC_LE_UN:
4079 case OP_MIPS_COND_EXC_LT_UN:
4081 case OP_MIPS_COND_EXC_OV:
4082 case OP_MIPS_COND_EXC_NO:
4083 case OP_MIPS_COND_EXC_C:
4084 case OP_MIPS_COND_EXC_NC:
4086 case OP_MIPS_COND_EXC_IEQ:
4087 case OP_MIPS_COND_EXC_IGE:
4088 case OP_MIPS_COND_EXC_IGT:
4089 case OP_MIPS_COND_EXC_ILE:
4090 case OP_MIPS_COND_EXC_ILT:
4091 case OP_MIPS_COND_EXC_INE_UN:
4092 case OP_MIPS_COND_EXC_IGE_UN:
4093 case OP_MIPS_COND_EXC_IGT_UN:
4094 case OP_MIPS_COND_EXC_ILE_UN:
4095 case OP_MIPS_COND_EXC_ILT_UN:
4097 case OP_MIPS_COND_EXC_IOV:
4098 case OP_MIPS_COND_EXC_INO:
4099 case OP_MIPS_COND_EXC_IC:
4100 case OP_MIPS_COND_EXC_INC: {
4104 /* If the condition is true, raise the exception */
4106 /* need to reverse test to skip around exception raising */
4108 /* For the moment, branch around a branch to avoid reversing
4111 /* Remember, an unpatched branch to 0 branches to the delay slot */
4112 switch (ins->opcode) {
4113 case OP_MIPS_COND_EXC_EQ:
4114 throw = (guint32 *)(void *)code;
4115 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4119 case OP_MIPS_COND_EXC_NE_UN:
4120 throw = (guint32 *)(void *)code;
4121 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4125 case OP_MIPS_COND_EXC_LE_UN:
4126 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4127 throw = (guint32 *)(void *)code;
4128 mips_beq (code, mips_at, mips_zero, 0);
4132 case OP_MIPS_COND_EXC_GT:
4133 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4134 throw = (guint32 *)(void *)code;
4135 mips_bne (code, mips_at, mips_zero, 0);
4139 case OP_MIPS_COND_EXC_GT_UN:
4140 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4141 throw = (guint32 *)(void *)code;
4142 mips_bne (code, mips_at, mips_zero, 0);
4146 case OP_MIPS_COND_EXC_LT:
4147 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4148 throw = (guint32 *)(void *)code;
4149 mips_bne (code, mips_at, mips_zero, 0);
4153 case OP_MIPS_COND_EXC_LT_UN:
4154 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4155 throw = (guint32 *)(void *)code;
4156 mips_bne (code, mips_at, mips_zero, 0);
4161 /* Not yet implemented */
4162 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4163 g_assert_not_reached ();
4165 skip = (guint32 *)(void *)code;
4166 mips_beq (code, mips_zero, mips_zero, 0);
4168 mips_patch (throw, (guint32)code);
4169 code = mips_emit_exc_by_name (code, ins->inst_p1);
4170 mips_patch (skip, (guint32)code);
4171 cfg->bb_exit->max_offset += 24;
4180 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4183 /* floating point opcodes */
4186 if (((guint32)ins->inst_p0) & (1 << 15))
4187 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4189 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4190 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4192 mips_load_const (code, mips_at, ins->inst_p0);
4193 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4194 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4198 if (((guint32)ins->inst_p0) & (1 << 15))
4199 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4201 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4202 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4203 #if PROMOTE_R4_TO_R8
4204 mips_cvtds (code, ins->dreg, ins->dreg);
4207 case OP_STORER8_MEMBASE_REG:
4208 if (mips_is_imm16 (ins->inst_offset)) {
4209 #if _MIPS_SIM == _ABIO32
4210 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4211 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4212 #elif _MIPS_SIM == _ABIN32
4213 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4216 mips_load_const (code, mips_at, ins->inst_offset);
4217 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4218 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4219 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4222 case OP_LOADR8_MEMBASE:
4223 if (mips_is_imm16 (ins->inst_offset)) {
4224 #if _MIPS_SIM == _ABIO32
4225 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4226 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4227 #elif _MIPS_SIM == _ABIN32
4228 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4231 mips_load_const (code, mips_at, ins->inst_offset);
4232 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4233 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4234 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4237 case OP_STORER4_MEMBASE_REG:
4238 g_assert (mips_is_imm16 (ins->inst_offset));
4239 #if PROMOTE_R4_TO_R8
4240 /* Need to convert ins->sreg1 to single-precision first */
4241 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4242 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4244 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4248 g_assert (mips_is_imm16 (ins->inst_offset));
4249 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4251 case OP_LOADR4_MEMBASE:
4252 g_assert (mips_is_imm16 (ins->inst_offset));
4253 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4254 #if PROMOTE_R4_TO_R8
4255 /* Convert to double precision in place */
4256 mips_cvtds (code, ins->dreg, ins->dreg);
4259 case OP_LOADR4_MEMINDEX:
4260 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4261 mips_lwc1 (code, ins->dreg, mips_at, 0);
4263 case OP_LOADR8_MEMINDEX:
4264 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4265 #if _MIPS_SIM == _ABIO32
4266 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4267 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4268 #elif _MIPS_SIM == _ABIN32
4269 mips_ldc1 (code, ins->dreg, mips_at, 0);
4272 case OP_STORER4_MEMINDEX:
4273 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4274 #if PROMOTE_R4_TO_R8
4275 /* Need to convert ins->sreg1 to single-precision first */
4276 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4277 mips_swc1 (code, mips_ftemp, mips_at, 0);
4279 mips_swc1 (code, ins->sreg1, mips_at, 0);
4282 case OP_STORER8_MEMINDEX:
4283 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4284 #if _MIPS_SIM == _ABIO32
4285 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4286 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4287 #elif _MIPS_SIM == _ABIN32
4288 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4291 case OP_ICONV_TO_R_UN: {
4292 static const guint64 adjust_val = 0x41F0000000000000ULL;
4294 /* convert unsigned int to double */
4295 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4296 mips_bgez (code, ins->sreg1, 5);
4297 mips_cvtdw (code, ins->dreg, mips_ftemp);
4299 mips_load (code, mips_at, (guint32) &adjust_val);
4300 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4301 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4302 /* target is here */
4305 case OP_ICONV_TO_R4:
4306 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4307 mips_cvtsw (code, ins->dreg, mips_ftemp);
4308 mips_cvtds (code, ins->dreg, ins->dreg);
4310 case OP_ICONV_TO_R8:
4311 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4312 mips_cvtdw (code, ins->dreg, mips_ftemp);
4314 case OP_FCONV_TO_I1:
4315 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4317 case OP_FCONV_TO_U1:
4318 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4320 case OP_FCONV_TO_I2:
4321 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4323 case OP_FCONV_TO_U2:
4324 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4326 case OP_FCONV_TO_I4:
4328 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4330 case OP_FCONV_TO_U4:
4332 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4335 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4338 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4341 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4344 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4347 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4350 mips_fnegd (code, ins->dreg, ins->sreg1);
4353 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4354 mips_addiu (code, ins->dreg, mips_zero, 1);
4355 mips_fbtrue (code, 2);
4357 MIPS_MOVE (code, ins->dreg, mips_zero);
4360 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4361 mips_addiu (code, ins->dreg, mips_zero, 1);
4362 mips_fbtrue (code, 2);
4364 MIPS_MOVE (code, ins->dreg, mips_zero);
4367 /* Less than, or Unordered */
4368 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4369 mips_addiu (code, ins->dreg, mips_zero, 1);
4370 mips_fbtrue (code, 2);
4372 MIPS_MOVE (code, ins->dreg, mips_zero);
4375 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4376 MIPS_MOVE (code, ins->dreg, mips_zero);
4377 mips_fbtrue (code, 2);
4379 mips_addiu (code, ins->dreg, mips_zero, 1);
4382 /* Greater than, or Unordered */
4383 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4384 MIPS_MOVE (code, ins->dreg, mips_zero);
4385 mips_fbtrue (code, 2);
4387 mips_addiu (code, ins->dreg, mips_zero, 1);
4392 case OP_MIPS_FBLT_UN:
4394 case OP_MIPS_FBGT_UN:
4396 case OP_MIPS_FBGE_UN:
4398 case OP_MIPS_FBLE_UN: {
4400 gboolean is_true = TRUE, is_ordered = FALSE;
4401 guint32 *buf = NULL;
4403 switch (ins->opcode) {
4417 case OP_MIPS_FBLT_UN:
4418 cond = MIPS_FPU_ULT;
4426 case OP_MIPS_FBGT_UN:
4427 cond = MIPS_FPU_OLE;
4435 case OP_MIPS_FBGE_UN:
4436 cond = MIPS_FPU_OLT;
4440 cond = MIPS_FPU_OLE;
4444 case OP_MIPS_FBLE_UN:
4445 cond = MIPS_FPU_ULE;
4449 g_assert_not_reached ();
4453 /* Skip the check if unordered */
4454 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4456 buf = (guint32*)code;
4457 mips_fbtrue (code, 0);
4461 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4463 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4465 mips_fbtrue (code, 0);
4467 mips_fbfalse (code, 0);
4471 mips_patch (buf, (guint32)code);
4475 guint32 *branch_patch;
4477 mips_mfc1 (code, mips_at, ins->sreg1+1);
4478 mips_srl (code, mips_at, mips_at, 16+4);
4479 mips_andi (code, mips_at, mips_at, 2047);
4480 mips_addiu (code, mips_at, mips_at, -2047);
4482 branch_patch = (guint32 *)(void *)code;
4483 mips_bne (code, mips_at, mips_zero, 0);
4486 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4487 mips_patch (branch_patch, (guint32)code);
4488 mips_fmovd (code, ins->dreg, ins->sreg1);
4492 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4493 mips_load (code, ins->dreg, 0x0f0f0f0f);
4495 case OP_GC_SAFE_POINT:
4500 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4501 g_assert_not_reached ();
4504 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4505 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4506 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4507 g_assert_not_reached ();
4513 last_offset = offset;
4516 cfg->code_len = code - cfg->native_code;
4520 mono_arch_register_lowlevel_calls (void)
4525 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4527 MonoJumpInfo *patch_info;
4531 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4532 unsigned char *ip = patch_info->ip.i + code;
4533 const unsigned char *target = NULL;
4535 switch (patch_info->type) {
4536 case MONO_PATCH_INFO_IP:
4537 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4539 case MONO_PATCH_INFO_SWITCH: {
4540 gpointer *table = (gpointer *)patch_info->data.table->table;
4543 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4545 for (i = 0; i < patch_info->data.table->table_size; i++) {
4546 table [i] = (int)patch_info->data.table->table [i] + code;
4550 case MONO_PATCH_INFO_METHODCONST:
4551 case MONO_PATCH_INFO_CLASS:
4552 case MONO_PATCH_INFO_IMAGE:
4553 case MONO_PATCH_INFO_FIELD:
4554 case MONO_PATCH_INFO_VTABLE:
4555 case MONO_PATCH_INFO_IID:
4556 case MONO_PATCH_INFO_SFLDA:
4557 case MONO_PATCH_INFO_LDSTR:
4558 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4559 case MONO_PATCH_INFO_LDTOKEN:
4560 case MONO_PATCH_INFO_R4:
4561 case MONO_PATCH_INFO_R8:
4562 /* from OP_AOTCONST : lui + addiu */
4563 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4564 return_if_nok (error);
4566 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4569 case MONO_PATCH_INFO_EXC_NAME:
4570 g_assert_not_reached ();
4571 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4574 case MONO_PATCH_INFO_NONE:
4575 /* everything is dealt with at epilog output time */
4578 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4579 return_if_nok (error);
4581 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4588 * Allow tracing to work with this interface (with an optional argument)
4590 * This code is expected to be inserted just after the 'real' prolog code,
4591 * and before the first basic block. We need to allocate a 2nd, temporary
4592 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4596 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4599 int offset = cfg->arch.tracing_offset;
4605 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4606 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4607 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4608 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4609 #if _MIPS_SIM == _ABIN32
4611 /* FIXME: Need a separate region for these */
4612 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4613 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4614 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4615 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4619 mips_load_const (code, mips_a0, cfg->method);
4620 mips_addiu (code, mips_a1, mips_sp, offset);
4621 mips_call (code, mips_t9, func);
4624 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4625 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4626 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4627 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4628 #if _MIPS_SIM == _ABIN32
4631 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4632 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4633 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4634 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4645 mips_adjust_stackframe(MonoCompile *cfg)
4648 int delta, threshold, i;
4649 MonoMethodSignature *sig;
4652 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4655 /* adjust cfg->stack_offset for account for down-spilling */
4656 cfg->stack_offset += SIZEOF_REGISTER;
4658 /* re-align cfg->stack_offset if needed (due to var spilling) */
4659 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4660 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4661 if (cfg->verbose_level > 2) {
4662 g_print ("mips_adjust_stackframe:\n");
4663 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4665 threshold = cfg->arch.local_alloc_offset;
4666 ra_offset = cfg->stack_offset - sizeof(gpointer);
4667 if (cfg->verbose_level > 2) {
4668 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4671 sig = mono_method_signature (cfg->method);
4672 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4673 cfg->vret_addr->inst_offset += delta;
4675 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4676 MonoInst *inst = cfg->args [i];
4678 inst->inst_offset += delta;
4682 * loads and stores based off the frame reg that (used to) lie
4683 * above the spill var area need to be increased by 'delta'
4684 * to make room for the spill vars.
4686 /* Need to find loads and stores to adjust that
4687 * are above where the spillvars were inserted, but
4688 * which are not the spillvar references themselves.
4690 * Idea - since all offsets from fp are positive, make
4691 * spillvar offsets negative to begin with so we can spot
4696 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4700 if (cfg->verbose_level > 2) {
4701 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4703 MONO_BB_FOR_EACH_INS (bb, ins) {
4707 if (cfg->verbose_level > 2) {
4708 mono_print_ins_index (ins_cnt, ins);
4710 /* The == mips_sp tests catch FP spills */
4711 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4712 (ins->inst_basereg == mips_sp))) {
4713 switch (ins->opcode) {
4714 case OP_LOADI8_MEMBASE:
4715 case OP_LOADR8_MEMBASE:
4722 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4723 (ins->dreg == mips_sp))) {
4724 switch (ins->opcode) {
4725 case OP_STOREI8_MEMBASE_REG:
4726 case OP_STORER8_MEMBASE_REG:
4727 case OP_STOREI8_MEMBASE_IMM:
4735 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4738 if (ins->inst_c0 >= threshold) {
4739 ins->inst_c0 += delta;
4740 if (cfg->verbose_level > 2) {
4742 mono_print_ins_index (ins_cnt, ins);
4745 else if (ins->inst_c0 < 0) {
4746 /* Adj_c0 holds the size of the datatype. */
4747 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4748 if (cfg->verbose_level > 2) {
4750 mono_print_ins_index (ins_cnt, ins);
4753 g_assert (ins->inst_c0 != ra_offset);
4756 if (ins->inst_imm >= threshold) {
4757 ins->inst_imm += delta;
4758 if (cfg->verbose_level > 2) {
4760 mono_print_ins_index (ins_cnt, ins);
4763 g_assert (ins->inst_c0 != ra_offset);
4773 * Stack frame layout:
4775 * ------------------- sp + cfg->stack_usage + cfg->param_area
4776 * param area incoming
4777 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4779 * ------------------- sp + cfg->stack_usage
4781 * ------------------- sp + cfg->stack_usage-4
4783 * ------------------- sp +
4784 * MonoLMF structure optional
4785 * ------------------- sp + cfg->arch.lmf_offset
4786 * saved registers s0-s8
4787 * ------------------- sp + cfg->arch.iregs_offset
4789 * ------------------- sp + cfg->param_area
4790 * param area outgoing
4791 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4793 * ------------------- sp
4797 mono_arch_emit_prolog (MonoCompile *cfg)
4799 MonoMethod *method = cfg->method;
4800 MonoMethodSignature *sig;
4802 int alloc_size, pos, i, max_offset;
4803 int alloc2_size = 0;
4807 guint32 iregs_to_save = 0;
4809 guint32 fregs_to_save = 0;
4811 /* lmf_offset is the offset of the LMF from our stack pointer. */
4812 guint32 lmf_offset = cfg->arch.lmf_offset;
4816 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4820 cfg->flags |= MONO_CFG_HAS_CALLS;
4822 sig = mono_method_signature (method);
4823 cfg->code_size = 768 + sig->param_count * 20;
4824 code = cfg->native_code = g_malloc (cfg->code_size);
4827 * compute max_offset in order to use short forward jumps.
4830 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4831 MonoInst *ins = bb->code;
4832 bb->max_offset = max_offset;
4834 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4837 MONO_BB_FOR_EACH_INS (bb, ins)
4838 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4840 if (max_offset > 0xffff)
4841 cfg->arch.long_branch = TRUE;
4844 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4845 * This means that we have to adjust the offsets inside instructions which reference
4846 * arguments received on the stack, since the initial offset doesn't take into
4847 * account spill slots.
4849 mips_adjust_stackframe (cfg);
4851 /* Offset between current sp and the CFA */
4853 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4855 /* stack_offset should not be changed here. */
4856 alloc_size = cfg->stack_offset;
4857 cfg->stack_usage = alloc_size;
4859 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4862 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4864 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4865 fregs_to_save |= (fregs_to_save << 1);
4868 /* If the stack size is too big, save 1024 bytes to start with
4869 * so the prologue can use imm16(reg) addressing, then allocate
4870 * the rest of the frame.
4872 if (alloc_size > ((1 << 15) - 1024)) {
4873 alloc2_size = alloc_size - 1024;
4877 g_assert (mips_is_imm16 (-alloc_size));
4878 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4879 cfa_offset = alloc_size;
4880 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4883 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4884 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4885 if (mips_is_imm16(offset))
4886 mips_sw (code, mips_ra, mips_sp, offset);
4888 g_assert_not_reached ();
4890 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4891 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4894 /* XXX - optimize this later to not save all regs if LMF constructed */
4895 pos = cfg->arch.iregs_offset - alloc2_size;
4897 if (iregs_to_save) {
4898 /* save used registers in own stack frame (at pos) */
4899 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4900 if (iregs_to_save & (1 << i)) {
4901 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4902 g_assert (mips_is_imm16(pos));
4903 MIPS_SW (code, i, mips_sp, pos);
4904 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4905 pos += SIZEOF_REGISTER;
4910 // FIXME: Don't save registers twice if there is an LMF
4911 // s8 has to be special cased since it is overwritten with the updated value
4913 if (method->save_lmf) {
4914 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4915 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4916 g_assert (mips_is_imm16(offset));
4917 if (MIPS_LMF_IREGMASK & (1 << i))
4918 MIPS_SW (code, i, mips_sp, offset);
4923 /* Save float registers */
4924 if (fregs_to_save) {
4925 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4926 if (fregs_to_save & (1 << i)) {
4927 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4928 g_assert (mips_is_imm16(pos));
4929 mips_swc1 (code, i, mips_sp, pos);
4930 pos += sizeof (gulong);
4935 if (method->save_lmf) {
4936 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4937 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4938 g_assert (mips_is_imm16(offset));
4939 mips_swc1 (code, i, mips_sp, offset);
4944 if (cfg->frame_reg != mips_sp) {
4945 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4946 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4948 if (method->save_lmf) {
4949 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4950 g_assert (mips_is_imm16(offset));
4951 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4955 /* store runtime generic context */
4956 if (cfg->rgctx_var) {
4957 MonoInst *ins = cfg->rgctx_var;
4959 g_assert (ins->opcode == OP_REGOFFSET);
4961 g_assert (mips_is_imm16 (ins->inst_offset));
4962 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4965 /* load arguments allocated to register from the stack */
4968 if (!cfg->arch.cinfo)
4969 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
4970 cinfo = cfg->arch.cinfo;
4972 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4973 ArgInfo *ainfo = &cinfo->ret;
4974 inst = cfg->vret_addr;
4975 if (inst->opcode == OP_REGVAR)
4976 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4977 else if (mips_is_imm16 (inst->inst_offset)) {
4978 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4980 mips_load_const (code, mips_at, inst->inst_offset);
4981 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4982 mips_sw (code, ainfo->reg, mips_at, 0);
4986 if (sig->call_convention == MONO_CALL_VARARG) {
4987 ArgInfo *cookie = &cinfo->sig_cookie;
4988 int offset = alloc_size + cookie->offset;
4990 /* Save the sig cookie address */
4991 g_assert (cookie->storage == ArgOnStack);
4993 g_assert (mips_is_imm16(offset));
4994 mips_addi (code, mips_at, cfg->frame_reg, offset);
4995 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
4998 /* Keep this in sync with emit_load_volatile_arguments */
4999 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5000 ArgInfo *ainfo = cinfo->args + i;
5001 inst = cfg->args [pos];
5003 if (cfg->verbose_level > 2)
5004 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5005 if (inst->opcode == OP_REGVAR) {
5006 /* Argument ends up in a register */
5007 if (ainfo->storage == ArgInIReg)
5008 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5009 else if (ainfo->storage == ArgInFReg) {
5010 g_assert_not_reached();
5012 ppc_fmr (code, inst->dreg, ainfo->reg);
5015 else if (ainfo->storage == ArgOnStack) {
5016 int offset = cfg->stack_usage + ainfo->offset;
5017 g_assert (mips_is_imm16(offset));
5018 mips_lw (code, inst->dreg, mips_sp, offset);
5020 g_assert_not_reached ();
5022 if (cfg->verbose_level > 2)
5023 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5025 /* Argument ends up on the stack */
5026 if (ainfo->storage == ArgInIReg) {
5028 /* Incoming parameters should be above this frame */
5029 if (cfg->verbose_level > 2)
5030 g_print ("stack slot at %d of %d+%d\n",
5031 inst->inst_offset, alloc_size, alloc2_size);
5032 /* g_assert (inst->inst_offset >= alloc_size); */
5033 g_assert (inst->inst_basereg == cfg->frame_reg);
5034 basereg_offset = inst->inst_offset - alloc2_size;
5035 g_assert (mips_is_imm16 (basereg_offset));
5036 switch (ainfo->size) {
5038 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5041 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5045 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5048 #if (SIZEOF_REGISTER == 4)
5049 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5050 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5051 #elif (SIZEOF_REGISTER == 8)
5052 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5056 g_assert_not_reached ();
5059 } else if (ainfo->storage == ArgOnStack) {
5061 * Argument comes in on the stack, and ends up on the stack
5062 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5063 * 8 and 16 bit quantities. Shorten them in place.
5065 g_assert (mips_is_imm16 (inst->inst_offset));
5066 switch (ainfo->size) {
5068 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5069 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5072 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5073 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5080 g_assert_not_reached ();
5082 } else if (ainfo->storage == ArgInFReg) {
5083 g_assert (mips_is_imm16 (inst->inst_offset));
5084 g_assert (mips_is_imm16 (inst->inst_offset+4));
5085 if (ainfo->size == 8) {
5086 #if _MIPS_SIM == _ABIO32
5087 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5088 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5089 #elif _MIPS_SIM == _ABIN32
5090 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5093 else if (ainfo->size == 4)
5094 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5096 g_assert_not_reached ();
5097 } else if (ainfo->storage == ArgStructByVal) {
5099 int doffset = inst->inst_offset;
5101 g_assert (mips_is_imm16 (inst->inst_offset));
5102 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5103 /* Push the argument registers into their stack slots */
5104 for (i = 0; i < ainfo->size; ++i) {
5105 g_assert (mips_is_imm16(doffset));
5106 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5107 doffset += SIZEOF_REGISTER;
5109 } else if (ainfo->storage == ArgStructByAddr) {
5110 g_assert (mips_is_imm16 (inst->inst_offset));
5111 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5112 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5114 g_assert_not_reached ();
5119 if (method->save_lmf) {
5120 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5121 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5123 /* This can/will clobber the a0-a3 registers */
5124 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5126 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5127 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5128 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5129 /* new_lmf->previous_lmf = *lmf_addr */
5130 mips_lw (code, mips_at, mips_v0, 0);
5131 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5132 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5133 /* *(lmf_addr) = sp + lmf_offset */
5134 g_assert (mips_is_imm16(lmf_offset));
5135 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5136 mips_sw (code, mips_at, mips_v0, 0);
5138 /* save method info */
5139 mips_load_const (code, mips_at, method);
5140 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5141 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5143 /* save the current IP */
5144 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5145 mips_load_const (code, mips_at, 0x01010101);
5146 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5150 if (mips_is_imm16 (-alloc2_size)) {
5151 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5154 mips_load_const (code, mips_at, -alloc2_size);
5155 mips_addu (code, mips_sp, mips_sp, mips_at);
5157 alloc_size += alloc2_size;
5158 cfa_offset += alloc2_size;
5159 if (cfg->frame_reg != mips_sp)
5160 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5162 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5166 #if _MIPS_SIM == _ABIO32
5167 cfg->arch.tracing_offset = cfg->stack_offset;
5168 #elif _MIPS_SIM == _ABIN32
5169 /* no stack slots by default for argument regs, reserve a special block */
5170 g_assert_not_reached ();
5172 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5175 cfg->code_len = code - cfg->native_code;
5176 g_assert (cfg->code_len < cfg->code_size);
5190 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5193 int save_mode = SAVE_NONE;
5195 MonoMethod *method = cfg->method;
5196 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5197 int save_offset = MIPS_STACK_PARAM_OFFSET;
5199 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5201 offset = code - cfg->native_code;
5202 /* we need about 16 instructions */
5203 if (offset > (cfg->code_size - 16 * 4)) {
5204 cfg->code_size *= 2;
5205 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5206 code = cfg->native_code + offset;
5211 case MONO_TYPE_VOID:
5212 /* special case string .ctor icall */
5213 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5214 save_mode = SAVE_ONE;
5216 save_mode = SAVE_NONE;
5220 save_mode = SAVE_FP;
5222 case MONO_TYPE_VALUETYPE:
5223 save_mode = SAVE_STRUCT;
5227 #if SIZEOF_REGISTER == 4
5228 save_mode = SAVE_TWO;
5229 #elif SIZEOF_REGISTER == 8
5230 save_mode = SAVE_ONE;
5234 save_mode = SAVE_ONE;
5238 mips_addiu (code, mips_sp, mips_sp, -32);
5239 g_assert (mips_is_imm16(save_offset));
5240 switch (save_mode) {
5242 mips_sw (code, mips_v0, mips_sp, save_offset);
5243 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5244 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5245 if (enable_arguments) {
5246 MIPS_MOVE (code, mips_a1, mips_v0);
5247 MIPS_MOVE (code, mips_a2, mips_v1);
5251 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5252 if (enable_arguments) {
5253 MIPS_MOVE (code, mips_a1, mips_v0);
5257 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5258 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5259 mips_lw (code, mips_a0, mips_sp, save_offset);
5260 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5261 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5268 mips_load_const (code, mips_a0, cfg->method);
5269 mips_call (code, mips_t9, func);
5271 switch (save_mode) {
5273 mips_lw (code, mips_v0, mips_sp, save_offset);
5274 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5275 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5278 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5281 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5288 mips_addiu (code, mips_sp, mips_sp, 32);
5295 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5297 MonoMethod *method = cfg->method;
5299 int max_epilog_size = 16 + 20*4;
5300 int alloc2_size = 0;
5301 guint32 iregs_to_restore;
5303 guint32 fregs_to_restore;
5306 if (cfg->method->save_lmf)
5307 max_epilog_size += 128;
5309 if (mono_jit_trace_calls != NULL)
5310 max_epilog_size += 50;
5313 pos = code - cfg->native_code;
5314 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5315 cfg->code_size *= 2;
5316 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5317 cfg->stat_code_reallocs++;
5321 * Keep in sync with OP_JMP
5324 code = cfg->native_code + pos;
5326 code = cfg->native_code + cfg->code_len;
5328 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5329 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5331 if (cfg->frame_reg != mips_sp) {
5332 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5334 /* If the stack frame is really large, deconstruct it in two steps */
5335 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5336 alloc2_size = cfg->stack_usage - 1024;
5337 /* partially deconstruct the stack */
5338 mips_load_const (code, mips_at, alloc2_size);
5339 mips_addu (code, mips_sp, mips_sp, mips_at);
5341 pos = cfg->arch.iregs_offset - alloc2_size;
5342 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5343 if (iregs_to_restore) {
5344 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5345 if (iregs_to_restore & (1 << i)) {
5346 g_assert (mips_is_imm16(pos));
5347 MIPS_LW (code, i, mips_sp, pos);
5348 pos += SIZEOF_REGISTER;
5355 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5357 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5358 fregs_to_restore |= (fregs_to_restore << 1);
5360 if (fregs_to_restore) {
5361 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5362 if (fregs_to_restore & (1 << i)) {
5363 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5364 g_assert (mips_is_imm16(pos));
5365 mips_lwc1 (code, i, mips_sp, pos);
5372 /* Unlink the LMF if necessary */
5373 if (method->save_lmf) {
5374 int lmf_offset = cfg->arch.lmf_offset;
5376 /* t0 = current_lmf->previous_lmf */
5377 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5378 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5380 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5381 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5382 /* (*lmf_addr) = previous_lmf */
5383 mips_sw (code, mips_temp, mips_t1, 0);
5387 /* Restore the fp */
5388 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5391 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5392 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5393 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5395 /* Restore the stack pointer */
5396 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5397 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5399 /* Caller will emit either return or tail-call sequence */
5401 cfg->code_len = code - cfg->native_code;
5403 g_assert (cfg->code_len < cfg->code_size);
5408 mono_arch_emit_epilog (MonoCompile *cfg)
5412 code = mono_arch_emit_epilog_sub (cfg, NULL);
5414 mips_jr (code, mips_ra);
5417 cfg->code_len = code - cfg->native_code;
5419 g_assert (cfg->code_len < cfg->code_size);
5422 /* remove once throw_exception_by_name is eliminated */
5425 exception_id_by_name (const char *name)
5427 if (strcmp (name, "IndexOutOfRangeException") == 0)
5428 return MONO_EXC_INDEX_OUT_OF_RANGE;
5429 if (strcmp (name, "OverflowException") == 0)
5430 return MONO_EXC_OVERFLOW;
5431 if (strcmp (name, "ArithmeticException") == 0)
5432 return MONO_EXC_ARITHMETIC;
5433 if (strcmp (name, "DivideByZeroException") == 0)
5434 return MONO_EXC_DIVIDE_BY_ZERO;
5435 if (strcmp (name, "InvalidCastException") == 0)
5436 return MONO_EXC_INVALID_CAST;
5437 if (strcmp (name, "NullReferenceException") == 0)
5438 return MONO_EXC_NULL_REF;
5439 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5440 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5441 if (strcmp (name, "ArgumentException") == 0)
5442 return MONO_EXC_ARGUMENT;
5443 g_error ("Unknown intrinsic exception %s\n", name);
5449 mono_arch_emit_exceptions (MonoCompile *cfg)
5452 MonoJumpInfo *patch_info;
5455 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5456 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5457 int max_epilog_size = 50;
5459 /* count the number of exception infos */
5462 * make sure we have enough space for exceptions
5463 * 24 is the simulated call to throw_exception_by_name
5465 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5467 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5468 i = exception_id_by_name (patch_info->data.target);
5469 g_assert (i < MONO_EXC_INTRINS_NUM);
5470 if (!exc_throw_found [i]) {
5471 max_epilog_size += 12;
5472 exc_throw_found [i] = TRUE;
5478 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5479 cfg->code_size *= 2;
5480 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5481 cfg->stat_code_reallocs++;
5484 code = cfg->native_code + cfg->code_len;
5486 /* add code to raise exceptions */
5487 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5488 switch (patch_info->type) {
5489 case MONO_PATCH_INFO_EXC: {
5491 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5493 i = exception_id_by_name (patch_info->data.target);
5494 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5495 if (!exc_throw_pos [i]) {
5498 exc_throw_pos [i] = code;
5499 //g_print ("exc: writing stub at %p\n", code);
5500 mips_load_const (code, mips_a0, patch_info->data.target);
5501 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5502 mips_load_const (code, mips_t9, addr);
5503 mips_jr (code, mips_t9);
5506 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5508 /* Turn into a Relative patch, pointing at code stub */
5509 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5510 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5512 g_assert_not_reached();
5522 cfg->code_len = code - cfg->native_code;
5524 g_assert (cfg->code_len < cfg->code_size);
5529 mono_arch_finish_init (void)
5534 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5539 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5541 int this_dreg = mips_a0;
5544 this_dreg = mips_a1;
5546 /* add the this argument */
5547 if (this_reg != -1) {
5549 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5550 this_ins->type = this_type;
5551 this_ins->sreg1 = this_reg;
5552 this_ins->dreg = mono_alloc_ireg (cfg);
5553 mono_bblock_add_inst (cfg->cbb, this_ins);
5554 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5559 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5560 vtarg->type = STACK_MP;
5561 vtarg->sreg1 = vt_reg;
5562 vtarg->dreg = mono_alloc_ireg (cfg);
5563 mono_bblock_add_inst (cfg->cbb, vtarg);
5564 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5569 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5571 MonoInst *ins = NULL;
5577 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5583 mono_arch_print_tree (MonoInst *tree, int arity)
5589 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5591 return ctx->sc_regs [reg];
5594 #define ENABLE_WRONG_METHOD_CHECK 0
5596 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5597 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5599 #define LOADSTORE_SIZE 4
5600 #define JUMP_IMM_SIZE 16
5601 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5602 #define LOAD_CONST_SIZE 8
5603 #define JUMP_JR_SIZE 8
5606 * LOCKING: called with the domain lock held
5609 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5610 gpointer fail_tramp)
5614 guint8 *code, *start, *patch;
5616 for (i = 0; i < count; ++i) {
5617 MonoIMTCheckItem *item = imt_entries [i];
5619 if (item->is_equals) {
5620 if (item->check_target_idx) {
5621 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5622 if (item->has_target_code)
5623 item->chunk_size += LOAD_CONST_SIZE;
5625 item->chunk_size += LOADSTORE_SIZE;
5628 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5629 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5630 if (!item->has_target_code)
5631 item->chunk_size += LOADSTORE_SIZE;
5633 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5634 #if ENABLE_WRONG_METHOD_CHECK
5635 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5640 item->chunk_size += CMP_SIZE + BR_SIZE;
5641 imt_entries [item->check_target_idx]->compare_done = TRUE;
5643 size += item->chunk_size;
5645 /* the initial load of the vtable address */
5646 size += MIPS_LOAD_SEQUENCE_LENGTH;
5648 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5650 code = mono_domain_code_reserve (domain, size);
5654 /* t7 points to the vtable */
5655 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5657 for (i = 0; i < count; ++i) {
5658 MonoIMTCheckItem *item = imt_entries [i];
5660 item->code_target = code;
5661 if (item->is_equals) {
5662 if (item->check_target_idx) {
5663 mips_load_const (code, mips_temp, (gsize)item->key);
5664 item->jmp_code = code;
5665 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5667 if (item->has_target_code) {
5668 mips_load_const (code, mips_t9,
5669 item->value.target_code);
5672 mips_lw (code, mips_t9, mips_t7,
5673 (sizeof (gpointer) * item->value.vtable_slot));
5675 mips_jr (code, mips_t9);
5679 mips_load_const (code, mips_temp, (gsize)item->key);
5681 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5683 if (item->has_target_code) {
5684 mips_load_const (code, mips_t9,
5685 item->value.target_code);
5688 mips_load_const (code, mips_at,
5689 & (vtable->vtable [item->value.vtable_slot]));
5690 mips_lw (code, mips_t9, mips_at, 0);
5692 mips_jr (code, mips_t9);
5694 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5695 mips_load_const (code, mips_t9, fail_tramp);
5696 mips_jr (code, mips_t9);
5699 /* enable the commented code to assert on wrong method */
5700 #if ENABLE_WRONG_METHOD_CHECK
5701 ppc_load (code, ppc_r0, (guint32)item->key);
5702 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5704 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5706 mips_lw (code, mips_t9, mips_t7,
5707 (sizeof (gpointer) * item->value.vtable_slot));
5708 mips_jr (code, mips_t9);
5711 #if ENABLE_WRONG_METHOD_CHECK
5712 ppc_patch (patch, code);
5718 mips_load_const (code, mips_temp, (gulong)item->key);
5719 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5721 item->jmp_code = code;
5722 mips_beq (code, mips_temp, mips_zero, 0);
5726 /* patch the branches to get to the target items */
5727 for (i = 0; i < count; ++i) {
5728 MonoIMTCheckItem *item = imt_entries [i];
5729 if (item->jmp_code && item->check_target_idx) {
5730 mips_patch ((guint32 *)item->jmp_code,
5731 (guint32)imt_entries [item->check_target_idx]->code_target);
5736 mono_stats.imt_trampolines_size += code - start;
5737 g_assert (code - start <= size);
5738 mono_arch_flush_icache (start, size);
5740 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5746 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5748 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5752 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5754 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5757 /* Soft Debug support */
5758 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5761 * mono_arch_set_breakpoint:
5763 * See mini-amd64.c for docs.
5766 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5769 guint32 addr = (guint32)bp_trigger_page;
5771 mips_load_const (code, mips_t9, addr);
5772 mips_lw (code, mips_t9, mips_t9, 0);
5774 mono_arch_flush_icache (ip, code - ip);
5778 * mono_arch_clear_breakpoint:
5780 * See mini-amd64.c for docs.
5783 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5791 mono_arch_flush_icache (ip, code - ip);
5795 * mono_arch_start_single_stepping:
5797 * See mini-amd64.c for docs.
5800 mono_arch_start_single_stepping (void)
5802 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5806 * mono_arch_stop_single_stepping:
5808 * See mini-amd64.c for docs.
5811 mono_arch_stop_single_stepping (void)
5813 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5817 * mono_arch_is_single_step_event:
5819 * See mini-amd64.c for docs.
5822 mono_arch_is_single_step_event (void *info, void *sigctx)
5824 siginfo_t* sinfo = (siginfo_t*) info;
5825 /* Sometimes the address is off by 4 */
5826 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5833 * mono_arch_is_breakpoint_event:
5835 * See mini-amd64.c for docs.
5838 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5840 siginfo_t* sinfo = (siginfo_t*) info;
5841 /* Sometimes the address is off by 4 */
5842 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5849 * mono_arch_skip_breakpoint:
5851 * See mini-amd64.c for docs.
5854 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5856 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5860 * mono_arch_skip_single_step:
5862 * See mini-amd64.c for docs.
5865 mono_arch_skip_single_step (MonoContext *ctx)
5867 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5871 * mono_arch_get_seq_point_info:
5873 * See mini-amd64.c for docs.
5876 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5883 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5885 ext->lmf.previous_lmf = prev_lmf;
5886 /* Mark that this is a MonoLMFExt */
5887 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5888 ext->lmf.iregs [mips_sp] = (gssize)ext;
5891 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5894 mono_arch_opcode_supported (int opcode)