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->prof_options & MONO_PROFILE_ENTER_LEAVE))
1356 cfg->arch.omit_fp = FALSE;
1358 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1359 * there are stack arguments.
1362 if (cinfo->stack_usage)
1363 cfg->arch.omit_fp = FALSE;
1367 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1368 MonoInst *ins = cfg->varinfo [i];
1371 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1374 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1378 * Set var information according to the calling convention. mips version.
1379 * The locals var stuff should most likely be split in another method.
1382 mono_arch_allocate_vars (MonoCompile *cfg)
1384 MonoMethodSignature *sig;
1385 MonoMethodHeader *header;
1387 int i, offset, size, align, curinst;
1388 int frame_reg = mips_sp;
1389 guint32 iregs_to_save = 0;
1391 guint32 fregs_to_restore;
1395 sig = mono_method_signature (cfg->method);
1397 if (!cfg->arch.cinfo)
1398 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1399 cinfo = cfg->arch.cinfo;
1401 mono_arch_compute_omit_fp (cfg);
1403 /* spill down, we'll fix it in a separate pass */
1404 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1406 /* allow room for the vararg method args: void* and long/double */
1407 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1408 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1410 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1411 * call convs needs to be handled this way.
1413 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1414 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1416 /* gtk-sharp and other broken code will dllimport vararg functions even with
1417 * non-varargs signatures. Since there is little hope people will get this right
1418 * we assume they won't.
1420 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1421 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1423 /* a0-a3 always present */
1424 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1426 header = cfg->header;
1428 if (cfg->arch.omit_fp)
1429 frame_reg = mips_sp;
1431 frame_reg = mips_fp;
1432 cfg->frame_reg = frame_reg;
1433 if (frame_reg != mips_sp) {
1434 cfg->used_int_regs |= 1 << frame_reg;
1439 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1440 /* FIXME: handle long and FP values */
1441 switch (mini_get_underlying_type (sig->ret)->type) {
1442 case MONO_TYPE_VOID:
1446 cfg->ret->opcode = OP_REGVAR;
1447 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1450 cfg->ret->opcode = OP_REGVAR;
1451 cfg->ret->inst_c0 = mips_v0;
1455 /* Space for outgoing parameters, including a0-a3 */
1456 offset += cfg->param_area;
1458 /* allow room to save the return value (if it's a struct) */
1459 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1462 /* Now handle the local variables */
1464 curinst = cfg->locals_start;
1465 for (i = curinst; i < cfg->num_varinfo; ++i) {
1466 inst = cfg->varinfo [i];
1467 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1470 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1471 * pinvoke wrappers when they call functions returning structure
1473 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1474 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1476 size = mono_type_size (inst->inst_vtype, &align);
1478 offset += align - 1;
1479 offset &= ~(align - 1);
1480 inst->inst_offset = offset;
1481 inst->opcode = OP_REGOFFSET;
1482 inst->inst_basereg = frame_reg;
1484 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1487 /* Space for LMF (if needed) */
1488 if (cfg->method->save_lmf) {
1489 /* align the offset to 16 bytes */
1490 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1491 cfg->arch.lmf_offset = offset;
1492 offset += sizeof (MonoLMF);
1495 if (sig->call_convention == MONO_CALL_VARARG) {
1499 /* Allocate a local slot to hold the sig cookie address */
1500 offset += align - 1;
1501 offset &= ~(align - 1);
1502 cfg->sig_cookie = offset;
1506 offset += SIZEOF_REGISTER - 1;
1507 offset &= ~(SIZEOF_REGISTER - 1);
1509 /* Space for saved registers */
1510 cfg->arch.iregs_offset = offset;
1511 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1512 if (iregs_to_save) {
1513 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1514 if (iregs_to_save & (1 << i)) {
1515 offset += SIZEOF_REGISTER;
1520 /* saved float registers */
1522 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1523 if (fregs_to_restore) {
1524 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1525 if (fregs_to_restore & (1 << i)) {
1526 offset += sizeof(double);
1532 #if _MIPS_SIM == _ABIO32
1533 /* Now add space for saving the ra */
1534 offset += SIZEOF_VOID_P;
1537 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1538 cfg->stack_offset = offset;
1539 cfg->arch.local_alloc_offset = cfg->stack_offset;
1543 * Now allocate stack slots for the int arg regs (a0 - a3)
1544 * On MIPS o32, these are just above the incoming stack pointer
1545 * Even if the arg has been assigned to a regvar, it gets a stack slot
1548 /* Return struct-by-value results in a hidden first argument */
1549 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1550 cfg->vret_addr->opcode = OP_REGOFFSET;
1551 cfg->vret_addr->inst_c0 = mips_a0;
1552 cfg->vret_addr->inst_offset = offset;
1553 cfg->vret_addr->inst_basereg = frame_reg;
1554 offset += SIZEOF_REGISTER;
1557 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1558 inst = cfg->args [i];
1559 if (inst->opcode != OP_REGVAR) {
1562 if (sig->hasthis && (i == 0))
1563 arg_type = &mono_defaults.object_class->byval_arg;
1565 arg_type = sig->params [i - sig->hasthis];
1567 inst->opcode = OP_REGOFFSET;
1568 size = mono_type_size (arg_type, &align);
1570 if (size < SIZEOF_REGISTER) {
1571 size = SIZEOF_REGISTER;
1572 align = SIZEOF_REGISTER;
1574 inst->inst_basereg = frame_reg;
1575 offset = (offset + align - 1) & ~(align - 1);
1576 inst->inst_offset = offset;
1578 if (cfg->verbose_level > 1)
1579 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1582 #if _MIPS_SIM == _ABIO32
1583 /* o32: Even a0-a3 get stack slots */
1584 size = SIZEOF_REGISTER;
1585 align = SIZEOF_REGISTER;
1586 inst->inst_basereg = frame_reg;
1587 offset = (offset + align - 1) & ~(align - 1);
1588 inst->inst_offset = offset;
1590 if (cfg->verbose_level > 1)
1591 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1595 #if _MIPS_SIM == _ABIN32
1596 /* Now add space for saving the ra */
1597 offset += SIZEOF_VOID_P;
1600 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1601 cfg->stack_offset = offset;
1602 cfg->arch.local_alloc_offset = cfg->stack_offset;
1607 mono_arch_create_vars (MonoCompile *cfg)
1609 MonoMethodSignature *sig;
1611 sig = mono_method_signature (cfg->method);
1613 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1614 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1615 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1616 printf ("vret_addr = ");
1617 mono_print_ins (cfg->vret_addr);
1622 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1623 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1627 * take the arguments and generate the arch-specific
1628 * instructions to properly call the function in call.
1629 * This includes pushing, moving arguments to the right register
1631 * Issue: who does the spilling if needed, and when?
1634 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1636 MonoMethodSignature *tmp_sig;
1639 if (call->tail_call)
1642 /* FIXME: Add support for signature tokens to AOT */
1643 cfg->disable_aot = TRUE;
1646 * mono_ArgIterator_Setup assumes the signature cookie is
1647 * passed first and all the arguments which were before it are
1648 * passed on the stack after the signature. So compensate by
1649 * passing a different signature.
1651 tmp_sig = mono_metadata_signature_dup (call->signature);
1652 tmp_sig->param_count -= call->signature->sentinelpos;
1653 tmp_sig->sentinelpos = 0;
1654 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1656 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1657 sig_arg->dreg = mono_alloc_ireg (cfg);
1658 sig_arg->inst_p0 = tmp_sig;
1659 MONO_ADD_INS (cfg->cbb, sig_arg);
1661 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1665 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1668 MonoMethodSignature *sig;
1673 sig = call->signature;
1674 n = sig->param_count + sig->hasthis;
1676 cinfo = get_call_info (cfg->mempool, sig);
1677 if (cinfo->struct_ret)
1678 call->used_iregs |= 1 << cinfo->struct_ret;
1680 for (i = 0; i < n; ++i) {
1681 ArgInfo *ainfo = cinfo->args + i;
1684 if (i >= sig->hasthis)
1685 t = sig->params [i - sig->hasthis];
1687 t = &mono_defaults.int_class->byval_arg;
1688 t = mini_get_underlying_type (t);
1690 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1691 /* Emit the signature cookie just before the implicit arguments */
1692 emit_sig_cookie (cfg, call, cinfo);
1695 if (is_virtual && i == 0) {
1696 /* the argument will be attached to the call instrucion */
1697 in = call->args [i];
1698 call->used_iregs |= 1 << ainfo->reg;
1701 in = call->args [i];
1702 if (ainfo->storage == ArgInIReg) {
1703 #if SIZEOF_REGISTER == 4
1704 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1705 MONO_INST_NEW (cfg, ins, OP_MOVE);
1706 ins->dreg = mono_alloc_ireg (cfg);
1707 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1708 MONO_ADD_INS (cfg->cbb, ins);
1709 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1711 MONO_INST_NEW (cfg, ins, OP_MOVE);
1712 ins->dreg = mono_alloc_ireg (cfg);
1713 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1714 MONO_ADD_INS (cfg->cbb, ins);
1715 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1718 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1721 #if PROMOTE_R4_TO_R8
1722 /* ??? - convert to single first? */
1723 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1724 ins->dreg = mono_alloc_freg (cfg);
1725 ins->sreg1 = in->dreg;
1726 MONO_ADD_INS (cfg->cbb, ins);
1731 /* trying to load float value into int registers */
1732 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1733 ins->dreg = mono_alloc_ireg (cfg);
1735 MONO_ADD_INS (cfg->cbb, ins);
1736 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1737 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1738 /* trying to load float value into int registers */
1739 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1740 ins->dreg = mono_alloc_ireg (cfg);
1741 ins->sreg1 = in->dreg;
1742 MONO_ADD_INS (cfg->cbb, ins);
1743 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1745 MONO_INST_NEW (cfg, ins, OP_MOVE);
1746 ins->dreg = mono_alloc_ireg (cfg);
1747 ins->sreg1 = in->dreg;
1748 MONO_ADD_INS (cfg->cbb, ins);
1749 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1751 } else if (ainfo->storage == ArgStructByAddr) {
1752 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1753 ins->opcode = OP_OUTARG_VT;
1754 ins->sreg1 = in->dreg;
1755 ins->klass = in->klass;
1756 ins->inst_p0 = call;
1757 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1758 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1759 MONO_ADD_INS (cfg->cbb, ins);
1760 } else if (ainfo->storage == ArgStructByVal) {
1761 /* this is further handled in mono_arch_emit_outarg_vt () */
1762 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1763 ins->opcode = OP_OUTARG_VT;
1764 ins->sreg1 = in->dreg;
1765 ins->klass = in->klass;
1766 ins->inst_p0 = call;
1767 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1768 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1769 MONO_ADD_INS (cfg->cbb, ins);
1770 } else if (ainfo->storage == ArgOnStack) {
1771 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1772 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1773 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1774 if (t->type == MONO_TYPE_R8)
1775 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1777 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1779 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1781 } else if (ainfo->storage == ArgInFReg) {
1782 if (t->type == MONO_TYPE_VALUETYPE) {
1783 /* this is further handled in mono_arch_emit_outarg_vt () */
1784 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1785 ins->opcode = OP_OUTARG_VT;
1786 ins->sreg1 = in->dreg;
1787 ins->klass = in->klass;
1788 ins->inst_p0 = call;
1789 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1790 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1791 MONO_ADD_INS (cfg->cbb, ins);
1793 cfg->flags |= MONO_CFG_HAS_FPOUT;
1795 int dreg = mono_alloc_freg (cfg);
1797 if (ainfo->size == 4) {
1798 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1800 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1802 ins->sreg1 = in->dreg;
1803 MONO_ADD_INS (cfg->cbb, ins);
1806 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1807 cfg->flags |= MONO_CFG_HAS_FPOUT;
1810 g_assert_not_reached ();
1814 /* Handle the case where there are no implicit arguments */
1815 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1816 emit_sig_cookie (cfg, call, cinfo);
1818 if (cinfo->struct_ret) {
1821 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1822 vtarg->sreg1 = call->vret_var->dreg;
1823 vtarg->dreg = mono_alloc_preg (cfg);
1824 MONO_ADD_INS (cfg->cbb, vtarg);
1826 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1830 * Reverse the call->out_args list.
1833 MonoInst *prev = NULL, *list = call->out_args, *next;
1840 call->out_args = prev;
1843 call->stack_usage = cinfo->stack_usage;
1844 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1845 #if _MIPS_SIM == _ABIO32
1846 /* a0-a3 always present */
1847 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1849 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1850 cfg->flags |= MONO_CFG_HAS_CALLS;
1852 * should set more info in call, such as the stack space
1853 * used by the args that needs to be added back to esp
1858 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1860 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1861 ArgInfo *ainfo = ins->inst_p1;
1862 int ovf_size = ainfo->vtsize;
1863 int doffset = ainfo->offset;
1864 int i, soffset, dreg;
1866 if (ainfo->storage == ArgStructByVal) {
1868 if (cfg->verbose_level > 0) {
1869 char* nm = mono_method_full_name (cfg->method, TRUE);
1870 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1871 nm, doffset, ainfo->size, ovf_size);
1877 for (i = 0; i < ainfo->size; ++i) {
1878 dreg = mono_alloc_ireg (cfg);
1879 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1880 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1881 soffset += SIZEOF_REGISTER;
1883 if (ovf_size != 0) {
1884 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1886 } else if (ainfo->storage == ArgInFReg) {
1887 int tmpr = mono_alloc_freg (cfg);
1889 if (ainfo->size == 4)
1890 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1892 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1893 dreg = mono_alloc_freg (cfg);
1894 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1895 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1897 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1901 /* FIXME: alignment? */
1902 if (call->signature->pinvoke) {
1903 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1904 vtcopy->backend.is_pinvoke = 1;
1906 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1909 g_assert (ovf_size > 0);
1911 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1912 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1915 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1917 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1922 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1924 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1927 #if (SIZEOF_REGISTER == 4)
1928 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1931 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1932 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1933 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1934 MONO_ADD_INS (cfg->cbb, ins);
1938 if (ret->type == MONO_TYPE_R8) {
1939 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1942 if (ret->type == MONO_TYPE_R4) {
1943 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1947 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1951 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1953 MonoInst *ins, *n, *last_ins = NULL;
1955 if (cfg->verbose_level > 2)
1956 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1959 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1960 if (cfg->verbose_level > 2)
1961 mono_print_ins_index (0, ins);
1963 switch (ins->opcode) {
1965 case OP_LOAD_MEMBASE:
1966 case OP_LOADI4_MEMBASE:
1968 * OP_IADD reg2, reg1, const1
1969 * OP_LOAD_MEMBASE const2(reg2), reg3
1971 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1973 if (last_ins && (last_ins->opcode == OP_IADD_IMM || last_ins->opcode == OP_ADD_IMM) && (last_ins->dreg == ins->inst_basereg) && (last_ins->sreg1 != last_ins->dreg)){
1974 int const1 = last_ins->inst_imm;
1975 int const2 = ins->inst_offset;
1977 if (mips_is_imm16 (const1 + const2)) {
1978 ins->inst_basereg = last_ins->sreg1;
1979 ins->inst_offset = const1 + const2;
1989 bb->last_ins = last_ins;
1993 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1995 MonoInst *ins, *n, *last_ins = NULL;
1998 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1999 MonoInst *last_ins = ins->prev;
2001 switch (ins->opcode) {
2003 /* remove unnecessary multiplication with 1 */
2004 if (ins->inst_imm == 1) {
2005 if (ins->dreg != ins->sreg1) {
2006 ins->opcode = OP_MOVE;
2008 MONO_DELETE_INS (bb, ins);
2012 int power2 = mono_is_power_of_two (ins->inst_imm);
2014 ins->opcode = OP_SHL_IMM;
2015 ins->inst_imm = power2;
2019 case OP_LOAD_MEMBASE:
2020 case OP_LOADI4_MEMBASE:
2022 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2023 * OP_LOAD_MEMBASE offset(basereg), reg
2025 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2026 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2027 ins->inst_basereg == last_ins->inst_destbasereg &&
2028 ins->inst_offset == last_ins->inst_offset) {
2029 if (ins->dreg == last_ins->sreg1) {
2030 MONO_DELETE_INS (bb, ins);
2033 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2034 ins->opcode = OP_MOVE;
2035 ins->sreg1 = last_ins->sreg1;
2040 * Note: reg1 must be different from the basereg in the second load
2041 * OP_LOAD_MEMBASE offset(basereg), reg1
2042 * OP_LOAD_MEMBASE offset(basereg), reg2
2044 * OP_LOAD_MEMBASE offset(basereg), reg1
2045 * OP_MOVE reg1, reg2
2047 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2048 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2049 ins->inst_basereg != last_ins->dreg &&
2050 ins->inst_basereg == last_ins->inst_basereg &&
2051 ins->inst_offset == last_ins->inst_offset) {
2053 if (ins->dreg == last_ins->dreg) {
2054 MONO_DELETE_INS (bb, ins);
2057 ins->opcode = OP_MOVE;
2058 ins->sreg1 = last_ins->dreg;
2061 //g_assert_not_reached ();
2066 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2067 * OP_LOAD_MEMBASE offset(basereg), reg
2069 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2070 * OP_ICONST reg, imm
2072 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2073 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2074 ins->inst_basereg == last_ins->inst_destbasereg &&
2075 ins->inst_offset == last_ins->inst_offset) {
2076 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2077 ins->opcode = OP_ICONST;
2078 ins->inst_c0 = last_ins->inst_imm;
2079 g_assert_not_reached (); // check this rule
2084 case OP_LOADU1_MEMBASE:
2085 case OP_LOADI1_MEMBASE:
2086 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2087 ins->inst_basereg == last_ins->inst_destbasereg &&
2088 ins->inst_offset == last_ins->inst_offset) {
2089 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2090 ins->sreg1 = last_ins->sreg1;
2093 case OP_LOADU2_MEMBASE:
2094 case OP_LOADI2_MEMBASE:
2095 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2096 ins->inst_basereg == last_ins->inst_destbasereg &&
2097 ins->inst_offset == last_ins->inst_offset) {
2098 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2099 ins->sreg1 = last_ins->sreg1;
2102 case OP_ICONV_TO_I4:
2103 case OP_ICONV_TO_U4:
2105 ins->opcode = OP_MOVE;
2109 if (ins->dreg == ins->sreg1) {
2110 MONO_DELETE_INS (bb, ins);
2114 * OP_MOVE sreg, dreg
2115 * OP_MOVE dreg, sreg
2117 if (last_ins && last_ins->opcode == OP_MOVE &&
2118 ins->sreg1 == last_ins->dreg &&
2119 ins->dreg == last_ins->sreg1) {
2120 MONO_DELETE_INS (bb, ins);
2128 bb->last_ins = last_ins;
2132 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2140 switch (ins->opcode) {
2142 tmp1 = mono_alloc_ireg (cfg);
2143 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2144 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2145 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2146 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2151 tmp1 = mono_alloc_ireg (cfg);
2152 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2153 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2154 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2155 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2160 tmp1 = mono_alloc_ireg (cfg);
2161 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2162 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2163 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2164 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2169 tmp1 = mono_alloc_ireg (cfg);
2170 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2171 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2172 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2173 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2178 tmp1 = mono_alloc_ireg (cfg);
2179 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2180 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2181 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2182 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2187 tmp1 = mono_alloc_ireg (cfg);
2188 tmp2 = mono_alloc_ireg (cfg);
2189 tmp3 = mono_alloc_ireg (cfg);
2190 tmp4 = mono_alloc_ireg (cfg);
2191 tmp5 = mono_alloc_ireg (cfg);
2193 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2195 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2196 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2198 /* add the high 32-bits, and add in the carry from the low 32-bits */
2199 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2200 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2202 /* Overflow happens if
2203 * neg + neg = pos or
2205 * XOR of the high bits returns 0 if the signs match
2206 * XOR of that with the high bit of the result return 1 if overflow.
2209 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2210 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2212 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2213 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2214 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2216 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2217 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2218 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2220 /* Now, if (tmp4 == 0) then overflow */
2221 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2225 case OP_LADD_OVF_UN:
2226 tmp1 = mono_alloc_ireg (cfg);
2227 tmp2 = mono_alloc_ireg (cfg);
2229 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2230 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2231 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2232 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2233 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2234 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2239 tmp1 = mono_alloc_ireg (cfg);
2240 tmp2 = mono_alloc_ireg (cfg);
2241 tmp3 = mono_alloc_ireg (cfg);
2242 tmp4 = mono_alloc_ireg (cfg);
2243 tmp5 = mono_alloc_ireg (cfg);
2245 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2247 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2248 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2249 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2251 /* Overflow happens if
2252 * neg - pos = pos or
2254 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2256 * tmp1 = (lhs ^ rhs)
2257 * tmp2 = (lhs ^ result)
2258 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2261 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2262 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2263 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2264 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2266 /* Now, if (tmp4 == 1) then overflow */
2267 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2271 case OP_LSUB_OVF_UN:
2272 tmp1 = mono_alloc_ireg (cfg);
2273 tmp2 = mono_alloc_ireg (cfg);
2275 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2276 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2277 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2278 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2280 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2281 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2284 case OP_LCONV_TO_OVF_I4_2:
2285 tmp1 = mono_alloc_ireg (cfg);
2287 /* Overflows if reg2 != sign extension of reg1 */
2288 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2289 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2290 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2299 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2307 switch (ins->opcode) {
2309 tmp1 = mono_alloc_ireg (cfg);
2310 tmp2 = mono_alloc_ireg (cfg);
2311 tmp3 = mono_alloc_ireg (cfg);
2312 tmp4 = mono_alloc_ireg (cfg);
2313 tmp5 = mono_alloc_ireg (cfg);
2315 /* add the operands */
2317 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2319 /* Overflow happens if
2320 * neg + neg = pos or
2323 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2324 * XOR of the high bit returns 0 if the signs match
2325 * XOR of that with the high bit of the result return 1 if overflow.
2328 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2329 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2331 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2332 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2333 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2335 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2336 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2338 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2340 /* Now, if (tmp5 == 0) then overflow */
2341 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2342 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2343 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2347 case OP_IADD_OVF_UN:
2348 tmp1 = mono_alloc_ireg (cfg);
2350 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2351 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2352 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2353 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2354 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2359 tmp1 = mono_alloc_ireg (cfg);
2360 tmp2 = mono_alloc_ireg (cfg);
2361 tmp3 = mono_alloc_ireg (cfg);
2362 tmp4 = mono_alloc_ireg (cfg);
2363 tmp5 = mono_alloc_ireg (cfg);
2365 /* add the operands */
2367 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2369 /* Overflow happens if
2370 * neg - pos = pos or
2372 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2374 * tmp1 = (lhs ^ rhs)
2375 * tmp2 = (lhs ^ result)
2376 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2379 /* tmp3 = 1 if the signs of the two inputs differ */
2380 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2381 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2382 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2383 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2384 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2386 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2387 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2388 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2392 case OP_ISUB_OVF_UN:
2393 tmp1 = mono_alloc_ireg (cfg);
2395 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2396 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2397 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2398 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2399 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2406 map_to_reg_reg_op (int op)
2415 case OP_COMPARE_IMM:
2417 case OP_ICOMPARE_IMM:
2419 case OP_LCOMPARE_IMM:
2435 case OP_LOAD_MEMBASE:
2436 return OP_LOAD_MEMINDEX;
2437 case OP_LOADI4_MEMBASE:
2438 return OP_LOADI4_MEMINDEX;
2439 case OP_LOADU4_MEMBASE:
2440 return OP_LOADU4_MEMINDEX;
2441 case OP_LOADU1_MEMBASE:
2442 return OP_LOADU1_MEMINDEX;
2443 case OP_LOADI2_MEMBASE:
2444 return OP_LOADI2_MEMINDEX;
2445 case OP_LOADU2_MEMBASE:
2446 return OP_LOADU2_MEMINDEX;
2447 case OP_LOADI1_MEMBASE:
2448 return OP_LOADI1_MEMINDEX;
2449 case OP_LOADR4_MEMBASE:
2450 return OP_LOADR4_MEMINDEX;
2451 case OP_LOADR8_MEMBASE:
2452 return OP_LOADR8_MEMINDEX;
2453 case OP_STOREI1_MEMBASE_REG:
2454 return OP_STOREI1_MEMINDEX;
2455 case OP_STOREI2_MEMBASE_REG:
2456 return OP_STOREI2_MEMINDEX;
2457 case OP_STOREI4_MEMBASE_REG:
2458 return OP_STOREI4_MEMINDEX;
2459 case OP_STORE_MEMBASE_REG:
2460 return OP_STORE_MEMINDEX;
2461 case OP_STORER4_MEMBASE_REG:
2462 return OP_STORER4_MEMINDEX;
2463 case OP_STORER8_MEMBASE_REG:
2464 return OP_STORER8_MEMINDEX;
2465 case OP_STORE_MEMBASE_IMM:
2466 return OP_STORE_MEMBASE_REG;
2467 case OP_STOREI1_MEMBASE_IMM:
2468 return OP_STOREI1_MEMBASE_REG;
2469 case OP_STOREI2_MEMBASE_IMM:
2470 return OP_STOREI2_MEMBASE_REG;
2471 case OP_STOREI4_MEMBASE_IMM:
2472 return OP_STOREI4_MEMBASE_REG;
2473 case OP_STOREI8_MEMBASE_IMM:
2474 return OP_STOREI8_MEMBASE_REG;
2476 if (mono_op_imm_to_op (op) == -1)
2477 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2478 return mono_op_imm_to_op (op);
2482 map_to_mips_op (int op)
2486 return OP_MIPS_FBEQ;
2488 return OP_MIPS_FBGE;
2490 return OP_MIPS_FBGT;
2492 return OP_MIPS_FBLE;
2494 return OP_MIPS_FBLT;
2496 return OP_MIPS_FBNE;
2498 return OP_MIPS_FBGE_UN;
2500 return OP_MIPS_FBGT_UN;
2502 return OP_MIPS_FBLE_UN;
2504 return OP_MIPS_FBLT_UN;
2512 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2513 g_assert_not_reached ();
2517 #define NEW_INS(cfg,after,dest,op) do { \
2518 MONO_INST_NEW((cfg), (dest), (op)); \
2519 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2522 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2524 MONO_INST_NEW(cfg, temp, (op)); \
2525 mono_bblock_insert_after_ins (bb, (pos), temp); \
2526 temp->dreg = (_dreg); \
2527 temp->sreg1 = (_sreg1); \
2528 temp->sreg2 = (_sreg2); \
2532 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2534 MONO_INST_NEW(cfg, temp, (op)); \
2535 mono_bblock_insert_after_ins (bb, (pos), temp); \
2536 temp->dreg = (_dreg); \
2537 temp->sreg1 = (_sreg1); \
2538 temp->inst_c0 = (_imm); \
2543 * Remove from the instruction list the instructions that can't be
2544 * represented with very simple instructions with no register
2548 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2550 MonoInst *ins, *next, *temp, *last_ins = NULL;
2554 if (cfg->verbose_level > 2) {
2557 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2558 MONO_BB_FOR_EACH_INS (bb, ins) {
2559 mono_print_ins_index (idx++, ins);
2565 MONO_BB_FOR_EACH_INS (bb, ins) {
2567 switch (ins->opcode) {
2572 /* Branch opts can eliminate the branch */
2573 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2579 case OP_COMPARE_IMM:
2580 case OP_ICOMPARE_IMM:
2581 case OP_LCOMPARE_IMM:
2583 /* Branch opts can eliminate the branch */
2584 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2588 if (ins->inst_imm) {
2589 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2590 temp->inst_c0 = ins->inst_imm;
2591 temp->dreg = mono_alloc_ireg (cfg);
2592 ins->sreg2 = temp->dreg;
2596 ins->sreg2 = mips_zero;
2598 if (ins->opcode == OP_COMPARE_IMM)
2599 ins->opcode = OP_COMPARE;
2600 else if (ins->opcode == OP_ICOMPARE_IMM)
2601 ins->opcode = OP_ICOMPARE;
2602 else if (ins->opcode == OP_LCOMPARE_IMM)
2603 ins->opcode = OP_LCOMPARE;
2606 case OP_IDIV_UN_IMM:
2609 case OP_IREM_UN_IMM:
2610 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2611 temp->inst_c0 = ins->inst_imm;
2612 temp->dreg = mono_alloc_ireg (cfg);
2613 ins->sreg2 = temp->dreg;
2614 if (ins->opcode == OP_IDIV_IMM)
2615 ins->opcode = OP_IDIV;
2616 else if (ins->opcode == OP_IREM_IMM)
2617 ins->opcode = OP_IREM;
2618 else if (ins->opcode == OP_IDIV_UN_IMM)
2619 ins->opcode = OP_IDIV_UN;
2620 else if (ins->opcode == OP_IREM_UN_IMM)
2621 ins->opcode = OP_IREM_UN;
2623 /* handle rem separately */
2630 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2631 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2632 temp->inst_c0 = ins->inst_imm;
2633 temp->dreg = mono_alloc_ireg (cfg);
2634 ins->sreg2 = temp->dreg;
2635 ins->opcode = map_to_reg_reg_op (ins->opcode);
2645 /* unsigned 16 bit immediate */
2646 if (ins->inst_imm & 0xffff0000) {
2647 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2648 temp->inst_c0 = ins->inst_imm;
2649 temp->dreg = mono_alloc_ireg (cfg);
2650 ins->sreg2 = temp->dreg;
2651 ins->opcode = map_to_reg_reg_op (ins->opcode);
2658 /* signed 16 bit immediate */
2659 if (!mips_is_imm16 (ins->inst_imm)) {
2660 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2661 temp->inst_c0 = ins->inst_imm;
2662 temp->dreg = mono_alloc_ireg (cfg);
2663 ins->sreg2 = temp->dreg;
2664 ins->opcode = map_to_reg_reg_op (ins->opcode);
2670 if (!mips_is_imm16 (-ins->inst_imm)) {
2671 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2672 temp->inst_c0 = ins->inst_imm;
2673 temp->dreg = mono_alloc_ireg (cfg);
2674 ins->sreg2 = temp->dreg;
2675 ins->opcode = map_to_reg_reg_op (ins->opcode);
2681 if (ins->inst_imm == 1) {
2682 ins->opcode = OP_MOVE;
2685 if (ins->inst_imm == 0) {
2686 ins->opcode = OP_ICONST;
2690 imm = mono_is_power_of_two (ins->inst_imm);
2692 ins->opcode = OP_SHL_IMM;
2693 ins->inst_imm = imm;
2696 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2697 temp->inst_c0 = ins->inst_imm;
2698 temp->dreg = mono_alloc_ireg (cfg);
2699 ins->sreg2 = temp->dreg;
2700 ins->opcode = map_to_reg_reg_op (ins->opcode);
2703 case OP_LOCALLOC_IMM:
2704 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2705 temp->inst_c0 = ins->inst_imm;
2706 temp->dreg = mono_alloc_ireg (cfg);
2707 ins->sreg1 = temp->dreg;
2708 ins->opcode = OP_LOCALLOC;
2711 case OP_LOADR4_MEMBASE:
2712 case OP_STORER4_MEMBASE_REG:
2713 /* we can do two things: load the immed in a register
2714 * and use an indexed load, or see if the immed can be
2715 * represented as an ad_imm + a load with a smaller offset
2716 * that fits. We just do the first for now, optimize later.
2718 if (mips_is_imm16 (ins->inst_offset))
2720 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2721 temp->inst_c0 = ins->inst_offset;
2722 temp->dreg = mono_alloc_ireg (cfg);
2723 ins->sreg2 = temp->dreg;
2724 ins->opcode = map_to_reg_reg_op (ins->opcode);
2727 case OP_STORE_MEMBASE_IMM:
2728 case OP_STOREI1_MEMBASE_IMM:
2729 case OP_STOREI2_MEMBASE_IMM:
2730 case OP_STOREI4_MEMBASE_IMM:
2731 case OP_STOREI8_MEMBASE_IMM:
2732 if (!ins->inst_imm) {
2733 ins->sreg1 = mips_zero;
2734 ins->opcode = map_to_reg_reg_op (ins->opcode);
2737 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2738 temp->inst_c0 = ins->inst_imm;
2739 temp->dreg = mono_alloc_ireg (cfg);
2740 ins->sreg1 = temp->dreg;
2741 ins->opcode = map_to_reg_reg_op (ins->opcode);
2743 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2749 /* Branch opts can eliminate the branch */
2750 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2757 * remap compare/branch and compare/set
2758 * to MIPS specific opcodes.
2760 next->opcode = map_to_mips_op (next->opcode);
2761 next->sreg1 = ins->sreg1;
2762 next->sreg2 = ins->sreg2;
2769 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2770 temp->inst_c0 = (guint32)ins->inst_p0;
2771 temp->dreg = mono_alloc_ireg (cfg);
2772 ins->inst_basereg = temp->dreg;
2773 ins->inst_offset = 0;
2774 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2776 /* make it handle the possibly big ins->inst_offset
2777 * later optimize to use lis + load_membase
2782 g_assert (ins_is_compare(last_ins));
2783 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2784 NULLIFY_INS(last_ins);
2788 g_assert (ins_is_compare(last_ins));
2789 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2790 NULLIFY_INS(last_ins);
2794 g_assert (ins_is_compare(last_ins));
2795 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2796 last_ins->dreg = mono_alloc_ireg (cfg);
2797 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2801 g_assert (ins_is_compare(last_ins));
2802 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2803 last_ins->dreg = mono_alloc_ireg (cfg);
2804 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2808 g_assert (ins_is_compare(last_ins));
2809 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2810 last_ins->dreg = mono_alloc_ireg (cfg);
2811 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2815 g_assert (ins_is_compare(last_ins));
2816 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2817 last_ins->dreg = mono_alloc_ireg (cfg);
2818 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2822 g_assert (ins_is_compare(last_ins));
2823 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2824 last_ins->dreg = mono_alloc_ireg (cfg);
2825 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2829 g_assert (ins_is_compare(last_ins));
2830 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2831 last_ins->dreg = mono_alloc_ireg (cfg);
2832 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2836 g_assert (ins_is_compare(last_ins));
2837 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2838 last_ins->dreg = mono_alloc_ireg (cfg);
2839 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2843 g_assert (ins_is_compare(last_ins));
2844 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2845 last_ins->dreg = mono_alloc_ireg (cfg);
2846 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2851 g_assert (ins_is_compare(last_ins));
2852 last_ins->opcode = OP_IXOR;
2853 last_ins->dreg = mono_alloc_ireg(cfg);
2854 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2859 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2860 NULLIFY_INS(last_ins);
2866 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2867 NULLIFY_INS(last_ins);
2872 g_assert (ins_is_compare(last_ins));
2873 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2874 MONO_DELETE_INS(bb, last_ins);
2879 g_assert (ins_is_compare(last_ins));
2880 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2881 MONO_DELETE_INS(bb, last_ins);
2884 case OP_COND_EXC_EQ:
2885 case OP_COND_EXC_IEQ:
2886 g_assert (ins_is_compare(last_ins));
2887 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2888 MONO_DELETE_INS(bb, last_ins);
2891 case OP_COND_EXC_GE:
2892 case OP_COND_EXC_IGE:
2893 g_assert (ins_is_compare(last_ins));
2894 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2895 MONO_DELETE_INS(bb, last_ins);
2898 case OP_COND_EXC_GT:
2899 case OP_COND_EXC_IGT:
2900 g_assert (ins_is_compare(last_ins));
2901 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2902 MONO_DELETE_INS(bb, last_ins);
2905 case OP_COND_EXC_LE:
2906 case OP_COND_EXC_ILE:
2907 g_assert (ins_is_compare(last_ins));
2908 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2909 MONO_DELETE_INS(bb, last_ins);
2912 case OP_COND_EXC_LT:
2913 case OP_COND_EXC_ILT:
2914 g_assert (ins_is_compare(last_ins));
2915 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2916 MONO_DELETE_INS(bb, last_ins);
2919 case OP_COND_EXC_NE_UN:
2920 case OP_COND_EXC_INE_UN:
2921 g_assert (ins_is_compare(last_ins));
2922 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2923 MONO_DELETE_INS(bb, last_ins);
2926 case OP_COND_EXC_GE_UN:
2927 case OP_COND_EXC_IGE_UN:
2928 g_assert (ins_is_compare(last_ins));
2929 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2930 MONO_DELETE_INS(bb, last_ins);
2933 case OP_COND_EXC_GT_UN:
2934 case OP_COND_EXC_IGT_UN:
2935 g_assert (ins_is_compare(last_ins));
2936 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2937 MONO_DELETE_INS(bb, last_ins);
2940 case OP_COND_EXC_LE_UN:
2941 case OP_COND_EXC_ILE_UN:
2942 g_assert (ins_is_compare(last_ins));
2943 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2944 MONO_DELETE_INS(bb, last_ins);
2947 case OP_COND_EXC_LT_UN:
2948 case OP_COND_EXC_ILT_UN:
2949 g_assert (ins_is_compare(last_ins));
2950 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2951 MONO_DELETE_INS(bb, last_ins);
2954 case OP_COND_EXC_OV:
2955 case OP_COND_EXC_IOV: {
2956 int tmp1, tmp2, tmp3, tmp4, tmp5;
2957 MonoInst *pos = last_ins;
2959 /* Overflow happens if
2960 * neg + neg = pos or
2963 * (bit31s of operands match) AND (bit31 of operand
2964 * != bit31 of result)
2965 * XOR of the high bit returns 0 if the signs match
2966 * XOR of that with the high bit of the result return 1
2969 g_assert (last_ins->opcode == OP_IADC);
2971 tmp1 = mono_alloc_ireg (cfg);
2972 tmp2 = mono_alloc_ireg (cfg);
2973 tmp3 = mono_alloc_ireg (cfg);
2974 tmp4 = mono_alloc_ireg (cfg);
2975 tmp5 = mono_alloc_ireg (cfg);
2977 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2978 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2980 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2981 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2982 INS (pos, OP_INOT, tmp3, tmp2, -1);
2984 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2985 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2986 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2988 /* Now, if (tmp5 == 0) then overflow */
2989 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2994 case OP_COND_EXC_NO:
2995 case OP_COND_EXC_INO:
2996 g_assert_not_reached ();
3000 case OP_COND_EXC_IC:
3001 g_assert_not_reached ();
3004 case OP_COND_EXC_NC:
3005 case OP_COND_EXC_INC:
3006 g_assert_not_reached ();
3012 bb->last_ins = last_ins;
3013 bb->max_vreg = cfg->next_vreg;
3016 if (cfg->verbose_level > 2) {
3019 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3020 MONO_BB_FOR_EACH_INS (bb, ins) {
3021 mono_print_ins_index (idx++, ins);
3030 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3032 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3034 mips_truncwd (code, mips_ftemp, sreg);
3036 mips_cvtwd (code, mips_ftemp, sreg);
3038 mips_mfc1 (code, dreg, mips_ftemp);
3041 mips_andi (code, dreg, dreg, 0xff);
3042 else if (size == 2) {
3043 mips_sll (code, dreg, dreg, 16);
3044 mips_srl (code, dreg, dreg, 16);
3048 mips_sll (code, dreg, dreg, 24);
3049 mips_sra (code, dreg, dreg, 24);
3051 else if (size == 2) {
3052 mips_sll (code, dreg, dreg, 16);
3053 mips_sra (code, dreg, dreg, 16);
3060 * emit_load_volatile_arguments:
3062 * Load volatile arguments from the stack to the original input registers.
3063 * Required before a tail call.
3066 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3068 MonoMethod *method = cfg->method;
3069 MonoMethodSignature *sig;
3074 sig = mono_method_signature (method);
3076 if (!cfg->arch.cinfo)
3077 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3078 cinfo = cfg->arch.cinfo;
3080 if (cinfo->struct_ret) {
3081 ArgInfo *ainfo = &cinfo->ret;
3082 inst = cfg->vret_addr;
3083 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3086 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3087 ArgInfo *ainfo = cinfo->args + i;
3088 inst = cfg->args [i];
3089 if (inst->opcode == OP_REGVAR) {
3090 if (ainfo->storage == ArgInIReg)
3091 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3092 else if (ainfo->storage == ArgInFReg)
3093 g_assert_not_reached();
3094 else if (ainfo->storage == ArgOnStack) {
3097 g_assert_not_reached ();
3099 if (ainfo->storage == ArgInIReg) {
3100 g_assert (mips_is_imm16 (inst->inst_offset));
3101 switch (ainfo->size) {
3103 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3106 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3110 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3113 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3114 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3117 g_assert_not_reached ();
3120 } else if (ainfo->storage == ArgOnStack) {
3122 } else if (ainfo->storage == ArgInFReg) {
3123 g_assert (mips_is_imm16 (inst->inst_offset));
3124 if (ainfo->size == 8) {
3125 #if _MIPS_SIM == _ABIO32
3126 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3127 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3128 #elif _MIPS_SIM == _ABIN32
3129 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3132 else if (ainfo->size == 4)
3133 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3135 g_assert_not_reached ();
3136 } else if (ainfo->storage == ArgStructByVal) {
3138 int doffset = inst->inst_offset;
3140 g_assert (mips_is_imm16 (inst->inst_offset));
3141 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3142 for (i = 0; i < ainfo->size; ++i) {
3143 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3144 doffset += SIZEOF_REGISTER;
3146 } else if (ainfo->storage == ArgStructByAddr) {
3147 g_assert (mips_is_imm16 (inst->inst_offset));
3148 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3150 g_assert_not_reached ();
3158 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3160 int size = cfg->param_area;
3162 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3163 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3168 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3169 if (ppc_is_imm16 (-size)) {
3170 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3172 ppc_load (code, ppc_r12, -size);
3173 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3180 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3182 int size = cfg->param_area;
3184 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3185 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3190 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3191 if (ppc_is_imm16 (size)) {
3192 ppc_stwu (code, ppc_r0, size, ppc_sp);
3194 ppc_load (code, ppc_r12, size);
3195 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3202 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3207 guint8 *code = cfg->native_code + cfg->code_len;
3208 MonoInst *last_ins = NULL;
3209 guint last_offset = 0;
3213 /* we don't align basic blocks of loops on mips */
3215 if (cfg->verbose_level > 2)
3216 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3218 cpos = bb->max_offset;
3221 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3222 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3223 g_assert (!mono_compile_aot);
3226 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3227 /* this is not thread save, but good enough */
3228 /* fixme: howto handle overflows? */
3229 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3230 mips_lw (code, mips_temp, mips_at, 0);
3231 mips_addiu (code, mips_temp, mips_temp, 1);
3232 mips_sw (code, mips_temp, mips_at, 0);
3235 MONO_BB_FOR_EACH_INS (bb, ins) {
3236 offset = code - cfg->native_code;
3238 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3240 if (offset > (cfg->code_size - max_len - 16)) {
3241 cfg->code_size *= 2;
3242 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3243 code = cfg->native_code + offset;
3245 mono_debug_record_line_number (cfg, ins, offset);
3246 if (cfg->verbose_level > 2) {
3247 g_print (" @ 0x%x\t", offset);
3248 mono_print_ins_index (ins_cnt++, ins);
3250 /* Check for virtual regs that snuck by */
3251 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3253 switch (ins->opcode) {
3254 case OP_RELAXED_NOP:
3257 case OP_DUMMY_STORE:
3258 case OP_NOT_REACHED:
3261 case OP_IL_SEQ_POINT:
3262 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3264 case OP_SEQ_POINT: {
3265 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3266 guint32 addr = (guint32)ss_trigger_page;
3268 mips_load_const (code, mips_t9, addr);
3269 mips_lw (code, mips_t9, mips_t9, 0);
3272 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3275 * A placeholder for a possible breakpoint inserted by
3276 * mono_arch_set_breakpoint ().
3278 /* mips_load_const () + mips_lw */
3285 mips_mult (code, ins->sreg1, ins->sreg2);
3286 mips_mflo (code, ins->dreg);
3287 mips_mfhi (code, ins->dreg+1);
3290 mips_multu (code, ins->sreg1, ins->sreg2);
3291 mips_mflo (code, ins->dreg);
3292 mips_mfhi (code, ins->dreg+1);
3294 case OP_MEMORY_BARRIER:
3295 mips_sync (code, 0);
3297 case OP_STOREI1_MEMBASE_IMM:
3298 mips_load_const (code, mips_temp, ins->inst_imm);
3299 if (mips_is_imm16 (ins->inst_offset)) {
3300 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3302 mips_load_const (code, mips_at, ins->inst_offset);
3303 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3306 case OP_STOREI2_MEMBASE_IMM:
3307 mips_load_const (code, mips_temp, ins->inst_imm);
3308 if (mips_is_imm16 (ins->inst_offset)) {
3309 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3311 mips_load_const (code, mips_at, ins->inst_offset);
3312 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3315 case OP_STOREI8_MEMBASE_IMM:
3316 mips_load_const (code, mips_temp, ins->inst_imm);
3317 if (mips_is_imm16 (ins->inst_offset)) {
3318 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3320 mips_load_const (code, mips_at, ins->inst_offset);
3321 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3324 case OP_STORE_MEMBASE_IMM:
3325 case OP_STOREI4_MEMBASE_IMM:
3326 mips_load_const (code, mips_temp, ins->inst_imm);
3327 if (mips_is_imm16 (ins->inst_offset)) {
3328 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3330 mips_load_const (code, mips_at, ins->inst_offset);
3331 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3334 case OP_STOREI1_MEMBASE_REG:
3335 if (mips_is_imm16 (ins->inst_offset)) {
3336 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3338 mips_load_const (code, mips_at, ins->inst_offset);
3339 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3340 mips_sb (code, ins->sreg1, mips_at, 0);
3343 case OP_STOREI2_MEMBASE_REG:
3344 if (mips_is_imm16 (ins->inst_offset)) {
3345 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3347 mips_load_const (code, mips_at, ins->inst_offset);
3348 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3349 mips_sh (code, ins->sreg1, mips_at, 0);
3352 case OP_STORE_MEMBASE_REG:
3353 case OP_STOREI4_MEMBASE_REG:
3354 if (mips_is_imm16 (ins->inst_offset)) {
3355 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3357 mips_load_const (code, mips_at, ins->inst_offset);
3358 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3359 mips_sw (code, ins->sreg1, mips_at, 0);
3362 case OP_STOREI8_MEMBASE_REG:
3363 if (mips_is_imm16 (ins->inst_offset)) {
3364 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3366 mips_load_const (code, mips_at, ins->inst_offset);
3367 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3368 mips_sd (code, ins->sreg1, mips_at, 0);
3372 g_assert_not_reached ();
3373 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3374 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3376 case OP_LOADI8_MEMBASE:
3377 if (mips_is_imm16 (ins->inst_offset)) {
3378 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3380 mips_load_const (code, mips_at, ins->inst_offset);
3381 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3382 mips_ld (code, ins->dreg, mips_at, 0);
3385 case OP_LOAD_MEMBASE:
3386 case OP_LOADI4_MEMBASE:
3387 case OP_LOADU4_MEMBASE:
3388 g_assert (ins->dreg != -1);
3389 if (mips_is_imm16 (ins->inst_offset)) {
3390 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3392 mips_load_const (code, mips_at, ins->inst_offset);
3393 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3394 mips_lw (code, ins->dreg, mips_at, 0);
3397 case OP_LOADI1_MEMBASE:
3398 if (mips_is_imm16 (ins->inst_offset)) {
3399 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3401 mips_load_const (code, mips_at, ins->inst_offset);
3402 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3403 mips_lb (code, ins->dreg, mips_at, 0);
3406 case OP_LOADU1_MEMBASE:
3407 if (mips_is_imm16 (ins->inst_offset)) {
3408 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3410 mips_load_const (code, mips_at, ins->inst_offset);
3411 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3412 mips_lbu (code, ins->dreg, mips_at, 0);
3415 case OP_LOADI2_MEMBASE:
3416 if (mips_is_imm16 (ins->inst_offset)) {
3417 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3419 mips_load_const (code, mips_at, ins->inst_offset);
3420 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3421 mips_lh (code, ins->dreg, mips_at, 0);
3424 case OP_LOADU2_MEMBASE:
3425 if (mips_is_imm16 (ins->inst_offset)) {
3426 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3428 mips_load_const (code, mips_at, ins->inst_offset);
3429 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3430 mips_lhu (code, ins->dreg, mips_at, 0);
3433 case OP_ICONV_TO_I1:
3434 mips_sll (code, mips_at, ins->sreg1, 24);
3435 mips_sra (code, ins->dreg, mips_at, 24);
3437 case OP_ICONV_TO_I2:
3438 mips_sll (code, mips_at, ins->sreg1, 16);
3439 mips_sra (code, ins->dreg, mips_at, 16);
3441 case OP_ICONV_TO_U1:
3442 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3444 case OP_ICONV_TO_U2:
3445 mips_sll (code, mips_at, ins->sreg1, 16);
3446 mips_srl (code, ins->dreg, mips_at, 16);
3449 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3452 g_assert (mips_is_imm16 (ins->inst_imm));
3453 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3456 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3459 g_assert (mips_is_imm16 (ins->inst_imm));
3460 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3464 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3465 * So instead of emitting a trap, we emit a call a C function and place a
3468 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3469 (gpointer)"mono_break");
3470 mips_load (code, mips_t9, 0x1f1f1f1f);
3471 mips_jalr (code, mips_t9, mips_ra);
3475 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3478 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3483 g_assert (mips_is_imm16 (ins->inst_imm));
3484 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3487 g_assert (mips_is_imm16 (ins->inst_imm));
3488 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3492 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3495 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3500 // we add the negated value
3501 g_assert (mips_is_imm16 (-ins->inst_imm));
3502 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3506 // we add the negated value
3507 g_assert (mips_is_imm16 (-ins->inst_imm));
3508 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3513 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3519 g_assert (!(ins->inst_imm & 0xffff0000));
3520 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3525 guint32 *divisor_is_m1;
3526 guint32 *dividend_is_minvalue;
3527 guint32 *divisor_is_zero;
3529 mips_load_const (code, mips_at, -1);
3530 divisor_is_m1 = (guint32 *)(void *)code;
3531 mips_bne (code, ins->sreg2, mips_at, 0);
3532 mips_lui (code, mips_at, mips_zero, 0x8000);
3533 dividend_is_minvalue = (guint32 *)(void *)code;
3534 mips_bne (code, ins->sreg1, mips_at, 0);
3537 /* Divide Int32.MinValue by -1 -- throw exception */
3538 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3540 mips_patch (divisor_is_m1, (guint32)code);
3541 mips_patch (dividend_is_minvalue, (guint32)code);
3543 /* Put divide in branch delay slot (NOT YET) */
3544 divisor_is_zero = (guint32 *)(void *)code;
3545 mips_bne (code, ins->sreg2, mips_zero, 0);
3548 /* Divide by zero -- throw exception */
3549 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3551 mips_patch (divisor_is_zero, (guint32)code);
3552 mips_div (code, ins->sreg1, ins->sreg2);
3553 if (ins->opcode == OP_IDIV)
3554 mips_mflo (code, ins->dreg);
3556 mips_mfhi (code, ins->dreg);
3561 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3563 /* Put divide in branch delay slot (NOT YET) */
3564 mips_bne (code, ins->sreg2, mips_zero, 0);
3567 /* Divide by zero -- throw exception */
3568 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3570 mips_patch (divisor_is_zero, (guint32)code);
3571 mips_divu (code, ins->sreg1, ins->sreg2);
3572 if (ins->opcode == OP_IDIV_UN)
3573 mips_mflo (code, ins->dreg);
3575 mips_mfhi (code, ins->dreg);
3579 g_assert_not_reached ();
3581 ppc_load (code, ppc_r12, ins->inst_imm);
3582 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3583 ppc_mfspr (code, ppc_r0, ppc_xer);
3584 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3585 /* FIXME: use OverflowException for 0x80000000/-1 */
3586 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3588 g_assert_not_reached();
3591 g_assert_not_reached ();
3593 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3597 g_assert (!(ins->inst_imm & 0xffff0000));
3598 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3601 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3605 /* unsigned 16-bit immediate */
3606 g_assert (!(ins->inst_imm & 0xffff0000));
3607 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3610 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3614 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3617 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3620 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3624 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3627 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3630 case OP_ISHR_UN_IMM:
3631 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3633 case OP_LSHR_UN_IMM:
3634 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3637 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3640 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3644 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3647 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3650 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3654 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3656 mips_mult (code, ins->sreg1, ins->sreg2);
3657 mips_mflo (code, ins->dreg);
3662 #if SIZEOF_REGISTER == 8
3664 mips_dmult (code, ins->sreg1, ins->sreg2);
3665 mips_mflo (code, ins->dreg);
3670 mips_mult (code, ins->sreg1, ins->sreg2);
3671 mips_mflo (code, ins->dreg);
3672 mips_mfhi (code, mips_at);
3675 mips_sra (code, mips_temp, ins->dreg, 31);
3676 patch = (guint32 *)(void *)code;
3677 mips_beq (code, mips_temp, mips_at, 0);
3679 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3680 mips_patch (patch, (guint32)code);
3683 case OP_IMUL_OVF_UN: {
3685 mips_mult (code, ins->sreg1, ins->sreg2);
3686 mips_mflo (code, ins->dreg);
3687 mips_mfhi (code, mips_at);
3690 patch = (guint32 *)(void *)code;
3691 mips_beq (code, mips_at, mips_zero, 0);
3693 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3694 mips_patch (patch, (guint32)code);
3698 mips_load_const (code, ins->dreg, ins->inst_c0);
3700 #if SIZEOF_REGISTER == 8
3702 mips_load_const (code, ins->dreg, ins->inst_c0);
3706 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3707 mips_load (code, ins->dreg, 0);
3711 mips_mtc1 (code, ins->dreg, ins->sreg1);
3713 case OP_MIPS_MTC1S_2:
3714 mips_mtc1 (code, ins->dreg, ins->sreg1);
3715 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3718 mips_mfc1 (code, ins->dreg, ins->sreg1);
3721 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3725 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3727 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3728 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3732 case OP_ICONV_TO_I4:
3733 case OP_ICONV_TO_U4:
3735 if (ins->dreg != ins->sreg1)
3736 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3738 #if SIZEOF_REGISTER == 8
3740 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3741 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3744 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3745 mips_dsra (code, ins->dreg, ins->dreg, 32);
3749 int lsreg = mips_v0 + ls_word_idx;
3750 int msreg = mips_v0 + ms_word_idx;
3752 /* Get sreg1 into lsreg, sreg2 into msreg */
3754 if (ins->sreg1 == msreg) {
3755 if (ins->sreg1 != mips_at)
3756 MIPS_MOVE (code, mips_at, ins->sreg1);
3757 if (ins->sreg2 != msreg)
3758 MIPS_MOVE (code, msreg, ins->sreg2);
3759 MIPS_MOVE (code, lsreg, mips_at);
3762 if (ins->sreg2 != msreg)
3763 MIPS_MOVE (code, msreg, ins->sreg2);
3764 if (ins->sreg1 != lsreg)
3765 MIPS_MOVE (code, lsreg, ins->sreg1);
3770 if (ins->dreg != ins->sreg1) {
3771 mips_fmovd (code, ins->dreg, ins->sreg1);
3774 case OP_MOVE_F_TO_I4:
3775 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3776 mips_mfc1 (code, ins->dreg, mips_ftemp);
3778 case OP_MOVE_I4_TO_F:
3779 mips_mtc1 (code, ins->dreg, ins->sreg1);
3780 mips_cvtds (code, ins->dreg, ins->dreg);
3783 /* Convert from double to float and leave it there */
3784 mips_cvtsd (code, ins->dreg, ins->sreg1);
3786 case OP_FCONV_TO_R4:
3788 mips_cvtsd (code, ins->dreg, ins->sreg1);
3790 /* Just a move, no precision change */
3791 if (ins->dreg != ins->sreg1) {
3792 mips_fmovd (code, ins->dreg, ins->sreg1);
3797 code = emit_load_volatile_arguments(cfg, code);
3800 * Pop our stack, then jump to specified method (tail-call)
3801 * Keep in sync with mono_arch_emit_epilog
3803 code = mono_arch_emit_epilog_sub (cfg, code);
3805 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3806 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3807 mips_load (code, mips_t9, 0);
3808 mips_jr (code, mips_t9);
3812 /* ensure ins->sreg1 is not NULL */
3813 mips_lw (code, mips_zero, ins->sreg1, 0);
3816 g_assert (mips_is_imm16 (cfg->sig_cookie));
3817 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3818 mips_sw (code, mips_at, ins->sreg1, 0);
3831 case OP_VOIDCALL_REG:
3833 case OP_FCALL_MEMBASE:
3834 case OP_LCALL_MEMBASE:
3835 case OP_VCALL_MEMBASE:
3836 case OP_VCALL2_MEMBASE:
3837 case OP_VOIDCALL_MEMBASE:
3838 case OP_CALL_MEMBASE:
3839 call = (MonoCallInst*)ins;
3840 switch (ins->opcode) {
3847 if (ins->flags & MONO_INST_HAS_METHOD) {
3848 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3849 mips_load (code, mips_t9, call->method);
3852 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3853 mips_load (code, mips_t9, call->fptr);
3855 mips_jalr (code, mips_t9, mips_ra);
3862 case OP_VOIDCALL_REG:
3864 MIPS_MOVE (code, mips_t9, ins->sreg1);
3865 mips_jalr (code, mips_t9, mips_ra);
3868 case OP_FCALL_MEMBASE:
3869 case OP_LCALL_MEMBASE:
3870 case OP_VCALL_MEMBASE:
3871 case OP_VCALL2_MEMBASE:
3872 case OP_VOIDCALL_MEMBASE:
3873 case OP_CALL_MEMBASE:
3874 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3875 mips_jalr (code, mips_t9, mips_ra);
3879 #if PROMOTE_R4_TO_R8
3880 /* returned an FP R4 (single), promote to R8 (double) in place */
3881 switch (ins->opcode) {
3884 case OP_FCALL_MEMBASE:
3885 if (call->signature->ret->type == MONO_TYPE_R4)
3886 mips_cvtds (code, mips_f0, mips_f0);
3894 int area_offset = cfg->param_area;
3896 /* Round up ins->sreg1, mips_at ends up holding size */
3897 mips_addiu (code, mips_at, ins->sreg1, 31);
3898 mips_addiu (code, mips_temp, mips_zero, ~31);
3899 mips_and (code, mips_at, mips_at, mips_temp);
3901 mips_subu (code, mips_sp, mips_sp, mips_at);
3902 g_assert (mips_is_imm16 (area_offset));
3903 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3905 if (ins->flags & MONO_INST_INIT) {
3908 buf = (guint32*)(void*)code;
3909 mips_beq (code, mips_at, mips_zero, 0);
3912 mips_move (code, mips_temp, ins->dreg);
3913 mips_sb (code, mips_zero, mips_temp, 0);
3914 mips_addiu (code, mips_at, mips_at, -1);
3915 mips_bne (code, mips_at, mips_zero, -3);
3916 mips_addiu (code, mips_temp, mips_temp, 1);
3918 mips_patch (buf, (guint32)code);
3923 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3924 mips_move (code, mips_a0, ins->sreg1);
3925 mips_call (code, mips_t9, addr);
3926 mips_break (code, 0xfc);
3930 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3931 mips_move (code, mips_a0, ins->sreg1);
3932 mips_call (code, mips_t9, addr);
3933 mips_break (code, 0xfb);
3936 case OP_START_HANDLER: {
3938 * The START_HANDLER instruction marks the beginning of
3939 * a handler block. It is called using a call
3940 * instruction, so mips_ra contains the return address.
3941 * Since the handler executes in the same stack frame
3942 * as the method itself, we can't use save/restore to
3943 * save the return address. Instead, we save it into
3944 * a dedicated variable.
3946 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3947 g_assert (spvar->inst_basereg != mips_sp);
3948 code = emit_reserve_param_area (cfg, code);
3950 if (mips_is_imm16 (spvar->inst_offset)) {
3951 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3953 mips_load_const (code, mips_at, spvar->inst_offset);
3954 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3955 mips_sw (code, mips_ra, mips_at, 0);
3959 case OP_ENDFILTER: {
3960 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3961 g_assert (spvar->inst_basereg != mips_sp);
3962 code = emit_unreserve_param_area (cfg, code);
3964 if (ins->sreg1 != mips_v0)
3965 MIPS_MOVE (code, mips_v0, ins->sreg1);
3966 if (mips_is_imm16 (spvar->inst_offset)) {
3967 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3969 mips_load_const (code, mips_at, spvar->inst_offset);
3970 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3971 mips_lw (code, mips_ra, mips_at, 0);
3973 mips_jr (code, mips_ra);
3977 case OP_ENDFINALLY: {
3978 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3979 g_assert (spvar->inst_basereg != mips_sp);
3980 code = emit_unreserve_param_area (cfg, code);
3981 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3982 mips_jalr (code, mips_t9, mips_ra);
3986 case OP_CALL_HANDLER:
3987 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3988 mips_lui (code, mips_t9, mips_zero, 0);
3989 mips_addiu (code, mips_t9, mips_t9, 0);
3990 mips_jalr (code, mips_t9, mips_ra);
3992 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3993 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3996 ins->inst_c0 = code - cfg->native_code;
3999 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4000 if (cfg->arch.long_branch) {
4001 mips_lui (code, mips_at, mips_zero, 0);
4002 mips_addiu (code, mips_at, mips_at, 0);
4003 mips_jr (code, mips_at);
4007 mips_beq (code, mips_zero, mips_zero, 0);
4012 mips_jr (code, ins->sreg1);
4018 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4019 if (offset > (cfg->code_size - max_len - 16)) {
4020 cfg->code_size += max_len;
4021 cfg->code_size *= 2;
4022 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4023 code = cfg->native_code + offset;
4025 g_assert (ins->sreg1 != -1);
4026 mips_sll (code, mips_at, ins->sreg1, 2);
4027 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4028 MIPS_MOVE (code, mips_t8, mips_ra);
4029 mips_bgezal (code, mips_zero, 1); /* bal */
4031 mips_addu (code, mips_t9, mips_ra, mips_at);
4032 /* Table is 16 or 20 bytes from target of bal above */
4033 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4034 MIPS_MOVE (code, mips_ra, mips_t8);
4035 mips_lw (code, mips_t9, mips_t9, 20);
4038 mips_lw (code, mips_t9, mips_t9, 16);
4039 mips_jalr (code, mips_t9, mips_t8);
4041 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4042 mips_emit32 (code, 0xfefefefe);
4047 mips_addiu (code, ins->dreg, mips_zero, 1);
4048 mips_beq (code, mips_at, mips_zero, 2);
4050 MIPS_MOVE (code, ins->dreg, mips_zero);
4056 mips_addiu (code, ins->dreg, mips_zero, 1);
4057 mips_bltz (code, mips_at, 2);
4059 MIPS_MOVE (code, ins->dreg, mips_zero);
4065 mips_addiu (code, ins->dreg, mips_zero, 1);
4066 mips_bgtz (code, mips_at, 2);
4068 MIPS_MOVE (code, ins->dreg, mips_zero);
4071 case OP_MIPS_COND_EXC_EQ:
4072 case OP_MIPS_COND_EXC_GE:
4073 case OP_MIPS_COND_EXC_GT:
4074 case OP_MIPS_COND_EXC_LE:
4075 case OP_MIPS_COND_EXC_LT:
4076 case OP_MIPS_COND_EXC_NE_UN:
4077 case OP_MIPS_COND_EXC_GE_UN:
4078 case OP_MIPS_COND_EXC_GT_UN:
4079 case OP_MIPS_COND_EXC_LE_UN:
4080 case OP_MIPS_COND_EXC_LT_UN:
4082 case OP_MIPS_COND_EXC_OV:
4083 case OP_MIPS_COND_EXC_NO:
4084 case OP_MIPS_COND_EXC_C:
4085 case OP_MIPS_COND_EXC_NC:
4087 case OP_MIPS_COND_EXC_IEQ:
4088 case OP_MIPS_COND_EXC_IGE:
4089 case OP_MIPS_COND_EXC_IGT:
4090 case OP_MIPS_COND_EXC_ILE:
4091 case OP_MIPS_COND_EXC_ILT:
4092 case OP_MIPS_COND_EXC_INE_UN:
4093 case OP_MIPS_COND_EXC_IGE_UN:
4094 case OP_MIPS_COND_EXC_IGT_UN:
4095 case OP_MIPS_COND_EXC_ILE_UN:
4096 case OP_MIPS_COND_EXC_ILT_UN:
4098 case OP_MIPS_COND_EXC_IOV:
4099 case OP_MIPS_COND_EXC_INO:
4100 case OP_MIPS_COND_EXC_IC:
4101 case OP_MIPS_COND_EXC_INC: {
4105 /* If the condition is true, raise the exception */
4107 /* need to reverse test to skip around exception raising */
4109 /* For the moment, branch around a branch to avoid reversing
4112 /* Remember, an unpatched branch to 0 branches to the delay slot */
4113 switch (ins->opcode) {
4114 case OP_MIPS_COND_EXC_EQ:
4115 throw = (guint32 *)(void *)code;
4116 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4120 case OP_MIPS_COND_EXC_NE_UN:
4121 throw = (guint32 *)(void *)code;
4122 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4126 case OP_MIPS_COND_EXC_LE_UN:
4127 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4128 throw = (guint32 *)(void *)code;
4129 mips_beq (code, mips_at, mips_zero, 0);
4133 case OP_MIPS_COND_EXC_GT:
4134 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4135 throw = (guint32 *)(void *)code;
4136 mips_bne (code, mips_at, mips_zero, 0);
4140 case OP_MIPS_COND_EXC_GT_UN:
4141 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4142 throw = (guint32 *)(void *)code;
4143 mips_bne (code, mips_at, mips_zero, 0);
4147 case OP_MIPS_COND_EXC_LT:
4148 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4149 throw = (guint32 *)(void *)code;
4150 mips_bne (code, mips_at, mips_zero, 0);
4154 case OP_MIPS_COND_EXC_LT_UN:
4155 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4156 throw = (guint32 *)(void *)code;
4157 mips_bne (code, mips_at, mips_zero, 0);
4162 /* Not yet implemented */
4163 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4164 g_assert_not_reached ();
4166 skip = (guint32 *)(void *)code;
4167 mips_beq (code, mips_zero, mips_zero, 0);
4169 mips_patch (throw, (guint32)code);
4170 code = mips_emit_exc_by_name (code, ins->inst_p1);
4171 mips_patch (skip, (guint32)code);
4172 cfg->bb_exit->max_offset += 24;
4181 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4184 /* floating point opcodes */
4187 if (((guint32)ins->inst_p0) & (1 << 15))
4188 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4190 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4191 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4193 mips_load_const (code, mips_at, ins->inst_p0);
4194 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4195 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4199 if (((guint32)ins->inst_p0) & (1 << 15))
4200 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4202 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4203 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4204 #if PROMOTE_R4_TO_R8
4205 mips_cvtds (code, ins->dreg, ins->dreg);
4208 case OP_STORER8_MEMBASE_REG:
4209 if (mips_is_imm16 (ins->inst_offset)) {
4210 #if _MIPS_SIM == _ABIO32
4211 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4212 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4213 #elif _MIPS_SIM == _ABIN32
4214 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4217 mips_load_const (code, mips_at, ins->inst_offset);
4218 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4219 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4220 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4223 case OP_LOADR8_MEMBASE:
4224 if (mips_is_imm16 (ins->inst_offset)) {
4225 #if _MIPS_SIM == _ABIO32
4226 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4227 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4228 #elif _MIPS_SIM == _ABIN32
4229 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4232 mips_load_const (code, mips_at, ins->inst_offset);
4233 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4234 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4235 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4238 case OP_STORER4_MEMBASE_REG:
4239 g_assert (mips_is_imm16 (ins->inst_offset));
4240 #if PROMOTE_R4_TO_R8
4241 /* Need to convert ins->sreg1 to single-precision first */
4242 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4243 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4245 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4249 g_assert (mips_is_imm16 (ins->inst_offset));
4250 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4252 case OP_LOADR4_MEMBASE:
4253 g_assert (mips_is_imm16 (ins->inst_offset));
4254 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4255 #if PROMOTE_R4_TO_R8
4256 /* Convert to double precision in place */
4257 mips_cvtds (code, ins->dreg, ins->dreg);
4260 case OP_LOADR4_MEMINDEX:
4261 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4262 mips_lwc1 (code, ins->dreg, mips_at, 0);
4264 case OP_LOADR8_MEMINDEX:
4265 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4266 #if _MIPS_SIM == _ABIO32
4267 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4268 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4269 #elif _MIPS_SIM == _ABIN32
4270 mips_ldc1 (code, ins->dreg, mips_at, 0);
4273 case OP_STORER4_MEMINDEX:
4274 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4275 #if PROMOTE_R4_TO_R8
4276 /* Need to convert ins->sreg1 to single-precision first */
4277 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4278 mips_swc1 (code, mips_ftemp, mips_at, 0);
4280 mips_swc1 (code, ins->sreg1, mips_at, 0);
4283 case OP_STORER8_MEMINDEX:
4284 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4285 #if _MIPS_SIM == _ABIO32
4286 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4287 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4288 #elif _MIPS_SIM == _ABIN32
4289 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4292 case OP_ICONV_TO_R_UN: {
4293 static const guint64 adjust_val = 0x41F0000000000000ULL;
4295 /* convert unsigned int to double */
4296 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4297 mips_bgez (code, ins->sreg1, 5);
4298 mips_cvtdw (code, ins->dreg, mips_ftemp);
4300 mips_load (code, mips_at, (guint32) &adjust_val);
4301 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4302 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4303 /* target is here */
4306 case OP_ICONV_TO_R4:
4307 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4308 mips_cvtsw (code, ins->dreg, mips_ftemp);
4309 mips_cvtds (code, ins->dreg, ins->dreg);
4311 case OP_ICONV_TO_R8:
4312 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4313 mips_cvtdw (code, ins->dreg, mips_ftemp);
4315 case OP_FCONV_TO_I1:
4316 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4318 case OP_FCONV_TO_U1:
4319 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4321 case OP_FCONV_TO_I2:
4322 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4324 case OP_FCONV_TO_U2:
4325 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4327 case OP_FCONV_TO_I4:
4329 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4331 case OP_FCONV_TO_U4:
4333 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4336 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4339 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4342 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4345 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4348 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4351 mips_fnegd (code, ins->dreg, ins->sreg1);
4354 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4355 mips_addiu (code, ins->dreg, mips_zero, 1);
4356 mips_fbtrue (code, 2);
4358 MIPS_MOVE (code, ins->dreg, mips_zero);
4361 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4362 mips_addiu (code, ins->dreg, mips_zero, 1);
4363 mips_fbtrue (code, 2);
4365 MIPS_MOVE (code, ins->dreg, mips_zero);
4368 /* Less than, or Unordered */
4369 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4370 mips_addiu (code, ins->dreg, mips_zero, 1);
4371 mips_fbtrue (code, 2);
4373 MIPS_MOVE (code, ins->dreg, mips_zero);
4376 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4377 MIPS_MOVE (code, ins->dreg, mips_zero);
4378 mips_fbtrue (code, 2);
4380 mips_addiu (code, ins->dreg, mips_zero, 1);
4383 /* Greater than, or Unordered */
4384 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4385 MIPS_MOVE (code, ins->dreg, mips_zero);
4386 mips_fbtrue (code, 2);
4388 mips_addiu (code, ins->dreg, mips_zero, 1);
4393 case OP_MIPS_FBLT_UN:
4395 case OP_MIPS_FBGT_UN:
4397 case OP_MIPS_FBGE_UN:
4399 case OP_MIPS_FBLE_UN: {
4401 gboolean is_true = TRUE, is_ordered = FALSE;
4402 guint32 *buf = NULL;
4404 switch (ins->opcode) {
4418 case OP_MIPS_FBLT_UN:
4419 cond = MIPS_FPU_ULT;
4427 case OP_MIPS_FBGT_UN:
4428 cond = MIPS_FPU_OLE;
4436 case OP_MIPS_FBGE_UN:
4437 cond = MIPS_FPU_OLT;
4441 cond = MIPS_FPU_OLE;
4445 case OP_MIPS_FBLE_UN:
4446 cond = MIPS_FPU_ULE;
4450 g_assert_not_reached ();
4454 /* Skip the check if unordered */
4455 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4457 buf = (guint32*)code;
4458 mips_fbtrue (code, 0);
4462 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4464 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4466 mips_fbtrue (code, 0);
4468 mips_fbfalse (code, 0);
4472 mips_patch (buf, (guint32)code);
4476 guint32 *branch_patch;
4478 mips_mfc1 (code, mips_at, ins->sreg1+1);
4479 mips_srl (code, mips_at, mips_at, 16+4);
4480 mips_andi (code, mips_at, mips_at, 2047);
4481 mips_addiu (code, mips_at, mips_at, -2047);
4483 branch_patch = (guint32 *)(void *)code;
4484 mips_bne (code, mips_at, mips_zero, 0);
4487 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4488 mips_patch (branch_patch, (guint32)code);
4489 mips_fmovd (code, ins->dreg, ins->sreg1);
4493 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4494 mips_load (code, ins->dreg, 0x0f0f0f0f);
4496 case OP_GC_SAFE_POINT:
4501 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4502 g_assert_not_reached ();
4505 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4506 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4507 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4508 g_assert_not_reached ();
4514 last_offset = offset;
4517 cfg->code_len = code - cfg->native_code;
4521 mono_arch_register_lowlevel_calls (void)
4526 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4528 MonoJumpInfo *patch_info;
4532 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4533 unsigned char *ip = patch_info->ip.i + code;
4534 const unsigned char *target = NULL;
4536 switch (patch_info->type) {
4537 case MONO_PATCH_INFO_IP:
4538 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4540 case MONO_PATCH_INFO_SWITCH: {
4541 gpointer *table = (gpointer *)patch_info->data.table->table;
4544 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4546 for (i = 0; i < patch_info->data.table->table_size; i++) {
4547 table [i] = (int)patch_info->data.table->table [i] + code;
4551 case MONO_PATCH_INFO_METHODCONST:
4552 case MONO_PATCH_INFO_CLASS:
4553 case MONO_PATCH_INFO_IMAGE:
4554 case MONO_PATCH_INFO_FIELD:
4555 case MONO_PATCH_INFO_VTABLE:
4556 case MONO_PATCH_INFO_IID:
4557 case MONO_PATCH_INFO_SFLDA:
4558 case MONO_PATCH_INFO_LDSTR:
4559 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4560 case MONO_PATCH_INFO_LDTOKEN:
4561 case MONO_PATCH_INFO_R4:
4562 case MONO_PATCH_INFO_R8:
4563 /* from OP_AOTCONST : lui + addiu */
4564 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4565 return_if_nok (error);
4567 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4570 case MONO_PATCH_INFO_EXC_NAME:
4571 g_assert_not_reached ();
4572 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4575 case MONO_PATCH_INFO_NONE:
4576 /* everything is dealt with at epilog output time */
4579 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4580 return_if_nok (error);
4582 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4589 * Allow tracing to work with this interface (with an optional argument)
4591 * This code is expected to be inserted just after the 'real' prolog code,
4592 * and before the first basic block. We need to allocate a 2nd, temporary
4593 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4597 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4600 int offset = cfg->arch.tracing_offset;
4606 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4607 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4608 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4609 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4610 #if _MIPS_SIM == _ABIN32
4612 /* FIXME: Need a separate region for these */
4613 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4614 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4615 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4616 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4620 mips_load_const (code, mips_a0, cfg->method);
4621 mips_addiu (code, mips_a1, mips_sp, offset);
4622 mips_call (code, mips_t9, func);
4625 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4626 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4627 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4628 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4629 #if _MIPS_SIM == _ABIN32
4632 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4633 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4634 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4635 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4646 mips_adjust_stackframe(MonoCompile *cfg)
4649 int delta, threshold, i;
4650 MonoMethodSignature *sig;
4653 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4656 /* adjust cfg->stack_offset for account for down-spilling */
4657 cfg->stack_offset += SIZEOF_REGISTER;
4659 /* re-align cfg->stack_offset if needed (due to var spilling) */
4660 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4661 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4662 if (cfg->verbose_level > 2) {
4663 g_print ("mips_adjust_stackframe:\n");
4664 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4666 threshold = cfg->arch.local_alloc_offset;
4667 ra_offset = cfg->stack_offset - sizeof(gpointer);
4668 if (cfg->verbose_level > 2) {
4669 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4672 sig = mono_method_signature (cfg->method);
4673 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4674 cfg->vret_addr->inst_offset += delta;
4676 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4677 MonoInst *inst = cfg->args [i];
4679 inst->inst_offset += delta;
4683 * loads and stores based off the frame reg that (used to) lie
4684 * above the spill var area need to be increased by 'delta'
4685 * to make room for the spill vars.
4687 /* Need to find loads and stores to adjust that
4688 * are above where the spillvars were inserted, but
4689 * which are not the spillvar references themselves.
4691 * Idea - since all offsets from fp are positive, make
4692 * spillvar offsets negative to begin with so we can spot
4697 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4701 if (cfg->verbose_level > 2) {
4702 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4704 MONO_BB_FOR_EACH_INS (bb, ins) {
4708 if (cfg->verbose_level > 2) {
4709 mono_print_ins_index (ins_cnt, ins);
4711 /* The == mips_sp tests catch FP spills */
4712 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4713 (ins->inst_basereg == mips_sp))) {
4714 switch (ins->opcode) {
4715 case OP_LOADI8_MEMBASE:
4716 case OP_LOADR8_MEMBASE:
4723 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4724 (ins->dreg == mips_sp))) {
4725 switch (ins->opcode) {
4726 case OP_STOREI8_MEMBASE_REG:
4727 case OP_STORER8_MEMBASE_REG:
4728 case OP_STOREI8_MEMBASE_IMM:
4736 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4739 if (ins->inst_c0 >= threshold) {
4740 ins->inst_c0 += delta;
4741 if (cfg->verbose_level > 2) {
4743 mono_print_ins_index (ins_cnt, ins);
4746 else if (ins->inst_c0 < 0) {
4747 /* Adj_c0 holds the size of the datatype. */
4748 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4749 if (cfg->verbose_level > 2) {
4751 mono_print_ins_index (ins_cnt, ins);
4754 g_assert (ins->inst_c0 != ra_offset);
4757 if (ins->inst_imm >= threshold) {
4758 ins->inst_imm += delta;
4759 if (cfg->verbose_level > 2) {
4761 mono_print_ins_index (ins_cnt, ins);
4764 g_assert (ins->inst_c0 != ra_offset);
4774 * Stack frame layout:
4776 * ------------------- sp + cfg->stack_usage + cfg->param_area
4777 * param area incoming
4778 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4780 * ------------------- sp + cfg->stack_usage
4782 * ------------------- sp + cfg->stack_usage-4
4784 * ------------------- sp +
4785 * MonoLMF structure optional
4786 * ------------------- sp + cfg->arch.lmf_offset
4787 * saved registers s0-s8
4788 * ------------------- sp + cfg->arch.iregs_offset
4790 * ------------------- sp + cfg->param_area
4791 * param area outgoing
4792 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4794 * ------------------- sp
4798 mono_arch_emit_prolog (MonoCompile *cfg)
4800 MonoMethod *method = cfg->method;
4801 MonoMethodSignature *sig;
4803 int alloc_size, pos, i, max_offset;
4804 int alloc2_size = 0;
4808 guint32 iregs_to_save = 0;
4810 guint32 fregs_to_save = 0;
4812 /* lmf_offset is the offset of the LMF from our stack pointer. */
4813 guint32 lmf_offset = cfg->arch.lmf_offset;
4817 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4821 cfg->flags |= MONO_CFG_HAS_CALLS;
4823 sig = mono_method_signature (method);
4824 cfg->code_size = 768 + sig->param_count * 20;
4825 code = cfg->native_code = g_malloc (cfg->code_size);
4828 * compute max_offset in order to use short forward jumps.
4831 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4832 MonoInst *ins = bb->code;
4833 bb->max_offset = max_offset;
4835 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4838 MONO_BB_FOR_EACH_INS (bb, ins)
4839 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4841 if (max_offset > 0xffff)
4842 cfg->arch.long_branch = TRUE;
4845 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4846 * This means that we have to adjust the offsets inside instructions which reference
4847 * arguments received on the stack, since the initial offset doesn't take into
4848 * account spill slots.
4850 mips_adjust_stackframe (cfg);
4852 /* Offset between current sp and the CFA */
4854 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4856 /* stack_offset should not be changed here. */
4857 alloc_size = cfg->stack_offset;
4858 cfg->stack_usage = alloc_size;
4860 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4863 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4865 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4866 fregs_to_save |= (fregs_to_save << 1);
4869 /* If the stack size is too big, save 1024 bytes to start with
4870 * so the prologue can use imm16(reg) addressing, then allocate
4871 * the rest of the frame.
4873 if (alloc_size > ((1 << 15) - 1024)) {
4874 alloc2_size = alloc_size - 1024;
4878 g_assert (mips_is_imm16 (-alloc_size));
4879 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4880 cfa_offset = alloc_size;
4881 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4884 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4885 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4886 if (mips_is_imm16(offset))
4887 mips_sw (code, mips_ra, mips_sp, offset);
4889 g_assert_not_reached ();
4891 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4892 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4895 /* XXX - optimize this later to not save all regs if LMF constructed */
4896 pos = cfg->arch.iregs_offset - alloc2_size;
4898 if (iregs_to_save) {
4899 /* save used registers in own stack frame (at pos) */
4900 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4901 if (iregs_to_save & (1 << i)) {
4902 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4903 g_assert (mips_is_imm16(pos));
4904 MIPS_SW (code, i, mips_sp, pos);
4905 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4906 pos += SIZEOF_REGISTER;
4911 // FIXME: Don't save registers twice if there is an LMF
4912 // s8 has to be special cased since it is overwritten with the updated value
4914 if (method->save_lmf) {
4915 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4916 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4917 g_assert (mips_is_imm16(offset));
4918 if (MIPS_LMF_IREGMASK & (1 << i))
4919 MIPS_SW (code, i, mips_sp, offset);
4924 /* Save float registers */
4925 if (fregs_to_save) {
4926 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4927 if (fregs_to_save & (1 << i)) {
4928 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4929 g_assert (mips_is_imm16(pos));
4930 mips_swc1 (code, i, mips_sp, pos);
4931 pos += sizeof (gulong);
4936 if (method->save_lmf) {
4937 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4938 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4939 g_assert (mips_is_imm16(offset));
4940 mips_swc1 (code, i, mips_sp, offset);
4945 if (cfg->frame_reg != mips_sp) {
4946 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4947 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4949 if (method->save_lmf) {
4950 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4951 g_assert (mips_is_imm16(offset));
4952 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4956 /* store runtime generic context */
4957 if (cfg->rgctx_var) {
4958 MonoInst *ins = cfg->rgctx_var;
4960 g_assert (ins->opcode == OP_REGOFFSET);
4962 g_assert (mips_is_imm16 (ins->inst_offset));
4963 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4966 /* load arguments allocated to register from the stack */
4969 if (!cfg->arch.cinfo)
4970 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
4971 cinfo = cfg->arch.cinfo;
4973 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4974 ArgInfo *ainfo = &cinfo->ret;
4975 inst = cfg->vret_addr;
4976 if (inst->opcode == OP_REGVAR)
4977 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4978 else if (mips_is_imm16 (inst->inst_offset)) {
4979 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4981 mips_load_const (code, mips_at, inst->inst_offset);
4982 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4983 mips_sw (code, ainfo->reg, mips_at, 0);
4987 if (sig->call_convention == MONO_CALL_VARARG) {
4988 ArgInfo *cookie = &cinfo->sig_cookie;
4989 int offset = alloc_size + cookie->offset;
4991 /* Save the sig cookie address */
4992 g_assert (cookie->storage == ArgOnStack);
4994 g_assert (mips_is_imm16(offset));
4995 mips_addi (code, mips_at, cfg->frame_reg, offset);
4996 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
4999 /* Keep this in sync with emit_load_volatile_arguments */
5000 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5001 ArgInfo *ainfo = cinfo->args + i;
5002 inst = cfg->args [pos];
5004 if (cfg->verbose_level > 2)
5005 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5006 if (inst->opcode == OP_REGVAR) {
5007 /* Argument ends up in a register */
5008 if (ainfo->storage == ArgInIReg)
5009 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5010 else if (ainfo->storage == ArgInFReg) {
5011 g_assert_not_reached();
5013 ppc_fmr (code, inst->dreg, ainfo->reg);
5016 else if (ainfo->storage == ArgOnStack) {
5017 int offset = cfg->stack_usage + ainfo->offset;
5018 g_assert (mips_is_imm16(offset));
5019 mips_lw (code, inst->dreg, mips_sp, offset);
5021 g_assert_not_reached ();
5023 if (cfg->verbose_level > 2)
5024 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5026 /* Argument ends up on the stack */
5027 if (ainfo->storage == ArgInIReg) {
5029 /* Incoming parameters should be above this frame */
5030 if (cfg->verbose_level > 2)
5031 g_print ("stack slot at %d of %d+%d\n",
5032 inst->inst_offset, alloc_size, alloc2_size);
5033 /* g_assert (inst->inst_offset >= alloc_size); */
5034 g_assert (inst->inst_basereg == cfg->frame_reg);
5035 basereg_offset = inst->inst_offset - alloc2_size;
5036 g_assert (mips_is_imm16 (basereg_offset));
5037 switch (ainfo->size) {
5039 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5042 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5046 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5049 #if (SIZEOF_REGISTER == 4)
5050 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5051 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5052 #elif (SIZEOF_REGISTER == 8)
5053 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5057 g_assert_not_reached ();
5060 } else if (ainfo->storage == ArgOnStack) {
5062 * Argument comes in on the stack, and ends up on the stack
5063 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5064 * 8 and 16 bit quantities. Shorten them in place.
5066 g_assert (mips_is_imm16 (inst->inst_offset));
5067 switch (ainfo->size) {
5069 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5070 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5073 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5074 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5081 g_assert_not_reached ();
5083 } else if (ainfo->storage == ArgInFReg) {
5084 g_assert (mips_is_imm16 (inst->inst_offset));
5085 g_assert (mips_is_imm16 (inst->inst_offset+4));
5086 if (ainfo->size == 8) {
5087 #if _MIPS_SIM == _ABIO32
5088 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5089 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5090 #elif _MIPS_SIM == _ABIN32
5091 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5094 else if (ainfo->size == 4)
5095 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5097 g_assert_not_reached ();
5098 } else if (ainfo->storage == ArgStructByVal) {
5100 int doffset = inst->inst_offset;
5102 g_assert (mips_is_imm16 (inst->inst_offset));
5103 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5104 /* Push the argument registers into their stack slots */
5105 for (i = 0; i < ainfo->size; ++i) {
5106 g_assert (mips_is_imm16(doffset));
5107 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5108 doffset += SIZEOF_REGISTER;
5110 } else if (ainfo->storage == ArgStructByAddr) {
5111 g_assert (mips_is_imm16 (inst->inst_offset));
5112 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5113 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5115 g_assert_not_reached ();
5120 if (method->save_lmf) {
5121 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5122 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5124 /* This can/will clobber the a0-a3 registers */
5125 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5127 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5128 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5129 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5130 /* new_lmf->previous_lmf = *lmf_addr */
5131 mips_lw (code, mips_at, mips_v0, 0);
5132 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5133 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5134 /* *(lmf_addr) = sp + lmf_offset */
5135 g_assert (mips_is_imm16(lmf_offset));
5136 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5137 mips_sw (code, mips_at, mips_v0, 0);
5139 /* save method info */
5140 mips_load_const (code, mips_at, method);
5141 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5142 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5144 /* save the current IP */
5145 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5146 mips_load_const (code, mips_at, 0x01010101);
5147 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5151 if (mips_is_imm16 (-alloc2_size)) {
5152 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5155 mips_load_const (code, mips_at, -alloc2_size);
5156 mips_addu (code, mips_sp, mips_sp, mips_at);
5158 alloc_size += alloc2_size;
5159 cfa_offset += alloc2_size;
5160 if (cfg->frame_reg != mips_sp)
5161 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5163 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5167 #if _MIPS_SIM == _ABIO32
5168 cfg->arch.tracing_offset = cfg->stack_offset;
5169 #elif _MIPS_SIM == _ABIN32
5170 /* no stack slots by default for argument regs, reserve a special block */
5171 g_assert_not_reached ();
5173 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5176 cfg->code_len = code - cfg->native_code;
5177 g_assert (cfg->code_len < cfg->code_size);
5191 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5194 int save_mode = SAVE_NONE;
5196 MonoMethod *method = cfg->method;
5197 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5198 int save_offset = MIPS_STACK_PARAM_OFFSET;
5200 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5202 offset = code - cfg->native_code;
5203 /* we need about 16 instructions */
5204 if (offset > (cfg->code_size - 16 * 4)) {
5205 cfg->code_size *= 2;
5206 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5207 code = cfg->native_code + offset;
5212 case MONO_TYPE_VOID:
5213 /* special case string .ctor icall */
5214 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5215 save_mode = SAVE_ONE;
5217 save_mode = SAVE_NONE;
5221 save_mode = SAVE_FP;
5223 case MONO_TYPE_VALUETYPE:
5224 save_mode = SAVE_STRUCT;
5228 #if SIZEOF_REGISTER == 4
5229 save_mode = SAVE_TWO;
5230 #elif SIZEOF_REGISTER == 8
5231 save_mode = SAVE_ONE;
5235 save_mode = SAVE_ONE;
5239 mips_addiu (code, mips_sp, mips_sp, -32);
5240 g_assert (mips_is_imm16(save_offset));
5241 switch (save_mode) {
5243 mips_sw (code, mips_v0, mips_sp, save_offset);
5244 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5245 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5246 if (enable_arguments) {
5247 MIPS_MOVE (code, mips_a1, mips_v0);
5248 MIPS_MOVE (code, mips_a2, mips_v1);
5252 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5253 if (enable_arguments) {
5254 MIPS_MOVE (code, mips_a1, mips_v0);
5258 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5259 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5260 mips_lw (code, mips_a0, mips_sp, save_offset);
5261 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5262 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5269 mips_load_const (code, mips_a0, cfg->method);
5270 mips_call (code, mips_t9, func);
5272 switch (save_mode) {
5274 mips_lw (code, mips_v0, mips_sp, save_offset);
5275 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5276 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5279 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5282 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5289 mips_addiu (code, mips_sp, mips_sp, 32);
5296 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5298 MonoMethod *method = cfg->method;
5300 int max_epilog_size = 16 + 20*4;
5301 int alloc2_size = 0;
5302 guint32 iregs_to_restore;
5304 guint32 fregs_to_restore;
5307 if (cfg->method->save_lmf)
5308 max_epilog_size += 128;
5310 if (mono_jit_trace_calls != NULL)
5311 max_epilog_size += 50;
5313 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5314 max_epilog_size += 50;
5317 pos = code - cfg->native_code;
5318 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5319 cfg->code_size *= 2;
5320 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5321 cfg->stat_code_reallocs++;
5325 * Keep in sync with OP_JMP
5328 code = cfg->native_code + pos;
5330 code = cfg->native_code + cfg->code_len;
5332 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5333 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5335 if (cfg->frame_reg != mips_sp) {
5336 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5338 /* If the stack frame is really large, deconstruct it in two steps */
5339 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5340 alloc2_size = cfg->stack_usage - 1024;
5341 /* partially deconstruct the stack */
5342 mips_load_const (code, mips_at, alloc2_size);
5343 mips_addu (code, mips_sp, mips_sp, mips_at);
5345 pos = cfg->arch.iregs_offset - alloc2_size;
5346 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5347 if (iregs_to_restore) {
5348 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5349 if (iregs_to_restore & (1 << i)) {
5350 g_assert (mips_is_imm16(pos));
5351 MIPS_LW (code, i, mips_sp, pos);
5352 pos += SIZEOF_REGISTER;
5359 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5361 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5362 fregs_to_restore |= (fregs_to_restore << 1);
5364 if (fregs_to_restore) {
5365 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5366 if (fregs_to_restore & (1 << i)) {
5367 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5368 g_assert (mips_is_imm16(pos));
5369 mips_lwc1 (code, i, mips_sp, pos);
5376 /* Unlink the LMF if necessary */
5377 if (method->save_lmf) {
5378 int lmf_offset = cfg->arch.lmf_offset;
5380 /* t0 = current_lmf->previous_lmf */
5381 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5382 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5384 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5385 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5386 /* (*lmf_addr) = previous_lmf */
5387 mips_sw (code, mips_temp, mips_t1, 0);
5391 /* Restore the fp */
5392 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5395 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5396 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5397 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5399 /* Restore the stack pointer */
5400 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5401 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5403 /* Caller will emit either return or tail-call sequence */
5405 cfg->code_len = code - cfg->native_code;
5407 g_assert (cfg->code_len < cfg->code_size);
5412 mono_arch_emit_epilog (MonoCompile *cfg)
5416 code = mono_arch_emit_epilog_sub (cfg, NULL);
5418 mips_jr (code, mips_ra);
5421 cfg->code_len = code - cfg->native_code;
5423 g_assert (cfg->code_len < cfg->code_size);
5426 /* remove once throw_exception_by_name is eliminated */
5429 exception_id_by_name (const char *name)
5431 if (strcmp (name, "IndexOutOfRangeException") == 0)
5432 return MONO_EXC_INDEX_OUT_OF_RANGE;
5433 if (strcmp (name, "OverflowException") == 0)
5434 return MONO_EXC_OVERFLOW;
5435 if (strcmp (name, "ArithmeticException") == 0)
5436 return MONO_EXC_ARITHMETIC;
5437 if (strcmp (name, "DivideByZeroException") == 0)
5438 return MONO_EXC_DIVIDE_BY_ZERO;
5439 if (strcmp (name, "InvalidCastException") == 0)
5440 return MONO_EXC_INVALID_CAST;
5441 if (strcmp (name, "NullReferenceException") == 0)
5442 return MONO_EXC_NULL_REF;
5443 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5444 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5445 if (strcmp (name, "ArgumentException") == 0)
5446 return MONO_EXC_ARGUMENT;
5447 g_error ("Unknown intrinsic exception %s\n", name);
5453 mono_arch_emit_exceptions (MonoCompile *cfg)
5456 MonoJumpInfo *patch_info;
5459 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5460 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5461 int max_epilog_size = 50;
5463 /* count the number of exception infos */
5466 * make sure we have enough space for exceptions
5467 * 24 is the simulated call to throw_exception_by_name
5469 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5471 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5472 i = exception_id_by_name (patch_info->data.target);
5473 g_assert (i < MONO_EXC_INTRINS_NUM);
5474 if (!exc_throw_found [i]) {
5475 max_epilog_size += 12;
5476 exc_throw_found [i] = TRUE;
5482 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5483 cfg->code_size *= 2;
5484 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5485 cfg->stat_code_reallocs++;
5488 code = cfg->native_code + cfg->code_len;
5490 /* add code to raise exceptions */
5491 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5492 switch (patch_info->type) {
5493 case MONO_PATCH_INFO_EXC: {
5495 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5497 i = exception_id_by_name (patch_info->data.target);
5498 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5499 if (!exc_throw_pos [i]) {
5502 exc_throw_pos [i] = code;
5503 //g_print ("exc: writing stub at %p\n", code);
5504 mips_load_const (code, mips_a0, patch_info->data.target);
5505 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5506 mips_load_const (code, mips_t9, addr);
5507 mips_jr (code, mips_t9);
5510 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5512 /* Turn into a Relative patch, pointing at code stub */
5513 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5514 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5516 g_assert_not_reached();
5526 cfg->code_len = code - cfg->native_code;
5528 g_assert (cfg->code_len < cfg->code_size);
5533 mono_arch_finish_init (void)
5538 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5543 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5545 int this_dreg = mips_a0;
5548 this_dreg = mips_a1;
5550 /* add the this argument */
5551 if (this_reg != -1) {
5553 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5554 this_ins->type = this_type;
5555 this_ins->sreg1 = this_reg;
5556 this_ins->dreg = mono_alloc_ireg (cfg);
5557 mono_bblock_add_inst (cfg->cbb, this_ins);
5558 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5563 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5564 vtarg->type = STACK_MP;
5565 vtarg->sreg1 = vt_reg;
5566 vtarg->dreg = mono_alloc_ireg (cfg);
5567 mono_bblock_add_inst (cfg->cbb, vtarg);
5568 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5573 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5575 MonoInst *ins = NULL;
5581 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5587 mono_arch_print_tree (MonoInst *tree, int arity)
5593 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5595 return ctx->sc_regs [reg];
5598 #define ENABLE_WRONG_METHOD_CHECK 0
5600 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5601 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5603 #define LOADSTORE_SIZE 4
5604 #define JUMP_IMM_SIZE 16
5605 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5606 #define LOAD_CONST_SIZE 8
5607 #define JUMP_JR_SIZE 8
5610 * LOCKING: called with the domain lock held
5613 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5614 gpointer fail_tramp)
5618 guint8 *code, *start, *patch;
5620 for (i = 0; i < count; ++i) {
5621 MonoIMTCheckItem *item = imt_entries [i];
5623 if (item->is_equals) {
5624 if (item->check_target_idx) {
5625 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5626 if (item->has_target_code)
5627 item->chunk_size += LOAD_CONST_SIZE;
5629 item->chunk_size += LOADSTORE_SIZE;
5632 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5633 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5634 if (!item->has_target_code)
5635 item->chunk_size += LOADSTORE_SIZE;
5637 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5638 #if ENABLE_WRONG_METHOD_CHECK
5639 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5644 item->chunk_size += CMP_SIZE + BR_SIZE;
5645 imt_entries [item->check_target_idx]->compare_done = TRUE;
5647 size += item->chunk_size;
5649 /* the initial load of the vtable address */
5650 size += MIPS_LOAD_SEQUENCE_LENGTH;
5652 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5654 code = mono_domain_code_reserve (domain, size);
5658 /* t7 points to the vtable */
5659 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5661 for (i = 0; i < count; ++i) {
5662 MonoIMTCheckItem *item = imt_entries [i];
5664 item->code_target = code;
5665 if (item->is_equals) {
5666 if (item->check_target_idx) {
5667 mips_load_const (code, mips_temp, (gsize)item->key);
5668 item->jmp_code = code;
5669 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5671 if (item->has_target_code) {
5672 mips_load_const (code, mips_t9,
5673 item->value.target_code);
5676 mips_lw (code, mips_t9, mips_t7,
5677 (sizeof (gpointer) * item->value.vtable_slot));
5679 mips_jr (code, mips_t9);
5683 mips_load_const (code, mips_temp, (gsize)item->key);
5685 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5687 if (item->has_target_code) {
5688 mips_load_const (code, mips_t9,
5689 item->value.target_code);
5692 mips_load_const (code, mips_at,
5693 & (vtable->vtable [item->value.vtable_slot]));
5694 mips_lw (code, mips_t9, mips_at, 0);
5696 mips_jr (code, mips_t9);
5698 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5699 mips_load_const (code, mips_t9, fail_tramp);
5700 mips_jr (code, mips_t9);
5703 /* enable the commented code to assert on wrong method */
5704 #if ENABLE_WRONG_METHOD_CHECK
5705 ppc_load (code, ppc_r0, (guint32)item->key);
5706 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5708 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5710 mips_lw (code, mips_t9, mips_t7,
5711 (sizeof (gpointer) * item->value.vtable_slot));
5712 mips_jr (code, mips_t9);
5715 #if ENABLE_WRONG_METHOD_CHECK
5716 ppc_patch (patch, code);
5722 mips_load_const (code, mips_temp, (gulong)item->key);
5723 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5725 item->jmp_code = code;
5726 mips_beq (code, mips_temp, mips_zero, 0);
5730 /* patch the branches to get to the target items */
5731 for (i = 0; i < count; ++i) {
5732 MonoIMTCheckItem *item = imt_entries [i];
5733 if (item->jmp_code && item->check_target_idx) {
5734 mips_patch ((guint32 *)item->jmp_code,
5735 (guint32)imt_entries [item->check_target_idx]->code_target);
5740 mono_stats.imt_trampolines_size += code - start;
5741 g_assert (code - start <= size);
5742 mono_arch_flush_icache (start, size);
5744 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5750 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5752 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5756 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5758 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5761 /* Soft Debug support */
5762 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5765 * mono_arch_set_breakpoint:
5767 * See mini-amd64.c for docs.
5770 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5773 guint32 addr = (guint32)bp_trigger_page;
5775 mips_load_const (code, mips_t9, addr);
5776 mips_lw (code, mips_t9, mips_t9, 0);
5778 mono_arch_flush_icache (ip, code - ip);
5782 * mono_arch_clear_breakpoint:
5784 * See mini-amd64.c for docs.
5787 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5795 mono_arch_flush_icache (ip, code - ip);
5799 * mono_arch_start_single_stepping:
5801 * See mini-amd64.c for docs.
5804 mono_arch_start_single_stepping (void)
5806 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5810 * mono_arch_stop_single_stepping:
5812 * See mini-amd64.c for docs.
5815 mono_arch_stop_single_stepping (void)
5817 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5821 * mono_arch_is_single_step_event:
5823 * See mini-amd64.c for docs.
5826 mono_arch_is_single_step_event (void *info, void *sigctx)
5828 siginfo_t* sinfo = (siginfo_t*) info;
5829 /* Sometimes the address is off by 4 */
5830 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5837 * mono_arch_is_breakpoint_event:
5839 * See mini-amd64.c for docs.
5842 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5844 siginfo_t* sinfo = (siginfo_t*) info;
5845 /* Sometimes the address is off by 4 */
5846 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5853 * mono_arch_skip_breakpoint:
5855 * See mini-amd64.c for docs.
5858 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5860 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5864 * mono_arch_skip_single_step:
5866 * See mini-amd64.c for docs.
5869 mono_arch_skip_single_step (MonoContext *ctx)
5871 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5875 * mono_arch_get_seq_point_info:
5877 * See mini-amd64.c for docs.
5880 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5887 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5889 ext->lmf.previous_lmf = prev_lmf;
5890 /* Mark that this is a MonoLMFExt */
5891 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5892 ext->lmf.iregs [mips_sp] = (gssize)ext;
5895 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5898 mono_arch_opcode_supported (int opcode)