3 * MIPS backend for the Mono code generator
6 * Mark Mason (mason@broadcom.com)
8 * Based on mini-ppc.c by
9 * Paolo Molaro (lupus@ximian.com)
10 * Dietmar Maurer (dietmar@ximian.com)
13 * (C) 2003 Ximian, Inc.
17 #include <asm/cachectl.h>
19 #include <mono/metadata/abi-details.h>
20 #include <mono/metadata/appdomain.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/utils/mono-mmap.h>
23 #include <mono/utils/mono-hwcap.h>
25 #include <mono/arch/mips/mips-codegen.h>
27 #include "mini-mips.h"
32 #define SAVE_FP_REGS 0
34 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
36 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
37 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
38 remember to update cpu-mips.md if you change this */
40 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
41 #define mips_call(c,D,v) do { \
42 guint32 _target = (guint32)(v); \
43 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
44 mips_load_const (c, D, _target); \
45 mips_jalr (c, D, mips_ra); \
48 mips_jumpl (c, _target >> 2); \
60 /* This mutex protects architecture specific caches */
61 #define mono_mini_arch_lock() mono_os_mutex_lock (&mini_arch_mutex)
62 #define mono_mini_arch_unlock() mono_os_mutex_unlock (&mini_arch_mutex)
63 static mono_mutex_t mini_arch_mutex;
65 int mono_exc_esp_offset = 0;
67 /* Whenever the host is little-endian */
68 static int little_endian;
69 /* Index of ms word/register */
70 static int ls_word_idx;
71 /* Index of ls word/register */
72 static int ms_word_idx;
73 /* Same for offsets */
74 static int ls_word_offset;
75 static int ms_word_offset;
78 * The code generated for sequence points reads from this location, which is
79 * made read-only when single stepping is enabled.
81 static gpointer ss_trigger_page;
83 /* Enabled breakpoints read from this trigger page */
84 static gpointer bp_trigger_page;
87 #define DEBUG(a) if (cfg->verbose_level > 1) a
93 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
95 code = mips_emit_exc_by_name (code, exc_name); \
96 cfg->bb_exit->max_offset += 16; \
99 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
101 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
102 inst->type = STACK_R8; \
104 inst->inst_p0 = (void*)(addr); \
105 mono_bblock_add_inst (cfg->cbb, inst); \
108 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
109 || ((ins)->opcode == OP_ICOMPARE) \
110 || ((ins)->opcode == OP_LCOMPARE)))
111 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
112 || ((ins)->opcode == OP_ICOMPARE_IMM) \
113 || ((ins)->opcode == OP_LCOMPARE_IMM)))
115 #define INS_REWRITE(ins, op, _s1, _s2) do { \
118 ins->opcode = (op); \
123 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
125 ins->opcode = (op); \
127 ins->inst_imm = (_imm); \
131 typedef struct InstList InstList;
149 guint16 vtsize; /* in param area */
152 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
161 gboolean vtype_retaddr;
170 void patch_lui_addiu(guint32 *ip, guint32 val);
171 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
172 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
173 void mips_adjust_stackframe(MonoCompile *cfg);
174 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
175 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
178 /* Not defined in asm/cachectl.h */
179 int cacheflush(char *addr, int nbytes, int cache);
182 mono_arch_flush_icache (guint8 *code, gint size)
184 /* Linux/MIPS specific */
185 cacheflush ((char*)code, size, BCACHE);
189 mono_arch_flush_register_windows (void)
194 mono_arch_is_inst_imm (gint64 imm)
200 mips_emit_exc_by_name(guint8 *code, const char *name)
203 MonoClass *exc_class;
205 exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", name);
207 mips_load_const (code, mips_a0, exc_class->type_token);
208 addr = mono_get_throw_corlib_exception ();
209 mips_call (code, mips_t9, addr);
215 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
217 if (mips_is_imm16 (v))
218 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
220 #if SIZEOF_REGISTER == 8
222 /* v is not a sign-extended 32-bit value */
223 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
224 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
225 mips_dsll (code, dreg, dreg, 16);
226 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
227 mips_dsll (code, dreg, dreg, 16);
228 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
232 if (((guint32)v) & (1 << 15)) {
233 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
236 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
238 if (((guint32)v) & 0xffff)
239 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
245 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
248 if (cfg->arch.long_branch) {
251 /* Invert test and emit branch around jump */
254 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
258 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
262 mips_bltz (code, ins->sreg1, br_offset);
266 mips_blez (code, ins->sreg1, br_offset);
270 mips_bgtz (code, ins->sreg1, br_offset);
274 mips_bgez (code, ins->sreg1, br_offset);
278 g_assert_not_reached ();
280 mono_add_patch_info (cfg, code - cfg->native_code,
281 MONO_PATCH_INFO_BB, ins->inst_true_bb);
282 mips_lui (code, mips_at, mips_zero, 0);
283 mips_addiu (code, mips_at, mips_at, 0);
284 mips_jr (code, mips_at);
288 mono_add_patch_info (cfg, code - cfg->native_code,
289 MONO_PATCH_INFO_BB, ins->inst_true_bb);
292 mips_beq (code, ins->sreg1, ins->sreg2, 0);
296 mips_bne (code, ins->sreg1, ins->sreg2, 0);
300 mips_bgez (code, ins->sreg1, 0);
304 mips_bgtz (code, ins->sreg1, 0);
308 mips_blez (code, ins->sreg1, 0);
312 mips_bltz (code, ins->sreg1, 0);
316 g_assert_not_reached ();
322 /* XXX - big-endian dependent? */
324 patch_lui_addiu(guint32 *ip, guint32 val)
326 guint16 *__lui_addiu = (guint16*)(void *)(ip);
329 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
330 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
333 if (((guint32)(val)) & (1 << 15))
334 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
336 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
337 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
338 mono_arch_flush_icache ((guint8 *)ip, 8);
343 mips_patch (guint32 *code, guint32 target)
346 guint32 op = ins >> 26;
347 guint32 diff, offset;
349 g_assert (trap_target != target);
350 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
352 case 0x00: /* jr ra */
353 if (ins == 0x3e00008)
355 g_assert_not_reached ();
359 g_assert (!(target & 0x03));
360 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
361 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
363 mono_arch_flush_icache ((guint8 *)code, 4);
365 case 0x01: /* BLTZ */
368 case 0x06: /* BLEZ */
369 case 0x07: /* BGTZ */
370 case 0x11: /* bc1t */
371 diff = target - (guint32)(code + 1);
372 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
373 g_assert (!(diff & 0x03));
374 offset = ((gint32)diff) >> 2;
375 if (((int)offset) != ((int)(short)offset))
376 g_assert (((int)offset) == ((int)(short)offset));
377 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
379 mono_arch_flush_icache ((guint8 *)code, 4);
381 case 0x0f: /* LUI / ADDIU pair */
382 g_assert ((code[1] >> 26) == 0x9);
383 patch_lui_addiu (code, target);
384 mono_arch_flush_icache ((guint8 *)code, 8);
388 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
389 g_assert_not_reached ();
393 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
396 mono_arch_regname (int reg) {
397 #if _MIPS_SIM == _ABIO32
398 static const char * rnames[] = {
399 "zero", "at", "v0", "v1",
400 "a0", "a1", "a2", "a3",
401 "t0", "t1", "t2", "t3",
402 "t4", "t5", "t6", "t7",
403 "s0", "s1", "s2", "s3",
404 "s4", "s5", "s6", "s7",
405 "t8", "t9", "k0", "k1",
406 "gp", "sp", "fp", "ra"
408 #elif _MIPS_SIM == _ABIN32
409 static const char * rnames[] = {
410 "zero", "at", "v0", "v1",
411 "a0", "a1", "a2", "a3",
412 "a4", "a5", "a6", "a7",
413 "t0", "t1", "t2", "t3",
414 "s0", "s1", "s2", "s3",
415 "s4", "s5", "s6", "s7",
416 "t8", "t9", "k0", "k1",
417 "gp", "sp", "fp", "ra"
420 if (reg >= 0 && reg < 32)
426 mono_arch_fregname (int reg) {
427 static const char * rnames[] = {
428 "f0", "f1", "f2", "f3",
429 "f4", "f5", "f6", "f7",
430 "f8", "f9", "f10", "f11",
431 "f12", "f13", "f14", "f15",
432 "f16", "f17", "f18", "f19",
433 "f20", "f21", "f22", "f23",
434 "f24", "f25", "f26", "f27",
435 "f28", "f29", "f30", "f31"
437 if (reg >= 0 && reg < 32)
442 /* this function overwrites at */
444 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
446 /* XXX write a loop, not an unrolled loop */
448 mips_lw (code, mips_at, sreg, soffset);
449 mips_sw (code, mips_at, dreg, doffset);
458 * mono_arch_get_argument_info:
459 * @csig: a method signature
460 * @param_count: the number of parameters to consider
461 * @arg_info: an array to store the result infos
463 * Gathers information on parameters such as size, alignment and
464 * padding. arg_info should be large enought to hold param_count + 1 entries.
466 * Returns the size of the activation frame.
469 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
471 int k, frame_size = 0;
472 guint32 size, align, pad;
475 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
476 frame_size += sizeof (gpointer);
480 arg_info [0].offset = offset;
483 frame_size += sizeof (gpointer);
487 arg_info [0].size = frame_size;
489 for (k = 0; k < param_count; k++) {
490 size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
492 /* ignore alignment for now */
495 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
496 arg_info [k].pad = pad;
498 arg_info [k + 1].pad = 0;
499 arg_info [k + 1].size = size;
501 arg_info [k + 1].offset = offset;
505 align = MONO_ARCH_FRAME_ALIGNMENT;
506 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
507 arg_info [k].pad = pad;
512 /* The delegate object plus 3 params */
513 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
516 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
518 guint8 *code, *start;
521 start = code = mono_global_codeman_reserve (16);
523 /* Replace the this argument with the target */
524 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
525 mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
526 mips_jr (code, mips_temp);
529 g_assert ((code - start) <= 16);
531 mono_arch_flush_icache (start, 16);
535 size = 16 + param_count * 4;
536 start = code = mono_global_codeman_reserve (size);
538 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
539 /* slide down the arguments */
540 for (i = 0; i < param_count; ++i) {
541 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
543 mips_jr (code, mips_temp);
546 g_assert ((code - start) <= size);
548 mono_arch_flush_icache (start, size);
552 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
554 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
555 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
563 * mono_arch_get_delegate_invoke_impls:
565 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
569 mono_arch_get_delegate_invoke_impls (void)
575 get_delegate_invoke_impl (&info, TRUE, 0);
576 res = g_slist_prepend (res, info);
578 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
579 get_delegate_invoke_impl (&info, FALSE, i);
580 res = g_slist_prepend (res, info);
587 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
589 guint8 *code, *start;
591 /* FIXME: Support more cases */
592 if (MONO_TYPE_ISSTRUCT (sig->ret))
596 static guint8* cached = NULL;
597 mono_mini_arch_lock ();
599 mono_mini_arch_unlock ();
604 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
607 start = get_delegate_invoke_impl (&info, TRUE, 0);
608 mono_tramp_info_register (info, NULL);
611 mono_mini_arch_unlock ();
614 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
617 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
619 for (i = 0; i < sig->param_count; ++i)
620 if (!mono_is_regsize_var (sig->params [i]))
623 mono_mini_arch_lock ();
624 code = cache [sig->param_count];
626 mono_mini_arch_unlock ();
631 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
632 start = mono_aot_get_trampoline (name);
636 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
637 mono_tramp_info_register (info, NULL);
639 cache [sig->param_count] = start;
640 mono_mini_arch_unlock ();
648 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
654 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
657 return (gpointer)regs [mips_a0];
661 * Initialize the cpu to execute managed code.
664 mono_arch_cpu_init (void)
666 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
675 ls_word_offset = ls_word_idx * 4;
676 ms_word_offset = ms_word_idx * 4;
680 * Initialize architecture specific code.
683 mono_arch_init (void)
685 mono_os_mutex_init_recursive (&mini_arch_mutex);
687 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
688 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT, MONO_MEM_ACCOUNT_OTHER);
689 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
693 * Cleanup architecture specific code.
696 mono_arch_cleanup (void)
698 mono_os_mutex_destroy (&mini_arch_mutex);
702 mono_arch_have_fast_tls (void)
708 * This function returns the optimizations supported on this cpu.
711 mono_arch_cpu_optimizations (guint32 *exclude_mask)
715 /* no mips-specific optimizations yet */
721 * This function test for all SIMD functions supported.
723 * Returns a bitmask corresponding to all supported versions.
727 mono_arch_cpu_enumerate_simd_versions (void)
729 /* SIMD is currently unimplemented */
734 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
739 for (i = 0; i < cfg->num_varinfo; i++) {
740 MonoInst *ins = cfg->varinfo [i];
741 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
744 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
747 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
750 /* we can only allocate 32 bit values */
751 if (mono_is_regsize_var (ins->inst_vtype)) {
752 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
753 g_assert (i == vmv->idx);
754 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
762 mono_arch_get_global_int_regs (MonoCompile *cfg)
766 regs = g_list_prepend (regs, (gpointer)mips_s0);
767 regs = g_list_prepend (regs, (gpointer)mips_s1);
768 regs = g_list_prepend (regs, (gpointer)mips_s2);
769 regs = g_list_prepend (regs, (gpointer)mips_s3);
770 regs = g_list_prepend (regs, (gpointer)mips_s4);
771 //regs = g_list_prepend (regs, (gpointer)mips_s5);
772 regs = g_list_prepend (regs, (gpointer)mips_s6);
773 regs = g_list_prepend (regs, (gpointer)mips_s7);
779 * mono_arch_regalloc_cost:
781 * Return the cost, in number of memory references, of the action of
782 * allocating the variable VMV into a register during global register
786 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
793 args_onto_stack (CallInfo *info)
795 g_assert (!info->on_stack);
796 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
797 info->on_stack = TRUE;
798 info->stack_size = MIPS_STACK_PARAM_OFFSET;
801 #if _MIPS_SIM == _ABIO32
803 * O32 calling convention version
807 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
808 /* First, see if we need to drop onto the stack */
809 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
810 args_onto_stack (info);
812 /* Now, place the argument */
813 if (info->on_stack) {
814 ainfo->storage = ArgOnStack;
815 ainfo->reg = mips_sp; /* in the caller */
816 ainfo->offset = info->stack_size;
819 ainfo->storage = ArgInIReg;
820 ainfo->reg = info->gr;
822 info->gr_passed = TRUE;
824 info->stack_size += 4;
828 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
829 /* First, see if we need to drop onto the stack */
830 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
831 args_onto_stack (info);
833 /* Now, place the argument */
834 if (info->on_stack) {
835 g_assert (info->stack_size % 4 == 0);
836 info->stack_size += (info->stack_size % 8);
838 ainfo->storage = ArgOnStack;
839 ainfo->reg = mips_sp; /* in the caller */
840 ainfo->offset = info->stack_size;
843 // info->gr must be a0 or a2
844 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
845 g_assert(info->gr <= MIPS_LAST_ARG_REG);
847 ainfo->storage = ArgInIReg;
848 ainfo->reg = info->gr;
850 info->gr_passed = TRUE;
852 info->stack_size += 8;
856 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
857 /* First, see if we need to drop onto the stack */
858 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
859 args_onto_stack (info);
861 /* Now, place the argument */
862 if (info->on_stack) {
863 ainfo->storage = ArgOnStack;
864 ainfo->reg = mips_sp; /* in the caller */
865 ainfo->offset = info->stack_size;
868 /* Only use FP regs for args if no int args passed yet */
869 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
870 ainfo->storage = ArgInFReg;
871 ainfo->reg = info->fr;
872 /* Even though it's a single-precision float, it takes up two FP regs */
874 /* FP and GP slots do not overlap */
878 /* Passing single-precision float arg in a GP register
879 * such as: func (0, 1.0, 2, 3);
880 * In this case, only one 'gr' register is consumed.
882 ainfo->storage = ArgInIReg;
883 ainfo->reg = info->gr;
886 info->gr_passed = TRUE;
889 info->stack_size += 4;
893 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
894 /* First, see if we need to drop onto the stack */
895 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
896 args_onto_stack (info);
898 /* Now, place the argument */
899 if (info->on_stack) {
900 g_assert(info->stack_size % 4 == 0);
901 info->stack_size += (info->stack_size % 8);
903 ainfo->storage = ArgOnStack;
904 ainfo->reg = mips_sp; /* in the caller */
905 ainfo->offset = info->stack_size;
908 /* Only use FP regs for args if no int args passed yet */
909 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
910 ainfo->storage = ArgInFReg;
911 ainfo->reg = info->fr;
913 /* FP and GP slots do not overlap */
917 // info->gr must be a0 or a2
918 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
919 g_assert(info->gr <= MIPS_LAST_ARG_REG);
921 ainfo->storage = ArgInIReg;
922 ainfo->reg = info->gr;
924 info->gr_passed = TRUE;
927 info->stack_size += 8;
929 #elif _MIPS_SIM == _ABIN32
931 * N32 calling convention version
935 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
936 /* First, see if we need to drop onto the stack */
937 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
938 args_onto_stack (info);
940 /* Now, place the argument */
941 if (info->on_stack) {
942 ainfo->storage = ArgOnStack;
943 ainfo->reg = mips_sp; /* in the caller */
944 ainfo->offset = info->stack_size;
945 info->stack_size += SIZEOF_REGISTER;
948 ainfo->storage = ArgInIReg;
949 ainfo->reg = info->gr;
951 info->gr_passed = TRUE;
956 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
957 /* First, see if we need to drop onto the stack */
958 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
959 args_onto_stack (info);
961 /* Now, place the argument */
962 if (info->on_stack) {
963 g_assert (info->stack_size % 4 == 0);
964 info->stack_size += (info->stack_size % 8);
966 ainfo->storage = ArgOnStack;
967 ainfo->reg = mips_sp; /* in the caller */
968 ainfo->offset = info->stack_size;
969 info->stack_size += SIZEOF_REGISTER;
972 g_assert (info->gr <= MIPS_LAST_ARG_REG);
974 ainfo->storage = ArgInIReg;
975 ainfo->reg = info->gr;
977 info->gr_passed = TRUE;
982 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
983 /* First, see if we need to drop onto the stack */
984 if (!info->on_stack) {
985 if (info->gr > MIPS_LAST_ARG_REG)
986 args_onto_stack (info);
987 else if (info->fr > MIPS_LAST_FPARG_REG)
988 args_onto_stack (info);
991 /* Now, place the argument */
992 if (info->on_stack) {
993 ainfo->storage = ArgOnStack;
994 ainfo->reg = mips_sp; /* in the caller */
995 ainfo->offset = info->stack_size;
996 info->stack_size += FREG_SIZE;
999 ainfo->storage = ArgInFReg;
1000 ainfo->reg = info->fr;
1002 /* FP and GP slots do not overlap */
1008 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1009 /* First, see if we need to drop onto the stack */
1010 if (!info->on_stack) {
1011 if (info->gr > MIPS_LAST_ARG_REG)
1012 args_onto_stack (info);
1013 else if (info->fr > MIPS_LAST_FPARG_REG)
1014 args_onto_stack (info);
1017 /* Now, place the argument */
1018 if (info->on_stack) {
1019 g_assert(info->stack_size % 4 == 0);
1020 info->stack_size += (info->stack_size % 8);
1022 ainfo->storage = ArgOnStack;
1023 ainfo->reg = mips_sp; /* in the caller */
1024 ainfo->offset = info->stack_size;
1025 info->stack_size += FREG_SIZE;
1028 ainfo->storage = ArgInFReg;
1029 ainfo->reg = info->fr;
1031 /* FP and GP slots do not overlap */
1038 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1041 int n = sig->hasthis + sig->param_count;
1043 MonoType* simpletype;
1045 gboolean is_pinvoke = sig->pinvoke;
1048 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1050 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1052 cinfo->fr = MIPS_FIRST_FPARG_REG;
1053 cinfo->gr = MIPS_FIRST_ARG_REG;
1054 cinfo->stack_size = 0;
1056 DEBUG(printf("calculate_sizes\n"));
1058 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1062 /* handle returning a struct */
1063 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1064 cinfo->struct_ret = cinfo->gr;
1065 add_int32_arg (cinfo, &cinfo->ret);
1069 add_int32_arg (cinfo, cinfo->args + n);
1074 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1075 * the first argument, allowing 'this' to be always passed in the first arg reg.
1076 * Also do this if the first argument is a reference type, since virtual calls
1077 * are sometimes made using calli without sig->hasthis set, like in the delegate
1080 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1082 add_int32_arg (cinfo, cinfo->args + n);
1085 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1089 add_int32_arg (cinfo, &cinfo->ret);
1090 cinfo->struct_ret = cinfo->ret.reg;
1094 add_int32_arg (cinfo, cinfo->args + n);
1098 if (cinfo->vtype_retaddr) {
1099 add_int32_arg (cinfo, &cinfo->ret);
1100 cinfo->struct_ret = cinfo->ret.reg;
1105 DEBUG(printf("params: %d\n", sig->param_count));
1106 for (i = pstart; i < sig->param_count; ++i) {
1107 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1108 /* Prevent implicit arguments and sig_cookie from
1109 being passed in registers */
1110 args_onto_stack (cinfo);
1111 /* Emit the signature cookie just before the implicit arguments */
1112 add_int32_arg (cinfo, &cinfo->sig_cookie);
1114 DEBUG(printf("param %d: ", i));
1115 simpletype = mini_get_underlying_type (sig->params [i]);
1116 switch (simpletype->type) {
1117 case MONO_TYPE_BOOLEAN:
1120 DEBUG(printf("1 byte\n"));
1121 cinfo->args [n].size = 1;
1122 add_int32_arg (cinfo, &cinfo->args[n]);
1125 case MONO_TYPE_CHAR:
1128 DEBUG(printf("2 bytes\n"));
1129 cinfo->args [n].size = 2;
1130 add_int32_arg (cinfo, &cinfo->args[n]);
1135 DEBUG(printf("4 bytes\n"));
1136 cinfo->args [n].size = 4;
1137 add_int32_arg (cinfo, &cinfo->args[n]);
1143 case MONO_TYPE_FNPTR:
1144 case MONO_TYPE_CLASS:
1145 case MONO_TYPE_OBJECT:
1146 case MONO_TYPE_STRING:
1147 case MONO_TYPE_SZARRAY:
1148 case MONO_TYPE_ARRAY:
1149 cinfo->args [n].size = sizeof (gpointer);
1150 add_int32_arg (cinfo, &cinfo->args[n]);
1153 case MONO_TYPE_GENERICINST:
1154 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1155 cinfo->args [n].size = sizeof (gpointer);
1156 add_int32_arg (cinfo, &cinfo->args[n]);
1161 case MONO_TYPE_TYPEDBYREF:
1162 case MONO_TYPE_VALUETYPE: {
1165 int has_offset = FALSE;
1167 gint size, alignment;
1170 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1171 size = sizeof (MonoTypedRef);
1172 alignment = sizeof (gpointer);
1174 klass = mono_class_from_mono_type (sig->params [i]);
1176 size = mono_class_native_size (klass, NULL);
1178 size = mono_class_value_size (klass, NULL);
1179 alignment = mono_class_min_align (klass);
1181 #if MIPS_PASS_STRUCTS_BY_VALUE
1182 /* Need to do alignment if struct contains long or double */
1183 if (alignment > 4) {
1184 /* Drop onto stack *before* looking at
1185 stack_size, if required. */
1186 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1187 args_onto_stack (cinfo);
1188 if (cinfo->stack_size & (alignment - 1)) {
1189 add_int32_arg (cinfo, &dummy_arg);
1191 g_assert (!(cinfo->stack_size & (alignment - 1)));
1195 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1196 mono_class_native_size (sig->params [i]->data.klass, NULL),
1197 cinfo->stack_size, alignment);
1199 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1200 g_assert (cinfo->args [n].size == 0);
1201 g_assert (cinfo->args [n].vtsize == 0);
1202 for (j = 0; j < nwords; ++j) {
1204 add_int32_arg (cinfo, &cinfo->args [n]);
1205 if (cinfo->on_stack)
1208 add_int32_arg (cinfo, &dummy_arg);
1209 if (!has_offset && cinfo->on_stack) {
1210 cinfo->args [n].offset = dummy_arg.offset;
1214 if (cinfo->on_stack)
1215 cinfo->args [n].vtsize += 1;
1217 cinfo->args [n].size += 1;
1219 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1220 cinfo->args [n].storage = ArgStructByVal;
1222 add_int32_arg (cinfo, &cinfo->args[n]);
1223 cinfo->args [n].storage = ArgStructByAddr;
1230 DEBUG(printf("8 bytes\n"));
1231 cinfo->args [n].size = 8;
1232 add_int64_arg (cinfo, &cinfo->args[n]);
1236 DEBUG(printf("R4\n"));
1237 cinfo->args [n].size = 4;
1238 add_float32_arg (cinfo, &cinfo->args[n]);
1242 DEBUG(printf("R8\n"));
1243 cinfo->args [n].size = 8;
1244 add_float64_arg (cinfo, &cinfo->args[n]);
1248 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1252 /* Handle the case where there are no implicit arguments */
1253 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1254 /* Prevent implicit arguments and sig_cookie from
1255 being passed in registers */
1256 args_onto_stack (cinfo);
1257 /* Emit the signature cookie just before the implicit arguments */
1258 add_int32_arg (cinfo, &cinfo->sig_cookie);
1262 simpletype = mini_get_underlying_type (sig->ret);
1263 switch (simpletype->type) {
1264 case MONO_TYPE_BOOLEAN:
1269 case MONO_TYPE_CHAR:
1275 case MONO_TYPE_FNPTR:
1276 case MONO_TYPE_CLASS:
1277 case MONO_TYPE_OBJECT:
1278 case MONO_TYPE_SZARRAY:
1279 case MONO_TYPE_ARRAY:
1280 case MONO_TYPE_STRING:
1281 cinfo->ret.reg = mips_v0;
1285 cinfo->ret.reg = mips_v0;
1289 cinfo->ret.reg = mips_f0;
1290 cinfo->ret.storage = ArgInFReg;
1292 case MONO_TYPE_GENERICINST:
1293 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1294 cinfo->ret.reg = mips_v0;
1298 case MONO_TYPE_VALUETYPE:
1299 case MONO_TYPE_TYPEDBYREF:
1301 case MONO_TYPE_VOID:
1304 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1308 /* align stack size to 16 */
1309 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1311 cinfo->stack_usage = cinfo->stack_size;
1316 debug_omit_fp (void)
1319 return mono_debug_count ();
1326 * mono_arch_compute_omit_fp:
1327 * Determine whether the frame pointer can be eliminated.
1330 mono_arch_compute_omit_fp (MonoCompile *cfg)
1332 MonoMethodSignature *sig;
1333 MonoMethodHeader *header;
1337 if (cfg->arch.omit_fp_computed)
1340 header = cfg->header;
1342 sig = mono_method_signature (cfg->method);
1344 if (!cfg->arch.cinfo)
1345 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1346 cinfo = cfg->arch.cinfo;
1349 * FIXME: Remove some of the restrictions.
1351 cfg->arch.omit_fp = TRUE;
1352 cfg->arch.omit_fp_computed = TRUE;
1354 if (cfg->disable_omit_fp)
1355 cfg->arch.omit_fp = FALSE;
1356 if (!debug_omit_fp ())
1357 cfg->arch.omit_fp = FALSE;
1358 if (cfg->method->save_lmf)
1359 cfg->arch.omit_fp = FALSE;
1360 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1361 cfg->arch.omit_fp = FALSE;
1362 if (header->num_clauses)
1363 cfg->arch.omit_fp = FALSE;
1364 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1365 cfg->arch.omit_fp = FALSE;
1366 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1367 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1368 cfg->arch.omit_fp = FALSE;
1370 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1371 * there are stack arguments.
1374 if (cinfo->stack_usage)
1375 cfg->arch.omit_fp = FALSE;
1379 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1380 MonoInst *ins = cfg->varinfo [i];
1383 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1386 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1390 * Set var information according to the calling convention. mips version.
1391 * The locals var stuff should most likely be split in another method.
1394 mono_arch_allocate_vars (MonoCompile *cfg)
1396 MonoMethodSignature *sig;
1397 MonoMethodHeader *header;
1399 int i, offset, size, align, curinst;
1400 int frame_reg = mips_sp;
1401 guint32 iregs_to_save = 0;
1403 guint32 fregs_to_restore;
1407 sig = mono_method_signature (cfg->method);
1409 if (!cfg->arch.cinfo)
1410 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1411 cinfo = cfg->arch.cinfo;
1413 mono_arch_compute_omit_fp (cfg);
1415 /* spill down, we'll fix it in a separate pass */
1416 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1418 /* allow room for the vararg method args: void* and long/double */
1419 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1420 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1422 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1423 * call convs needs to be handled this way.
1425 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1426 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1428 /* gtk-sharp and other broken code will dllimport vararg functions even with
1429 * non-varargs signatures. Since there is little hope people will get this right
1430 * we assume they won't.
1432 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1433 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1435 /* a0-a3 always present */
1436 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1438 header = cfg->header;
1440 if (cfg->arch.omit_fp)
1441 frame_reg = mips_sp;
1443 frame_reg = mips_fp;
1444 cfg->frame_reg = frame_reg;
1445 if (frame_reg != mips_sp) {
1446 cfg->used_int_regs |= 1 << frame_reg;
1451 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1452 /* FIXME: handle long and FP values */
1453 switch (mini_get_underlying_type (sig->ret)->type) {
1454 case MONO_TYPE_VOID:
1458 cfg->ret->opcode = OP_REGVAR;
1459 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1462 cfg->ret->opcode = OP_REGVAR;
1463 cfg->ret->inst_c0 = mips_v0;
1467 /* Space for outgoing parameters, including a0-a3 */
1468 offset += cfg->param_area;
1470 /* allow room to save the return value (if it's a struct) */
1471 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1474 /* Now handle the local variables */
1476 curinst = cfg->locals_start;
1477 for (i = curinst; i < cfg->num_varinfo; ++i) {
1478 inst = cfg->varinfo [i];
1479 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1482 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1483 * pinvoke wrappers when they call functions returning structure
1485 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1486 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1488 size = mono_type_size (inst->inst_vtype, &align);
1490 offset += align - 1;
1491 offset &= ~(align - 1);
1492 inst->inst_offset = offset;
1493 inst->opcode = OP_REGOFFSET;
1494 inst->inst_basereg = frame_reg;
1496 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1499 /* Space for LMF (if needed) */
1500 if (cfg->method->save_lmf) {
1501 /* align the offset to 16 bytes */
1502 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1503 cfg->arch.lmf_offset = offset;
1504 offset += sizeof (MonoLMF);
1507 if (sig->call_convention == MONO_CALL_VARARG) {
1511 /* Allocate a local slot to hold the sig cookie address */
1512 offset += align - 1;
1513 offset &= ~(align - 1);
1514 cfg->sig_cookie = offset;
1518 offset += SIZEOF_REGISTER - 1;
1519 offset &= ~(SIZEOF_REGISTER - 1);
1521 /* Space for saved registers */
1522 cfg->arch.iregs_offset = offset;
1523 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1524 if (iregs_to_save) {
1525 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1526 if (iregs_to_save & (1 << i)) {
1527 offset += SIZEOF_REGISTER;
1532 /* saved float registers */
1534 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1535 if (fregs_to_restore) {
1536 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1537 if (fregs_to_restore & (1 << i)) {
1538 offset += sizeof(double);
1544 #if _MIPS_SIM == _ABIO32
1545 /* Now add space for saving the ra */
1546 offset += SIZEOF_VOID_P;
1549 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1550 cfg->stack_offset = offset;
1551 cfg->arch.local_alloc_offset = cfg->stack_offset;
1555 * Now allocate stack slots for the int arg regs (a0 - a3)
1556 * On MIPS o32, these are just above the incoming stack pointer
1557 * Even if the arg has been assigned to a regvar, it gets a stack slot
1560 /* Return struct-by-value results in a hidden first argument */
1561 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1562 cfg->vret_addr->opcode = OP_REGOFFSET;
1563 cfg->vret_addr->inst_c0 = mips_a0;
1564 cfg->vret_addr->inst_offset = offset;
1565 cfg->vret_addr->inst_basereg = frame_reg;
1566 offset += SIZEOF_REGISTER;
1569 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1570 inst = cfg->args [i];
1571 if (inst->opcode != OP_REGVAR) {
1574 if (sig->hasthis && (i == 0))
1575 arg_type = &mono_defaults.object_class->byval_arg;
1577 arg_type = sig->params [i - sig->hasthis];
1579 inst->opcode = OP_REGOFFSET;
1580 size = mono_type_size (arg_type, &align);
1582 if (size < SIZEOF_REGISTER) {
1583 size = SIZEOF_REGISTER;
1584 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);
1594 #if _MIPS_SIM == _ABIO32
1595 /* o32: Even a0-a3 get stack slots */
1596 size = SIZEOF_REGISTER;
1597 align = SIZEOF_REGISTER;
1598 inst->inst_basereg = frame_reg;
1599 offset = (offset + align - 1) & ~(align - 1);
1600 inst->inst_offset = offset;
1602 if (cfg->verbose_level > 1)
1603 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1607 #if _MIPS_SIM == _ABIN32
1608 /* Now add space for saving the ra */
1609 offset += SIZEOF_VOID_P;
1612 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1613 cfg->stack_offset = offset;
1614 cfg->arch.local_alloc_offset = cfg->stack_offset;
1619 mono_arch_create_vars (MonoCompile *cfg)
1621 MonoMethodSignature *sig;
1623 sig = mono_method_signature (cfg->method);
1625 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1626 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1627 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1628 printf ("vret_addr = ");
1629 mono_print_ins (cfg->vret_addr);
1634 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1635 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1639 * take the arguments and generate the arch-specific
1640 * instructions to properly call the function in call.
1641 * This includes pushing, moving arguments to the right register
1643 * Issue: who does the spilling if needed, and when?
1646 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1648 MonoMethodSignature *tmp_sig;
1651 if (call->tail_call)
1654 /* FIXME: Add support for signature tokens to AOT */
1655 cfg->disable_aot = TRUE;
1658 * mono_ArgIterator_Setup assumes the signature cookie is
1659 * passed first and all the arguments which were before it are
1660 * passed on the stack after the signature. So compensate by
1661 * passing a different signature.
1663 tmp_sig = mono_metadata_signature_dup (call->signature);
1664 tmp_sig->param_count -= call->signature->sentinelpos;
1665 tmp_sig->sentinelpos = 0;
1666 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1668 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1669 sig_arg->dreg = mono_alloc_ireg (cfg);
1670 sig_arg->inst_p0 = tmp_sig;
1671 MONO_ADD_INS (cfg->cbb, sig_arg);
1673 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1677 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1680 MonoMethodSignature *sig;
1685 sig = call->signature;
1686 n = sig->param_count + sig->hasthis;
1688 cinfo = get_call_info (cfg->mempool, sig);
1689 if (cinfo->struct_ret)
1690 call->used_iregs |= 1 << cinfo->struct_ret;
1692 for (i = 0; i < n; ++i) {
1693 ArgInfo *ainfo = cinfo->args + i;
1696 if (i >= sig->hasthis)
1697 t = sig->params [i - sig->hasthis];
1699 t = &mono_defaults.int_class->byval_arg;
1700 t = mini_get_underlying_type (t);
1702 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1703 /* Emit the signature cookie just before the implicit arguments */
1704 emit_sig_cookie (cfg, call, cinfo);
1707 if (is_virtual && i == 0) {
1708 /* the argument will be attached to the call instrucion */
1709 in = call->args [i];
1710 call->used_iregs |= 1 << ainfo->reg;
1713 in = call->args [i];
1714 if (ainfo->storage == ArgInIReg) {
1715 #if SIZEOF_REGISTER == 4
1716 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1717 MONO_INST_NEW (cfg, ins, OP_MOVE);
1718 ins->dreg = mono_alloc_ireg (cfg);
1719 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1720 MONO_ADD_INS (cfg->cbb, ins);
1721 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1723 MONO_INST_NEW (cfg, ins, OP_MOVE);
1724 ins->dreg = mono_alloc_ireg (cfg);
1725 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1726 MONO_ADD_INS (cfg->cbb, ins);
1727 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1730 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1733 #if PROMOTE_R4_TO_R8
1734 /* ??? - convert to single first? */
1735 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1736 ins->dreg = mono_alloc_freg (cfg);
1737 ins->sreg1 = in->dreg;
1738 MONO_ADD_INS (cfg->cbb, ins);
1743 /* trying to load float value into int registers */
1744 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1745 ins->dreg = mono_alloc_ireg (cfg);
1747 MONO_ADD_INS (cfg->cbb, ins);
1748 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1749 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1750 /* trying to load float value into int registers */
1751 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1752 ins->dreg = mono_alloc_ireg (cfg);
1753 ins->sreg1 = in->dreg;
1754 MONO_ADD_INS (cfg->cbb, ins);
1755 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1757 MONO_INST_NEW (cfg, ins, OP_MOVE);
1758 ins->dreg = mono_alloc_ireg (cfg);
1759 ins->sreg1 = in->dreg;
1760 MONO_ADD_INS (cfg->cbb, ins);
1761 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1763 } else if (ainfo->storage == ArgStructByAddr) {
1764 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1765 ins->opcode = OP_OUTARG_VT;
1766 ins->sreg1 = in->dreg;
1767 ins->klass = in->klass;
1768 ins->inst_p0 = call;
1769 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1770 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1771 MONO_ADD_INS (cfg->cbb, ins);
1772 } else if (ainfo->storage == ArgStructByVal) {
1773 /* this is further handled in mono_arch_emit_outarg_vt () */
1774 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1775 ins->opcode = OP_OUTARG_VT;
1776 ins->sreg1 = in->dreg;
1777 ins->klass = in->klass;
1778 ins->inst_p0 = call;
1779 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1780 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1781 MONO_ADD_INS (cfg->cbb, ins);
1782 } else if (ainfo->storage == ArgOnStack) {
1783 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1784 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1785 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1786 if (t->type == MONO_TYPE_R8)
1787 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1789 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1791 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1793 } else if (ainfo->storage == ArgInFReg) {
1794 if (t->type == MONO_TYPE_VALUETYPE) {
1795 /* this is further handled in mono_arch_emit_outarg_vt () */
1796 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1797 ins->opcode = OP_OUTARG_VT;
1798 ins->sreg1 = in->dreg;
1799 ins->klass = in->klass;
1800 ins->inst_p0 = call;
1801 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1802 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1803 MONO_ADD_INS (cfg->cbb, ins);
1805 cfg->flags |= MONO_CFG_HAS_FPOUT;
1807 int dreg = mono_alloc_freg (cfg);
1809 if (ainfo->size == 4) {
1810 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1812 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1814 ins->sreg1 = in->dreg;
1815 MONO_ADD_INS (cfg->cbb, ins);
1818 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1819 cfg->flags |= MONO_CFG_HAS_FPOUT;
1822 g_assert_not_reached ();
1826 /* Handle the case where there are no implicit arguments */
1827 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1828 emit_sig_cookie (cfg, call, cinfo);
1830 if (cinfo->struct_ret) {
1833 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1834 vtarg->sreg1 = call->vret_var->dreg;
1835 vtarg->dreg = mono_alloc_preg (cfg);
1836 MONO_ADD_INS (cfg->cbb, vtarg);
1838 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1842 * Reverse the call->out_args list.
1845 MonoInst *prev = NULL, *list = call->out_args, *next;
1852 call->out_args = prev;
1855 call->stack_usage = cinfo->stack_usage;
1856 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1857 #if _MIPS_SIM == _ABIO32
1858 /* a0-a3 always present */
1859 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1861 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1862 cfg->flags |= MONO_CFG_HAS_CALLS;
1864 * should set more info in call, such as the stack space
1865 * used by the args that needs to be added back to esp
1870 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1872 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1873 ArgInfo *ainfo = ins->inst_p1;
1874 int ovf_size = ainfo->vtsize;
1875 int doffset = ainfo->offset;
1876 int i, soffset, dreg;
1878 if (ainfo->storage == ArgStructByVal) {
1880 if (cfg->verbose_level > 0) {
1881 char* nm = mono_method_full_name (cfg->method, TRUE);
1882 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1883 nm, doffset, ainfo->size, ovf_size);
1889 for (i = 0; i < ainfo->size; ++i) {
1890 dreg = mono_alloc_ireg (cfg);
1891 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1892 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1893 soffset += SIZEOF_REGISTER;
1895 if (ovf_size != 0) {
1896 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1898 } else if (ainfo->storage == ArgInFReg) {
1899 int tmpr = mono_alloc_freg (cfg);
1901 if (ainfo->size == 4)
1902 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1904 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1905 dreg = mono_alloc_freg (cfg);
1906 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1907 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1909 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1913 /* FIXME: alignment? */
1914 if (call->signature->pinvoke) {
1915 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1916 vtcopy->backend.is_pinvoke = 1;
1918 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1921 g_assert (ovf_size > 0);
1923 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1924 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1927 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1929 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1934 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1936 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1939 #if (SIZEOF_REGISTER == 4)
1940 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1943 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1944 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1945 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1946 MONO_ADD_INS (cfg->cbb, ins);
1950 if (ret->type == MONO_TYPE_R8) {
1951 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1954 if (ret->type == MONO_TYPE_R4) {
1955 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1959 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1963 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1965 MonoInst *ins, *n, *last_ins = NULL;
1967 if (cfg->verbose_level > 2)
1968 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1971 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1972 if (cfg->verbose_level > 2)
1973 mono_print_ins_index (0, ins);
1975 switch (ins->opcode) {
1977 case OP_LOAD_MEMBASE:
1978 case OP_LOADI4_MEMBASE:
1980 * OP_IADD reg2, reg1, const1
1981 * OP_LOAD_MEMBASE const2(reg2), reg3
1983 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1985 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)){
1986 int const1 = last_ins->inst_imm;
1987 int const2 = ins->inst_offset;
1989 if (mips_is_imm16 (const1 + const2)) {
1990 ins->inst_basereg = last_ins->sreg1;
1991 ins->inst_offset = const1 + const2;
2001 bb->last_ins = last_ins;
2005 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2007 MonoInst *ins, *n, *last_ins = NULL;
2010 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2011 MonoInst *last_ins = ins->prev;
2013 switch (ins->opcode) {
2015 /* remove unnecessary multiplication with 1 */
2016 if (ins->inst_imm == 1) {
2017 if (ins->dreg != ins->sreg1) {
2018 ins->opcode = OP_MOVE;
2020 MONO_DELETE_INS (bb, ins);
2024 int power2 = mono_is_power_of_two (ins->inst_imm);
2026 ins->opcode = OP_SHL_IMM;
2027 ins->inst_imm = power2;
2031 case OP_LOAD_MEMBASE:
2032 case OP_LOADI4_MEMBASE:
2034 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2035 * OP_LOAD_MEMBASE offset(basereg), reg
2037 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2038 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2039 ins->inst_basereg == last_ins->inst_destbasereg &&
2040 ins->inst_offset == last_ins->inst_offset) {
2041 if (ins->dreg == last_ins->sreg1) {
2042 MONO_DELETE_INS (bb, ins);
2045 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2046 ins->opcode = OP_MOVE;
2047 ins->sreg1 = last_ins->sreg1;
2052 * Note: reg1 must be different from the basereg in the second load
2053 * OP_LOAD_MEMBASE offset(basereg), reg1
2054 * OP_LOAD_MEMBASE offset(basereg), reg2
2056 * OP_LOAD_MEMBASE offset(basereg), reg1
2057 * OP_MOVE reg1, reg2
2059 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2060 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2061 ins->inst_basereg != last_ins->dreg &&
2062 ins->inst_basereg == last_ins->inst_basereg &&
2063 ins->inst_offset == last_ins->inst_offset) {
2065 if (ins->dreg == last_ins->dreg) {
2066 MONO_DELETE_INS (bb, ins);
2069 ins->opcode = OP_MOVE;
2070 ins->sreg1 = last_ins->dreg;
2073 //g_assert_not_reached ();
2078 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2079 * OP_LOAD_MEMBASE offset(basereg), reg
2081 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2082 * OP_ICONST reg, imm
2084 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2085 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2086 ins->inst_basereg == last_ins->inst_destbasereg &&
2087 ins->inst_offset == last_ins->inst_offset) {
2088 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2089 ins->opcode = OP_ICONST;
2090 ins->inst_c0 = last_ins->inst_imm;
2091 g_assert_not_reached (); // check this rule
2096 case OP_LOADU1_MEMBASE:
2097 case OP_LOADI1_MEMBASE:
2098 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2099 ins->inst_basereg == last_ins->inst_destbasereg &&
2100 ins->inst_offset == last_ins->inst_offset) {
2101 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2102 ins->sreg1 = last_ins->sreg1;
2105 case OP_LOADU2_MEMBASE:
2106 case OP_LOADI2_MEMBASE:
2107 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2108 ins->inst_basereg == last_ins->inst_destbasereg &&
2109 ins->inst_offset == last_ins->inst_offset) {
2110 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2111 ins->sreg1 = last_ins->sreg1;
2114 case OP_ICONV_TO_I4:
2115 case OP_ICONV_TO_U4:
2117 ins->opcode = OP_MOVE;
2121 if (ins->dreg == ins->sreg1) {
2122 MONO_DELETE_INS (bb, ins);
2126 * OP_MOVE sreg, dreg
2127 * OP_MOVE dreg, sreg
2129 if (last_ins && last_ins->opcode == OP_MOVE &&
2130 ins->sreg1 == last_ins->dreg &&
2131 ins->dreg == last_ins->sreg1) {
2132 MONO_DELETE_INS (bb, ins);
2140 bb->last_ins = last_ins;
2144 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2152 switch (ins->opcode) {
2154 tmp1 = mono_alloc_ireg (cfg);
2155 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2156 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2157 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2158 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2163 tmp1 = mono_alloc_ireg (cfg);
2164 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2165 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2166 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2167 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2172 tmp1 = mono_alloc_ireg (cfg);
2173 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2174 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2175 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2176 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2181 tmp1 = mono_alloc_ireg (cfg);
2182 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2183 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2184 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2185 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2190 tmp1 = mono_alloc_ireg (cfg);
2191 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2193 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2194 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2199 tmp1 = mono_alloc_ireg (cfg);
2200 tmp2 = mono_alloc_ireg (cfg);
2201 tmp3 = mono_alloc_ireg (cfg);
2202 tmp4 = mono_alloc_ireg (cfg);
2203 tmp5 = mono_alloc_ireg (cfg);
2205 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2207 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2208 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2210 /* add the high 32-bits, and add in the carry from the low 32-bits */
2211 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2212 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2214 /* Overflow happens if
2215 * neg + neg = pos or
2217 * XOR of the high bits returns 0 if the signs match
2218 * XOR of that with the high bit of the result return 1 if overflow.
2221 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2222 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2224 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2225 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2226 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2228 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2229 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2230 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2232 /* Now, if (tmp4 == 0) then overflow */
2233 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2237 case OP_LADD_OVF_UN:
2238 tmp1 = mono_alloc_ireg (cfg);
2239 tmp2 = mono_alloc_ireg (cfg);
2241 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2242 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2243 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2244 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2245 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2246 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2251 tmp1 = mono_alloc_ireg (cfg);
2252 tmp2 = mono_alloc_ireg (cfg);
2253 tmp3 = mono_alloc_ireg (cfg);
2254 tmp4 = mono_alloc_ireg (cfg);
2255 tmp5 = mono_alloc_ireg (cfg);
2257 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2259 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2260 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2261 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2263 /* Overflow happens if
2264 * neg - pos = pos or
2266 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2268 * tmp1 = (lhs ^ rhs)
2269 * tmp2 = (lhs ^ result)
2270 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2273 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2274 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2275 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2276 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2278 /* Now, if (tmp4 == 1) then overflow */
2279 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2283 case OP_LSUB_OVF_UN:
2284 tmp1 = mono_alloc_ireg (cfg);
2285 tmp2 = mono_alloc_ireg (cfg);
2287 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2288 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2289 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2290 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2292 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2293 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2296 case OP_LCONV_TO_OVF_I4_2:
2297 tmp1 = mono_alloc_ireg (cfg);
2299 /* Overflows if reg2 != sign extension of reg1 */
2300 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2301 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2302 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2311 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2319 switch (ins->opcode) {
2321 tmp1 = mono_alloc_ireg (cfg);
2322 tmp2 = mono_alloc_ireg (cfg);
2323 tmp3 = mono_alloc_ireg (cfg);
2324 tmp4 = mono_alloc_ireg (cfg);
2325 tmp5 = mono_alloc_ireg (cfg);
2327 /* add the operands */
2329 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2331 /* Overflow happens if
2332 * neg + neg = pos or
2335 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2336 * XOR of the high bit returns 0 if the signs match
2337 * XOR of that with the high bit of the result return 1 if overflow.
2340 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2341 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2343 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2344 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2345 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2347 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2348 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2350 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2352 /* Now, if (tmp5 == 0) then overflow */
2353 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2354 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2355 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2359 case OP_IADD_OVF_UN:
2360 tmp1 = mono_alloc_ireg (cfg);
2362 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2363 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2364 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2365 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2366 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2371 tmp1 = mono_alloc_ireg (cfg);
2372 tmp2 = mono_alloc_ireg (cfg);
2373 tmp3 = mono_alloc_ireg (cfg);
2374 tmp4 = mono_alloc_ireg (cfg);
2375 tmp5 = mono_alloc_ireg (cfg);
2377 /* add the operands */
2379 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2381 /* Overflow happens if
2382 * neg - pos = pos or
2384 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2386 * tmp1 = (lhs ^ rhs)
2387 * tmp2 = (lhs ^ result)
2388 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2391 /* tmp3 = 1 if the signs of the two inputs differ */
2392 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2393 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2394 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2395 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2396 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2398 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2399 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2400 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2404 case OP_ISUB_OVF_UN:
2405 tmp1 = mono_alloc_ireg (cfg);
2407 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2408 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2409 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2410 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2411 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2418 map_to_reg_reg_op (int op)
2427 case OP_COMPARE_IMM:
2429 case OP_ICOMPARE_IMM:
2431 case OP_LCOMPARE_IMM:
2447 case OP_LOAD_MEMBASE:
2448 return OP_LOAD_MEMINDEX;
2449 case OP_LOADI4_MEMBASE:
2450 return OP_LOADI4_MEMINDEX;
2451 case OP_LOADU4_MEMBASE:
2452 return OP_LOADU4_MEMINDEX;
2453 case OP_LOADU1_MEMBASE:
2454 return OP_LOADU1_MEMINDEX;
2455 case OP_LOADI2_MEMBASE:
2456 return OP_LOADI2_MEMINDEX;
2457 case OP_LOADU2_MEMBASE:
2458 return OP_LOADU2_MEMINDEX;
2459 case OP_LOADI1_MEMBASE:
2460 return OP_LOADI1_MEMINDEX;
2461 case OP_LOADR4_MEMBASE:
2462 return OP_LOADR4_MEMINDEX;
2463 case OP_LOADR8_MEMBASE:
2464 return OP_LOADR8_MEMINDEX;
2465 case OP_STOREI1_MEMBASE_REG:
2466 return OP_STOREI1_MEMINDEX;
2467 case OP_STOREI2_MEMBASE_REG:
2468 return OP_STOREI2_MEMINDEX;
2469 case OP_STOREI4_MEMBASE_REG:
2470 return OP_STOREI4_MEMINDEX;
2471 case OP_STORE_MEMBASE_REG:
2472 return OP_STORE_MEMINDEX;
2473 case OP_STORER4_MEMBASE_REG:
2474 return OP_STORER4_MEMINDEX;
2475 case OP_STORER8_MEMBASE_REG:
2476 return OP_STORER8_MEMINDEX;
2477 case OP_STORE_MEMBASE_IMM:
2478 return OP_STORE_MEMBASE_REG;
2479 case OP_STOREI1_MEMBASE_IMM:
2480 return OP_STOREI1_MEMBASE_REG;
2481 case OP_STOREI2_MEMBASE_IMM:
2482 return OP_STOREI2_MEMBASE_REG;
2483 case OP_STOREI4_MEMBASE_IMM:
2484 return OP_STOREI4_MEMBASE_REG;
2485 case OP_STOREI8_MEMBASE_IMM:
2486 return OP_STOREI8_MEMBASE_REG;
2488 if (mono_op_imm_to_op (op) == -1)
2489 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2490 return mono_op_imm_to_op (op);
2494 map_to_mips_op (int op)
2498 return OP_MIPS_FBEQ;
2500 return OP_MIPS_FBGE;
2502 return OP_MIPS_FBGT;
2504 return OP_MIPS_FBLE;
2506 return OP_MIPS_FBLT;
2508 return OP_MIPS_FBNE;
2510 return OP_MIPS_FBGE_UN;
2512 return OP_MIPS_FBGT_UN;
2514 return OP_MIPS_FBLE_UN;
2516 return OP_MIPS_FBLT_UN;
2524 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2525 g_assert_not_reached ();
2529 #define NEW_INS(cfg,after,dest,op) do { \
2530 MONO_INST_NEW((cfg), (dest), (op)); \
2531 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2534 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2536 MONO_INST_NEW(cfg, temp, (op)); \
2537 mono_bblock_insert_after_ins (bb, (pos), temp); \
2538 temp->dreg = (_dreg); \
2539 temp->sreg1 = (_sreg1); \
2540 temp->sreg2 = (_sreg2); \
2544 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2546 MONO_INST_NEW(cfg, temp, (op)); \
2547 mono_bblock_insert_after_ins (bb, (pos), temp); \
2548 temp->dreg = (_dreg); \
2549 temp->sreg1 = (_sreg1); \
2550 temp->inst_c0 = (_imm); \
2555 * Remove from the instruction list the instructions that can't be
2556 * represented with very simple instructions with no register
2560 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2562 MonoInst *ins, *next, *temp, *last_ins = NULL;
2566 if (cfg->verbose_level > 2) {
2569 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2570 MONO_BB_FOR_EACH_INS (bb, ins) {
2571 mono_print_ins_index (idx++, ins);
2577 MONO_BB_FOR_EACH_INS (bb, ins) {
2579 switch (ins->opcode) {
2584 /* Branch opts can eliminate the branch */
2585 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2591 case OP_COMPARE_IMM:
2592 case OP_ICOMPARE_IMM:
2593 case OP_LCOMPARE_IMM:
2595 /* Branch opts can eliminate the branch */
2596 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2600 if (ins->inst_imm) {
2601 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2602 temp->inst_c0 = ins->inst_imm;
2603 temp->dreg = mono_alloc_ireg (cfg);
2604 ins->sreg2 = temp->dreg;
2608 ins->sreg2 = mips_zero;
2610 if (ins->opcode == OP_COMPARE_IMM)
2611 ins->opcode = OP_COMPARE;
2612 else if (ins->opcode == OP_ICOMPARE_IMM)
2613 ins->opcode = OP_ICOMPARE;
2614 else if (ins->opcode == OP_LCOMPARE_IMM)
2615 ins->opcode = OP_LCOMPARE;
2618 case OP_IDIV_UN_IMM:
2621 case OP_IREM_UN_IMM:
2622 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2623 temp->inst_c0 = ins->inst_imm;
2624 temp->dreg = mono_alloc_ireg (cfg);
2625 ins->sreg2 = temp->dreg;
2626 if (ins->opcode == OP_IDIV_IMM)
2627 ins->opcode = OP_IDIV;
2628 else if (ins->opcode == OP_IREM_IMM)
2629 ins->opcode = OP_IREM;
2630 else if (ins->opcode == OP_IDIV_UN_IMM)
2631 ins->opcode = OP_IDIV_UN;
2632 else if (ins->opcode == OP_IREM_UN_IMM)
2633 ins->opcode = OP_IREM_UN;
2635 /* handle rem separately */
2642 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2643 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2644 temp->inst_c0 = ins->inst_imm;
2645 temp->dreg = mono_alloc_ireg (cfg);
2646 ins->sreg2 = temp->dreg;
2647 ins->opcode = map_to_reg_reg_op (ins->opcode);
2657 /* unsigned 16 bit immediate */
2658 if (ins->inst_imm & 0xffff0000) {
2659 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2660 temp->inst_c0 = ins->inst_imm;
2661 temp->dreg = mono_alloc_ireg (cfg);
2662 ins->sreg2 = temp->dreg;
2663 ins->opcode = map_to_reg_reg_op (ins->opcode);
2670 /* signed 16 bit immediate */
2671 if (!mips_is_imm16 (ins->inst_imm)) {
2672 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2673 temp->inst_c0 = ins->inst_imm;
2674 temp->dreg = mono_alloc_ireg (cfg);
2675 ins->sreg2 = temp->dreg;
2676 ins->opcode = map_to_reg_reg_op (ins->opcode);
2682 if (!mips_is_imm16 (-ins->inst_imm)) {
2683 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2684 temp->inst_c0 = ins->inst_imm;
2685 temp->dreg = mono_alloc_ireg (cfg);
2686 ins->sreg2 = temp->dreg;
2687 ins->opcode = map_to_reg_reg_op (ins->opcode);
2693 if (ins->inst_imm == 1) {
2694 ins->opcode = OP_MOVE;
2697 if (ins->inst_imm == 0) {
2698 ins->opcode = OP_ICONST;
2702 imm = mono_is_power_of_two (ins->inst_imm);
2704 ins->opcode = OP_SHL_IMM;
2705 ins->inst_imm = imm;
2708 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2709 temp->inst_c0 = ins->inst_imm;
2710 temp->dreg = mono_alloc_ireg (cfg);
2711 ins->sreg2 = temp->dreg;
2712 ins->opcode = map_to_reg_reg_op (ins->opcode);
2715 case OP_LOCALLOC_IMM:
2716 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2717 temp->inst_c0 = ins->inst_imm;
2718 temp->dreg = mono_alloc_ireg (cfg);
2719 ins->sreg1 = temp->dreg;
2720 ins->opcode = OP_LOCALLOC;
2723 case OP_LOADR4_MEMBASE:
2724 case OP_STORER4_MEMBASE_REG:
2725 /* we can do two things: load the immed in a register
2726 * and use an indexed load, or see if the immed can be
2727 * represented as an ad_imm + a load with a smaller offset
2728 * that fits. We just do the first for now, optimize later.
2730 if (mips_is_imm16 (ins->inst_offset))
2732 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2733 temp->inst_c0 = ins->inst_offset;
2734 temp->dreg = mono_alloc_ireg (cfg);
2735 ins->sreg2 = temp->dreg;
2736 ins->opcode = map_to_reg_reg_op (ins->opcode);
2739 case OP_STORE_MEMBASE_IMM:
2740 case OP_STOREI1_MEMBASE_IMM:
2741 case OP_STOREI2_MEMBASE_IMM:
2742 case OP_STOREI4_MEMBASE_IMM:
2743 case OP_STOREI8_MEMBASE_IMM:
2744 if (!ins->inst_imm) {
2745 ins->sreg1 = mips_zero;
2746 ins->opcode = map_to_reg_reg_op (ins->opcode);
2749 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2750 temp->inst_c0 = ins->inst_imm;
2751 temp->dreg = mono_alloc_ireg (cfg);
2752 ins->sreg1 = temp->dreg;
2753 ins->opcode = map_to_reg_reg_op (ins->opcode);
2755 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2761 /* Branch opts can eliminate the branch */
2762 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2769 * remap compare/branch and compare/set
2770 * to MIPS specific opcodes.
2772 next->opcode = map_to_mips_op (next->opcode);
2773 next->sreg1 = ins->sreg1;
2774 next->sreg2 = ins->sreg2;
2781 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2782 temp->inst_c0 = (guint32)ins->inst_p0;
2783 temp->dreg = mono_alloc_ireg (cfg);
2784 ins->inst_basereg = temp->dreg;
2785 ins->inst_offset = 0;
2786 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2788 /* make it handle the possibly big ins->inst_offset
2789 * later optimize to use lis + load_membase
2794 g_assert (ins_is_compare(last_ins));
2795 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2796 NULLIFY_INS(last_ins);
2800 g_assert (ins_is_compare(last_ins));
2801 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2802 NULLIFY_INS(last_ins);
2806 g_assert (ins_is_compare(last_ins));
2807 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2808 last_ins->dreg = mono_alloc_ireg (cfg);
2809 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2813 g_assert (ins_is_compare(last_ins));
2814 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2815 last_ins->dreg = mono_alloc_ireg (cfg);
2816 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2820 g_assert (ins_is_compare(last_ins));
2821 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2822 last_ins->dreg = mono_alloc_ireg (cfg);
2823 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2827 g_assert (ins_is_compare(last_ins));
2828 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2829 last_ins->dreg = mono_alloc_ireg (cfg);
2830 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2834 g_assert (ins_is_compare(last_ins));
2835 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2836 last_ins->dreg = mono_alloc_ireg (cfg);
2837 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2841 g_assert (ins_is_compare(last_ins));
2842 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2843 last_ins->dreg = mono_alloc_ireg (cfg);
2844 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2848 g_assert (ins_is_compare(last_ins));
2849 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2850 last_ins->dreg = mono_alloc_ireg (cfg);
2851 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2855 g_assert (ins_is_compare(last_ins));
2856 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2857 last_ins->dreg = mono_alloc_ireg (cfg);
2858 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2863 g_assert (ins_is_compare(last_ins));
2864 last_ins->opcode = OP_IXOR;
2865 last_ins->dreg = mono_alloc_ireg(cfg);
2866 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2871 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2872 NULLIFY_INS(last_ins);
2878 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2879 NULLIFY_INS(last_ins);
2884 g_assert (ins_is_compare(last_ins));
2885 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2886 MONO_DELETE_INS(bb, last_ins);
2891 g_assert (ins_is_compare(last_ins));
2892 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2893 MONO_DELETE_INS(bb, last_ins);
2896 case OP_COND_EXC_EQ:
2897 case OP_COND_EXC_IEQ:
2898 g_assert (ins_is_compare(last_ins));
2899 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2900 MONO_DELETE_INS(bb, last_ins);
2903 case OP_COND_EXC_GE:
2904 case OP_COND_EXC_IGE:
2905 g_assert (ins_is_compare(last_ins));
2906 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2907 MONO_DELETE_INS(bb, last_ins);
2910 case OP_COND_EXC_GT:
2911 case OP_COND_EXC_IGT:
2912 g_assert (ins_is_compare(last_ins));
2913 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2914 MONO_DELETE_INS(bb, last_ins);
2917 case OP_COND_EXC_LE:
2918 case OP_COND_EXC_ILE:
2919 g_assert (ins_is_compare(last_ins));
2920 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2921 MONO_DELETE_INS(bb, last_ins);
2924 case OP_COND_EXC_LT:
2925 case OP_COND_EXC_ILT:
2926 g_assert (ins_is_compare(last_ins));
2927 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2928 MONO_DELETE_INS(bb, last_ins);
2931 case OP_COND_EXC_NE_UN:
2932 case OP_COND_EXC_INE_UN:
2933 g_assert (ins_is_compare(last_ins));
2934 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2935 MONO_DELETE_INS(bb, last_ins);
2938 case OP_COND_EXC_GE_UN:
2939 case OP_COND_EXC_IGE_UN:
2940 g_assert (ins_is_compare(last_ins));
2941 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2942 MONO_DELETE_INS(bb, last_ins);
2945 case OP_COND_EXC_GT_UN:
2946 case OP_COND_EXC_IGT_UN:
2947 g_assert (ins_is_compare(last_ins));
2948 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2949 MONO_DELETE_INS(bb, last_ins);
2952 case OP_COND_EXC_LE_UN:
2953 case OP_COND_EXC_ILE_UN:
2954 g_assert (ins_is_compare(last_ins));
2955 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2956 MONO_DELETE_INS(bb, last_ins);
2959 case OP_COND_EXC_LT_UN:
2960 case OP_COND_EXC_ILT_UN:
2961 g_assert (ins_is_compare(last_ins));
2962 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2963 MONO_DELETE_INS(bb, last_ins);
2966 case OP_COND_EXC_OV:
2967 case OP_COND_EXC_IOV: {
2968 int tmp1, tmp2, tmp3, tmp4, tmp5;
2969 MonoInst *pos = last_ins;
2971 /* Overflow happens if
2972 * neg + neg = pos or
2975 * (bit31s of operands match) AND (bit31 of operand
2976 * != bit31 of result)
2977 * XOR of the high bit returns 0 if the signs match
2978 * XOR of that with the high bit of the result return 1
2981 g_assert (last_ins->opcode == OP_IADC);
2983 tmp1 = mono_alloc_ireg (cfg);
2984 tmp2 = mono_alloc_ireg (cfg);
2985 tmp3 = mono_alloc_ireg (cfg);
2986 tmp4 = mono_alloc_ireg (cfg);
2987 tmp5 = mono_alloc_ireg (cfg);
2989 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2990 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2992 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2993 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2994 INS (pos, OP_INOT, tmp3, tmp2, -1);
2996 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2997 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2998 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3000 /* Now, if (tmp5 == 0) then overflow */
3001 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3006 case OP_COND_EXC_NO:
3007 case OP_COND_EXC_INO:
3008 g_assert_not_reached ();
3012 case OP_COND_EXC_IC:
3013 g_assert_not_reached ();
3016 case OP_COND_EXC_NC:
3017 case OP_COND_EXC_INC:
3018 g_assert_not_reached ();
3024 bb->last_ins = last_ins;
3025 bb->max_vreg = cfg->next_vreg;
3028 if (cfg->verbose_level > 2) {
3031 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3032 MONO_BB_FOR_EACH_INS (bb, ins) {
3033 mono_print_ins_index (idx++, ins);
3042 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3044 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3046 mips_truncwd (code, mips_ftemp, sreg);
3048 mips_cvtwd (code, mips_ftemp, sreg);
3050 mips_mfc1 (code, dreg, mips_ftemp);
3053 mips_andi (code, dreg, dreg, 0xff);
3054 else if (size == 2) {
3055 mips_sll (code, dreg, dreg, 16);
3056 mips_srl (code, dreg, dreg, 16);
3060 mips_sll (code, dreg, dreg, 24);
3061 mips_sra (code, dreg, dreg, 24);
3063 else if (size == 2) {
3064 mips_sll (code, dreg, dreg, 16);
3065 mips_sra (code, dreg, dreg, 16);
3072 * emit_load_volatile_arguments:
3074 * Load volatile arguments from the stack to the original input registers.
3075 * Required before a tail call.
3078 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3080 MonoMethod *method = cfg->method;
3081 MonoMethodSignature *sig;
3086 sig = mono_method_signature (method);
3088 if (!cfg->arch.cinfo)
3089 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3090 cinfo = cfg->arch.cinfo;
3092 if (cinfo->struct_ret) {
3093 ArgInfo *ainfo = &cinfo->ret;
3094 inst = cfg->vret_addr;
3095 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3098 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3099 ArgInfo *ainfo = cinfo->args + i;
3100 inst = cfg->args [i];
3101 if (inst->opcode == OP_REGVAR) {
3102 if (ainfo->storage == ArgInIReg)
3103 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3104 else if (ainfo->storage == ArgInFReg)
3105 g_assert_not_reached();
3106 else if (ainfo->storage == ArgOnStack) {
3109 g_assert_not_reached ();
3111 if (ainfo->storage == ArgInIReg) {
3112 g_assert (mips_is_imm16 (inst->inst_offset));
3113 switch (ainfo->size) {
3115 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3118 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3122 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3125 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3126 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3129 g_assert_not_reached ();
3132 } else if (ainfo->storage == ArgOnStack) {
3134 } else if (ainfo->storage == ArgInFReg) {
3135 g_assert (mips_is_imm16 (inst->inst_offset));
3136 if (ainfo->size == 8) {
3137 #if _MIPS_SIM == _ABIO32
3138 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3139 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3140 #elif _MIPS_SIM == _ABIN32
3141 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3144 else if (ainfo->size == 4)
3145 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3147 g_assert_not_reached ();
3148 } else if (ainfo->storage == ArgStructByVal) {
3150 int doffset = inst->inst_offset;
3152 g_assert (mips_is_imm16 (inst->inst_offset));
3153 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3154 for (i = 0; i < ainfo->size; ++i) {
3155 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3156 doffset += SIZEOF_REGISTER;
3158 } else if (ainfo->storage == ArgStructByAddr) {
3159 g_assert (mips_is_imm16 (inst->inst_offset));
3160 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3162 g_assert_not_reached ();
3170 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3172 int size = cfg->param_area;
3174 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3175 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3180 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3181 if (ppc_is_imm16 (-size)) {
3182 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3184 ppc_load (code, ppc_r12, -size);
3185 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3192 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3194 int size = cfg->param_area;
3196 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3197 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3202 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3203 if (ppc_is_imm16 (size)) {
3204 ppc_stwu (code, ppc_r0, size, ppc_sp);
3206 ppc_load (code, ppc_r12, size);
3207 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3214 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3219 guint8 *code = cfg->native_code + cfg->code_len;
3220 MonoInst *last_ins = NULL;
3221 guint last_offset = 0;
3225 /* we don't align basic blocks of loops on mips */
3227 if (cfg->verbose_level > 2)
3228 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3230 cpos = bb->max_offset;
3233 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3234 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3235 g_assert (!mono_compile_aot);
3238 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3239 /* this is not thread save, but good enough */
3240 /* fixme: howto handle overflows? */
3241 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3242 mips_lw (code, mips_temp, mips_at, 0);
3243 mips_addiu (code, mips_temp, mips_temp, 1);
3244 mips_sw (code, mips_temp, mips_at, 0);
3247 MONO_BB_FOR_EACH_INS (bb, ins) {
3248 offset = code - cfg->native_code;
3250 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3252 if (offset > (cfg->code_size - max_len - 16)) {
3253 cfg->code_size *= 2;
3254 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3255 code = cfg->native_code + offset;
3257 mono_debug_record_line_number (cfg, ins, offset);
3258 if (cfg->verbose_level > 2) {
3259 g_print (" @ 0x%x\t", offset);
3260 mono_print_ins_index (ins_cnt++, ins);
3262 /* Check for virtual regs that snuck by */
3263 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3265 switch (ins->opcode) {
3266 case OP_RELAXED_NOP:
3269 case OP_DUMMY_STORE:
3270 case OP_NOT_REACHED:
3273 case OP_IL_SEQ_POINT:
3274 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3276 case OP_SEQ_POINT: {
3277 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3278 guint32 addr = (guint32)ss_trigger_page;
3280 mips_load_const (code, mips_t9, addr);
3281 mips_lw (code, mips_t9, mips_t9, 0);
3284 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3287 * A placeholder for a possible breakpoint inserted by
3288 * mono_arch_set_breakpoint ().
3290 /* mips_load_const () + mips_lw */
3297 mips_mult (code, ins->sreg1, ins->sreg2);
3298 mips_mflo (code, ins->dreg);
3299 mips_mfhi (code, ins->dreg+1);
3302 mips_multu (code, ins->sreg1, ins->sreg2);
3303 mips_mflo (code, ins->dreg);
3304 mips_mfhi (code, ins->dreg+1);
3306 case OP_MEMORY_BARRIER:
3307 mips_sync (code, 0);
3309 case OP_STOREI1_MEMBASE_IMM:
3310 mips_load_const (code, mips_temp, ins->inst_imm);
3311 if (mips_is_imm16 (ins->inst_offset)) {
3312 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3314 mips_load_const (code, mips_at, ins->inst_offset);
3315 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3318 case OP_STOREI2_MEMBASE_IMM:
3319 mips_load_const (code, mips_temp, ins->inst_imm);
3320 if (mips_is_imm16 (ins->inst_offset)) {
3321 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3323 mips_load_const (code, mips_at, ins->inst_offset);
3324 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3327 case OP_STOREI8_MEMBASE_IMM:
3328 mips_load_const (code, mips_temp, ins->inst_imm);
3329 if (mips_is_imm16 (ins->inst_offset)) {
3330 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3332 mips_load_const (code, mips_at, ins->inst_offset);
3333 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3336 case OP_STORE_MEMBASE_IMM:
3337 case OP_STOREI4_MEMBASE_IMM:
3338 mips_load_const (code, mips_temp, ins->inst_imm);
3339 if (mips_is_imm16 (ins->inst_offset)) {
3340 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3342 mips_load_const (code, mips_at, ins->inst_offset);
3343 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3346 case OP_STOREI1_MEMBASE_REG:
3347 if (mips_is_imm16 (ins->inst_offset)) {
3348 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3350 mips_load_const (code, mips_at, ins->inst_offset);
3351 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3352 mips_sb (code, ins->sreg1, mips_at, 0);
3355 case OP_STOREI2_MEMBASE_REG:
3356 if (mips_is_imm16 (ins->inst_offset)) {
3357 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3359 mips_load_const (code, mips_at, ins->inst_offset);
3360 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3361 mips_sh (code, ins->sreg1, mips_at, 0);
3364 case OP_STORE_MEMBASE_REG:
3365 case OP_STOREI4_MEMBASE_REG:
3366 if (mips_is_imm16 (ins->inst_offset)) {
3367 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3369 mips_load_const (code, mips_at, ins->inst_offset);
3370 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3371 mips_sw (code, ins->sreg1, mips_at, 0);
3374 case OP_STOREI8_MEMBASE_REG:
3375 if (mips_is_imm16 (ins->inst_offset)) {
3376 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3378 mips_load_const (code, mips_at, ins->inst_offset);
3379 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3380 mips_sd (code, ins->sreg1, mips_at, 0);
3384 g_assert_not_reached ();
3385 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3386 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3388 case OP_LOADI8_MEMBASE:
3389 if (mips_is_imm16 (ins->inst_offset)) {
3390 mips_ld (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_ld (code, ins->dreg, mips_at, 0);
3397 case OP_LOAD_MEMBASE:
3398 case OP_LOADI4_MEMBASE:
3399 case OP_LOADU4_MEMBASE:
3400 g_assert (ins->dreg != -1);
3401 if (mips_is_imm16 (ins->inst_offset)) {
3402 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3404 mips_load_const (code, mips_at, ins->inst_offset);
3405 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3406 mips_lw (code, ins->dreg, mips_at, 0);
3409 case OP_LOADI1_MEMBASE:
3410 if (mips_is_imm16 (ins->inst_offset)) {
3411 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3413 mips_load_const (code, mips_at, ins->inst_offset);
3414 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3415 mips_lb (code, ins->dreg, mips_at, 0);
3418 case OP_LOADU1_MEMBASE:
3419 if (mips_is_imm16 (ins->inst_offset)) {
3420 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3422 mips_load_const (code, mips_at, ins->inst_offset);
3423 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3424 mips_lbu (code, ins->dreg, mips_at, 0);
3427 case OP_LOADI2_MEMBASE:
3428 if (mips_is_imm16 (ins->inst_offset)) {
3429 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3431 mips_load_const (code, mips_at, ins->inst_offset);
3432 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3433 mips_lh (code, ins->dreg, mips_at, 0);
3436 case OP_LOADU2_MEMBASE:
3437 if (mips_is_imm16 (ins->inst_offset)) {
3438 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3440 mips_load_const (code, mips_at, ins->inst_offset);
3441 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3442 mips_lhu (code, ins->dreg, mips_at, 0);
3445 case OP_ICONV_TO_I1:
3446 mips_sll (code, mips_at, ins->sreg1, 24);
3447 mips_sra (code, ins->dreg, mips_at, 24);
3449 case OP_ICONV_TO_I2:
3450 mips_sll (code, mips_at, ins->sreg1, 16);
3451 mips_sra (code, ins->dreg, mips_at, 16);
3453 case OP_ICONV_TO_U1:
3454 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3456 case OP_ICONV_TO_U2:
3457 mips_sll (code, mips_at, ins->sreg1, 16);
3458 mips_srl (code, ins->dreg, mips_at, 16);
3461 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3464 g_assert (mips_is_imm16 (ins->inst_imm));
3465 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3468 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3471 g_assert (mips_is_imm16 (ins->inst_imm));
3472 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3476 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3477 * So instead of emitting a trap, we emit a call a C function and place a
3480 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3481 (gpointer)"mono_break");
3482 mips_load (code, mips_t9, 0x1f1f1f1f);
3483 mips_jalr (code, mips_t9, mips_ra);
3487 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3490 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3495 g_assert (mips_is_imm16 (ins->inst_imm));
3496 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3499 g_assert (mips_is_imm16 (ins->inst_imm));
3500 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3504 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3507 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3512 // we add the negated value
3513 g_assert (mips_is_imm16 (-ins->inst_imm));
3514 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3518 // we add the negated value
3519 g_assert (mips_is_imm16 (-ins->inst_imm));
3520 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3525 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3531 g_assert (!(ins->inst_imm & 0xffff0000));
3532 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3537 guint32 *divisor_is_m1;
3538 guint32 *dividend_is_minvalue;
3539 guint32 *divisor_is_zero;
3541 mips_load_const (code, mips_at, -1);
3542 divisor_is_m1 = (guint32 *)(void *)code;
3543 mips_bne (code, ins->sreg2, mips_at, 0);
3544 mips_lui (code, mips_at, mips_zero, 0x8000);
3545 dividend_is_minvalue = (guint32 *)(void *)code;
3546 mips_bne (code, ins->sreg1, mips_at, 0);
3549 /* Divide Int32.MinValue by -1 -- throw exception */
3550 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3552 mips_patch (divisor_is_m1, (guint32)code);
3553 mips_patch (dividend_is_minvalue, (guint32)code);
3555 /* Put divide in branch delay slot (NOT YET) */
3556 divisor_is_zero = (guint32 *)(void *)code;
3557 mips_bne (code, ins->sreg2, mips_zero, 0);
3560 /* Divide by zero -- throw exception */
3561 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3563 mips_patch (divisor_is_zero, (guint32)code);
3564 mips_div (code, ins->sreg1, ins->sreg2);
3565 if (ins->opcode == OP_IDIV)
3566 mips_mflo (code, ins->dreg);
3568 mips_mfhi (code, ins->dreg);
3573 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3575 /* Put divide in branch delay slot (NOT YET) */
3576 mips_bne (code, ins->sreg2, mips_zero, 0);
3579 /* Divide by zero -- throw exception */
3580 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3582 mips_patch (divisor_is_zero, (guint32)code);
3583 mips_divu (code, ins->sreg1, ins->sreg2);
3584 if (ins->opcode == OP_IDIV_UN)
3585 mips_mflo (code, ins->dreg);
3587 mips_mfhi (code, ins->dreg);
3591 g_assert_not_reached ();
3593 ppc_load (code, ppc_r12, ins->inst_imm);
3594 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3595 ppc_mfspr (code, ppc_r0, ppc_xer);
3596 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3597 /* FIXME: use OverflowException for 0x80000000/-1 */
3598 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3600 g_assert_not_reached();
3603 g_assert_not_reached ();
3605 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3609 g_assert (!(ins->inst_imm & 0xffff0000));
3610 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3613 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3617 /* unsigned 16-bit immediate */
3618 g_assert (!(ins->inst_imm & 0xffff0000));
3619 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3622 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3626 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3629 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3632 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3636 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3639 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3642 case OP_ISHR_UN_IMM:
3643 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3645 case OP_LSHR_UN_IMM:
3646 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3649 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3652 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3656 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3659 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3662 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3666 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3668 mips_mult (code, ins->sreg1, ins->sreg2);
3669 mips_mflo (code, ins->dreg);
3674 #if SIZEOF_REGISTER == 8
3676 mips_dmult (code, ins->sreg1, ins->sreg2);
3677 mips_mflo (code, ins->dreg);
3682 mips_mult (code, ins->sreg1, ins->sreg2);
3683 mips_mflo (code, ins->dreg);
3684 mips_mfhi (code, mips_at);
3687 mips_sra (code, mips_temp, ins->dreg, 31);
3688 patch = (guint32 *)(void *)code;
3689 mips_beq (code, mips_temp, mips_at, 0);
3691 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3692 mips_patch (patch, (guint32)code);
3695 case OP_IMUL_OVF_UN: {
3697 mips_mult (code, ins->sreg1, ins->sreg2);
3698 mips_mflo (code, ins->dreg);
3699 mips_mfhi (code, mips_at);
3702 patch = (guint32 *)(void *)code;
3703 mips_beq (code, mips_at, mips_zero, 0);
3705 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3706 mips_patch (patch, (guint32)code);
3710 mips_load_const (code, ins->dreg, ins->inst_c0);
3712 #if SIZEOF_REGISTER == 8
3714 mips_load_const (code, ins->dreg, ins->inst_c0);
3718 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3719 mips_load (code, ins->dreg, 0);
3723 mips_mtc1 (code, ins->dreg, ins->sreg1);
3725 case OP_MIPS_MTC1S_2:
3726 mips_mtc1 (code, ins->dreg, ins->sreg1);
3727 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3730 mips_mfc1 (code, ins->dreg, ins->sreg1);
3733 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3737 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3739 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3740 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3744 case OP_ICONV_TO_I4:
3745 case OP_ICONV_TO_U4:
3747 if (ins->dreg != ins->sreg1)
3748 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3750 #if SIZEOF_REGISTER == 8
3752 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3753 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3756 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3757 mips_dsra (code, ins->dreg, ins->dreg, 32);
3761 int lsreg = mips_v0 + ls_word_idx;
3762 int msreg = mips_v0 + ms_word_idx;
3764 /* Get sreg1 into lsreg, sreg2 into msreg */
3766 if (ins->sreg1 == msreg) {
3767 if (ins->sreg1 != mips_at)
3768 MIPS_MOVE (code, mips_at, ins->sreg1);
3769 if (ins->sreg2 != msreg)
3770 MIPS_MOVE (code, msreg, ins->sreg2);
3771 MIPS_MOVE (code, lsreg, mips_at);
3774 if (ins->sreg2 != msreg)
3775 MIPS_MOVE (code, msreg, ins->sreg2);
3776 if (ins->sreg1 != lsreg)
3777 MIPS_MOVE (code, lsreg, ins->sreg1);
3782 if (ins->dreg != ins->sreg1) {
3783 mips_fmovd (code, ins->dreg, ins->sreg1);
3786 case OP_MOVE_F_TO_I4:
3787 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3788 mips_mfc1 (code, ins->dreg, mips_ftemp);
3790 case OP_MOVE_I4_TO_F:
3791 mips_mtc1 (code, ins->dreg, ins->sreg1);
3792 mips_cvtds (code, ins->dreg, ins->dreg);
3795 /* Convert from double to float and leave it there */
3796 mips_cvtsd (code, ins->dreg, ins->sreg1);
3798 case OP_FCONV_TO_R4:
3800 mips_cvtsd (code, ins->dreg, ins->sreg1);
3802 /* Just a move, no precision change */
3803 if (ins->dreg != ins->sreg1) {
3804 mips_fmovd (code, ins->dreg, ins->sreg1);
3809 code = emit_load_volatile_arguments(cfg, code);
3812 * Pop our stack, then jump to specified method (tail-call)
3813 * Keep in sync with mono_arch_emit_epilog
3815 code = mono_arch_emit_epilog_sub (cfg, code);
3817 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3818 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3819 mips_load (code, mips_t9, 0);
3820 mips_jr (code, mips_t9);
3824 /* ensure ins->sreg1 is not NULL */
3825 mips_lw (code, mips_zero, ins->sreg1, 0);
3828 g_assert (mips_is_imm16 (cfg->sig_cookie));
3829 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3830 mips_sw (code, mips_at, ins->sreg1, 0);
3843 case OP_VOIDCALL_REG:
3845 case OP_FCALL_MEMBASE:
3846 case OP_LCALL_MEMBASE:
3847 case OP_VCALL_MEMBASE:
3848 case OP_VCALL2_MEMBASE:
3849 case OP_VOIDCALL_MEMBASE:
3850 case OP_CALL_MEMBASE:
3851 call = (MonoCallInst*)ins;
3852 switch (ins->opcode) {
3859 if (ins->flags & MONO_INST_HAS_METHOD) {
3860 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3861 mips_load (code, mips_t9, call->method);
3864 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3865 mips_load (code, mips_t9, call->fptr);
3867 mips_jalr (code, mips_t9, mips_ra);
3874 case OP_VOIDCALL_REG:
3876 MIPS_MOVE (code, mips_t9, ins->sreg1);
3877 mips_jalr (code, mips_t9, mips_ra);
3880 case OP_FCALL_MEMBASE:
3881 case OP_LCALL_MEMBASE:
3882 case OP_VCALL_MEMBASE:
3883 case OP_VCALL2_MEMBASE:
3884 case OP_VOIDCALL_MEMBASE:
3885 case OP_CALL_MEMBASE:
3886 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3887 mips_jalr (code, mips_t9, mips_ra);
3891 #if PROMOTE_R4_TO_R8
3892 /* returned an FP R4 (single), promote to R8 (double) in place */
3893 switch (ins->opcode) {
3896 case OP_FCALL_MEMBASE:
3897 if (call->signature->ret->type == MONO_TYPE_R4)
3898 mips_cvtds (code, mips_f0, mips_f0);
3906 int area_offset = cfg->param_area;
3908 /* Round up ins->sreg1, mips_at ends up holding size */
3909 mips_addiu (code, mips_at, ins->sreg1, 31);
3910 mips_addiu (code, mips_temp, mips_zero, ~31);
3911 mips_and (code, mips_at, mips_at, mips_temp);
3913 mips_subu (code, mips_sp, mips_sp, mips_at);
3914 g_assert (mips_is_imm16 (area_offset));
3915 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3917 if (ins->flags & MONO_INST_INIT) {
3920 buf = (guint32*)(void*)code;
3921 mips_beq (code, mips_at, mips_zero, 0);
3924 mips_move (code, mips_temp, ins->dreg);
3925 mips_sb (code, mips_zero, mips_temp, 0);
3926 mips_addiu (code, mips_at, mips_at, -1);
3927 mips_bne (code, mips_at, mips_zero, -3);
3928 mips_addiu (code, mips_temp, mips_temp, 1);
3930 mips_patch (buf, (guint32)code);
3935 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3936 mips_move (code, mips_a0, ins->sreg1);
3937 mips_call (code, mips_t9, addr);
3938 mips_break (code, 0xfc);
3942 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3943 mips_move (code, mips_a0, ins->sreg1);
3944 mips_call (code, mips_t9, addr);
3945 mips_break (code, 0xfb);
3948 case OP_START_HANDLER: {
3950 * The START_HANDLER instruction marks the beginning of
3951 * a handler block. It is called using a call
3952 * instruction, so mips_ra contains the return address.
3953 * Since the handler executes in the same stack frame
3954 * as the method itself, we can't use save/restore to
3955 * save the return address. Instead, we save it into
3956 * a dedicated variable.
3958 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3959 g_assert (spvar->inst_basereg != mips_sp);
3960 code = emit_reserve_param_area (cfg, code);
3962 if (mips_is_imm16 (spvar->inst_offset)) {
3963 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3965 mips_load_const (code, mips_at, spvar->inst_offset);
3966 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3967 mips_sw (code, mips_ra, mips_at, 0);
3971 case OP_ENDFILTER: {
3972 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3973 g_assert (spvar->inst_basereg != mips_sp);
3974 code = emit_unreserve_param_area (cfg, code);
3976 if (ins->sreg1 != mips_v0)
3977 MIPS_MOVE (code, mips_v0, ins->sreg1);
3978 if (mips_is_imm16 (spvar->inst_offset)) {
3979 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3981 mips_load_const (code, mips_at, spvar->inst_offset);
3982 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3983 mips_lw (code, mips_ra, mips_at, 0);
3985 mips_jr (code, mips_ra);
3989 case OP_ENDFINALLY: {
3990 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3991 g_assert (spvar->inst_basereg != mips_sp);
3992 code = emit_unreserve_param_area (cfg, code);
3993 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3994 mips_jalr (code, mips_t9, mips_ra);
3998 case OP_CALL_HANDLER:
3999 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4000 mips_lui (code, mips_t9, mips_zero, 0);
4001 mips_addiu (code, mips_t9, mips_t9, 0);
4002 mips_jalr (code, mips_t9, mips_ra);
4004 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4005 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4008 ins->inst_c0 = code - cfg->native_code;
4011 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4012 if (cfg->arch.long_branch) {
4013 mips_lui (code, mips_at, mips_zero, 0);
4014 mips_addiu (code, mips_at, mips_at, 0);
4015 mips_jr (code, mips_at);
4019 mips_beq (code, mips_zero, mips_zero, 0);
4024 mips_jr (code, ins->sreg1);
4030 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4031 if (offset > (cfg->code_size - max_len - 16)) {
4032 cfg->code_size += max_len;
4033 cfg->code_size *= 2;
4034 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4035 code = cfg->native_code + offset;
4037 g_assert (ins->sreg1 != -1);
4038 mips_sll (code, mips_at, ins->sreg1, 2);
4039 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4040 MIPS_MOVE (code, mips_t8, mips_ra);
4041 mips_bgezal (code, mips_zero, 1); /* bal */
4043 mips_addu (code, mips_t9, mips_ra, mips_at);
4044 /* Table is 16 or 20 bytes from target of bal above */
4045 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4046 MIPS_MOVE (code, mips_ra, mips_t8);
4047 mips_lw (code, mips_t9, mips_t9, 20);
4050 mips_lw (code, mips_t9, mips_t9, 16);
4051 mips_jalr (code, mips_t9, mips_t8);
4053 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4054 mips_emit32 (code, 0xfefefefe);
4059 mips_addiu (code, ins->dreg, mips_zero, 1);
4060 mips_beq (code, mips_at, mips_zero, 2);
4062 MIPS_MOVE (code, ins->dreg, mips_zero);
4068 mips_addiu (code, ins->dreg, mips_zero, 1);
4069 mips_bltz (code, mips_at, 2);
4071 MIPS_MOVE (code, ins->dreg, mips_zero);
4077 mips_addiu (code, ins->dreg, mips_zero, 1);
4078 mips_bgtz (code, mips_at, 2);
4080 MIPS_MOVE (code, ins->dreg, mips_zero);
4083 case OP_MIPS_COND_EXC_EQ:
4084 case OP_MIPS_COND_EXC_GE:
4085 case OP_MIPS_COND_EXC_GT:
4086 case OP_MIPS_COND_EXC_LE:
4087 case OP_MIPS_COND_EXC_LT:
4088 case OP_MIPS_COND_EXC_NE_UN:
4089 case OP_MIPS_COND_EXC_GE_UN:
4090 case OP_MIPS_COND_EXC_GT_UN:
4091 case OP_MIPS_COND_EXC_LE_UN:
4092 case OP_MIPS_COND_EXC_LT_UN:
4094 case OP_MIPS_COND_EXC_OV:
4095 case OP_MIPS_COND_EXC_NO:
4096 case OP_MIPS_COND_EXC_C:
4097 case OP_MIPS_COND_EXC_NC:
4099 case OP_MIPS_COND_EXC_IEQ:
4100 case OP_MIPS_COND_EXC_IGE:
4101 case OP_MIPS_COND_EXC_IGT:
4102 case OP_MIPS_COND_EXC_ILE:
4103 case OP_MIPS_COND_EXC_ILT:
4104 case OP_MIPS_COND_EXC_INE_UN:
4105 case OP_MIPS_COND_EXC_IGE_UN:
4106 case OP_MIPS_COND_EXC_IGT_UN:
4107 case OP_MIPS_COND_EXC_ILE_UN:
4108 case OP_MIPS_COND_EXC_ILT_UN:
4110 case OP_MIPS_COND_EXC_IOV:
4111 case OP_MIPS_COND_EXC_INO:
4112 case OP_MIPS_COND_EXC_IC:
4113 case OP_MIPS_COND_EXC_INC: {
4117 /* If the condition is true, raise the exception */
4119 /* need to reverse test to skip around exception raising */
4121 /* For the moment, branch around a branch to avoid reversing
4124 /* Remember, an unpatched branch to 0 branches to the delay slot */
4125 switch (ins->opcode) {
4126 case OP_MIPS_COND_EXC_EQ:
4127 throw = (guint32 *)(void *)code;
4128 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4132 case OP_MIPS_COND_EXC_NE_UN:
4133 throw = (guint32 *)(void *)code;
4134 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4138 case OP_MIPS_COND_EXC_LE_UN:
4139 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4140 throw = (guint32 *)(void *)code;
4141 mips_beq (code, mips_at, mips_zero, 0);
4145 case OP_MIPS_COND_EXC_GT:
4146 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4147 throw = (guint32 *)(void *)code;
4148 mips_bne (code, mips_at, mips_zero, 0);
4152 case OP_MIPS_COND_EXC_GT_UN:
4153 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4154 throw = (guint32 *)(void *)code;
4155 mips_bne (code, mips_at, mips_zero, 0);
4159 case OP_MIPS_COND_EXC_LT:
4160 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4161 throw = (guint32 *)(void *)code;
4162 mips_bne (code, mips_at, mips_zero, 0);
4166 case OP_MIPS_COND_EXC_LT_UN:
4167 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4168 throw = (guint32 *)(void *)code;
4169 mips_bne (code, mips_at, mips_zero, 0);
4174 /* Not yet implemented */
4175 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4176 g_assert_not_reached ();
4178 skip = (guint32 *)(void *)code;
4179 mips_beq (code, mips_zero, mips_zero, 0);
4181 mips_patch (throw, (guint32)code);
4182 code = mips_emit_exc_by_name (code, ins->inst_p1);
4183 mips_patch (skip, (guint32)code);
4184 cfg->bb_exit->max_offset += 24;
4193 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4196 /* floating point opcodes */
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_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4205 mips_load_const (code, mips_at, ins->inst_p0);
4206 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4207 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4211 if (((guint32)ins->inst_p0) & (1 << 15))
4212 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4214 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4215 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4216 #if PROMOTE_R4_TO_R8
4217 mips_cvtds (code, ins->dreg, ins->dreg);
4220 case OP_STORER8_MEMBASE_REG:
4221 if (mips_is_imm16 (ins->inst_offset)) {
4222 #if _MIPS_SIM == _ABIO32
4223 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4224 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4225 #elif _MIPS_SIM == _ABIN32
4226 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4229 mips_load_const (code, mips_at, ins->inst_offset);
4230 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4231 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4232 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4235 case OP_LOADR8_MEMBASE:
4236 if (mips_is_imm16 (ins->inst_offset)) {
4237 #if _MIPS_SIM == _ABIO32
4238 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4239 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4240 #elif _MIPS_SIM == _ABIN32
4241 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4244 mips_load_const (code, mips_at, ins->inst_offset);
4245 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4246 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4247 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4250 case OP_STORER4_MEMBASE_REG:
4251 g_assert (mips_is_imm16 (ins->inst_offset));
4252 #if PROMOTE_R4_TO_R8
4253 /* Need to convert ins->sreg1 to single-precision first */
4254 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4255 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4257 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4261 g_assert (mips_is_imm16 (ins->inst_offset));
4262 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4264 case OP_LOADR4_MEMBASE:
4265 g_assert (mips_is_imm16 (ins->inst_offset));
4266 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4267 #if PROMOTE_R4_TO_R8
4268 /* Convert to double precision in place */
4269 mips_cvtds (code, ins->dreg, ins->dreg);
4272 case OP_LOADR4_MEMINDEX:
4273 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4274 mips_lwc1 (code, ins->dreg, mips_at, 0);
4276 case OP_LOADR8_MEMINDEX:
4277 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4278 #if _MIPS_SIM == _ABIO32
4279 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4280 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4281 #elif _MIPS_SIM == _ABIN32
4282 mips_ldc1 (code, ins->dreg, mips_at, 0);
4285 case OP_STORER4_MEMINDEX:
4286 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4287 #if PROMOTE_R4_TO_R8
4288 /* Need to convert ins->sreg1 to single-precision first */
4289 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4290 mips_swc1 (code, mips_ftemp, mips_at, 0);
4292 mips_swc1 (code, ins->sreg1, mips_at, 0);
4295 case OP_STORER8_MEMINDEX:
4296 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4297 #if _MIPS_SIM == _ABIO32
4298 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4299 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4300 #elif _MIPS_SIM == _ABIN32
4301 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4304 case OP_ICONV_TO_R_UN: {
4305 static const guint64 adjust_val = 0x41F0000000000000ULL;
4307 /* convert unsigned int to double */
4308 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4309 mips_bgez (code, ins->sreg1, 5);
4310 mips_cvtdw (code, ins->dreg, mips_ftemp);
4312 mips_load (code, mips_at, (guint32) &adjust_val);
4313 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4314 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4315 /* target is here */
4318 case OP_ICONV_TO_R4:
4319 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4320 mips_cvtsw (code, ins->dreg, mips_ftemp);
4321 mips_cvtds (code, ins->dreg, ins->dreg);
4323 case OP_ICONV_TO_R8:
4324 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4325 mips_cvtdw (code, ins->dreg, mips_ftemp);
4327 case OP_FCONV_TO_I1:
4328 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4330 case OP_FCONV_TO_U1:
4331 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4333 case OP_FCONV_TO_I2:
4334 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4336 case OP_FCONV_TO_U2:
4337 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4339 case OP_FCONV_TO_I4:
4341 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4343 case OP_FCONV_TO_U4:
4345 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4348 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4351 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4354 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4357 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4360 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4363 mips_fnegd (code, ins->dreg, ins->sreg1);
4366 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4367 mips_addiu (code, ins->dreg, mips_zero, 1);
4368 mips_fbtrue (code, 2);
4370 MIPS_MOVE (code, ins->dreg, mips_zero);
4373 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4374 mips_addiu (code, ins->dreg, mips_zero, 1);
4375 mips_fbtrue (code, 2);
4377 MIPS_MOVE (code, ins->dreg, mips_zero);
4380 /* Less than, or Unordered */
4381 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4382 mips_addiu (code, ins->dreg, mips_zero, 1);
4383 mips_fbtrue (code, 2);
4385 MIPS_MOVE (code, ins->dreg, mips_zero);
4388 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4389 MIPS_MOVE (code, ins->dreg, mips_zero);
4390 mips_fbtrue (code, 2);
4392 mips_addiu (code, ins->dreg, mips_zero, 1);
4395 /* Greater than, or Unordered */
4396 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4397 MIPS_MOVE (code, ins->dreg, mips_zero);
4398 mips_fbtrue (code, 2);
4400 mips_addiu (code, ins->dreg, mips_zero, 1);
4405 case OP_MIPS_FBLT_UN:
4407 case OP_MIPS_FBGT_UN:
4409 case OP_MIPS_FBGE_UN:
4411 case OP_MIPS_FBLE_UN: {
4413 gboolean is_true = TRUE, is_ordered = FALSE;
4414 guint32 *buf = NULL;
4416 switch (ins->opcode) {
4430 case OP_MIPS_FBLT_UN:
4431 cond = MIPS_FPU_ULT;
4439 case OP_MIPS_FBGT_UN:
4440 cond = MIPS_FPU_OLE;
4448 case OP_MIPS_FBGE_UN:
4449 cond = MIPS_FPU_OLT;
4453 cond = MIPS_FPU_OLE;
4457 case OP_MIPS_FBLE_UN:
4458 cond = MIPS_FPU_ULE;
4462 g_assert_not_reached ();
4466 /* Skip the check if unordered */
4467 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4469 buf = (guint32*)code;
4470 mips_fbtrue (code, 0);
4474 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4476 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4478 mips_fbtrue (code, 0);
4480 mips_fbfalse (code, 0);
4484 mips_patch (buf, (guint32)code);
4488 guint32 *branch_patch;
4490 mips_mfc1 (code, mips_at, ins->sreg1+1);
4491 mips_srl (code, mips_at, mips_at, 16+4);
4492 mips_andi (code, mips_at, mips_at, 2047);
4493 mips_addiu (code, mips_at, mips_at, -2047);
4495 branch_patch = (guint32 *)(void *)code;
4496 mips_bne (code, mips_at, mips_zero, 0);
4499 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4500 mips_patch (branch_patch, (guint32)code);
4501 mips_fmovd (code, ins->dreg, ins->sreg1);
4505 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4506 mips_load (code, ins->dreg, 0x0f0f0f0f);
4508 case OP_GC_SAFE_POINT:
4513 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4514 g_assert_not_reached ();
4517 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4518 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4519 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4520 g_assert_not_reached ();
4526 last_offset = offset;
4529 cfg->code_len = code - cfg->native_code;
4533 mono_arch_register_lowlevel_calls (void)
4538 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors, MonoError *error)
4540 MonoJumpInfo *patch_info;
4544 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4545 unsigned char *ip = patch_info->ip.i + code;
4546 const unsigned char *target = NULL;
4548 switch (patch_info->type) {
4549 case MONO_PATCH_INFO_IP:
4550 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4552 case MONO_PATCH_INFO_SWITCH: {
4553 gpointer *table = (gpointer *)patch_info->data.table->table;
4556 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4558 for (i = 0; i < patch_info->data.table->table_size; i++) {
4559 table [i] = (int)patch_info->data.table->table [i] + code;
4563 case MONO_PATCH_INFO_METHODCONST:
4564 case MONO_PATCH_INFO_CLASS:
4565 case MONO_PATCH_INFO_IMAGE:
4566 case MONO_PATCH_INFO_FIELD:
4567 case MONO_PATCH_INFO_VTABLE:
4568 case MONO_PATCH_INFO_IID:
4569 case MONO_PATCH_INFO_SFLDA:
4570 case MONO_PATCH_INFO_LDSTR:
4571 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4572 case MONO_PATCH_INFO_LDTOKEN:
4573 case MONO_PATCH_INFO_R4:
4574 case MONO_PATCH_INFO_R8:
4575 /* from OP_AOTCONST : lui + addiu */
4576 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4577 return_if_nok (error);
4579 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4582 case MONO_PATCH_INFO_EXC_NAME:
4583 g_assert_not_reached ();
4584 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4587 case MONO_PATCH_INFO_NONE:
4588 /* everything is dealt with at epilog output time */
4591 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, error);
4592 return_if_nok (error);
4594 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4601 * Allow tracing to work with this interface (with an optional argument)
4603 * This code is expected to be inserted just after the 'real' prolog code,
4604 * and before the first basic block. We need to allocate a 2nd, temporary
4605 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4609 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4612 int offset = cfg->arch.tracing_offset;
4618 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4619 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4620 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4621 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4622 #if _MIPS_SIM == _ABIN32
4624 /* FIXME: Need a separate region for these */
4625 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4626 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4627 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4628 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4632 mips_load_const (code, mips_a0, cfg->method);
4633 mips_addiu (code, mips_a1, mips_sp, offset);
4634 mips_call (code, mips_t9, func);
4637 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4638 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4639 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4640 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4641 #if _MIPS_SIM == _ABIN32
4644 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4645 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4646 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4647 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4658 mips_adjust_stackframe(MonoCompile *cfg)
4661 int delta, threshold, i;
4662 MonoMethodSignature *sig;
4665 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4668 /* adjust cfg->stack_offset for account for down-spilling */
4669 cfg->stack_offset += SIZEOF_REGISTER;
4671 /* re-align cfg->stack_offset if needed (due to var spilling) */
4672 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4673 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4674 if (cfg->verbose_level > 2) {
4675 g_print ("mips_adjust_stackframe:\n");
4676 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4678 threshold = cfg->arch.local_alloc_offset;
4679 ra_offset = cfg->stack_offset - sizeof(gpointer);
4680 if (cfg->verbose_level > 2) {
4681 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4684 sig = mono_method_signature (cfg->method);
4685 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4686 cfg->vret_addr->inst_offset += delta;
4688 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4689 MonoInst *inst = cfg->args [i];
4691 inst->inst_offset += delta;
4695 * loads and stores based off the frame reg that (used to) lie
4696 * above the spill var area need to be increased by 'delta'
4697 * to make room for the spill vars.
4699 /* Need to find loads and stores to adjust that
4700 * are above where the spillvars were inserted, but
4701 * which are not the spillvar references themselves.
4703 * Idea - since all offsets from fp are positive, make
4704 * spillvar offsets negative to begin with so we can spot
4709 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4713 if (cfg->verbose_level > 2) {
4714 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4716 MONO_BB_FOR_EACH_INS (bb, ins) {
4720 if (cfg->verbose_level > 2) {
4721 mono_print_ins_index (ins_cnt, ins);
4723 /* The == mips_sp tests catch FP spills */
4724 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4725 (ins->inst_basereg == mips_sp))) {
4726 switch (ins->opcode) {
4727 case OP_LOADI8_MEMBASE:
4728 case OP_LOADR8_MEMBASE:
4735 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4736 (ins->dreg == mips_sp))) {
4737 switch (ins->opcode) {
4738 case OP_STOREI8_MEMBASE_REG:
4739 case OP_STORER8_MEMBASE_REG:
4740 case OP_STOREI8_MEMBASE_IMM:
4748 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4751 if (ins->inst_c0 >= threshold) {
4752 ins->inst_c0 += delta;
4753 if (cfg->verbose_level > 2) {
4755 mono_print_ins_index (ins_cnt, ins);
4758 else if (ins->inst_c0 < 0) {
4759 /* Adj_c0 holds the size of the datatype. */
4760 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4761 if (cfg->verbose_level > 2) {
4763 mono_print_ins_index (ins_cnt, ins);
4766 g_assert (ins->inst_c0 != ra_offset);
4769 if (ins->inst_imm >= threshold) {
4770 ins->inst_imm += delta;
4771 if (cfg->verbose_level > 2) {
4773 mono_print_ins_index (ins_cnt, ins);
4776 g_assert (ins->inst_c0 != ra_offset);
4786 * Stack frame layout:
4788 * ------------------- sp + cfg->stack_usage + cfg->param_area
4789 * param area incoming
4790 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4792 * ------------------- sp + cfg->stack_usage
4794 * ------------------- sp + cfg->stack_usage-4
4796 * ------------------- sp +
4797 * MonoLMF structure optional
4798 * ------------------- sp + cfg->arch.lmf_offset
4799 * saved registers s0-s8
4800 * ------------------- sp + cfg->arch.iregs_offset
4802 * ------------------- sp + cfg->param_area
4803 * param area outgoing
4804 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4806 * ------------------- sp
4810 mono_arch_emit_prolog (MonoCompile *cfg)
4812 MonoMethod *method = cfg->method;
4813 MonoMethodSignature *sig;
4815 int alloc_size, pos, i, max_offset;
4816 int alloc2_size = 0;
4820 guint32 iregs_to_save = 0;
4822 guint32 fregs_to_save = 0;
4824 /* lmf_offset is the offset of the LMF from our stack pointer. */
4825 guint32 lmf_offset = cfg->arch.lmf_offset;
4829 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4833 cfg->flags |= MONO_CFG_HAS_CALLS;
4835 sig = mono_method_signature (method);
4836 cfg->code_size = 768 + sig->param_count * 20;
4837 code = cfg->native_code = g_malloc (cfg->code_size);
4840 * compute max_offset in order to use short forward jumps.
4843 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4844 MonoInst *ins = bb->code;
4845 bb->max_offset = max_offset;
4847 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4850 MONO_BB_FOR_EACH_INS (bb, ins)
4851 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4853 if (max_offset > 0xffff)
4854 cfg->arch.long_branch = TRUE;
4857 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4858 * This means that we have to adjust the offsets inside instructions which reference
4859 * arguments received on the stack, since the initial offset doesn't take into
4860 * account spill slots.
4862 mips_adjust_stackframe (cfg);
4864 /* Offset between current sp and the CFA */
4866 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4868 /* stack_offset should not be changed here. */
4869 alloc_size = cfg->stack_offset;
4870 cfg->stack_usage = alloc_size;
4872 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4875 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4877 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4878 fregs_to_save |= (fregs_to_save << 1);
4881 /* If the stack size is too big, save 1024 bytes to start with
4882 * so the prologue can use imm16(reg) addressing, then allocate
4883 * the rest of the frame.
4885 if (alloc_size > ((1 << 15) - 1024)) {
4886 alloc2_size = alloc_size - 1024;
4890 g_assert (mips_is_imm16 (-alloc_size));
4891 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4892 cfa_offset = alloc_size;
4893 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4896 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4897 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4898 if (mips_is_imm16(offset))
4899 mips_sw (code, mips_ra, mips_sp, offset);
4901 g_assert_not_reached ();
4903 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4904 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4907 /* XXX - optimize this later to not save all regs if LMF constructed */
4908 pos = cfg->arch.iregs_offset - alloc2_size;
4910 if (iregs_to_save) {
4911 /* save used registers in own stack frame (at pos) */
4912 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4913 if (iregs_to_save & (1 << i)) {
4914 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4915 g_assert (mips_is_imm16(pos));
4916 MIPS_SW (code, i, mips_sp, pos);
4917 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4918 pos += SIZEOF_REGISTER;
4923 // FIXME: Don't save registers twice if there is an LMF
4924 // s8 has to be special cased since it is overwritten with the updated value
4926 if (method->save_lmf) {
4927 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4928 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4929 g_assert (mips_is_imm16(offset));
4930 if (MIPS_LMF_IREGMASK & (1 << i))
4931 MIPS_SW (code, i, mips_sp, offset);
4936 /* Save float registers */
4937 if (fregs_to_save) {
4938 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4939 if (fregs_to_save & (1 << i)) {
4940 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4941 g_assert (mips_is_imm16(pos));
4942 mips_swc1 (code, i, mips_sp, pos);
4943 pos += sizeof (gulong);
4948 if (method->save_lmf) {
4949 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4950 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4951 g_assert (mips_is_imm16(offset));
4952 mips_swc1 (code, i, mips_sp, offset);
4957 if (cfg->frame_reg != mips_sp) {
4958 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4959 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4961 if (method->save_lmf) {
4962 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4963 g_assert (mips_is_imm16(offset));
4964 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4968 /* store runtime generic context */
4969 if (cfg->rgctx_var) {
4970 MonoInst *ins = cfg->rgctx_var;
4972 g_assert (ins->opcode == OP_REGOFFSET);
4974 g_assert (mips_is_imm16 (ins->inst_offset));
4975 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4978 /* load arguments allocated to register from the stack */
4981 if (!cfg->arch.cinfo)
4982 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
4983 cinfo = cfg->arch.cinfo;
4985 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4986 ArgInfo *ainfo = &cinfo->ret;
4987 inst = cfg->vret_addr;
4988 if (inst->opcode == OP_REGVAR)
4989 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4990 else if (mips_is_imm16 (inst->inst_offset)) {
4991 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4993 mips_load_const (code, mips_at, inst->inst_offset);
4994 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4995 mips_sw (code, ainfo->reg, mips_at, 0);
4999 if (sig->call_convention == MONO_CALL_VARARG) {
5000 ArgInfo *cookie = &cinfo->sig_cookie;
5001 int offset = alloc_size + cookie->offset;
5003 /* Save the sig cookie address */
5004 g_assert (cookie->storage == ArgOnStack);
5006 g_assert (mips_is_imm16(offset));
5007 mips_addi (code, mips_at, cfg->frame_reg, offset);
5008 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5011 /* Keep this in sync with emit_load_volatile_arguments */
5012 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5013 ArgInfo *ainfo = cinfo->args + i;
5014 inst = cfg->args [pos];
5016 if (cfg->verbose_level > 2)
5017 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5018 if (inst->opcode == OP_REGVAR) {
5019 /* Argument ends up in a register */
5020 if (ainfo->storage == ArgInIReg)
5021 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5022 else if (ainfo->storage == ArgInFReg) {
5023 g_assert_not_reached();
5025 ppc_fmr (code, inst->dreg, ainfo->reg);
5028 else if (ainfo->storage == ArgOnStack) {
5029 int offset = cfg->stack_usage + ainfo->offset;
5030 g_assert (mips_is_imm16(offset));
5031 mips_lw (code, inst->dreg, mips_sp, offset);
5033 g_assert_not_reached ();
5035 if (cfg->verbose_level > 2)
5036 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5038 /* Argument ends up on the stack */
5039 if (ainfo->storage == ArgInIReg) {
5041 /* Incoming parameters should be above this frame */
5042 if (cfg->verbose_level > 2)
5043 g_print ("stack slot at %d of %d+%d\n",
5044 inst->inst_offset, alloc_size, alloc2_size);
5045 /* g_assert (inst->inst_offset >= alloc_size); */
5046 g_assert (inst->inst_basereg == cfg->frame_reg);
5047 basereg_offset = inst->inst_offset - alloc2_size;
5048 g_assert (mips_is_imm16 (basereg_offset));
5049 switch (ainfo->size) {
5051 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5054 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5058 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5061 #if (SIZEOF_REGISTER == 4)
5062 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5063 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5064 #elif (SIZEOF_REGISTER == 8)
5065 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5069 g_assert_not_reached ();
5072 } else if (ainfo->storage == ArgOnStack) {
5074 * Argument comes in on the stack, and ends up on the stack
5075 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5076 * 8 and 16 bit quantities. Shorten them in place.
5078 g_assert (mips_is_imm16 (inst->inst_offset));
5079 switch (ainfo->size) {
5081 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5082 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5085 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5086 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5093 g_assert_not_reached ();
5095 } else if (ainfo->storage == ArgInFReg) {
5096 g_assert (mips_is_imm16 (inst->inst_offset));
5097 g_assert (mips_is_imm16 (inst->inst_offset+4));
5098 if (ainfo->size == 8) {
5099 #if _MIPS_SIM == _ABIO32
5100 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5101 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5102 #elif _MIPS_SIM == _ABIN32
5103 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5106 else if (ainfo->size == 4)
5107 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5109 g_assert_not_reached ();
5110 } else if (ainfo->storage == ArgStructByVal) {
5112 int doffset = inst->inst_offset;
5114 g_assert (mips_is_imm16 (inst->inst_offset));
5115 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5116 /* Push the argument registers into their stack slots */
5117 for (i = 0; i < ainfo->size; ++i) {
5118 g_assert (mips_is_imm16(doffset));
5119 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5120 doffset += SIZEOF_REGISTER;
5122 } else if (ainfo->storage == ArgStructByAddr) {
5123 g_assert (mips_is_imm16 (inst->inst_offset));
5124 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5125 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5127 g_assert_not_reached ();
5132 if (method->save_lmf) {
5133 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5134 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5136 /* This can/will clobber the a0-a3 registers */
5137 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5139 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5140 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5141 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5142 /* new_lmf->previous_lmf = *lmf_addr */
5143 mips_lw (code, mips_at, mips_v0, 0);
5144 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5145 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5146 /* *(lmf_addr) = sp + lmf_offset */
5147 g_assert (mips_is_imm16(lmf_offset));
5148 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5149 mips_sw (code, mips_at, mips_v0, 0);
5151 /* save method info */
5152 mips_load_const (code, mips_at, method);
5153 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5154 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5156 /* save the current IP */
5157 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5158 mips_load_const (code, mips_at, 0x01010101);
5159 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5163 if (mips_is_imm16 (-alloc2_size)) {
5164 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5167 mips_load_const (code, mips_at, -alloc2_size);
5168 mips_addu (code, mips_sp, mips_sp, mips_at);
5170 alloc_size += alloc2_size;
5171 cfa_offset += alloc2_size;
5172 if (cfg->frame_reg != mips_sp)
5173 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5175 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5179 #if _MIPS_SIM == _ABIO32
5180 cfg->arch.tracing_offset = cfg->stack_offset;
5181 #elif _MIPS_SIM == _ABIN32
5182 /* no stack slots by default for argument regs, reserve a special block */
5183 g_assert_not_reached ();
5185 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5188 cfg->code_len = code - cfg->native_code;
5189 g_assert (cfg->code_len < cfg->code_size);
5203 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5206 int save_mode = SAVE_NONE;
5208 MonoMethod *method = cfg->method;
5209 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5210 int save_offset = MIPS_STACK_PARAM_OFFSET;
5212 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5214 offset = code - cfg->native_code;
5215 /* we need about 16 instructions */
5216 if (offset > (cfg->code_size - 16 * 4)) {
5217 cfg->code_size *= 2;
5218 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5219 code = cfg->native_code + offset;
5224 case MONO_TYPE_VOID:
5225 /* special case string .ctor icall */
5226 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5227 save_mode = SAVE_ONE;
5229 save_mode = SAVE_NONE;
5233 save_mode = SAVE_FP;
5235 case MONO_TYPE_VALUETYPE:
5236 save_mode = SAVE_STRUCT;
5240 #if SIZEOF_REGISTER == 4
5241 save_mode = SAVE_TWO;
5242 #elif SIZEOF_REGISTER == 8
5243 save_mode = SAVE_ONE;
5247 save_mode = SAVE_ONE;
5251 mips_addiu (code, mips_sp, mips_sp, -32);
5252 g_assert (mips_is_imm16(save_offset));
5253 switch (save_mode) {
5255 mips_sw (code, mips_v0, mips_sp, save_offset);
5256 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5257 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5258 if (enable_arguments) {
5259 MIPS_MOVE (code, mips_a1, mips_v0);
5260 MIPS_MOVE (code, mips_a2, mips_v1);
5264 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5265 if (enable_arguments) {
5266 MIPS_MOVE (code, mips_a1, mips_v0);
5270 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5271 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5272 mips_lw (code, mips_a0, mips_sp, save_offset);
5273 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5274 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5281 mips_load_const (code, mips_a0, cfg->method);
5282 mips_call (code, mips_t9, func);
5284 switch (save_mode) {
5286 mips_lw (code, mips_v0, mips_sp, save_offset);
5287 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5288 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5291 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5294 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5301 mips_addiu (code, mips_sp, mips_sp, 32);
5308 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5310 MonoMethod *method = cfg->method;
5312 int max_epilog_size = 16 + 20*4;
5313 int alloc2_size = 0;
5314 guint32 iregs_to_restore;
5316 guint32 fregs_to_restore;
5319 if (cfg->method->save_lmf)
5320 max_epilog_size += 128;
5322 if (mono_jit_trace_calls != NULL)
5323 max_epilog_size += 50;
5325 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5326 max_epilog_size += 50;
5329 pos = code - cfg->native_code;
5330 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5331 cfg->code_size *= 2;
5332 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5333 cfg->stat_code_reallocs++;
5337 * Keep in sync with OP_JMP
5340 code = cfg->native_code + pos;
5342 code = cfg->native_code + cfg->code_len;
5344 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5345 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5347 if (cfg->frame_reg != mips_sp) {
5348 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5350 /* If the stack frame is really large, deconstruct it in two steps */
5351 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5352 alloc2_size = cfg->stack_usage - 1024;
5353 /* partially deconstruct the stack */
5354 mips_load_const (code, mips_at, alloc2_size);
5355 mips_addu (code, mips_sp, mips_sp, mips_at);
5357 pos = cfg->arch.iregs_offset - alloc2_size;
5358 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5359 if (iregs_to_restore) {
5360 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5361 if (iregs_to_restore & (1 << i)) {
5362 g_assert (mips_is_imm16(pos));
5363 MIPS_LW (code, i, mips_sp, pos);
5364 pos += SIZEOF_REGISTER;
5371 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5373 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5374 fregs_to_restore |= (fregs_to_restore << 1);
5376 if (fregs_to_restore) {
5377 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5378 if (fregs_to_restore & (1 << i)) {
5379 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5380 g_assert (mips_is_imm16(pos));
5381 mips_lwc1 (code, i, mips_sp, pos);
5388 /* Unlink the LMF if necessary */
5389 if (method->save_lmf) {
5390 int lmf_offset = cfg->arch.lmf_offset;
5392 /* t0 = current_lmf->previous_lmf */
5393 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5394 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5396 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5397 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5398 /* (*lmf_addr) = previous_lmf */
5399 mips_sw (code, mips_temp, mips_t1, 0);
5403 /* Restore the fp */
5404 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5407 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5408 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5409 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5411 /* Restore the stack pointer */
5412 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5413 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5415 /* Caller will emit either return or tail-call sequence */
5417 cfg->code_len = code - cfg->native_code;
5419 g_assert (cfg->code_len < cfg->code_size);
5424 mono_arch_emit_epilog (MonoCompile *cfg)
5428 code = mono_arch_emit_epilog_sub (cfg, NULL);
5430 mips_jr (code, mips_ra);
5433 cfg->code_len = code - cfg->native_code;
5435 g_assert (cfg->code_len < cfg->code_size);
5438 /* remove once throw_exception_by_name is eliminated */
5441 exception_id_by_name (const char *name)
5443 if (strcmp (name, "IndexOutOfRangeException") == 0)
5444 return MONO_EXC_INDEX_OUT_OF_RANGE;
5445 if (strcmp (name, "OverflowException") == 0)
5446 return MONO_EXC_OVERFLOW;
5447 if (strcmp (name, "ArithmeticException") == 0)
5448 return MONO_EXC_ARITHMETIC;
5449 if (strcmp (name, "DivideByZeroException") == 0)
5450 return MONO_EXC_DIVIDE_BY_ZERO;
5451 if (strcmp (name, "InvalidCastException") == 0)
5452 return MONO_EXC_INVALID_CAST;
5453 if (strcmp (name, "NullReferenceException") == 0)
5454 return MONO_EXC_NULL_REF;
5455 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5456 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5457 if (strcmp (name, "ArgumentException") == 0)
5458 return MONO_EXC_ARGUMENT;
5459 g_error ("Unknown intrinsic exception %s\n", name);
5465 mono_arch_emit_exceptions (MonoCompile *cfg)
5468 MonoJumpInfo *patch_info;
5471 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5472 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5473 int max_epilog_size = 50;
5475 /* count the number of exception infos */
5478 * make sure we have enough space for exceptions
5479 * 24 is the simulated call to throw_exception_by_name
5481 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5483 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5484 i = exception_id_by_name (patch_info->data.target);
5485 g_assert (i < MONO_EXC_INTRINS_NUM);
5486 if (!exc_throw_found [i]) {
5487 max_epilog_size += 12;
5488 exc_throw_found [i] = TRUE;
5494 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5495 cfg->code_size *= 2;
5496 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5497 cfg->stat_code_reallocs++;
5500 code = cfg->native_code + cfg->code_len;
5502 /* add code to raise exceptions */
5503 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5504 switch (patch_info->type) {
5505 case MONO_PATCH_INFO_EXC: {
5507 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5509 i = exception_id_by_name (patch_info->data.target);
5510 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5511 if (!exc_throw_pos [i]) {
5514 exc_throw_pos [i] = code;
5515 //g_print ("exc: writing stub at %p\n", code);
5516 mips_load_const (code, mips_a0, patch_info->data.target);
5517 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5518 mips_load_const (code, mips_t9, addr);
5519 mips_jr (code, mips_t9);
5522 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5524 /* Turn into a Relative patch, pointing at code stub */
5525 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5526 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5528 g_assert_not_reached();
5538 cfg->code_len = code - cfg->native_code;
5540 g_assert (cfg->code_len < cfg->code_size);
5545 mono_arch_finish_init (void)
5550 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5555 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5557 int this_dreg = mips_a0;
5560 this_dreg = mips_a1;
5562 /* add the this argument */
5563 if (this_reg != -1) {
5565 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5566 this_ins->type = this_type;
5567 this_ins->sreg1 = this_reg;
5568 this_ins->dreg = mono_alloc_ireg (cfg);
5569 mono_bblock_add_inst (cfg->cbb, this_ins);
5570 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5575 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5576 vtarg->type = STACK_MP;
5577 vtarg->sreg1 = vt_reg;
5578 vtarg->dreg = mono_alloc_ireg (cfg);
5579 mono_bblock_add_inst (cfg->cbb, vtarg);
5580 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5585 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5587 MonoInst *ins = NULL;
5593 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5599 mono_arch_print_tree (MonoInst *tree, int arity)
5605 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5607 return ctx->sc_regs [reg];
5610 #define ENABLE_WRONG_METHOD_CHECK 0
5612 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5613 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5615 #define LOADSTORE_SIZE 4
5616 #define JUMP_IMM_SIZE 16
5617 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5618 #define LOAD_CONST_SIZE 8
5619 #define JUMP_JR_SIZE 8
5622 * LOCKING: called with the domain lock held
5625 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5626 gpointer fail_tramp)
5630 guint8 *code, *start, *patch;
5632 for (i = 0; i < count; ++i) {
5633 MonoIMTCheckItem *item = imt_entries [i];
5635 if (item->is_equals) {
5636 if (item->check_target_idx) {
5637 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5638 if (item->has_target_code)
5639 item->chunk_size += LOAD_CONST_SIZE;
5641 item->chunk_size += LOADSTORE_SIZE;
5644 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5645 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5646 if (!item->has_target_code)
5647 item->chunk_size += LOADSTORE_SIZE;
5649 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5650 #if ENABLE_WRONG_METHOD_CHECK
5651 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5656 item->chunk_size += CMP_SIZE + BR_SIZE;
5657 imt_entries [item->check_target_idx]->compare_done = TRUE;
5659 size += item->chunk_size;
5661 /* the initial load of the vtable address */
5662 size += MIPS_LOAD_SEQUENCE_LENGTH;
5664 code = mono_method_alloc_generic_virtual_trampoline (domain, size);
5666 code = mono_domain_code_reserve (domain, size);
5670 /* t7 points to the vtable */
5671 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5673 for (i = 0; i < count; ++i) {
5674 MonoIMTCheckItem *item = imt_entries [i];
5676 item->code_target = code;
5677 if (item->is_equals) {
5678 if (item->check_target_idx) {
5679 mips_load_const (code, mips_temp, (gsize)item->key);
5680 item->jmp_code = code;
5681 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5683 if (item->has_target_code) {
5684 mips_load_const (code, mips_t9,
5685 item->value.target_code);
5688 mips_lw (code, mips_t9, mips_t7,
5689 (sizeof (gpointer) * item->value.vtable_slot));
5691 mips_jr (code, mips_t9);
5695 mips_load_const (code, mips_temp, (gsize)item->key);
5697 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5699 if (item->has_target_code) {
5700 mips_load_const (code, mips_t9,
5701 item->value.target_code);
5704 mips_load_const (code, mips_at,
5705 & (vtable->vtable [item->value.vtable_slot]));
5706 mips_lw (code, mips_t9, mips_at, 0);
5708 mips_jr (code, mips_t9);
5710 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5711 mips_load_const (code, mips_t9, fail_tramp);
5712 mips_jr (code, mips_t9);
5715 /* enable the commented code to assert on wrong method */
5716 #if ENABLE_WRONG_METHOD_CHECK
5717 ppc_load (code, ppc_r0, (guint32)item->key);
5718 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5720 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5722 mips_lw (code, mips_t9, mips_t7,
5723 (sizeof (gpointer) * item->value.vtable_slot));
5724 mips_jr (code, mips_t9);
5727 #if ENABLE_WRONG_METHOD_CHECK
5728 ppc_patch (patch, code);
5734 mips_load_const (code, mips_temp, (gulong)item->key);
5735 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5737 item->jmp_code = code;
5738 mips_beq (code, mips_temp, mips_zero, 0);
5742 /* patch the branches to get to the target items */
5743 for (i = 0; i < count; ++i) {
5744 MonoIMTCheckItem *item = imt_entries [i];
5745 if (item->jmp_code && item->check_target_idx) {
5746 mips_patch ((guint32 *)item->jmp_code,
5747 (guint32)imt_entries [item->check_target_idx]->code_target);
5752 mono_stats.imt_trampolines_size += code - start;
5753 g_assert (code - start <= size);
5754 mono_arch_flush_icache (start, size);
5756 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
5762 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5764 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5768 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5770 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5773 /* Soft Debug support */
5774 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5777 * mono_arch_set_breakpoint:
5779 * See mini-amd64.c for docs.
5782 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5785 guint32 addr = (guint32)bp_trigger_page;
5787 mips_load_const (code, mips_t9, addr);
5788 mips_lw (code, mips_t9, mips_t9, 0);
5790 mono_arch_flush_icache (ip, code - ip);
5794 * mono_arch_clear_breakpoint:
5796 * See mini-amd64.c for docs.
5799 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5807 mono_arch_flush_icache (ip, code - ip);
5811 * mono_arch_start_single_stepping:
5813 * See mini-amd64.c for docs.
5816 mono_arch_start_single_stepping (void)
5818 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5822 * mono_arch_stop_single_stepping:
5824 * See mini-amd64.c for docs.
5827 mono_arch_stop_single_stepping (void)
5829 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5833 * mono_arch_is_single_step_event:
5835 * See mini-amd64.c for docs.
5838 mono_arch_is_single_step_event (void *info, void *sigctx)
5840 siginfo_t* sinfo = (siginfo_t*) info;
5841 /* Sometimes the address is off by 4 */
5842 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5849 * mono_arch_is_breakpoint_event:
5851 * See mini-amd64.c for docs.
5854 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5856 siginfo_t* sinfo = (siginfo_t*) info;
5857 /* Sometimes the address is off by 4 */
5858 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5865 * mono_arch_skip_breakpoint:
5867 * See mini-amd64.c for docs.
5870 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5872 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5876 * mono_arch_skip_single_step:
5878 * See mini-amd64.c for docs.
5881 mono_arch_skip_single_step (MonoContext *ctx)
5883 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5887 * mono_arch_get_seq_point_info:
5889 * See mini-amd64.c for docs.
5892 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5899 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
5901 ext->lmf.previous_lmf = prev_lmf;
5902 /* Mark that this is a MonoLMFExt */
5903 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
5904 ext->lmf.iregs [mips_sp] = (gssize)ext;
5907 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5910 mono_arch_opcode_supported (int opcode)