2 * mini-mips.c: MIPS backend for the Mono code generator
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2003 Ximian, Inc.
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/utils/mono-mmap.h>
22 #include <mono/arch/mips/mips-codegen.h>
24 #include "mini-mips.h"
29 #define SAVE_FP_REGS 0
31 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
33 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
34 #define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
36 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
37 #define mips_call(c,D,v) do { \
38 guint32 _target = (guint32)(v); \
39 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
40 mips_load_const (c, D, _target); \
41 mips_jalr (c, D, mips_ra); \
44 mips_jumpl (c, _target >> 2); \
56 /* This mutex protects architecture specific caches */
57 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
58 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
59 static CRITICAL_SECTION mini_arch_mutex;
61 int mono_exc_esp_offset = 0;
62 static int tls_mode = TLS_MODE_DETECT;
63 static int lmf_pthread_key = -1;
64 static int monothread_key = -1;
65 static int monodomain_key = -1;
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; \
100 #define emit_linuxthreads_tls(code,dreg,key) do {\
102 off1 = offsets_from_pthread_key ((key), &off2); \
103 g_assert_not_reached (); \
104 ppc_lwz ((code), (dreg), off1, ppc_r2); \
105 ppc_lwz ((code), (dreg), off2, (dreg)); \
109 #define emit_tls_access(code,dreg,key) do { \
110 switch (tls_mode) { \
111 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
112 default: g_assert_not_reached (); \
116 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
118 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
119 inst->type = STACK_R8; \
121 inst->inst_p0 = (void*)(addr); \
122 mono_bblock_add_inst (cfg->cbb, inst); \
125 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
126 || ((ins)->opcode == OP_ICOMPARE) \
127 || ((ins)->opcode == OP_LCOMPARE)))
128 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
129 || ((ins)->opcode == OP_ICOMPARE_IMM) \
130 || ((ins)->opcode == OP_LCOMPARE_IMM)))
132 #define INS_REWRITE(ins, op, _s1, _s2) do { \
135 ins->opcode = (op); \
140 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
142 ins->opcode = (op); \
144 ins->inst_imm = (_imm); \
148 typedef struct InstList InstList;
166 guint16 vtsize; /* in param area */
169 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
178 gboolean vtype_retaddr;
187 void patch_lui_addiu(guint32 *ip, guint32 val);
188 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
189 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
190 void mips_adjust_stackframe(MonoCompile *cfg);
191 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
192 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
195 /* Not defined in asm/cachectl.h */
196 int cacheflush(char *addr, int nbytes, int cache);
199 mono_arch_flush_icache (guint8 *code, gint size)
201 /* Linux/MIPS specific */
202 cacheflush ((char*)code, size, BCACHE);
206 mono_arch_flush_register_windows (void)
211 mono_arch_is_inst_imm (gint64 imm)
217 mips_emit_exc_by_name(guint8 *code, const char *name)
220 MonoClass *exc_class;
222 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
223 g_assert (exc_class);
225 mips_load_const (code, mips_a0, exc_class->type_token);
226 addr = mono_get_throw_corlib_exception ();
227 mips_call (code, mips_t9, addr);
233 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
235 if (mips_is_imm16 (v))
236 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
238 #if SIZEOF_REGISTER == 8
240 /* v is not a sign-extended 32-bit value */
241 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
242 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
243 mips_dsll (code, dreg, dreg, 16);
244 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
245 mips_dsll (code, dreg, dreg, 16);
246 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
250 if (((guint32)v) & (1 << 15)) {
251 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
254 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
256 if (((guint32)v) & 0xffff)
257 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
263 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
266 if (cfg->arch.long_branch) {
269 /* Invert test and emit branch around jump */
272 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
276 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
280 mips_bltz (code, ins->sreg1, br_offset);
284 mips_blez (code, ins->sreg1, br_offset);
288 mips_bgtz (code, ins->sreg1, br_offset);
292 mips_bgez (code, ins->sreg1, br_offset);
296 g_assert_not_reached ();
298 mono_add_patch_info (cfg, code - cfg->native_code,
299 MONO_PATCH_INFO_BB, ins->inst_true_bb);
300 mips_lui (code, mips_at, mips_zero, 0);
301 mips_addiu (code, mips_at, mips_at, 0);
302 mips_jr (code, mips_at);
306 mono_add_patch_info (cfg, code - cfg->native_code,
307 MONO_PATCH_INFO_BB, ins->inst_true_bb);
310 mips_beq (code, ins->sreg1, ins->sreg2, 0);
314 mips_bne (code, ins->sreg1, ins->sreg2, 0);
318 mips_bgez (code, ins->sreg1, 0);
322 mips_bgtz (code, ins->sreg1, 0);
326 mips_blez (code, ins->sreg1, 0);
330 mips_bltz (code, ins->sreg1, 0);
334 g_assert_not_reached ();
340 /* XXX - big-endian dependent? */
342 patch_lui_addiu(guint32 *ip, guint32 val)
344 guint16 *__lui_addiu = (guint16*)(void *)(ip);
347 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
348 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
351 if (((guint32)(val)) & (1 << 15))
352 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
354 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
355 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
356 mono_arch_flush_icache ((guint8 *)ip, 8);
361 mips_patch (guint32 *code, guint32 target)
364 guint32 op = ins >> 26;
365 guint32 diff, offset;
367 g_assert (trap_target != target);
368 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
370 case 0x00: /* jr ra */
371 if (ins == 0x3e00008)
373 g_assert_not_reached ();
377 g_assert (!(target & 0x03));
378 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
379 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
381 mono_arch_flush_icache ((guint8 *)code, 4);
383 case 0x01: /* BLTZ */
386 case 0x06: /* BLEZ */
387 case 0x07: /* BGTZ */
388 case 0x11: /* bc1t */
389 diff = target - (guint32)(code + 1);
390 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
391 g_assert (!(diff & 0x03));
392 offset = ((gint32)diff) >> 2;
393 if (((int)offset) != ((int)(short)offset))
394 g_assert (((int)offset) == ((int)(short)offset));
395 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
397 mono_arch_flush_icache ((guint8 *)code, 4);
399 case 0x0f: /* LUI / ADDIU pair */
400 g_assert ((code[1] >> 26) == 0x9);
401 patch_lui_addiu (code, target);
402 mono_arch_flush_icache ((guint8 *)code, 8);
406 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
407 g_assert_not_reached ();
413 offsets_from_pthread_key (guint32 key, int *offset2)
417 *offset2 = idx2 * sizeof (gpointer);
418 return 284 + idx1 * sizeof (gpointer);
422 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
425 mono_arch_regname (int reg) {
426 #if _MIPS_SIM == _ABIO32
427 static const char * rnames[] = {
428 "zero", "at", "v0", "v1",
429 "a0", "a1", "a2", "a3",
430 "t0", "t1", "t2", "t3",
431 "t4", "t5", "t6", "t7",
432 "s0", "s1", "s2", "s3",
433 "s4", "s5", "s6", "s7",
434 "t8", "t9", "k0", "k1",
435 "gp", "sp", "fp", "ra"
437 #elif _MIPS_SIM == _ABIN32
438 static const char * rnames[] = {
439 "zero", "at", "v0", "v1",
440 "a0", "a1", "a2", "a3",
441 "a4", "a5", "a6", "a7",
442 "t0", "t1", "t2", "t3",
443 "s0", "s1", "s2", "s3",
444 "s4", "s5", "s6", "s7",
445 "t8", "t9", "k0", "k1",
446 "gp", "sp", "fp", "ra"
449 if (reg >= 0 && reg < 32)
455 mono_arch_fregname (int reg) {
456 static const char * rnames[] = {
457 "f0", "f1", "f2", "f3",
458 "f4", "f5", "f6", "f7",
459 "f8", "f9", "f10", "f11",
460 "f12", "f13", "f14", "f15",
461 "f16", "f17", "f18", "f19",
462 "f20", "f21", "f22", "f23",
463 "f24", "f25", "f26", "f27",
464 "f28", "f29", "f30", "f31"
466 if (reg >= 0 && reg < 32)
471 /* this function overwrites at */
473 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
475 /* XXX write a loop, not an unrolled loop */
477 mips_lw (code, mips_at, sreg, soffset);
478 mips_sw (code, mips_at, dreg, doffset);
487 * mono_arch_get_argument_info:
488 * @csig: a method signature
489 * @param_count: the number of parameters to consider
490 * @arg_info: an array to store the result infos
492 * Gathers information on parameters such as size, alignment and
493 * padding. arg_info should be large enought to hold param_count + 1 entries.
495 * Returns the size of the activation frame.
498 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
500 int k, frame_size = 0;
501 guint32 size, align, pad;
504 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
505 frame_size += sizeof (gpointer);
509 arg_info [0].offset = offset;
512 frame_size += sizeof (gpointer);
516 arg_info [0].size = frame_size;
518 for (k = 0; k < param_count; k++) {
519 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
521 /* ignore alignment for now */
524 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
525 arg_info [k].pad = pad;
527 arg_info [k + 1].pad = 0;
528 arg_info [k + 1].size = size;
530 arg_info [k + 1].offset = offset;
534 align = MONO_ARCH_FRAME_ALIGNMENT;
535 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
536 arg_info [k].pad = pad;
541 /* The delegate object plus 3 params */
542 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
545 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
547 guint8 *code, *start;
550 start = code = mono_global_codeman_reserve (16);
552 /* Replace the this argument with the target */
553 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
554 mips_lw (code, mips_a0, mips_a0, G_STRUCT_OFFSET (MonoDelegate, target));
555 mips_jr (code, mips_temp);
558 g_assert ((code - start) <= 16);
560 mono_arch_flush_icache (start, 16);
564 size = 16 + param_count * 4;
565 start = code = mono_global_codeman_reserve (size);
567 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
568 /* slide down the arguments */
569 for (i = 0; i < param_count; ++i) {
570 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
572 mips_jr (code, mips_temp);
575 g_assert ((code - start) <= size);
577 mono_arch_flush_icache (start, size);
581 *code_size = code - start;
587 * mono_arch_get_delegate_invoke_impls:
589 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
593 mono_arch_get_delegate_invoke_impls (void)
600 code = get_delegate_invoke_impl (TRUE, 0, &code_len);
601 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
603 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
604 code = get_delegate_invoke_impl (FALSE, i, &code_len);
605 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
612 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
614 guint8 *code, *start;
616 /* FIXME: Support more cases */
617 if (MONO_TYPE_ISSTRUCT (sig->ret))
621 static guint8* cached = NULL;
622 mono_mini_arch_lock ();
624 mono_mini_arch_unlock ();
629 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
631 start = get_delegate_invoke_impl (TRUE, 0, NULL);
633 mono_mini_arch_unlock ();
636 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
639 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
641 for (i = 0; i < sig->param_count; ++i)
642 if (!mono_is_regsize_var (sig->params [i]))
645 mono_mini_arch_lock ();
646 code = cache [sig->param_count];
648 mono_mini_arch_unlock ();
653 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
654 start = mono_aot_get_trampoline (name);
657 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
659 cache [sig->param_count] = start;
660 mono_mini_arch_unlock ();
668 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
671 return (gpointer)regs [mips_a0];
675 * Initialize the cpu to execute managed code.
678 mono_arch_cpu_init (void)
680 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
689 ls_word_offset = ls_word_idx * 4;
690 ms_word_offset = ms_word_idx * 4;
694 * Initialize architecture specific code.
697 mono_arch_init (void)
699 InitializeCriticalSection (&mini_arch_mutex);
701 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
702 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
703 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
707 * Cleanup architecture specific code.
710 mono_arch_cleanup (void)
712 DeleteCriticalSection (&mini_arch_mutex);
716 * This function returns the optimizations supported on this cpu.
719 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
723 /* no mips-specific optimizations yet */
729 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
734 for (i = 0; i < cfg->num_varinfo; i++) {
735 MonoInst *ins = cfg->varinfo [i];
736 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
739 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
742 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
745 /* we can only allocate 32 bit values */
746 if (mono_is_regsize_var (ins->inst_vtype)) {
747 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
748 g_assert (i == vmv->idx);
749 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
757 mono_arch_get_global_int_regs (MonoCompile *cfg)
761 regs = g_list_prepend (regs, (gpointer)mips_s0);
762 regs = g_list_prepend (regs, (gpointer)mips_s1);
763 regs = g_list_prepend (regs, (gpointer)mips_s2);
764 regs = g_list_prepend (regs, (gpointer)mips_s3);
765 regs = g_list_prepend (regs, (gpointer)mips_s4);
766 //regs = g_list_prepend (regs, (gpointer)mips_s5);
767 regs = g_list_prepend (regs, (gpointer)mips_s6);
768 regs = g_list_prepend (regs, (gpointer)mips_s7);
774 * mono_arch_regalloc_cost:
776 * Return the cost, in number of memory references, of the action of
777 * allocating the variable VMV into a register during global register
781 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
788 args_onto_stack (CallInfo *info)
790 g_assert (!info->on_stack);
791 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
792 info->on_stack = TRUE;
793 info->stack_size = MIPS_STACK_PARAM_OFFSET;
796 #if _MIPS_SIM == _ABIO32
798 * O32 calling convention version
802 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
803 /* First, see if we need to drop onto the stack */
804 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
805 args_onto_stack (info);
807 /* Now, place the argument */
808 if (info->on_stack) {
809 ainfo->storage = ArgOnStack;
810 ainfo->reg = mips_sp; /* in the caller */
811 ainfo->offset = info->stack_size;
814 ainfo->storage = ArgInIReg;
815 ainfo->reg = info->gr;
817 info->gr_passed = TRUE;
819 info->stack_size += 4;
823 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
824 /* First, see if we need to drop onto the stack */
825 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
826 args_onto_stack (info);
828 /* Now, place the argument */
829 if (info->on_stack) {
830 g_assert (info->stack_size % 4 == 0);
831 info->stack_size += (info->stack_size % 8);
833 ainfo->storage = ArgOnStack;
834 ainfo->reg = mips_sp; /* in the caller */
835 ainfo->offset = info->stack_size;
838 // info->gr must be a0 or a2
839 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
840 g_assert(info->gr <= MIPS_LAST_ARG_REG);
842 ainfo->storage = ArgInIReg;
843 ainfo->reg = info->gr;
845 info->gr_passed = TRUE;
847 info->stack_size += 8;
851 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
852 /* First, see if we need to drop onto the stack */
853 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
854 args_onto_stack (info);
856 /* Now, place the argument */
857 if (info->on_stack) {
858 ainfo->storage = ArgOnStack;
859 ainfo->reg = mips_sp; /* in the caller */
860 ainfo->offset = info->stack_size;
863 /* Only use FP regs for args if no int args passed yet */
864 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
865 ainfo->storage = ArgInFReg;
866 ainfo->reg = info->fr;
867 /* Even though it's a single-precision float, it takes up two FP regs */
869 /* FP and GP slots do not overlap */
873 /* Passing single-precision float arg in a GP register
874 * such as: func (0, 1.0, 2, 3);
875 * In this case, only one 'gr' register is consumed.
877 ainfo->storage = ArgInIReg;
878 ainfo->reg = info->gr;
881 info->gr_passed = TRUE;
884 info->stack_size += 4;
888 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
889 /* First, see if we need to drop onto the stack */
890 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
891 args_onto_stack (info);
893 /* Now, place the argument */
894 if (info->on_stack) {
895 g_assert(info->stack_size % 4 == 0);
896 info->stack_size += (info->stack_size % 8);
898 ainfo->storage = ArgOnStack;
899 ainfo->reg = mips_sp; /* in the caller */
900 ainfo->offset = info->stack_size;
903 /* Only use FP regs for args if no int args passed yet */
904 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
905 ainfo->storage = ArgInFReg;
906 ainfo->reg = info->fr;
908 /* FP and GP slots do not overlap */
912 // info->gr must be a0 or a2
913 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
914 g_assert(info->gr <= MIPS_LAST_ARG_REG);
916 ainfo->storage = ArgInIReg;
917 ainfo->reg = info->gr;
919 info->gr_passed = TRUE;
922 info->stack_size += 8;
924 #elif _MIPS_SIM == _ABIN32
926 * N32 calling convention version
930 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
931 /* First, see if we need to drop onto the stack */
932 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
933 args_onto_stack (info);
935 /* Now, place the argument */
936 if (info->on_stack) {
937 ainfo->storage = ArgOnStack;
938 ainfo->reg = mips_sp; /* in the caller */
939 ainfo->offset = info->stack_size;
940 info->stack_size += SIZEOF_REGISTER;
943 ainfo->storage = ArgInIReg;
944 ainfo->reg = info->gr;
946 info->gr_passed = TRUE;
951 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
952 /* First, see if we need to drop onto the stack */
953 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
954 args_onto_stack (info);
956 /* Now, place the argument */
957 if (info->on_stack) {
958 g_assert (info->stack_size % 4 == 0);
959 info->stack_size += (info->stack_size % 8);
961 ainfo->storage = ArgOnStack;
962 ainfo->reg = mips_sp; /* in the caller */
963 ainfo->offset = info->stack_size;
964 info->stack_size += SIZEOF_REGISTER;
967 g_assert (info->gr <= MIPS_LAST_ARG_REG);
969 ainfo->storage = ArgInIReg;
970 ainfo->reg = info->gr;
972 info->gr_passed = TRUE;
977 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
978 /* First, see if we need to drop onto the stack */
979 if (!info->on_stack) {
980 if (info->gr > MIPS_LAST_ARG_REG)
981 args_onto_stack (info);
982 else if (info->fr > MIPS_LAST_FPARG_REG)
983 args_onto_stack (info);
986 /* Now, place the argument */
987 if (info->on_stack) {
988 ainfo->storage = ArgOnStack;
989 ainfo->reg = mips_sp; /* in the caller */
990 ainfo->offset = info->stack_size;
991 info->stack_size += FREG_SIZE;
994 ainfo->storage = ArgInFReg;
995 ainfo->reg = info->fr;
997 /* FP and GP slots do not overlap */
1003 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1004 /* First, see if we need to drop onto the stack */
1005 if (!info->on_stack) {
1006 if (info->gr > MIPS_LAST_ARG_REG)
1007 args_onto_stack (info);
1008 else if (info->fr > MIPS_LAST_FPARG_REG)
1009 args_onto_stack (info);
1012 /* Now, place the argument */
1013 if (info->on_stack) {
1014 g_assert(info->stack_size % 4 == 0);
1015 info->stack_size += (info->stack_size % 8);
1017 ainfo->storage = ArgOnStack;
1018 ainfo->reg = mips_sp; /* in the caller */
1019 ainfo->offset = info->stack_size;
1020 info->stack_size += FREG_SIZE;
1023 ainfo->storage = ArgInFReg;
1024 ainfo->reg = info->fr;
1026 /* FP and GP slots do not overlap */
1033 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
1036 int n = sig->hasthis + sig->param_count;
1038 MonoType* simpletype;
1040 gboolean is_pinvoke = sig->pinvoke;
1043 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1045 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1047 cinfo->fr = MIPS_FIRST_FPARG_REG;
1048 cinfo->gr = MIPS_FIRST_ARG_REG;
1049 cinfo->stack_size = 0;
1051 DEBUG(printf("calculate_sizes\n"));
1053 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1057 /* handle returning a struct */
1058 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1059 cinfo->struct_ret = cinfo->gr;
1060 add_int32_arg (cinfo, &cinfo->ret);
1064 add_int32_arg (cinfo, cinfo->args + n);
1069 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1070 * the first argument, allowing 'this' to be always passed in the first arg reg.
1071 * Also do this if the first argument is a reference type, since virtual calls
1072 * are sometimes made using calli without sig->hasthis set, like in the delegate
1075 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1077 add_int32_arg (cinfo, cinfo->args + n);
1080 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1084 add_int32_arg (cinfo, &cinfo->ret);
1085 cinfo->struct_ret = cinfo->ret.reg;
1089 add_int32_arg (cinfo, cinfo->args + n);
1093 if (cinfo->vtype_retaddr) {
1094 add_int32_arg (cinfo, &cinfo->ret);
1095 cinfo->struct_ret = cinfo->ret.reg;
1100 DEBUG(printf("params: %d\n", sig->param_count));
1101 for (i = pstart; i < sig->param_count; ++i) {
1102 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1103 /* Prevent implicit arguments and sig_cookie from
1104 being passed in registers */
1105 args_onto_stack (cinfo);
1106 /* Emit the signature cookie just before the implicit arguments */
1107 add_int32_arg (cinfo, &cinfo->sig_cookie);
1109 DEBUG(printf("param %d: ", i));
1110 simpletype = mini_type_get_underlying_type (gsctx, sig->params [i]);
1111 switch (simpletype->type) {
1112 case MONO_TYPE_BOOLEAN:
1115 DEBUG(printf("1 byte\n"));
1116 cinfo->args [n].size = 1;
1117 add_int32_arg (cinfo, &cinfo->args[n]);
1120 case MONO_TYPE_CHAR:
1123 DEBUG(printf("2 bytes\n"));
1124 cinfo->args [n].size = 2;
1125 add_int32_arg (cinfo, &cinfo->args[n]);
1130 DEBUG(printf("4 bytes\n"));
1131 cinfo->args [n].size = 4;
1132 add_int32_arg (cinfo, &cinfo->args[n]);
1138 case MONO_TYPE_FNPTR:
1139 case MONO_TYPE_CLASS:
1140 case MONO_TYPE_OBJECT:
1141 case MONO_TYPE_STRING:
1142 case MONO_TYPE_SZARRAY:
1143 case MONO_TYPE_ARRAY:
1144 cinfo->args [n].size = sizeof (gpointer);
1145 add_int32_arg (cinfo, &cinfo->args[n]);
1148 case MONO_TYPE_GENERICINST:
1149 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1150 cinfo->args [n].size = sizeof (gpointer);
1151 add_int32_arg (cinfo, &cinfo->args[n]);
1156 case MONO_TYPE_TYPEDBYREF:
1157 case MONO_TYPE_VALUETYPE: {
1160 int has_offset = FALSE;
1162 gint size, alignment;
1165 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1166 size = sizeof (MonoTypedRef);
1167 alignment = sizeof (gpointer);
1169 klass = mono_class_from_mono_type (sig->params [i]);
1171 size = mono_class_native_size (klass, NULL);
1173 size = mono_class_value_size (klass, NULL);
1174 alignment = mono_class_min_align (klass);
1176 #if MIPS_PASS_STRUCTS_BY_VALUE
1177 /* Need to do alignment if struct contains long or double */
1178 if (alignment > 4) {
1179 /* Drop onto stack *before* looking at
1180 stack_size, if required. */
1181 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1182 args_onto_stack (cinfo);
1183 if (cinfo->stack_size & (alignment - 1)) {
1184 add_int32_arg (cinfo, &dummy_arg);
1186 g_assert (!(cinfo->stack_size & (alignment - 1)));
1190 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1191 mono_class_native_size (sig->params [i]->data.klass, NULL),
1192 cinfo->stack_size, alignment);
1194 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1195 g_assert (cinfo->args [n].size == 0);
1196 g_assert (cinfo->args [n].vtsize == 0);
1197 for (j = 0; j < nwords; ++j) {
1199 add_int32_arg (cinfo, &cinfo->args [n]);
1200 if (cinfo->on_stack)
1203 add_int32_arg (cinfo, &dummy_arg);
1204 if (!has_offset && cinfo->on_stack) {
1205 cinfo->args [n].offset = dummy_arg.offset;
1209 if (cinfo->on_stack)
1210 cinfo->args [n].vtsize += 1;
1212 cinfo->args [n].size += 1;
1214 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1215 cinfo->args [n].storage = ArgStructByVal;
1217 add_int32_arg (cinfo, &cinfo->args[n]);
1218 cinfo->args [n].storage = ArgStructByAddr;
1225 DEBUG(printf("8 bytes\n"));
1226 cinfo->args [n].size = 8;
1227 add_int64_arg (cinfo, &cinfo->args[n]);
1231 DEBUG(printf("R4\n"));
1232 cinfo->args [n].size = 4;
1233 add_float32_arg (cinfo, &cinfo->args[n]);
1237 DEBUG(printf("R8\n"));
1238 cinfo->args [n].size = 8;
1239 add_float64_arg (cinfo, &cinfo->args[n]);
1243 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1247 /* Handle the case where there are no implicit arguments */
1248 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1249 /* Prevent implicit arguments and sig_cookie from
1250 being passed in registers */
1251 args_onto_stack (cinfo);
1252 /* Emit the signature cookie just before the implicit arguments */
1253 add_int32_arg (cinfo, &cinfo->sig_cookie);
1257 simpletype = mini_type_get_underlying_type (gsctx, sig->ret);
1258 switch (simpletype->type) {
1259 case MONO_TYPE_BOOLEAN:
1264 case MONO_TYPE_CHAR:
1270 case MONO_TYPE_FNPTR:
1271 case MONO_TYPE_CLASS:
1272 case MONO_TYPE_OBJECT:
1273 case MONO_TYPE_SZARRAY:
1274 case MONO_TYPE_ARRAY:
1275 case MONO_TYPE_STRING:
1276 cinfo->ret.reg = mips_v0;
1280 cinfo->ret.reg = mips_v0;
1284 cinfo->ret.reg = mips_f0;
1285 cinfo->ret.storage = ArgInFReg;
1287 case MONO_TYPE_GENERICINST:
1288 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1289 cinfo->ret.reg = mips_v0;
1293 case MONO_TYPE_VALUETYPE:
1294 case MONO_TYPE_TYPEDBYREF:
1296 case MONO_TYPE_VOID:
1299 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1303 /* align stack size to 16 */
1304 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1306 cinfo->stack_usage = cinfo->stack_size;
1310 G_GNUC_UNUSED static void
1315 G_GNUC_UNUSED static gboolean
1318 static int count = 0;
1321 if (!getenv ("COUNT"))
1324 if (count == atoi (getenv ("COUNT"))) {
1328 if (count > atoi (getenv ("COUNT"))) {
1336 debug_omit_fp (void)
1339 return debug_count ();
1346 * mono_arch_compute_omit_fp:
1348 * Determine whenever the frame pointer can be eliminated.
1351 mono_arch_compute_omit_fp (MonoCompile *cfg)
1353 MonoMethodSignature *sig;
1354 MonoMethodHeader *header;
1358 if (cfg->arch.omit_fp_computed)
1361 header = cfg->header;
1363 sig = mono_method_signature (cfg->method);
1365 if (!cfg->arch.cinfo)
1366 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1367 cinfo = cfg->arch.cinfo;
1370 * FIXME: Remove some of the restrictions.
1372 cfg->arch.omit_fp = TRUE;
1373 cfg->arch.omit_fp_computed = TRUE;
1375 if (cfg->disable_omit_fp)
1376 cfg->arch.omit_fp = FALSE;
1377 if (!debug_omit_fp ())
1378 cfg->arch.omit_fp = FALSE;
1379 if (cfg->method->save_lmf)
1380 cfg->arch.omit_fp = FALSE;
1381 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1382 cfg->arch.omit_fp = FALSE;
1383 if (header->num_clauses)
1384 cfg->arch.omit_fp = FALSE;
1385 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1386 cfg->arch.omit_fp = FALSE;
1387 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1388 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1389 cfg->arch.omit_fp = FALSE;
1391 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1392 * there are stack arguments.
1395 if (cinfo->stack_usage)
1396 cfg->arch.omit_fp = FALSE;
1400 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1401 MonoInst *ins = cfg->varinfo [i];
1404 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1407 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1411 * Set var information according to the calling convention. mips version.
1412 * The locals var stuff should most likely be split in another method.
1415 mono_arch_allocate_vars (MonoCompile *cfg)
1417 MonoMethodSignature *sig;
1418 MonoMethodHeader *header;
1420 int i, offset, size, align, curinst;
1421 int frame_reg = mips_sp;
1422 guint32 iregs_to_save = 0;
1424 guint32 fregs_to_restore;
1428 sig = mono_method_signature (cfg->method);
1430 if (!cfg->arch.cinfo)
1431 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1432 cinfo = cfg->arch.cinfo;
1434 mono_arch_compute_omit_fp (cfg);
1436 /* spill down, we'll fix it in a separate pass */
1437 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1439 /* allow room for the vararg method args: void* and long/double */
1440 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1441 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1443 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1444 * call convs needs to be handled this way.
1446 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1447 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1449 /* gtk-sharp and other broken code will dllimport vararg functions even with
1450 * non-varargs signatures. Since there is little hope people will get this right
1451 * we assume they won't.
1453 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1454 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1456 /* a0-a3 always present */
1457 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1459 header = cfg->header;
1461 if (cfg->arch.omit_fp)
1462 frame_reg = mips_sp;
1464 frame_reg = mips_fp;
1465 cfg->frame_reg = frame_reg;
1466 if (frame_reg != mips_sp) {
1467 cfg->used_int_regs |= 1 << frame_reg;
1472 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1473 /* FIXME: handle long and FP values */
1474 switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
1475 case MONO_TYPE_VOID:
1479 cfg->ret->opcode = OP_REGVAR;
1480 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1483 cfg->ret->opcode = OP_REGVAR;
1484 cfg->ret->inst_c0 = mips_v0;
1488 /* Space for outgoing parameters, including a0-a3 */
1489 offset += cfg->param_area;
1491 /* allow room to save the return value (if it's a struct) */
1492 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1495 /* Now handle the local variables */
1497 curinst = cfg->locals_start;
1498 for (i = curinst; i < cfg->num_varinfo; ++i) {
1499 inst = cfg->varinfo [i];
1500 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1503 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1504 * pinvoke wrappers when they call functions returning structure
1506 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1507 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1509 size = mono_type_size (inst->inst_vtype, &align);
1511 offset += align - 1;
1512 offset &= ~(align - 1);
1513 inst->inst_offset = offset;
1514 inst->opcode = OP_REGOFFSET;
1515 inst->inst_basereg = frame_reg;
1517 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1520 /* Space for LMF (if needed) */
1521 if (cfg->method->save_lmf) {
1522 /* align the offset to 16 bytes */
1523 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1524 cfg->arch.lmf_offset = offset;
1525 offset += sizeof (MonoLMF);
1528 if (sig->call_convention == MONO_CALL_VARARG) {
1532 /* Allocate a local slot to hold the sig cookie address */
1533 offset += align - 1;
1534 offset &= ~(align - 1);
1535 cfg->sig_cookie = offset;
1539 offset += SIZEOF_REGISTER - 1;
1540 offset &= ~(SIZEOF_REGISTER - 1);
1542 /* Space for saved registers */
1543 cfg->arch.iregs_offset = offset;
1544 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1545 if (iregs_to_save) {
1546 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1547 if (iregs_to_save & (1 << i)) {
1548 offset += SIZEOF_REGISTER;
1553 /* saved float registers */
1555 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1556 if (fregs_to_restore) {
1557 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1558 if (fregs_to_restore & (1 << i)) {
1559 offset += sizeof(double);
1565 #if _MIPS_SIM == _ABIO32
1566 /* Now add space for saving the ra */
1567 offset += SIZEOF_VOID_P;
1570 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1571 cfg->stack_offset = offset;
1572 cfg->arch.local_alloc_offset = cfg->stack_offset;
1576 * Now allocate stack slots for the int arg regs (a0 - a3)
1577 * On MIPS o32, these are just above the incoming stack pointer
1578 * Even if the arg has been assigned to a regvar, it gets a stack slot
1581 /* Return struct-by-value results in a hidden first argument */
1582 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1583 cfg->vret_addr->opcode = OP_REGOFFSET;
1584 cfg->vret_addr->inst_c0 = mips_a0;
1585 cfg->vret_addr->inst_offset = offset;
1586 cfg->vret_addr->inst_basereg = frame_reg;
1587 offset += SIZEOF_REGISTER;
1590 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1591 inst = cfg->args [i];
1592 if (inst->opcode != OP_REGVAR) {
1595 if (sig->hasthis && (i == 0))
1596 arg_type = &mono_defaults.object_class->byval_arg;
1598 arg_type = sig->params [i - sig->hasthis];
1600 inst->opcode = OP_REGOFFSET;
1601 size = mono_type_size (arg_type, &align);
1603 if (size < SIZEOF_REGISTER) {
1604 size = SIZEOF_REGISTER;
1605 align = SIZEOF_REGISTER;
1607 inst->inst_basereg = frame_reg;
1608 offset = (offset + align - 1) & ~(align - 1);
1609 inst->inst_offset = offset;
1611 if (cfg->verbose_level > 1)
1612 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1615 #if _MIPS_SIM == _ABIO32
1616 /* o32: Even a0-a3 get stack slots */
1617 size = SIZEOF_REGISTER;
1618 align = SIZEOF_REGISTER;
1619 inst->inst_basereg = frame_reg;
1620 offset = (offset + align - 1) & ~(align - 1);
1621 inst->inst_offset = offset;
1623 if (cfg->verbose_level > 1)
1624 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1628 #if _MIPS_SIM == _ABIN32
1629 /* Now add space for saving the ra */
1630 offset += SIZEOF_VOID_P;
1633 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1634 cfg->stack_offset = offset;
1635 cfg->arch.local_alloc_offset = cfg->stack_offset;
1640 mono_arch_create_vars (MonoCompile *cfg)
1642 MonoMethodSignature *sig;
1644 sig = mono_method_signature (cfg->method);
1646 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1647 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1648 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1649 printf ("vret_addr = ");
1650 mono_print_ins (cfg->vret_addr);
1655 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1656 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1660 * take the arguments and generate the arch-specific
1661 * instructions to properly call the function in call.
1662 * This includes pushing, moving arguments to the right register
1664 * Issue: who does the spilling if needed, and when?
1667 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1669 MonoMethodSignature *tmp_sig;
1672 if (call->tail_call)
1675 /* FIXME: Add support for signature tokens to AOT */
1676 cfg->disable_aot = TRUE;
1679 * mono_ArgIterator_Setup assumes the signature cookie is
1680 * passed first and all the arguments which were before it are
1681 * passed on the stack after the signature. So compensate by
1682 * passing a different signature.
1684 tmp_sig = mono_metadata_signature_dup (call->signature);
1685 tmp_sig->param_count -= call->signature->sentinelpos;
1686 tmp_sig->sentinelpos = 0;
1687 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1689 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1690 sig_arg->dreg = mono_alloc_ireg (cfg);
1691 sig_arg->inst_p0 = tmp_sig;
1692 MONO_ADD_INS (cfg->cbb, sig_arg);
1694 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1698 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1701 MonoMethodSignature *sig;
1706 sig = call->signature;
1707 n = sig->param_count + sig->hasthis;
1709 cinfo = get_call_info (NULL, cfg->mempool, sig);
1710 if (cinfo->struct_ret)
1711 call->used_iregs |= 1 << cinfo->struct_ret;
1713 for (i = 0; i < n; ++i) {
1714 ArgInfo *ainfo = cinfo->args + i;
1717 if (i >= sig->hasthis)
1718 t = sig->params [i - sig->hasthis];
1720 t = &mono_defaults.int_class->byval_arg;
1721 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1723 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1724 /* Emit the signature cookie just before the implicit arguments */
1725 emit_sig_cookie (cfg, call, cinfo);
1728 if (is_virtual && i == 0) {
1729 /* the argument will be attached to the call instrucion */
1730 in = call->args [i];
1731 call->used_iregs |= 1 << ainfo->reg;
1734 in = call->args [i];
1735 if (ainfo->storage == ArgInIReg) {
1736 #if SIZEOF_REGISTER == 4
1737 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1738 MONO_INST_NEW (cfg, ins, OP_MOVE);
1739 ins->dreg = mono_alloc_ireg (cfg);
1740 ins->sreg1 = in->dreg + 1;
1741 MONO_ADD_INS (cfg->cbb, ins);
1742 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1744 MONO_INST_NEW (cfg, ins, OP_MOVE);
1745 ins->dreg = mono_alloc_ireg (cfg);
1746 ins->sreg1 = in->dreg + 2;
1747 MONO_ADD_INS (cfg->cbb, ins);
1748 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1751 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1754 #if PROMOTE_R4_TO_R8
1755 /* ??? - convert to single first? */
1756 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1757 ins->dreg = mono_alloc_freg (cfg);
1758 ins->sreg1 = in->dreg;
1759 MONO_ADD_INS (cfg->cbb, ins);
1764 /* trying to load float value into int registers */
1765 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1766 ins->dreg = mono_alloc_ireg (cfg);
1768 MONO_ADD_INS (cfg->cbb, ins);
1769 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1770 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1771 /* trying to load float value into int registers */
1772 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1773 ins->dreg = mono_alloc_ireg (cfg);
1774 ins->sreg1 = in->dreg;
1775 MONO_ADD_INS (cfg->cbb, ins);
1776 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1778 MONO_INST_NEW (cfg, ins, OP_MOVE);
1779 ins->dreg = mono_alloc_ireg (cfg);
1780 ins->sreg1 = in->dreg;
1781 MONO_ADD_INS (cfg->cbb, ins);
1782 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1784 } else if (ainfo->storage == ArgStructByAddr) {
1785 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1786 ins->opcode = OP_OUTARG_VT;
1787 ins->sreg1 = in->dreg;
1788 ins->klass = in->klass;
1789 ins->inst_p0 = call;
1790 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1791 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1792 MONO_ADD_INS (cfg->cbb, ins);
1793 } else if (ainfo->storage == ArgStructByVal) {
1794 /* this is further handled in mono_arch_emit_outarg_vt () */
1795 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1796 ins->opcode = OP_OUTARG_VT;
1797 ins->sreg1 = in->dreg;
1798 ins->klass = in->klass;
1799 ins->inst_p0 = call;
1800 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1801 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1802 MONO_ADD_INS (cfg->cbb, ins);
1803 } else if (ainfo->storage == ArgOnStack) {
1804 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1805 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1806 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1807 if (t->type == MONO_TYPE_R8)
1808 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1810 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1812 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1814 } else if (ainfo->storage == ArgInFReg) {
1815 if (t->type == MONO_TYPE_VALUETYPE) {
1816 /* this is further handled in mono_arch_emit_outarg_vt () */
1817 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1818 ins->opcode = OP_OUTARG_VT;
1819 ins->sreg1 = in->dreg;
1820 ins->klass = in->klass;
1821 ins->inst_p0 = call;
1822 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1823 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1824 MONO_ADD_INS (cfg->cbb, ins);
1826 cfg->flags |= MONO_CFG_HAS_FPOUT;
1828 int dreg = mono_alloc_freg (cfg);
1830 if (ainfo->size == 4) {
1831 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1833 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1835 ins->sreg1 = in->dreg;
1836 MONO_ADD_INS (cfg->cbb, ins);
1839 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1840 cfg->flags |= MONO_CFG_HAS_FPOUT;
1843 g_assert_not_reached ();
1847 /* Handle the case where there are no implicit arguments */
1848 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1849 emit_sig_cookie (cfg, call, cinfo);
1851 if (cinfo->struct_ret) {
1854 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1855 vtarg->sreg1 = call->vret_var->dreg;
1856 vtarg->dreg = mono_alloc_preg (cfg);
1857 MONO_ADD_INS (cfg->cbb, vtarg);
1859 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1863 * Reverse the call->out_args list.
1866 MonoInst *prev = NULL, *list = call->out_args, *next;
1873 call->out_args = prev;
1876 call->stack_usage = cinfo->stack_usage;
1877 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1878 #if _MIPS_SIM == _ABIO32
1879 /* a0-a3 always present */
1880 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1882 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1883 cfg->flags |= MONO_CFG_HAS_CALLS;
1885 * should set more info in call, such as the stack space
1886 * used by the args that needs to be added back to esp
1891 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1893 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1894 ArgInfo *ainfo = ins->inst_p1;
1895 int ovf_size = ainfo->vtsize;
1896 int doffset = ainfo->offset;
1897 int i, soffset, dreg;
1899 if (ainfo->storage == ArgStructByVal) {
1901 if (cfg->verbose_level > 0) {
1902 char* nm = mono_method_full_name (cfg->method, TRUE);
1903 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1904 nm, doffset, ainfo->size, ovf_size);
1910 for (i = 0; i < ainfo->size; ++i) {
1911 dreg = mono_alloc_ireg (cfg);
1912 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1913 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1914 soffset += SIZEOF_REGISTER;
1916 if (ovf_size != 0) {
1917 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1919 } else if (ainfo->storage == ArgInFReg) {
1920 int tmpr = mono_alloc_freg (cfg);
1922 if (ainfo->size == 4)
1923 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1925 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1926 dreg = mono_alloc_freg (cfg);
1927 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1928 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1930 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1934 /* FIXME: alignment? */
1935 if (call->signature->pinvoke) {
1936 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1937 vtcopy->backend.is_pinvoke = 1;
1939 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1942 g_assert (ovf_size > 0);
1944 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1945 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1948 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1950 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1955 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1957 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1958 mono_method_signature (method)->ret);
1961 #if (SIZEOF_REGISTER == 4)
1962 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1965 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1966 ins->sreg1 = val->dreg + 1;
1967 ins->sreg2 = val->dreg + 2;
1968 MONO_ADD_INS (cfg->cbb, ins);
1972 if (ret->type == MONO_TYPE_R8) {
1973 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1976 if (ret->type == MONO_TYPE_R4) {
1977 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1981 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1985 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1987 MonoInst *ins, *n, *last_ins = NULL;
1989 if (cfg->verbose_level > 2)
1990 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1993 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1994 if (cfg->verbose_level > 2)
1995 mono_print_ins_index (0, ins);
1997 switch (ins->opcode) {
1999 case OP_LOAD_MEMBASE:
2000 case OP_LOADI4_MEMBASE:
2002 * OP_IADD reg2, reg1, const1
2003 * OP_LOAD_MEMBASE const2(reg2), reg3
2005 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
2007 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)){
2008 int const1 = last_ins->inst_imm;
2009 int const2 = ins->inst_offset;
2011 if (mips_is_imm16 (const1 + const2)) {
2012 ins->inst_basereg = last_ins->sreg1;
2013 ins->inst_offset = const1 + const2;
2023 bb->last_ins = last_ins;
2027 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2029 MonoInst *ins, *n, *last_ins = NULL;
2032 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2033 MonoInst *last_ins = ins->prev;
2035 switch (ins->opcode) {
2037 /* remove unnecessary multiplication with 1 */
2038 if (ins->inst_imm == 1) {
2039 if (ins->dreg != ins->sreg1) {
2040 ins->opcode = OP_MOVE;
2042 MONO_DELETE_INS (bb, ins);
2046 int power2 = mono_is_power_of_two (ins->inst_imm);
2048 ins->opcode = OP_SHL_IMM;
2049 ins->inst_imm = power2;
2053 case OP_LOAD_MEMBASE:
2054 case OP_LOADI4_MEMBASE:
2056 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2057 * OP_LOAD_MEMBASE offset(basereg), reg
2059 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2060 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2061 ins->inst_basereg == last_ins->inst_destbasereg &&
2062 ins->inst_offset == last_ins->inst_offset) {
2063 if (ins->dreg == last_ins->sreg1) {
2064 MONO_DELETE_INS (bb, ins);
2067 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2068 ins->opcode = OP_MOVE;
2069 ins->sreg1 = last_ins->sreg1;
2074 * Note: reg1 must be different from the basereg in the second load
2075 * OP_LOAD_MEMBASE offset(basereg), reg1
2076 * OP_LOAD_MEMBASE offset(basereg), reg2
2078 * OP_LOAD_MEMBASE offset(basereg), reg1
2079 * OP_MOVE reg1, reg2
2081 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2082 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2083 ins->inst_basereg != last_ins->dreg &&
2084 ins->inst_basereg == last_ins->inst_basereg &&
2085 ins->inst_offset == last_ins->inst_offset) {
2087 if (ins->dreg == last_ins->dreg) {
2088 MONO_DELETE_INS (bb, ins);
2091 ins->opcode = OP_MOVE;
2092 ins->sreg1 = last_ins->dreg;
2095 //g_assert_not_reached ();
2100 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2101 * OP_LOAD_MEMBASE offset(basereg), reg
2103 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2104 * OP_ICONST reg, imm
2106 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2107 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2108 ins->inst_basereg == last_ins->inst_destbasereg &&
2109 ins->inst_offset == last_ins->inst_offset) {
2110 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2111 ins->opcode = OP_ICONST;
2112 ins->inst_c0 = last_ins->inst_imm;
2113 g_assert_not_reached (); // check this rule
2118 case OP_LOADU1_MEMBASE:
2119 case OP_LOADI1_MEMBASE:
2120 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2121 ins->inst_basereg == last_ins->inst_destbasereg &&
2122 ins->inst_offset == last_ins->inst_offset) {
2123 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2124 ins->sreg1 = last_ins->sreg1;
2127 case OP_LOADU2_MEMBASE:
2128 case OP_LOADI2_MEMBASE:
2129 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2130 ins->inst_basereg == last_ins->inst_destbasereg &&
2131 ins->inst_offset == last_ins->inst_offset) {
2132 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2133 ins->sreg1 = last_ins->sreg1;
2136 case OP_ICONV_TO_I4:
2137 case OP_ICONV_TO_U4:
2139 ins->opcode = OP_MOVE;
2143 if (ins->dreg == ins->sreg1) {
2144 MONO_DELETE_INS (bb, ins);
2148 * OP_MOVE sreg, dreg
2149 * OP_MOVE dreg, sreg
2151 if (last_ins && last_ins->opcode == OP_MOVE &&
2152 ins->sreg1 == last_ins->dreg &&
2153 ins->dreg == last_ins->sreg1) {
2154 MONO_DELETE_INS (bb, ins);
2162 bb->last_ins = last_ins;
2166 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2174 switch (ins->opcode) {
2177 case OP_LCOMPARE_IMM:
2178 mono_print_ins (ins);
2179 g_assert_not_reached ();
2182 tmp1 = mono_alloc_ireg (cfg);
2183 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2184 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2185 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2186 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2191 tmp1 = mono_alloc_ireg (cfg);
2192 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2193 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2194 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2195 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2200 tmp1 = mono_alloc_ireg (cfg);
2201 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2202 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2203 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2204 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2209 tmp1 = mono_alloc_ireg (cfg);
2210 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2211 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2212 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2213 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2225 mono_print_ins (ins);
2226 g_assert_not_reached ();
2229 tmp1 = mono_alloc_ireg (cfg);
2230 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2231 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2232 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2233 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2241 case OP_LCONV_TO_I1:
2242 case OP_LCONV_TO_I2:
2243 case OP_LCONV_TO_I4:
2244 case OP_LCONV_TO_I8:
2245 case OP_LCONV_TO_R4:
2246 case OP_LCONV_TO_R8:
2247 case OP_LCONV_TO_U4:
2248 case OP_LCONV_TO_U8:
2249 case OP_LCONV_TO_U2:
2250 case OP_LCONV_TO_U1:
2252 case OP_LCONV_TO_OVF_I:
2253 case OP_LCONV_TO_OVF_U:
2255 mono_print_ins (ins);
2256 g_assert_not_reached ();
2259 tmp1 = mono_alloc_ireg (cfg);
2260 tmp2 = mono_alloc_ireg (cfg);
2261 tmp3 = mono_alloc_ireg (cfg);
2262 tmp4 = mono_alloc_ireg (cfg);
2263 tmp5 = mono_alloc_ireg (cfg);
2265 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2267 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2268 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2270 /* add the high 32-bits, and add in the carry from the low 32-bits */
2271 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2272 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2274 /* Overflow happens if
2275 * neg + neg = pos or
2277 * XOR of the high bits returns 0 if the signs match
2278 * XOR of that with the high bit of the result return 1 if overflow.
2281 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2282 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2284 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2285 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2286 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2288 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2289 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2290 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2292 /* Now, if (tmp4 == 0) then overflow */
2293 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2297 case OP_LADD_OVF_UN:
2298 tmp1 = mono_alloc_ireg (cfg);
2299 tmp2 = mono_alloc_ireg (cfg);
2301 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2302 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2303 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2304 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2305 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2306 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2311 case OP_LMUL_OVF_UN:
2312 mono_print_ins (ins);
2313 g_assert_not_reached ();
2316 tmp1 = mono_alloc_ireg (cfg);
2317 tmp2 = mono_alloc_ireg (cfg);
2318 tmp3 = mono_alloc_ireg (cfg);
2319 tmp4 = mono_alloc_ireg (cfg);
2320 tmp5 = mono_alloc_ireg (cfg);
2322 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2324 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2325 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2326 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2328 /* Overflow happens if
2329 * neg - pos = pos or
2331 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2333 * tmp1 = (lhs ^ rhs)
2334 * tmp2 = (lhs ^ result)
2335 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2338 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2339 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2340 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2341 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2343 /* Now, if (tmp4 == 1) then overflow */
2344 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2348 case OP_LSUB_OVF_UN:
2349 tmp1 = mono_alloc_ireg (cfg);
2350 tmp2 = mono_alloc_ireg (cfg);
2352 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2353 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2354 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2355 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2357 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2358 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2362 case OP_LCONV_TO_OVF_I1_UN:
2363 case OP_LCONV_TO_OVF_I2_UN:
2364 case OP_LCONV_TO_OVF_I4_UN:
2365 case OP_LCONV_TO_OVF_I8_UN:
2366 case OP_LCONV_TO_OVF_U1_UN:
2367 case OP_LCONV_TO_OVF_U2_UN:
2368 case OP_LCONV_TO_OVF_U4_UN:
2369 case OP_LCONV_TO_OVF_U8_UN:
2370 case OP_LCONV_TO_OVF_I_UN:
2371 case OP_LCONV_TO_OVF_U_UN:
2372 case OP_LCONV_TO_OVF_I1:
2373 case OP_LCONV_TO_OVF_U1:
2374 case OP_LCONV_TO_OVF_I2:
2375 case OP_LCONV_TO_OVF_U2:
2376 case OP_LCONV_TO_OVF_I4:
2377 case OP_LCONV_TO_OVF_U4:
2378 case OP_LCONV_TO_OVF_I8:
2379 case OP_LCONV_TO_OVF_U8:
2387 case OP_LCONV_TO_R_UN:
2393 case OP_LSHR_UN_IMM:
2395 case OP_LDIV_UN_IMM:
2397 case OP_LREM_UN_IMM:
2408 mono_print_ins (ins);
2409 g_assert_not_reached ();
2411 case OP_LCONV_TO_R8_2:
2412 case OP_LCONV_TO_R4_2:
2413 case OP_LCONV_TO_R_UN_2:
2415 case OP_LCONV_TO_OVF_I4_2:
2416 tmp1 = mono_alloc_ireg (cfg);
2418 /* Overflows if reg2 != sign extension of reg1 */
2419 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2420 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2421 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2429 mono_print_ins (ins);
2430 g_assert_not_reached ();
2438 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2446 switch (ins->opcode) {
2448 tmp1 = mono_alloc_ireg (cfg);
2449 tmp2 = mono_alloc_ireg (cfg);
2450 tmp3 = mono_alloc_ireg (cfg);
2451 tmp4 = mono_alloc_ireg (cfg);
2452 tmp5 = mono_alloc_ireg (cfg);
2454 /* add the operands */
2456 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2458 /* Overflow happens if
2459 * neg + neg = pos or
2462 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2463 * XOR of the high bit returns 0 if the signs match
2464 * XOR of that with the high bit of the result return 1 if overflow.
2467 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2468 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2470 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2471 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2472 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2474 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2475 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2477 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2479 /* Now, if (tmp5 == 0) then overflow */
2480 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2481 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2482 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2486 case OP_IADD_OVF_UN:
2487 tmp1 = mono_alloc_ireg (cfg);
2489 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2490 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2491 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2492 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2493 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2498 tmp1 = mono_alloc_ireg (cfg);
2499 tmp2 = mono_alloc_ireg (cfg);
2500 tmp3 = mono_alloc_ireg (cfg);
2501 tmp4 = mono_alloc_ireg (cfg);
2502 tmp5 = mono_alloc_ireg (cfg);
2504 /* add the operands */
2506 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2508 /* Overflow happens if
2509 * neg - pos = pos or
2511 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2513 * tmp1 = (lhs ^ rhs)
2514 * tmp2 = (lhs ^ result)
2515 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2518 /* tmp3 = 1 if the signs of the two inputs differ */
2519 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2520 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2521 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2522 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2523 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2525 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2526 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2527 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2531 case OP_ISUB_OVF_UN:
2532 tmp1 = mono_alloc_ireg (cfg);
2534 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2535 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2536 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2537 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2538 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2545 map_to_reg_reg_op (int op)
2554 case OP_COMPARE_IMM:
2556 case OP_ICOMPARE_IMM:
2558 case OP_LCOMPARE_IMM:
2574 case OP_LOAD_MEMBASE:
2575 return OP_LOAD_MEMINDEX;
2576 case OP_LOADI4_MEMBASE:
2577 return OP_LOADI4_MEMINDEX;
2578 case OP_LOADU4_MEMBASE:
2579 return OP_LOADU4_MEMINDEX;
2580 case OP_LOADU1_MEMBASE:
2581 return OP_LOADU1_MEMINDEX;
2582 case OP_LOADI2_MEMBASE:
2583 return OP_LOADI2_MEMINDEX;
2584 case OP_LOADU2_MEMBASE:
2585 return OP_LOADU2_MEMINDEX;
2586 case OP_LOADI1_MEMBASE:
2587 return OP_LOADI1_MEMINDEX;
2588 case OP_LOADR4_MEMBASE:
2589 return OP_LOADR4_MEMINDEX;
2590 case OP_LOADR8_MEMBASE:
2591 return OP_LOADR8_MEMINDEX;
2592 case OP_STOREI1_MEMBASE_REG:
2593 return OP_STOREI1_MEMINDEX;
2594 case OP_STOREI2_MEMBASE_REG:
2595 return OP_STOREI2_MEMINDEX;
2596 case OP_STOREI4_MEMBASE_REG:
2597 return OP_STOREI4_MEMINDEX;
2598 case OP_STORE_MEMBASE_REG:
2599 return OP_STORE_MEMINDEX;
2600 case OP_STORER4_MEMBASE_REG:
2601 return OP_STORER4_MEMINDEX;
2602 case OP_STORER8_MEMBASE_REG:
2603 return OP_STORER8_MEMINDEX;
2604 case OP_STORE_MEMBASE_IMM:
2605 return OP_STORE_MEMBASE_REG;
2606 case OP_STOREI1_MEMBASE_IMM:
2607 return OP_STOREI1_MEMBASE_REG;
2608 case OP_STOREI2_MEMBASE_IMM:
2609 return OP_STOREI2_MEMBASE_REG;
2610 case OP_STOREI4_MEMBASE_IMM:
2611 return OP_STOREI4_MEMBASE_REG;
2612 case OP_STOREI8_MEMBASE_IMM:
2613 return OP_STOREI8_MEMBASE_REG;
2615 return mono_op_imm_to_op (op);
2619 map_to_mips_op (int op)
2623 return OP_MIPS_FBEQ;
2625 return OP_MIPS_FBGE;
2627 return OP_MIPS_FBGT;
2629 return OP_MIPS_FBLE;
2631 return OP_MIPS_FBLT;
2633 return OP_MIPS_FBNE;
2635 return OP_MIPS_FBGE_UN;
2637 return OP_MIPS_FBGT_UN;
2639 return OP_MIPS_FBLE_UN;
2641 return OP_MIPS_FBLT_UN;
2649 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2650 g_assert_not_reached ();
2654 #define NEW_INS(cfg,after,dest,op) do { \
2655 MONO_INST_NEW((cfg), (dest), (op)); \
2656 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2659 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2661 MONO_INST_NEW(cfg, temp, (op)); \
2662 mono_bblock_insert_after_ins (bb, (pos), temp); \
2663 temp->dreg = (_dreg); \
2664 temp->sreg1 = (_sreg1); \
2665 temp->sreg2 = (_sreg2); \
2669 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2671 MONO_INST_NEW(cfg, temp, (op)); \
2672 mono_bblock_insert_after_ins (bb, (pos), temp); \
2673 temp->dreg = (_dreg); \
2674 temp->sreg1 = (_sreg1); \
2675 temp->inst_c0 = (_imm); \
2680 * Remove from the instruction list the instructions that can't be
2681 * represented with very simple instructions with no register
2685 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2687 MonoInst *ins, *next, *temp, *last_ins = NULL;
2691 if (cfg->verbose_level > 2) {
2694 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2695 MONO_BB_FOR_EACH_INS (bb, ins) {
2696 mono_print_ins_index (idx++, ins);
2702 MONO_BB_FOR_EACH_INS (bb, ins) {
2704 switch (ins->opcode) {
2709 /* Branch opts can eliminate the branch */
2710 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2716 case OP_COMPARE_IMM:
2717 case OP_ICOMPARE_IMM:
2718 case OP_LCOMPARE_IMM:
2720 /* Branch opts can eliminate the branch */
2721 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2725 if (ins->inst_imm) {
2726 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2727 temp->inst_c0 = ins->inst_imm;
2728 temp->dreg = mono_alloc_ireg (cfg);
2729 ins->sreg2 = temp->dreg;
2733 ins->sreg2 = mips_zero;
2735 if (ins->opcode == OP_COMPARE_IMM)
2736 ins->opcode = OP_COMPARE;
2737 else if (ins->opcode == OP_ICOMPARE_IMM)
2738 ins->opcode = OP_ICOMPARE;
2739 else if (ins->opcode == OP_LCOMPARE_IMM)
2740 ins->opcode = OP_LCOMPARE;
2743 case OP_IDIV_UN_IMM:
2746 case OP_IREM_UN_IMM:
2747 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2748 temp->inst_c0 = ins->inst_imm;
2749 temp->dreg = mono_alloc_ireg (cfg);
2750 ins->sreg2 = temp->dreg;
2751 if (ins->opcode == OP_IDIV_IMM)
2752 ins->opcode = OP_IDIV;
2753 else if (ins->opcode == OP_IREM_IMM)
2754 ins->opcode = OP_IREM;
2755 else if (ins->opcode == OP_IDIV_UN_IMM)
2756 ins->opcode = OP_IDIV_UN;
2757 else if (ins->opcode == OP_IREM_UN_IMM)
2758 ins->opcode = OP_IREM_UN;
2760 /* handle rem separately */
2767 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2768 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2769 temp->inst_c0 = ins->inst_imm;
2770 temp->dreg = mono_alloc_ireg (cfg);
2771 ins->sreg2 = temp->dreg;
2772 ins->opcode = map_to_reg_reg_op (ins->opcode);
2782 /* unsigned 16 bit immediate */
2783 if (ins->inst_imm & 0xffff0000) {
2784 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2785 temp->inst_c0 = ins->inst_imm;
2786 temp->dreg = mono_alloc_ireg (cfg);
2787 ins->sreg2 = temp->dreg;
2788 ins->opcode = map_to_reg_reg_op (ins->opcode);
2795 /* signed 16 bit immediate */
2796 if (!mips_is_imm16 (ins->inst_imm)) {
2797 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2798 temp->inst_c0 = ins->inst_imm;
2799 temp->dreg = mono_alloc_ireg (cfg);
2800 ins->sreg2 = temp->dreg;
2801 ins->opcode = map_to_reg_reg_op (ins->opcode);
2807 if (!mips_is_imm16 (-ins->inst_imm)) {
2808 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2809 temp->inst_c0 = ins->inst_imm;
2810 temp->dreg = mono_alloc_ireg (cfg);
2811 ins->sreg2 = temp->dreg;
2812 ins->opcode = map_to_reg_reg_op (ins->opcode);
2818 if (ins->inst_imm == 1) {
2819 ins->opcode = OP_MOVE;
2822 if (ins->inst_imm == 0) {
2823 ins->opcode = OP_ICONST;
2827 imm = mono_is_power_of_two (ins->inst_imm);
2829 ins->opcode = OP_SHL_IMM;
2830 ins->inst_imm = imm;
2833 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2834 temp->inst_c0 = ins->inst_imm;
2835 temp->dreg = mono_alloc_ireg (cfg);
2836 ins->sreg2 = temp->dreg;
2837 ins->opcode = map_to_reg_reg_op (ins->opcode);
2840 case OP_LOCALLOC_IMM:
2841 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2842 temp->inst_c0 = ins->inst_imm;
2843 temp->dreg = mono_alloc_ireg (cfg);
2844 ins->sreg1 = temp->dreg;
2845 ins->opcode = OP_LOCALLOC;
2848 case OP_LOADR4_MEMBASE:
2849 case OP_STORER4_MEMBASE_REG:
2850 /* we can do two things: load the immed in a register
2851 * and use an indexed load, or see if the immed can be
2852 * represented as an ad_imm + a load with a smaller offset
2853 * that fits. We just do the first for now, optimize later.
2855 if (mips_is_imm16 (ins->inst_offset))
2857 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2858 temp->inst_c0 = ins->inst_offset;
2859 temp->dreg = mono_alloc_ireg (cfg);
2860 ins->sreg2 = temp->dreg;
2861 ins->opcode = map_to_reg_reg_op (ins->opcode);
2864 case OP_STORE_MEMBASE_IMM:
2865 case OP_STOREI1_MEMBASE_IMM:
2866 case OP_STOREI2_MEMBASE_IMM:
2867 case OP_STOREI4_MEMBASE_IMM:
2868 case OP_STOREI8_MEMBASE_IMM:
2869 if (!ins->inst_imm) {
2870 ins->sreg1 = mips_zero;
2871 ins->opcode = map_to_reg_reg_op (ins->opcode);
2874 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2875 temp->inst_c0 = ins->inst_imm;
2876 temp->dreg = mono_alloc_ireg (cfg);
2877 ins->sreg1 = temp->dreg;
2878 ins->opcode = map_to_reg_reg_op (ins->opcode);
2880 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2886 /* Branch opts can eliminate the branch */
2887 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2894 * remap compare/branch and compare/set
2895 * to MIPS specific opcodes.
2897 next->opcode = map_to_mips_op (next->opcode);
2898 next->sreg1 = ins->sreg1;
2899 next->sreg2 = ins->sreg2;
2906 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2907 temp->inst_c0 = (guint32)ins->inst_p0;
2908 temp->dreg = mono_alloc_ireg (cfg);
2909 ins->inst_basereg = temp->dreg;
2910 ins->inst_offset = 0;
2911 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2913 /* make it handle the possibly big ins->inst_offset
2914 * later optimize to use lis + load_membase
2919 g_assert (ins_is_compare(last_ins));
2920 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2921 NULLIFY_INS(last_ins);
2925 g_assert (ins_is_compare(last_ins));
2926 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2927 NULLIFY_INS(last_ins);
2931 g_assert (ins_is_compare(last_ins));
2932 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2933 last_ins->dreg = mono_alloc_ireg (cfg);
2934 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2938 g_assert (ins_is_compare(last_ins));
2939 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2940 last_ins->dreg = mono_alloc_ireg (cfg);
2941 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2945 g_assert (ins_is_compare(last_ins));
2946 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2947 last_ins->dreg = mono_alloc_ireg (cfg);
2948 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2952 g_assert (ins_is_compare(last_ins));
2953 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2954 last_ins->dreg = mono_alloc_ireg (cfg);
2955 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2959 g_assert (ins_is_compare(last_ins));
2960 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2961 last_ins->dreg = mono_alloc_ireg (cfg);
2962 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2966 g_assert (ins_is_compare(last_ins));
2967 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2968 last_ins->dreg = mono_alloc_ireg (cfg);
2969 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2973 g_assert (ins_is_compare(last_ins));
2974 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2975 last_ins->dreg = mono_alloc_ireg (cfg);
2976 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2980 g_assert (ins_is_compare(last_ins));
2981 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2982 last_ins->dreg = mono_alloc_ireg (cfg);
2983 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2988 g_assert (ins_is_compare(last_ins));
2989 last_ins->opcode = OP_IXOR;
2990 last_ins->dreg = mono_alloc_ireg(cfg);
2991 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2996 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2997 NULLIFY_INS(last_ins);
3003 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
3004 NULLIFY_INS(last_ins);
3009 g_assert (ins_is_compare(last_ins));
3010 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
3011 MONO_DELETE_INS(bb, last_ins);
3016 g_assert (ins_is_compare(last_ins));
3017 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3018 MONO_DELETE_INS(bb, last_ins);
3021 case OP_COND_EXC_EQ:
3022 case OP_COND_EXC_IEQ:
3023 g_assert (ins_is_compare(last_ins));
3024 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3025 MONO_DELETE_INS(bb, last_ins);
3028 case OP_COND_EXC_GE:
3029 case OP_COND_EXC_IGE:
3030 g_assert (ins_is_compare(last_ins));
3031 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3032 MONO_DELETE_INS(bb, last_ins);
3035 case OP_COND_EXC_GT:
3036 case OP_COND_EXC_IGT:
3037 g_assert (ins_is_compare(last_ins));
3038 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3039 MONO_DELETE_INS(bb, last_ins);
3042 case OP_COND_EXC_LE:
3043 case OP_COND_EXC_ILE:
3044 g_assert (ins_is_compare(last_ins));
3045 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3046 MONO_DELETE_INS(bb, last_ins);
3049 case OP_COND_EXC_LT:
3050 case OP_COND_EXC_ILT:
3051 g_assert (ins_is_compare(last_ins));
3052 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3053 MONO_DELETE_INS(bb, last_ins);
3056 case OP_COND_EXC_NE_UN:
3057 case OP_COND_EXC_INE_UN:
3058 g_assert (ins_is_compare(last_ins));
3059 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3060 MONO_DELETE_INS(bb, last_ins);
3063 case OP_COND_EXC_GE_UN:
3064 case OP_COND_EXC_IGE_UN:
3065 g_assert (ins_is_compare(last_ins));
3066 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3067 MONO_DELETE_INS(bb, last_ins);
3070 case OP_COND_EXC_GT_UN:
3071 case OP_COND_EXC_IGT_UN:
3072 g_assert (ins_is_compare(last_ins));
3073 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3074 MONO_DELETE_INS(bb, last_ins);
3077 case OP_COND_EXC_LE_UN:
3078 case OP_COND_EXC_ILE_UN:
3079 g_assert (ins_is_compare(last_ins));
3080 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3081 MONO_DELETE_INS(bb, last_ins);
3084 case OP_COND_EXC_LT_UN:
3085 case OP_COND_EXC_ILT_UN:
3086 g_assert (ins_is_compare(last_ins));
3087 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3088 MONO_DELETE_INS(bb, last_ins);
3091 case OP_COND_EXC_OV:
3092 case OP_COND_EXC_IOV: {
3093 int tmp1, tmp2, tmp3, tmp4, tmp5;
3094 MonoInst *pos = last_ins;
3096 /* Overflow happens if
3097 * neg + neg = pos or
3100 * (bit31s of operands match) AND (bit31 of operand
3101 * != bit31 of result)
3102 * XOR of the high bit returns 0 if the signs match
3103 * XOR of that with the high bit of the result return 1
3106 g_assert (last_ins->opcode == OP_IADC);
3108 tmp1 = mono_alloc_ireg (cfg);
3109 tmp2 = mono_alloc_ireg (cfg);
3110 tmp3 = mono_alloc_ireg (cfg);
3111 tmp4 = mono_alloc_ireg (cfg);
3112 tmp5 = mono_alloc_ireg (cfg);
3114 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3115 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3117 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3118 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3119 INS (pos, OP_INOT, tmp3, tmp2, -1);
3121 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3122 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3123 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3125 /* Now, if (tmp5 == 0) then overflow */
3126 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3131 case OP_COND_EXC_NO:
3132 case OP_COND_EXC_INO:
3133 g_assert_not_reached ();
3137 case OP_COND_EXC_IC:
3138 g_assert_not_reached ();
3141 case OP_COND_EXC_NC:
3142 case OP_COND_EXC_INC:
3143 g_assert_not_reached ();
3149 bb->last_ins = last_ins;
3150 bb->max_vreg = cfg->next_vreg;
3153 if (cfg->verbose_level > 2) {
3156 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3157 MONO_BB_FOR_EACH_INS (bb, ins) {
3158 mono_print_ins_index (idx++, ins);
3167 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3169 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3171 mips_truncwd (code, mips_ftemp, sreg);
3173 mips_cvtwd (code, mips_ftemp, sreg);
3175 mips_mfc1 (code, dreg, mips_ftemp);
3178 mips_andi (code, dreg, dreg, 0xff);
3179 else if (size == 2) {
3180 mips_sll (code, dreg, dreg, 16);
3181 mips_srl (code, dreg, dreg, 16);
3185 mips_sll (code, dreg, dreg, 24);
3186 mips_sra (code, dreg, dreg, 24);
3188 else if (size == 2) {
3189 mips_sll (code, dreg, dreg, 16);
3190 mips_sra (code, dreg, dreg, 16);
3197 * emit_load_volatile_arguments:
3199 * Load volatile arguments from the stack to the original input registers.
3200 * Required before a tail call.
3203 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3205 MonoMethod *method = cfg->method;
3206 MonoMethodSignature *sig;
3211 sig = mono_method_signature (method);
3213 if (!cfg->arch.cinfo)
3214 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
3215 cinfo = cfg->arch.cinfo;
3217 if (cinfo->struct_ret) {
3218 ArgInfo *ainfo = &cinfo->ret;
3219 inst = cfg->vret_addr;
3220 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3223 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3224 ArgInfo *ainfo = cinfo->args + i;
3225 inst = cfg->args [i];
3226 if (inst->opcode == OP_REGVAR) {
3227 if (ainfo->storage == ArgInIReg)
3228 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3229 else if (ainfo->storage == ArgInFReg)
3230 g_assert_not_reached();
3231 else if (ainfo->storage == ArgOnStack) {
3234 g_assert_not_reached ();
3236 if (ainfo->storage == ArgInIReg) {
3237 g_assert (mips_is_imm16 (inst->inst_offset));
3238 switch (ainfo->size) {
3240 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3243 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3247 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3250 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3251 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3254 g_assert_not_reached ();
3257 } else if (ainfo->storage == ArgOnStack) {
3259 } else if (ainfo->storage == ArgInFReg) {
3260 g_assert (mips_is_imm16 (inst->inst_offset));
3261 if (ainfo->size == 8) {
3262 #if _MIPS_SIM == _ABIO32
3263 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3264 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3265 #elif _MIPS_SIM == _ABIN32
3266 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3269 else if (ainfo->size == 4)
3270 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3272 g_assert_not_reached ();
3273 } else if (ainfo->storage == ArgStructByVal) {
3275 int doffset = inst->inst_offset;
3277 g_assert (mips_is_imm16 (inst->inst_offset));
3278 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3279 for (i = 0; i < ainfo->size; ++i) {
3280 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3281 doffset += SIZEOF_REGISTER;
3283 } else if (ainfo->storage == ArgStructByAddr) {
3284 g_assert (mips_is_imm16 (inst->inst_offset));
3285 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3287 g_assert_not_reached ();
3295 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3297 int size = cfg->param_area;
3299 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3300 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3305 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3306 if (ppc_is_imm16 (-size)) {
3307 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3309 ppc_load (code, ppc_r11, -size);
3310 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3317 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3319 int size = cfg->param_area;
3321 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3322 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3327 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3328 if (ppc_is_imm16 (size)) {
3329 ppc_stwu (code, ppc_r0, size, ppc_sp);
3331 ppc_load (code, ppc_r11, size);
3332 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3339 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3344 guint8 *code = cfg->native_code + cfg->code_len;
3345 MonoInst *last_ins = NULL;
3346 guint last_offset = 0;
3350 /* we don't align basic blocks of loops on mips */
3352 if (cfg->verbose_level > 2)
3353 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3355 cpos = bb->max_offset;
3358 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3359 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3360 g_assert (!mono_compile_aot);
3363 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3364 /* this is not thread save, but good enough */
3365 /* fixme: howto handle overflows? */
3366 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3367 mips_lw (code, mips_temp, mips_at, 0);
3368 mips_addiu (code, mips_temp, mips_temp, 1);
3369 mips_sw (code, mips_temp, mips_at, 0);
3372 MONO_BB_FOR_EACH_INS (bb, ins) {
3373 offset = code - cfg->native_code;
3375 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3377 if (offset > (cfg->code_size - max_len - 16)) {
3378 cfg->code_size *= 2;
3379 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3380 code = cfg->native_code + offset;
3382 mono_debug_record_line_number (cfg, ins, offset);
3383 if (cfg->verbose_level > 2) {
3384 g_print (" @ 0x%x\t", offset);
3385 mono_print_ins_index (ins_cnt++, ins);
3387 /* Check for virtual regs that snuck by */
3388 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3390 switch (ins->opcode) {
3391 case OP_RELAXED_NOP:
3394 case OP_DUMMY_STORE:
3395 case OP_NOT_REACHED:
3398 case OP_SEQ_POINT: {
3399 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3400 guint32 addr = (guint32)ss_trigger_page;
3402 mips_load_const (code, mips_t9, addr);
3403 mips_lw (code, mips_t9, mips_t9, 0);
3406 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3409 * A placeholder for a possible breakpoint inserted by
3410 * mono_arch_set_breakpoint ().
3412 /* mips_load_const () + mips_lw */
3419 g_assert_not_reached();
3421 emit_tls_access (code, ins->dreg, ins->inst_offset);
3425 mips_mult (code, ins->sreg1, ins->sreg2);
3426 mips_mflo (code, ins->dreg);
3427 mips_mfhi (code, ins->dreg+1);
3430 mips_multu (code, ins->sreg1, ins->sreg2);
3431 mips_mflo (code, ins->dreg);
3432 mips_mfhi (code, ins->dreg+1);
3434 case OP_MEMORY_BARRIER:
3439 case OP_STOREI1_MEMBASE_IMM:
3440 mips_load_const (code, mips_temp, ins->inst_imm);
3441 if (mips_is_imm16 (ins->inst_offset)) {
3442 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3444 mips_load_const (code, mips_at, ins->inst_offset);
3445 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3448 case OP_STOREI2_MEMBASE_IMM:
3449 mips_load_const (code, mips_temp, ins->inst_imm);
3450 if (mips_is_imm16 (ins->inst_offset)) {
3451 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3453 mips_load_const (code, mips_at, ins->inst_offset);
3454 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3457 case OP_STOREI8_MEMBASE_IMM:
3458 mips_load_const (code, mips_temp, ins->inst_imm);
3459 if (mips_is_imm16 (ins->inst_offset)) {
3460 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3462 mips_load_const (code, mips_at, ins->inst_offset);
3463 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3466 case OP_STORE_MEMBASE_IMM:
3467 case OP_STOREI4_MEMBASE_IMM:
3468 mips_load_const (code, mips_temp, ins->inst_imm);
3469 if (mips_is_imm16 (ins->inst_offset)) {
3470 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3472 mips_load_const (code, mips_at, ins->inst_offset);
3473 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3476 case OP_STOREI1_MEMBASE_REG:
3477 if (mips_is_imm16 (ins->inst_offset)) {
3478 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3480 mips_load_const (code, mips_at, ins->inst_offset);
3481 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3482 mips_sb (code, ins->sreg1, mips_at, 0);
3485 case OP_STOREI2_MEMBASE_REG:
3486 if (mips_is_imm16 (ins->inst_offset)) {
3487 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3489 mips_load_const (code, mips_at, ins->inst_offset);
3490 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3491 mips_sh (code, ins->sreg1, mips_at, 0);
3494 case OP_STORE_MEMBASE_REG:
3495 case OP_STOREI4_MEMBASE_REG:
3496 if (mips_is_imm16 (ins->inst_offset)) {
3497 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3499 mips_load_const (code, mips_at, ins->inst_offset);
3500 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3501 mips_sw (code, ins->sreg1, mips_at, 0);
3504 case OP_STOREI8_MEMBASE_REG:
3505 if (mips_is_imm16 (ins->inst_offset)) {
3506 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3508 mips_load_const (code, mips_at, ins->inst_offset);
3509 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3510 mips_sd (code, ins->sreg1, mips_at, 0);
3514 g_assert_not_reached ();
3515 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3516 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3518 case OP_LOADI8_MEMBASE:
3519 if (mips_is_imm16 (ins->inst_offset)) {
3520 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3522 mips_load_const (code, mips_at, ins->inst_offset);
3523 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3524 mips_ld (code, ins->dreg, mips_at, 0);
3527 case OP_LOAD_MEMBASE:
3528 case OP_LOADI4_MEMBASE:
3529 case OP_LOADU4_MEMBASE:
3530 g_assert (ins->dreg != -1);
3531 if (mips_is_imm16 (ins->inst_offset)) {
3532 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3534 mips_load_const (code, mips_at, ins->inst_offset);
3535 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3536 mips_lw (code, ins->dreg, mips_at, 0);
3539 case OP_LOADI1_MEMBASE:
3540 if (mips_is_imm16 (ins->inst_offset)) {
3541 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3543 mips_load_const (code, mips_at, ins->inst_offset);
3544 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3545 mips_lb (code, ins->dreg, mips_at, 0);
3548 case OP_LOADU1_MEMBASE:
3549 if (mips_is_imm16 (ins->inst_offset)) {
3550 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3552 mips_load_const (code, mips_at, ins->inst_offset);
3553 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3554 mips_lbu (code, ins->dreg, mips_at, 0);
3557 case OP_LOADI2_MEMBASE:
3558 if (mips_is_imm16 (ins->inst_offset)) {
3559 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3561 mips_load_const (code, mips_at, ins->inst_offset);
3562 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3563 mips_lh (code, ins->dreg, mips_at, 0);
3566 case OP_LOADU2_MEMBASE:
3567 if (mips_is_imm16 (ins->inst_offset)) {
3568 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3570 mips_load_const (code, mips_at, ins->inst_offset);
3571 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3572 mips_lhu (code, ins->dreg, mips_at, 0);
3575 case OP_ICONV_TO_I1:
3576 mips_sll (code, mips_at, ins->sreg1, 24);
3577 mips_sra (code, ins->dreg, mips_at, 24);
3579 case OP_ICONV_TO_I2:
3580 mips_sll (code, mips_at, ins->sreg1, 16);
3581 mips_sra (code, ins->dreg, mips_at, 16);
3583 case OP_ICONV_TO_U1:
3584 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3586 case OP_ICONV_TO_U2:
3587 mips_sll (code, mips_at, ins->sreg1, 16);
3588 mips_srl (code, ins->dreg, mips_at, 16);
3591 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3594 g_assert (mips_is_imm16 (ins->inst_imm));
3595 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3598 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3601 g_assert (mips_is_imm16 (ins->inst_imm));
3602 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3606 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3607 * So instead of emitting a trap, we emit a call a C function and place a
3610 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3611 (gpointer)"mono_break");
3612 mips_load (code, mips_t9, 0x1f1f1f1f);
3613 mips_jalr (code, mips_t9, mips_ra);
3617 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3620 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3625 g_assert (mips_is_imm16 (ins->inst_imm));
3626 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3629 g_assert (mips_is_imm16 (ins->inst_imm));
3630 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3634 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3637 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3642 // we add the negated value
3643 g_assert (mips_is_imm16 (-ins->inst_imm));
3644 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3648 // we add the negated value
3649 g_assert (mips_is_imm16 (-ins->inst_imm));
3650 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3655 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3661 g_assert (!(ins->inst_imm & 0xffff0000));
3662 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3667 guint32 *divisor_is_m1;
3668 guint32 *dividend_is_minvalue;
3669 guint32 *divisor_is_zero;
3671 mips_load_const (code, mips_at, -1);
3672 divisor_is_m1 = (guint32 *)(void *)code;
3673 mips_bne (code, ins->sreg2, mips_at, 0);
3674 mips_lui (code, mips_at, mips_zero, 0x8000);
3675 dividend_is_minvalue = (guint32 *)(void *)code;
3676 mips_bne (code, ins->sreg1, mips_at, 0);
3679 /* Divide Int32.MinValue by -1 -- throw exception */
3680 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3682 mips_patch (divisor_is_m1, (guint32)code);
3683 mips_patch (dividend_is_minvalue, (guint32)code);
3685 /* Put divide in branch delay slot (NOT YET) */
3686 divisor_is_zero = (guint32 *)(void *)code;
3687 mips_bne (code, ins->sreg2, mips_zero, 0);
3690 /* Divide by zero -- throw exception */
3691 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3693 mips_patch (divisor_is_zero, (guint32)code);
3694 mips_div (code, ins->sreg1, ins->sreg2);
3695 if (ins->opcode == OP_IDIV)
3696 mips_mflo (code, ins->dreg);
3698 mips_mfhi (code, ins->dreg);
3703 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3705 /* Put divide in branch delay slot (NOT YET) */
3706 mips_bne (code, ins->sreg2, mips_zero, 0);
3709 /* Divide by zero -- throw exception */
3710 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3712 mips_patch (divisor_is_zero, (guint32)code);
3713 mips_divu (code, ins->sreg1, ins->sreg2);
3714 if (ins->opcode == OP_IDIV_UN)
3715 mips_mflo (code, ins->dreg);
3717 mips_mfhi (code, ins->dreg);
3721 g_assert_not_reached ();
3723 ppc_load (code, ppc_r11, ins->inst_imm);
3724 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3725 ppc_mfspr (code, ppc_r0, ppc_xer);
3726 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3727 /* FIXME: use OverflowException for 0x80000000/-1 */
3728 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3730 g_assert_not_reached();
3733 g_assert_not_reached ();
3735 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3739 g_assert (!(ins->inst_imm & 0xffff0000));
3740 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3743 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3747 /* unsigned 16-bit immediate */
3748 g_assert (!(ins->inst_imm & 0xffff0000));
3749 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3752 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3756 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3759 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3762 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3766 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3769 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3772 case OP_ISHR_UN_IMM:
3773 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3775 case OP_LSHR_UN_IMM:
3776 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3779 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3782 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3786 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3789 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3792 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3796 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3798 mips_mult (code, ins->sreg1, ins->sreg2);
3799 mips_mflo (code, ins->dreg);
3804 #if SIZEOF_REGISTER == 8
3806 mips_dmult (code, ins->sreg1, ins->sreg2);
3807 mips_mflo (code, ins->dreg);
3812 mips_mult (code, ins->sreg1, ins->sreg2);
3813 mips_mflo (code, ins->dreg);
3814 mips_mfhi (code, mips_at);
3817 mips_sra (code, mips_temp, ins->dreg, 31);
3818 patch = (guint32 *)(void *)code;
3819 mips_beq (code, mips_temp, mips_at, 0);
3821 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3822 mips_patch (patch, (guint32)code);
3825 case OP_IMUL_OVF_UN: {
3827 mips_mult (code, ins->sreg1, ins->sreg2);
3828 mips_mflo (code, ins->dreg);
3829 mips_mfhi (code, mips_at);
3832 patch = (guint32 *)(void *)code;
3833 mips_beq (code, mips_at, mips_zero, 0);
3835 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3836 mips_patch (patch, (guint32)code);
3840 mips_load_const (code, ins->dreg, ins->inst_c0);
3842 #if SIZEOF_REGISTER == 8
3844 mips_load_const (code, ins->dreg, ins->inst_c0);
3848 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3849 mips_load (code, ins->dreg, 0);
3853 mips_mtc1 (code, ins->dreg, ins->sreg1);
3855 case OP_MIPS_MTC1S_2:
3856 mips_mtc1 (code, ins->dreg, ins->sreg1);
3857 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3860 mips_mfc1 (code, ins->dreg, ins->sreg1);
3863 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3867 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3869 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3870 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3874 case OP_ICONV_TO_I4:
3875 case OP_ICONV_TO_U4:
3877 if (ins->dreg != ins->sreg1)
3878 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3880 #if SIZEOF_REGISTER == 8
3882 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3883 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3886 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3887 mips_dsra (code, ins->dreg, ins->dreg, 32);
3891 int lsreg = mips_v0 + ls_word_idx;
3892 int msreg = mips_v0 + ms_word_idx;
3894 /* Get sreg1 into lsreg, sreg2 into msreg */
3896 if (ins->sreg1 == msreg) {
3897 if (ins->sreg1 != mips_at)
3898 MIPS_MOVE (code, mips_at, ins->sreg1);
3899 if (ins->sreg2 != msreg)
3900 MIPS_MOVE (code, msreg, ins->sreg2);
3901 MIPS_MOVE (code, lsreg, mips_at);
3904 if (ins->sreg2 != msreg)
3905 MIPS_MOVE (code, msreg, ins->sreg2);
3906 if (ins->sreg1 != lsreg)
3907 MIPS_MOVE (code, lsreg, ins->sreg1);
3912 if (ins->dreg != ins->sreg1) {
3913 mips_fmovd (code, ins->dreg, ins->sreg1);
3917 /* Convert from double to float and leave it there */
3918 mips_cvtsd (code, ins->dreg, ins->sreg1);
3920 case OP_FCONV_TO_R4:
3922 mips_cvtsd (code, ins->dreg, ins->sreg1);
3924 /* Just a move, no precision change */
3925 if (ins->dreg != ins->sreg1) {
3926 mips_fmovd (code, ins->dreg, ins->sreg1);
3931 code = emit_load_volatile_arguments(cfg, code);
3934 * Pop our stack, then jump to specified method (tail-call)
3935 * Keep in sync with mono_arch_emit_epilog
3937 code = mono_arch_emit_epilog_sub (cfg, code);
3939 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3940 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3941 mips_load (code, mips_t9, 0);
3942 mips_jr (code, mips_t9);
3946 /* ensure ins->sreg1 is not NULL */
3947 mips_lw (code, mips_zero, ins->sreg1, 0);
3950 g_assert (mips_is_imm16 (cfg->sig_cookie));
3951 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3952 mips_sw (code, mips_at, ins->sreg1, 0);
3965 case OP_VOIDCALL_REG:
3967 case OP_FCALL_MEMBASE:
3968 case OP_LCALL_MEMBASE:
3969 case OP_VCALL_MEMBASE:
3970 case OP_VCALL2_MEMBASE:
3971 case OP_VOIDCALL_MEMBASE:
3972 case OP_CALL_MEMBASE:
3973 call = (MonoCallInst*)ins;
3974 switch (ins->opcode) {
3981 if (ins->flags & MONO_INST_HAS_METHOD) {
3982 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3983 mips_load (code, mips_t9, call->method);
3986 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3987 mips_load (code, mips_t9, call->fptr);
3989 mips_jalr (code, mips_t9, mips_ra);
3996 case OP_VOIDCALL_REG:
3998 MIPS_MOVE (code, mips_t9, ins->sreg1);
3999 mips_jalr (code, mips_t9, mips_ra);
4002 case OP_FCALL_MEMBASE:
4003 case OP_LCALL_MEMBASE:
4004 case OP_VCALL_MEMBASE:
4005 case OP_VCALL2_MEMBASE:
4006 case OP_VOIDCALL_MEMBASE:
4007 case OP_CALL_MEMBASE:
4008 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
4009 mips_jalr (code, mips_t9, mips_ra);
4013 #if PROMOTE_R4_TO_R8
4014 /* returned an FP R4 (single), promote to R8 (double) in place */
4015 switch (ins->opcode) {
4018 case OP_FCALL_MEMBASE:
4019 if (call->signature->ret->type == MONO_TYPE_R4)
4020 mips_cvtds (code, mips_f0, mips_f0);
4028 int area_offset = cfg->param_area;
4030 /* Round up ins->sreg1, mips_at ends up holding size */
4031 mips_addiu (code, mips_at, ins->sreg1, 31);
4032 mips_addiu (code, mips_temp, mips_zero, ~31);
4033 mips_and (code, mips_at, mips_at, mips_temp);
4035 mips_subu (code, mips_sp, mips_sp, mips_at);
4036 g_assert (mips_is_imm16 (area_offset));
4037 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4039 if (ins->flags & MONO_INST_INIT) {
4042 buf = (guint32*)(void*)code;
4043 mips_beq (code, mips_at, mips_zero, 0);
4046 mips_move (code, mips_temp, ins->dreg);
4047 mips_sb (code, mips_zero, mips_temp, 0);
4048 mips_addiu (code, mips_at, mips_at, -1);
4049 mips_bne (code, mips_at, mips_zero, -3);
4050 mips_addiu (code, mips_temp, mips_temp, 1);
4052 mips_patch (buf, (guint32)code);
4057 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4058 mips_move (code, mips_a0, ins->sreg1);
4059 mips_call (code, mips_t9, addr);
4060 mips_break (code, 0xfc);
4064 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4065 mips_move (code, mips_a0, ins->sreg1);
4066 mips_call (code, mips_t9, addr);
4067 mips_break (code, 0xfb);
4070 case OP_START_HANDLER: {
4072 * The START_HANDLER instruction marks the beginning of
4073 * a handler block. It is called using a call
4074 * instruction, so mips_ra contains the return address.
4075 * Since the handler executes in the same stack frame
4076 * as the method itself, we can't use save/restore to
4077 * save the return address. Instead, we save it into
4078 * a dedicated variable.
4080 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4081 g_assert (spvar->inst_basereg != mips_sp);
4082 code = emit_reserve_param_area (cfg, code);
4084 if (mips_is_imm16 (spvar->inst_offset)) {
4085 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4087 mips_load_const (code, mips_at, spvar->inst_offset);
4088 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4089 mips_sw (code, mips_ra, mips_at, 0);
4093 case OP_ENDFILTER: {
4094 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4095 g_assert (spvar->inst_basereg != mips_sp);
4096 code = emit_unreserve_param_area (cfg, code);
4098 if (ins->sreg1 != mips_v0)
4099 MIPS_MOVE (code, mips_v0, ins->sreg1);
4100 if (mips_is_imm16 (spvar->inst_offset)) {
4101 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4103 mips_load_const (code, mips_at, spvar->inst_offset);
4104 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4105 mips_lw (code, mips_ra, mips_at, 0);
4107 mips_jr (code, mips_ra);
4111 case OP_ENDFINALLY: {
4112 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4113 g_assert (spvar->inst_basereg != mips_sp);
4114 code = emit_unreserve_param_area (cfg, code);
4115 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4116 mips_jalr (code, mips_t9, mips_ra);
4120 case OP_CALL_HANDLER:
4121 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4122 mips_lui (code, mips_t9, mips_zero, 0);
4123 mips_addiu (code, mips_t9, mips_t9, 0);
4124 mips_jalr (code, mips_t9, mips_ra);
4126 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4127 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4130 ins->inst_c0 = code - cfg->native_code;
4133 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4134 if (cfg->arch.long_branch) {
4135 mips_lui (code, mips_at, mips_zero, 0);
4136 mips_addiu (code, mips_at, mips_at, 0);
4137 mips_jr (code, mips_at);
4141 mips_beq (code, mips_zero, mips_zero, 0);
4146 mips_jr (code, ins->sreg1);
4152 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4153 if (offset > (cfg->code_size - max_len - 16)) {
4154 cfg->code_size += max_len;
4155 cfg->code_size *= 2;
4156 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4157 code = cfg->native_code + offset;
4159 g_assert (ins->sreg1 != -1);
4160 mips_sll (code, mips_at, ins->sreg1, 2);
4161 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4162 MIPS_MOVE (code, mips_t8, mips_ra);
4163 mips_bgezal (code, mips_zero, 1); /* bal */
4165 mips_addu (code, mips_t9, mips_ra, mips_at);
4166 /* Table is 16 or 20 bytes from target of bal above */
4167 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4168 MIPS_MOVE (code, mips_ra, mips_t8);
4169 mips_lw (code, mips_t9, mips_t9, 20);
4172 mips_lw (code, mips_t9, mips_t9, 16);
4173 mips_jalr (code, mips_t9, mips_t8);
4175 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4176 mips_emit32 (code, 0xfefefefe);
4181 mips_addiu (code, ins->dreg, mips_zero, 1);
4182 mips_beq (code, mips_at, mips_zero, 2);
4184 MIPS_MOVE (code, ins->dreg, mips_zero);
4190 mips_addiu (code, ins->dreg, mips_zero, 1);
4191 mips_bltz (code, mips_at, 2);
4193 MIPS_MOVE (code, ins->dreg, mips_zero);
4199 mips_addiu (code, ins->dreg, mips_zero, 1);
4200 mips_bgtz (code, mips_at, 2);
4202 MIPS_MOVE (code, ins->dreg, mips_zero);
4205 case OP_MIPS_COND_EXC_EQ:
4206 case OP_MIPS_COND_EXC_GE:
4207 case OP_MIPS_COND_EXC_GT:
4208 case OP_MIPS_COND_EXC_LE:
4209 case OP_MIPS_COND_EXC_LT:
4210 case OP_MIPS_COND_EXC_NE_UN:
4211 case OP_MIPS_COND_EXC_GE_UN:
4212 case OP_MIPS_COND_EXC_GT_UN:
4213 case OP_MIPS_COND_EXC_LE_UN:
4214 case OP_MIPS_COND_EXC_LT_UN:
4216 case OP_MIPS_COND_EXC_OV:
4217 case OP_MIPS_COND_EXC_NO:
4218 case OP_MIPS_COND_EXC_C:
4219 case OP_MIPS_COND_EXC_NC:
4221 case OP_MIPS_COND_EXC_IEQ:
4222 case OP_MIPS_COND_EXC_IGE:
4223 case OP_MIPS_COND_EXC_IGT:
4224 case OP_MIPS_COND_EXC_ILE:
4225 case OP_MIPS_COND_EXC_ILT:
4226 case OP_MIPS_COND_EXC_INE_UN:
4227 case OP_MIPS_COND_EXC_IGE_UN:
4228 case OP_MIPS_COND_EXC_IGT_UN:
4229 case OP_MIPS_COND_EXC_ILE_UN:
4230 case OP_MIPS_COND_EXC_ILT_UN:
4232 case OP_MIPS_COND_EXC_IOV:
4233 case OP_MIPS_COND_EXC_INO:
4234 case OP_MIPS_COND_EXC_IC:
4235 case OP_MIPS_COND_EXC_INC: {
4239 /* If the condition is true, raise the exception */
4241 /* need to reverse test to skip around exception raising */
4243 /* For the moment, branch around a branch to avoid reversing
4246 /* Remember, an unpatched branch to 0 branches to the delay slot */
4247 switch (ins->opcode) {
4248 case OP_MIPS_COND_EXC_EQ:
4249 throw = (guint32 *)(void *)code;
4250 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4254 case OP_MIPS_COND_EXC_NE_UN:
4255 throw = (guint32 *)(void *)code;
4256 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4260 case OP_MIPS_COND_EXC_LE_UN:
4261 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4262 throw = (guint32 *)(void *)code;
4263 mips_beq (code, mips_at, mips_zero, 0);
4267 case OP_MIPS_COND_EXC_GT:
4268 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4269 throw = (guint32 *)(void *)code;
4270 mips_bne (code, mips_at, mips_zero, 0);
4274 case OP_MIPS_COND_EXC_GT_UN:
4275 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4276 throw = (guint32 *)(void *)code;
4277 mips_bne (code, mips_at, mips_zero, 0);
4281 case OP_MIPS_COND_EXC_LT:
4282 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4283 throw = (guint32 *)(void *)code;
4284 mips_bne (code, mips_at, mips_zero, 0);
4288 case OP_MIPS_COND_EXC_LT_UN:
4289 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4290 throw = (guint32 *)(void *)code;
4291 mips_bne (code, mips_at, mips_zero, 0);
4296 /* Not yet implemented */
4297 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4298 g_assert_not_reached ();
4300 skip = (guint32 *)(void *)code;
4301 mips_beq (code, mips_zero, mips_zero, 0);
4303 mips_patch (throw, (guint32)code);
4304 code = mips_emit_exc_by_name (code, ins->inst_p1);
4305 mips_patch (skip, (guint32)code);
4306 cfg->bb_exit->max_offset += 24;
4315 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4318 /* floating point opcodes */
4321 if (((guint32)ins->inst_p0) & (1 << 15))
4322 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4324 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4325 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4327 mips_load_const (code, mips_at, ins->inst_p0);
4328 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4329 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4333 if (((guint32)ins->inst_p0) & (1 << 15))
4334 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4336 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4337 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4338 #if PROMOTE_R4_TO_R8
4339 mips_cvtds (code, ins->dreg, ins->dreg);
4342 case OP_STORER8_MEMBASE_REG:
4343 if (mips_is_imm16 (ins->inst_offset)) {
4344 #if _MIPS_SIM == _ABIO32
4345 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4346 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4347 #elif _MIPS_SIM == _ABIN32
4348 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4351 mips_load_const (code, mips_at, ins->inst_offset);
4352 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4353 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4354 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4357 case OP_LOADR8_MEMBASE:
4358 if (mips_is_imm16 (ins->inst_offset)) {
4359 #if _MIPS_SIM == _ABIO32
4360 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4361 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4362 #elif _MIPS_SIM == _ABIN32
4363 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4366 mips_load_const (code, mips_at, ins->inst_offset);
4367 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4368 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4369 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4372 case OP_STORER4_MEMBASE_REG:
4373 g_assert (mips_is_imm16 (ins->inst_offset));
4374 #if PROMOTE_R4_TO_R8
4375 /* Need to convert ins->sreg1 to single-precision first */
4376 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4377 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4379 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4383 g_assert (mips_is_imm16 (ins->inst_offset));
4384 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4386 case OP_LOADR4_MEMBASE:
4387 g_assert (mips_is_imm16 (ins->inst_offset));
4388 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4389 #if PROMOTE_R4_TO_R8
4390 /* Convert to double precision in place */
4391 mips_cvtds (code, ins->dreg, ins->dreg);
4394 case OP_LOADR4_MEMINDEX:
4395 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4396 mips_lwc1 (code, ins->dreg, mips_at, 0);
4398 case OP_LOADR8_MEMINDEX:
4399 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4400 #if _MIPS_SIM == _ABIO32
4401 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4402 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4403 #elif _MIPS_SIM == _ABIN32
4404 mips_ldc1 (code, ins->dreg, mips_at, 0);
4407 case OP_STORER4_MEMINDEX:
4408 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4409 #if PROMOTE_R4_TO_R8
4410 /* Need to convert ins->sreg1 to single-precision first */
4411 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4412 mips_swc1 (code, mips_ftemp, mips_at, 0);
4414 mips_swc1 (code, ins->sreg1, mips_at, 0);
4417 case OP_STORER8_MEMINDEX:
4418 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4419 #if _MIPS_SIM == _ABIO32
4420 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4421 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4422 #elif _MIPS_SIM == _ABIN32
4423 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4426 case OP_ICONV_TO_R_UN: {
4427 static const guint64 adjust_val = 0x41F0000000000000ULL;
4429 /* convert unsigned int to double */
4430 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4431 mips_bgez (code, ins->sreg1, 5);
4432 mips_cvtdw (code, ins->dreg, mips_ftemp);
4434 mips_load (code, mips_at, (guint32) &adjust_val);
4435 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4436 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4437 /* target is here */
4440 case OP_ICONV_TO_R4:
4441 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4442 mips_cvtsw (code, ins->dreg, mips_ftemp);
4443 mips_cvtds (code, ins->dreg, ins->dreg);
4445 case OP_ICONV_TO_R8:
4446 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4447 mips_cvtdw (code, ins->dreg, mips_ftemp);
4449 case OP_FCONV_TO_I1:
4450 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4452 case OP_FCONV_TO_U1:
4453 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4455 case OP_FCONV_TO_I2:
4456 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4458 case OP_FCONV_TO_U2:
4459 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4461 case OP_FCONV_TO_I4:
4463 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4465 case OP_FCONV_TO_U4:
4467 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4470 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4473 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4476 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4479 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4482 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4485 mips_fnegd (code, ins->dreg, ins->sreg1);
4488 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4489 mips_addiu (code, ins->dreg, mips_zero, 1);
4490 mips_fbtrue (code, 2);
4492 MIPS_MOVE (code, ins->dreg, mips_zero);
4495 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4496 mips_addiu (code, ins->dreg, mips_zero, 1);
4497 mips_fbtrue (code, 2);
4499 MIPS_MOVE (code, ins->dreg, mips_zero);
4502 /* Less than, or Unordered */
4503 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4504 mips_addiu (code, ins->dreg, mips_zero, 1);
4505 mips_fbtrue (code, 2);
4507 MIPS_MOVE (code, ins->dreg, mips_zero);
4510 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4511 MIPS_MOVE (code, ins->dreg, mips_zero);
4512 mips_fbtrue (code, 2);
4514 mips_addiu (code, ins->dreg, mips_zero, 1);
4517 /* Greater than, or Unordered */
4518 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4519 MIPS_MOVE (code, ins->dreg, mips_zero);
4520 mips_fbtrue (code, 2);
4522 mips_addiu (code, ins->dreg, mips_zero, 1);
4527 case OP_MIPS_FBLT_UN:
4529 case OP_MIPS_FBGT_UN:
4531 case OP_MIPS_FBGE_UN:
4533 case OP_MIPS_FBLE_UN: {
4535 gboolean is_true = TRUE, is_ordered = FALSE;
4536 guint32 *buf = NULL;
4538 switch (ins->opcode) {
4552 case OP_MIPS_FBLT_UN:
4553 cond = MIPS_FPU_ULT;
4561 case OP_MIPS_FBGT_UN:
4562 cond = MIPS_FPU_OLE;
4570 case OP_MIPS_FBGE_UN:
4571 cond = MIPS_FPU_OLT;
4575 cond = MIPS_FPU_OLE;
4579 case OP_MIPS_FBLE_UN:
4580 cond = MIPS_FPU_ULE;
4584 g_assert_not_reached ();
4588 /* Skip the check if unordered */
4589 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4591 buf = (guint32*)code;
4592 mips_fbtrue (code, 0);
4596 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4598 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4600 mips_fbtrue (code, 0);
4602 mips_fbfalse (code, 0);
4606 mips_patch (buf, (guint32)code);
4610 guint32 *branch_patch;
4612 mips_mfc1 (code, mips_at, ins->sreg1+1);
4613 mips_srl (code, mips_at, mips_at, 16+4);
4614 mips_andi (code, mips_at, mips_at, 2047);
4615 mips_addiu (code, mips_at, mips_at, -2047);
4617 branch_patch = (guint32 *)(void *)code;
4618 mips_bne (code, mips_at, mips_zero, 0);
4621 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4622 mips_patch (branch_patch, (guint32)code);
4623 mips_fmovd (code, ins->dreg, ins->sreg1);
4627 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4628 mips_load (code, ins->dreg, 0x0f0f0f0f);
4633 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4634 g_assert_not_reached ();
4637 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4638 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4639 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4640 g_assert_not_reached ();
4646 last_offset = offset;
4649 cfg->code_len = code - cfg->native_code;
4653 mono_arch_register_lowlevel_calls (void)
4658 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4660 MonoJumpInfo *patch_info;
4662 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4663 unsigned char *ip = patch_info->ip.i + code;
4664 const unsigned char *target = NULL;
4666 switch (patch_info->type) {
4667 case MONO_PATCH_INFO_IP:
4668 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4670 case MONO_PATCH_INFO_SWITCH: {
4671 gpointer *table = (gpointer *)patch_info->data.table->table;
4674 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4676 for (i = 0; i < patch_info->data.table->table_size; i++) {
4677 table [i] = (int)patch_info->data.table->table [i] + code;
4681 case MONO_PATCH_INFO_METHODCONST:
4682 case MONO_PATCH_INFO_CLASS:
4683 case MONO_PATCH_INFO_IMAGE:
4684 case MONO_PATCH_INFO_FIELD:
4685 case MONO_PATCH_INFO_VTABLE:
4686 case MONO_PATCH_INFO_IID:
4687 case MONO_PATCH_INFO_SFLDA:
4688 case MONO_PATCH_INFO_LDSTR:
4689 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4690 case MONO_PATCH_INFO_LDTOKEN:
4691 case MONO_PATCH_INFO_R4:
4692 case MONO_PATCH_INFO_R8:
4693 /* from OP_AOTCONST : lui + addiu */
4694 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4695 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4698 case MONO_PATCH_INFO_EXC_NAME:
4699 g_assert_not_reached ();
4700 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4703 case MONO_PATCH_INFO_NONE:
4704 /* everything is dealt with at epilog output time */
4707 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4708 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4715 * Allow tracing to work with this interface (with an optional argument)
4717 * This code is expected to be inserted just after the 'real' prolog code,
4718 * and before the first basic block. We need to allocate a 2nd, temporary
4719 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4723 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4726 int offset = cfg->arch.tracing_offset;
4732 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4733 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4734 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4735 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4736 #if _MIPS_SIM == _ABIN32
4738 /* FIXME: Need a separate region for these */
4739 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4740 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4741 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4742 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4746 mips_load_const (code, mips_a0, cfg->method);
4747 mips_addiu (code, mips_a1, mips_sp, offset);
4748 mips_call (code, mips_t9, func);
4751 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4752 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4753 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4754 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4755 #if _MIPS_SIM == _ABIN32
4758 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4759 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4760 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4761 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4772 mips_adjust_stackframe(MonoCompile *cfg)
4775 int delta, threshold, i;
4776 MonoMethodSignature *sig;
4779 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4782 /* adjust cfg->stack_offset for account for down-spilling */
4783 cfg->stack_offset += SIZEOF_REGISTER;
4785 /* re-align cfg->stack_offset if needed (due to var spilling) */
4786 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4787 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4788 if (cfg->verbose_level > 2) {
4789 g_print ("mips_adjust_stackframe:\n");
4790 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4792 threshold = cfg->arch.local_alloc_offset;
4793 ra_offset = cfg->stack_offset - sizeof(gpointer);
4794 if (cfg->verbose_level > 2) {
4795 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4798 sig = mono_method_signature (cfg->method);
4799 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4800 cfg->vret_addr->inst_offset += delta;
4802 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4803 MonoInst *inst = cfg->args [i];
4805 inst->inst_offset += delta;
4809 * loads and stores based off the frame reg that (used to) lie
4810 * above the spill var area need to be increased by 'delta'
4811 * to make room for the spill vars.
4813 /* Need to find loads and stores to adjust that
4814 * are above where the spillvars were inserted, but
4815 * which are not the spillvar references themselves.
4817 * Idea - since all offsets from fp are positive, make
4818 * spillvar offsets negative to begin with so we can spot
4823 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4827 if (cfg->verbose_level > 2) {
4828 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4830 MONO_BB_FOR_EACH_INS (bb, ins) {
4834 if (cfg->verbose_level > 2) {
4835 mono_print_ins_index (ins_cnt, ins);
4837 /* The == mips_sp tests catch FP spills */
4838 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4839 (ins->inst_basereg == mips_sp))) {
4840 switch (ins->opcode) {
4841 case OP_LOADI8_MEMBASE:
4842 case OP_LOADR8_MEMBASE:
4849 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4850 (ins->dreg == mips_sp))) {
4851 switch (ins->opcode) {
4852 case OP_STOREI8_MEMBASE_REG:
4853 case OP_STORER8_MEMBASE_REG:
4854 case OP_STOREI8_MEMBASE_IMM:
4862 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4865 if (ins->inst_c0 >= threshold) {
4866 ins->inst_c0 += delta;
4867 if (cfg->verbose_level > 2) {
4869 mono_print_ins_index (ins_cnt, ins);
4872 else if (ins->inst_c0 < 0) {
4873 /* Adj_c0 holds the size of the datatype. */
4874 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4875 if (cfg->verbose_level > 2) {
4877 mono_print_ins_index (ins_cnt, ins);
4880 g_assert (ins->inst_c0 != ra_offset);
4883 if (ins->inst_imm >= threshold) {
4884 ins->inst_imm += delta;
4885 if (cfg->verbose_level > 2) {
4887 mono_print_ins_index (ins_cnt, ins);
4890 g_assert (ins->inst_c0 != ra_offset);
4900 * Stack frame layout:
4902 * ------------------- sp + cfg->stack_usage + cfg->param_area
4903 * param area incoming
4904 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4906 * ------------------- sp + cfg->stack_usage
4908 * ------------------- sp + cfg->stack_usage-4
4910 * ------------------- sp +
4911 * MonoLMF structure optional
4912 * ------------------- sp + cfg->arch.lmf_offset
4913 * saved registers s0-s8
4914 * ------------------- sp + cfg->arch.iregs_offset
4916 * ------------------- sp + cfg->param_area
4917 * param area outgoing
4918 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4920 * ------------------- sp
4924 mono_arch_emit_prolog (MonoCompile *cfg)
4926 MonoMethod *method = cfg->method;
4927 MonoMethodSignature *sig;
4929 int alloc_size, pos, i, max_offset;
4930 int alloc2_size = 0;
4934 guint32 iregs_to_save = 0;
4936 guint32 fregs_to_save = 0;
4938 /* lmf_offset is the offset of the LMF from our stack pointer. */
4939 guint32 lmf_offset = cfg->arch.lmf_offset;
4943 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4947 cfg->flags |= MONO_CFG_HAS_CALLS;
4949 sig = mono_method_signature (method);
4950 cfg->code_size = 768 + sig->param_count * 20;
4951 code = cfg->native_code = g_malloc (cfg->code_size);
4954 * compute max_offset in order to use short forward jumps.
4957 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4958 MonoInst *ins = bb->code;
4959 bb->max_offset = max_offset;
4961 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4964 MONO_BB_FOR_EACH_INS (bb, ins)
4965 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4967 if (max_offset > 0xffff)
4968 cfg->arch.long_branch = TRUE;
4971 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4972 * This means that we have to adjust the offsets inside instructions which reference
4973 * arguments received on the stack, since the initial offset doesn't take into
4974 * account spill slots.
4976 mips_adjust_stackframe (cfg);
4978 /* Offset between current sp and the CFA */
4980 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4982 /* stack_offset should not be changed here. */
4983 alloc_size = cfg->stack_offset;
4984 cfg->stack_usage = alloc_size;
4986 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4989 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4991 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4992 fregs_to_save |= (fregs_to_save << 1);
4995 /* If the stack size is too big, save 1024 bytes to start with
4996 * so the prologue can use imm16(reg) addressing, then allocate
4997 * the rest of the frame.
4999 if (alloc_size > ((1 << 15) - 1024)) {
5000 alloc2_size = alloc_size - 1024;
5004 g_assert (mips_is_imm16 (-alloc_size));
5005 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
5006 cfa_offset = alloc_size;
5007 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5010 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5011 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5012 if (mips_is_imm16(offset))
5013 mips_sw (code, mips_ra, mips_sp, offset);
5015 g_assert_not_reached ();
5017 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5018 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5021 /* XXX - optimize this later to not save all regs if LMF constructed */
5022 pos = cfg->arch.iregs_offset - alloc2_size;
5024 if (iregs_to_save) {
5025 /* save used registers in own stack frame (at pos) */
5026 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5027 if (iregs_to_save & (1 << i)) {
5028 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5029 g_assert (mips_is_imm16(pos));
5030 MIPS_SW (code, i, mips_sp, pos);
5031 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5032 pos += SIZEOF_REGISTER;
5037 // FIXME: Don't save registers twice if there is an LMF
5038 // s8 has to be special cased since it is overwritten with the updated value
5040 if (method->save_lmf) {
5041 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5042 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5043 g_assert (mips_is_imm16(offset));
5044 if (MIPS_LMF_IREGMASK & (1 << i))
5045 MIPS_SW (code, i, mips_sp, offset);
5050 /* Save float registers */
5051 if (fregs_to_save) {
5052 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5053 if (fregs_to_save & (1 << i)) {
5054 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5055 g_assert (mips_is_imm16(pos));
5056 mips_swc1 (code, i, mips_sp, pos);
5057 pos += sizeof (gulong);
5062 if (method->save_lmf) {
5063 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5064 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5065 g_assert (mips_is_imm16(offset));
5066 mips_swc1 (code, i, mips_sp, offset);
5071 if (cfg->frame_reg != mips_sp) {
5072 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5073 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5075 if (method->save_lmf) {
5076 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5077 g_assert (mips_is_imm16(offset));
5078 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5082 /* store runtime generic context */
5083 if (cfg->rgctx_var) {
5084 MonoInst *ins = cfg->rgctx_var;
5086 g_assert (ins->opcode == OP_REGOFFSET);
5088 g_assert (mips_is_imm16 (ins->inst_offset));
5089 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5092 /* load arguments allocated to register from the stack */
5095 if (!cfg->arch.cinfo)
5096 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
5097 cinfo = cfg->arch.cinfo;
5099 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5100 ArgInfo *ainfo = &cinfo->ret;
5101 inst = cfg->vret_addr;
5102 if (inst->opcode == OP_REGVAR)
5103 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5104 else if (mips_is_imm16 (inst->inst_offset)) {
5105 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5107 mips_load_const (code, mips_at, inst->inst_offset);
5108 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5109 mips_sw (code, ainfo->reg, mips_at, 0);
5113 if (sig->call_convention == MONO_CALL_VARARG) {
5114 ArgInfo *cookie = &cinfo->sig_cookie;
5115 int offset = alloc_size + cookie->offset;
5117 /* Save the sig cookie address */
5118 g_assert (cookie->storage == ArgOnStack);
5120 g_assert (mips_is_imm16(offset));
5121 mips_addi (code, mips_at, cfg->frame_reg, offset);
5122 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5125 /* Keep this in sync with emit_load_volatile_arguments */
5126 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5127 ArgInfo *ainfo = cinfo->args + i;
5128 inst = cfg->args [pos];
5130 if (cfg->verbose_level > 2)
5131 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5132 if (inst->opcode == OP_REGVAR) {
5133 /* Argument ends up in a register */
5134 if (ainfo->storage == ArgInIReg)
5135 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5136 else if (ainfo->storage == ArgInFReg) {
5137 g_assert_not_reached();
5139 ppc_fmr (code, inst->dreg, ainfo->reg);
5142 else if (ainfo->storage == ArgOnStack) {
5143 int offset = cfg->stack_usage + ainfo->offset;
5144 g_assert (mips_is_imm16(offset));
5145 mips_lw (code, inst->dreg, mips_sp, offset);
5147 g_assert_not_reached ();
5149 if (cfg->verbose_level > 2)
5150 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5152 /* Argument ends up on the stack */
5153 if (ainfo->storage == ArgInIReg) {
5155 /* Incoming parameters should be above this frame */
5156 if (cfg->verbose_level > 2)
5157 g_print ("stack slot at %d of %d+%d\n",
5158 inst->inst_offset, alloc_size, alloc2_size);
5159 /* g_assert (inst->inst_offset >= alloc_size); */
5160 g_assert (inst->inst_basereg == cfg->frame_reg);
5161 basereg_offset = inst->inst_offset - alloc2_size;
5162 g_assert (mips_is_imm16 (basereg_offset));
5163 switch (ainfo->size) {
5165 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5168 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5172 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5175 #if (SIZEOF_REGISTER == 4)
5176 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5177 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5178 #elif (SIZEOF_REGISTER == 8)
5179 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5183 g_assert_not_reached ();
5186 } else if (ainfo->storage == ArgOnStack) {
5188 * Argument comes in on the stack, and ends up on the stack
5189 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5190 * 8 and 16 bit quantities. Shorten them in place.
5192 g_assert (mips_is_imm16 (inst->inst_offset));
5193 switch (ainfo->size) {
5195 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5196 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5199 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5200 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5207 g_assert_not_reached ();
5209 } else if (ainfo->storage == ArgInFReg) {
5210 g_assert (mips_is_imm16 (inst->inst_offset));
5211 g_assert (mips_is_imm16 (inst->inst_offset+4));
5212 if (ainfo->size == 8) {
5213 #if _MIPS_SIM == _ABIO32
5214 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5215 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5216 #elif _MIPS_SIM == _ABIN32
5217 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5220 else if (ainfo->size == 4)
5221 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5223 g_assert_not_reached ();
5224 } else if (ainfo->storage == ArgStructByVal) {
5226 int doffset = inst->inst_offset;
5228 g_assert (mips_is_imm16 (inst->inst_offset));
5229 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5230 /* Push the argument registers into their stack slots */
5231 for (i = 0; i < ainfo->size; ++i) {
5232 g_assert (mips_is_imm16(doffset));
5233 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5234 doffset += SIZEOF_REGISTER;
5236 } else if (ainfo->storage == ArgStructByAddr) {
5237 g_assert (mips_is_imm16 (inst->inst_offset));
5238 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5239 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5241 g_assert_not_reached ();
5246 if (method->save_lmf) {
5247 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5248 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5250 if (lmf_pthread_key != -1) {
5251 g_assert_not_reached();
5253 emit_tls_access (code, mips_temp, lmf_pthread_key);
5255 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5256 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5257 g_assert (mips_is_imm16(offset));
5258 mips_addiu (code, mips_a0, mips_temp, offset);
5261 /* This can/will clobber the a0-a3 registers */
5262 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5265 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5266 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5267 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5268 /* new_lmf->previous_lmf = *lmf_addr */
5269 mips_lw (code, mips_at, mips_v0, 0);
5270 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5271 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5272 /* *(lmf_addr) = sp + lmf_offset */
5273 g_assert (mips_is_imm16(lmf_offset));
5274 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5275 mips_sw (code, mips_at, mips_v0, 0);
5277 /* save method info */
5278 mips_load_const (code, mips_at, method);
5279 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5280 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5282 /* save the current IP */
5283 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5284 mips_load_const (code, mips_at, 0x01010101);
5285 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5289 if (mips_is_imm16 (-alloc2_size)) {
5290 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5293 mips_load_const (code, mips_at, -alloc2_size);
5294 mips_addu (code, mips_sp, mips_sp, mips_at);
5296 alloc_size += alloc2_size;
5297 cfa_offset += alloc2_size;
5298 if (cfg->frame_reg != mips_sp)
5299 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5301 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5305 #if _MIPS_SIM == _ABIO32
5306 cfg->arch.tracing_offset = cfg->stack_offset;
5307 #elif _MIPS_SIM == _ABIN32
5308 /* no stack slots by default for argument regs, reserve a special block */
5309 g_assert_not_reached ();
5311 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5314 cfg->code_len = code - cfg->native_code;
5315 g_assert (cfg->code_len < cfg->code_size);
5329 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5332 int save_mode = SAVE_NONE;
5334 MonoMethod *method = cfg->method;
5335 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type;
5336 int save_offset = MIPS_STACK_PARAM_OFFSET;
5338 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5340 offset = code - cfg->native_code;
5341 /* we need about 16 instructions */
5342 if (offset > (cfg->code_size - 16 * 4)) {
5343 cfg->code_size *= 2;
5344 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5345 code = cfg->native_code + offset;
5350 case MONO_TYPE_VOID:
5351 /* special case string .ctor icall */
5352 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5353 save_mode = SAVE_ONE;
5355 save_mode = SAVE_NONE;
5359 save_mode = SAVE_FP;
5361 case MONO_TYPE_VALUETYPE:
5362 save_mode = SAVE_STRUCT;
5366 #if SIZEOF_REGISTER == 4
5367 save_mode = SAVE_TWO;
5368 #elif SIZEOF_REGISTER == 8
5369 save_mode = SAVE_ONE;
5373 save_mode = SAVE_ONE;
5377 mips_addiu (code, mips_sp, mips_sp, -32);
5378 g_assert (mips_is_imm16(save_offset));
5379 switch (save_mode) {
5381 mips_sw (code, mips_v0, mips_sp, save_offset);
5382 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5383 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5384 if (enable_arguments) {
5385 MIPS_MOVE (code, mips_a1, mips_v0);
5386 MIPS_MOVE (code, mips_a2, mips_v1);
5390 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5391 if (enable_arguments) {
5392 MIPS_MOVE (code, mips_a1, mips_v0);
5396 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5397 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5398 mips_lw (code, mips_a0, mips_sp, save_offset);
5399 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5400 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5407 mips_load_const (code, mips_a0, cfg->method);
5408 mips_call (code, mips_t9, func);
5410 switch (save_mode) {
5412 mips_lw (code, mips_v0, mips_sp, save_offset);
5413 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5414 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5417 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5420 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5427 mips_addiu (code, mips_sp, mips_sp, 32);
5434 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5436 MonoMethod *method = cfg->method;
5438 int max_epilog_size = 16 + 20*4;
5439 int alloc2_size = 0;
5440 guint32 iregs_to_restore;
5442 guint32 fregs_to_restore;
5445 if (cfg->method->save_lmf)
5446 max_epilog_size += 128;
5448 if (mono_jit_trace_calls != NULL)
5449 max_epilog_size += 50;
5451 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5452 max_epilog_size += 50;
5455 pos = code - cfg->native_code;
5456 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5457 cfg->code_size *= 2;
5458 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5459 cfg->stat_code_reallocs++;
5463 * Keep in sync with OP_JMP
5466 code = cfg->native_code + pos;
5468 code = cfg->native_code + cfg->code_len;
5470 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5471 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5473 if (cfg->frame_reg != mips_sp) {
5474 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5476 /* If the stack frame is really large, deconstruct it in two steps */
5477 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5478 alloc2_size = cfg->stack_usage - 1024;
5479 /* partially deconstruct the stack */
5480 mips_load_const (code, mips_at, alloc2_size);
5481 mips_addu (code, mips_sp, mips_sp, mips_at);
5483 pos = cfg->arch.iregs_offset - alloc2_size;
5484 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5485 if (iregs_to_restore) {
5486 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5487 if (iregs_to_restore & (1 << i)) {
5488 g_assert (mips_is_imm16(pos));
5489 MIPS_LW (code, i, mips_sp, pos);
5490 pos += SIZEOF_REGISTER;
5497 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5499 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5500 fregs_to_restore |= (fregs_to_restore << 1);
5502 if (fregs_to_restore) {
5503 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5504 if (fregs_to_restore & (1 << i)) {
5505 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5506 g_assert (mips_is_imm16(pos));
5507 mips_lwc1 (code, i, mips_sp, pos);
5514 /* Unlink the LMF if necessary */
5515 if (method->save_lmf) {
5516 int lmf_offset = cfg->arch.lmf_offset;
5518 /* t0 = current_lmf->previous_lmf */
5519 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5520 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5522 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5523 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5524 /* (*lmf_addr) = previous_lmf */
5525 mips_sw (code, mips_temp, mips_t1, 0);
5529 /* Restore the fp */
5530 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5533 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5534 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5535 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5537 /* Restore the stack pointer */
5538 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5539 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5541 /* Caller will emit either return or tail-call sequence */
5543 cfg->code_len = code - cfg->native_code;
5545 g_assert (cfg->code_len < cfg->code_size);
5550 mono_arch_emit_epilog (MonoCompile *cfg)
5554 code = mono_arch_emit_epilog_sub (cfg, NULL);
5556 mips_jr (code, mips_ra);
5559 cfg->code_len = code - cfg->native_code;
5561 g_assert (cfg->code_len < cfg->code_size);
5564 /* remove once throw_exception_by_name is eliminated */
5567 exception_id_by_name (const char *name)
5569 if (strcmp (name, "IndexOutOfRangeException") == 0)
5570 return MONO_EXC_INDEX_OUT_OF_RANGE;
5571 if (strcmp (name, "OverflowException") == 0)
5572 return MONO_EXC_OVERFLOW;
5573 if (strcmp (name, "ArithmeticException") == 0)
5574 return MONO_EXC_ARITHMETIC;
5575 if (strcmp (name, "DivideByZeroException") == 0)
5576 return MONO_EXC_DIVIDE_BY_ZERO;
5577 if (strcmp (name, "InvalidCastException") == 0)
5578 return MONO_EXC_INVALID_CAST;
5579 if (strcmp (name, "NullReferenceException") == 0)
5580 return MONO_EXC_NULL_REF;
5581 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5582 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5583 if (strcmp (name, "ArgumentException") == 0)
5584 return MONO_EXC_ARGUMENT;
5585 g_error ("Unknown intrinsic exception %s\n", name);
5591 mono_arch_emit_exceptions (MonoCompile *cfg)
5594 MonoJumpInfo *patch_info;
5597 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5598 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5599 int max_epilog_size = 50;
5601 /* count the number of exception infos */
5604 * make sure we have enough space for exceptions
5605 * 24 is the simulated call to throw_exception_by_name
5607 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5609 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5610 i = exception_id_by_name (patch_info->data.target);
5611 g_assert (i < MONO_EXC_INTRINS_NUM);
5612 if (!exc_throw_found [i]) {
5613 max_epilog_size += 12;
5614 exc_throw_found [i] = TRUE;
5620 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5621 cfg->code_size *= 2;
5622 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5623 cfg->stat_code_reallocs++;
5626 code = cfg->native_code + cfg->code_len;
5628 /* add code to raise exceptions */
5629 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5630 switch (patch_info->type) {
5631 case MONO_PATCH_INFO_EXC: {
5633 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5635 i = exception_id_by_name (patch_info->data.target);
5636 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5637 if (!exc_throw_pos [i]) {
5640 exc_throw_pos [i] = code;
5641 //g_print ("exc: writing stub at %p\n", code);
5642 mips_load_const (code, mips_a0, patch_info->data.target);
5643 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5644 mips_load_const (code, mips_t9, addr);
5645 mips_jr (code, mips_t9);
5648 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5650 /* Turn into a Relative patch, pointing at code stub */
5651 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5652 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5654 g_assert_not_reached();
5664 cfg->code_len = code - cfg->native_code;
5666 g_assert (cfg->code_len < cfg->code_size);
5671 * Thread local storage support
5674 setup_tls_access (void)
5677 //guint32 *ins, *code;
5679 if (tls_mode == TLS_MODE_FAILED)
5682 if (g_getenv ("MONO_NO_TLS")) {
5683 tls_mode = TLS_MODE_FAILED;
5687 if (tls_mode == TLS_MODE_DETECT) {
5689 tls_mode = TLS_MODE_FAILED;
5693 ins = (guint32*)pthread_getspecific;
5694 /* uncond branch to the real method */
5695 if ((*ins >> 26) == 18) {
5697 val = (*ins & ~3) << 6;
5701 ins = (guint32*)val;
5703 ins = (guint32*) ((char*)ins + val);
5706 code = &cmplwi_1023;
5707 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5709 ppc_li (code, ppc_r4, 0x48);
5712 if (*ins == cmplwi_1023) {
5713 int found_lwz_284 = 0;
5714 for (ptk = 0; ptk < 20; ++ptk) {
5716 if (!*ins || *ins == blr_ins)
5718 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5723 if (!found_lwz_284) {
5724 tls_mode = TLS_MODE_FAILED;
5727 tls_mode = TLS_MODE_LTHREADS;
5728 } else if (*ins == li_0x48) {
5730 /* uncond branch to the real method */
5731 if ((*ins >> 26) == 18) {
5733 val = (*ins & ~3) << 6;
5737 ins = (guint32*)val;
5739 ins = (guint32*) ((char*)ins + val);
5742 ppc_li (code, ppc_r0, 0x7FF2);
5743 if (ins [1] == val) {
5744 /* Darwin on G4, implement */
5745 tls_mode = TLS_MODE_FAILED;
5749 ppc_mfspr (code, ppc_r3, 104);
5750 if (ins [1] != val) {
5751 tls_mode = TLS_MODE_FAILED;
5754 tls_mode = TLS_MODE_DARWIN_G5;
5757 tls_mode = TLS_MODE_FAILED;
5761 tls_mode = TLS_MODE_FAILED;
5766 if (monodomain_key == -1) {
5767 ptk = mono_domain_get_tls_key ();
5769 monodomain_key = ptk;
5771 if (lmf_pthread_key == -1) {
5772 ptk = mono_jit_tls_id;
5774 /*g_print ("MonoLMF at: %d\n", ptk);*/
5775 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5776 init_tls_failed = 1;
5779 lmf_pthread_key = ptk;
5782 if (monothread_key == -1) {
5783 ptk = mono_thread_get_tls_key ();
5785 monothread_key = ptk;
5786 /*g_print ("thread inited: %d\n", ptk);*/
5788 /*g_print ("thread not inited yet %d\n", ptk);*/
5794 mono_arch_finish_init (void)
5796 setup_tls_access ();
5800 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5805 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5807 int this_dreg = mips_a0;
5810 this_dreg = mips_a1;
5812 /* add the this argument */
5813 if (this_reg != -1) {
5815 MONO_INST_NEW (cfg, this, OP_MOVE);
5816 this->type = this_type;
5817 this->sreg1 = this_reg;
5818 this->dreg = mono_alloc_ireg (cfg);
5819 mono_bblock_add_inst (cfg->cbb, this);
5820 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5825 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5826 vtarg->type = STACK_MP;
5827 vtarg->sreg1 = vt_reg;
5828 vtarg->dreg = mono_alloc_ireg (cfg);
5829 mono_bblock_add_inst (cfg->cbb, vtarg);
5830 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5835 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5837 MonoInst *ins = NULL;
5843 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5849 mono_arch_print_tree (MonoInst *tree, int arity)
5854 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5858 setup_tls_access ();
5859 if (monodomain_key == -1)
5862 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5863 ins->inst_offset = monodomain_key;
5868 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5870 return ctx->sc_regs [reg];
5873 #ifdef MONO_ARCH_HAVE_IMT
5875 #define ENABLE_WRONG_METHOD_CHECK 0
5877 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5878 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5880 #define LOADSTORE_SIZE 4
5881 #define JUMP_IMM_SIZE 16
5882 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5883 #define LOAD_CONST_SIZE 8
5884 #define JUMP_JR_SIZE 8
5887 * LOCKING: called with the domain lock held
5890 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5891 gpointer fail_tramp)
5895 guint8 *code, *start, *patch;
5897 for (i = 0; i < count; ++i) {
5898 MonoIMTCheckItem *item = imt_entries [i];
5900 if (item->is_equals) {
5901 if (item->check_target_idx) {
5902 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5903 if (item->has_target_code)
5904 item->chunk_size += LOAD_CONST_SIZE;
5906 item->chunk_size += LOADSTORE_SIZE;
5909 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5910 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5911 if (!item->has_target_code)
5912 item->chunk_size += LOADSTORE_SIZE;
5914 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5915 #if ENABLE_WRONG_METHOD_CHECK
5916 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5921 item->chunk_size += CMP_SIZE + BR_SIZE;
5922 imt_entries [item->check_target_idx]->compare_done = TRUE;
5924 size += item->chunk_size;
5926 /* the initial load of the vtable address */
5927 size += MIPS_LOAD_SEQUENCE_LENGTH;
5929 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5931 code = mono_domain_code_reserve (domain, size);
5935 /* t7 points to the vtable */
5936 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5938 for (i = 0; i < count; ++i) {
5939 MonoIMTCheckItem *item = imt_entries [i];
5941 item->code_target = code;
5942 if (item->is_equals) {
5943 if (item->check_target_idx) {
5944 mips_load_const (code, mips_temp, (gsize)item->key);
5945 item->jmp_code = code;
5946 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5948 if (item->has_target_code) {
5949 mips_load_const (code, mips_t9,
5950 item->value.target_code);
5953 mips_lw (code, mips_t9, mips_t7,
5954 (sizeof (gpointer) * item->value.vtable_slot));
5956 mips_jr (code, mips_t9);
5960 mips_load_const (code, mips_temp, (gsize)item->key);
5962 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5964 if (item->has_target_code) {
5965 mips_load_const (code, mips_t9,
5966 item->value.target_code);
5969 mips_load_const (code, mips_at,
5970 & (vtable->vtable [item->value.vtable_slot]));
5971 mips_lw (code, mips_t9, mips_at, 0);
5973 mips_jr (code, mips_t9);
5975 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5976 mips_load_const (code, mips_t9, fail_tramp);
5977 mips_jr (code, mips_t9);
5980 /* enable the commented code to assert on wrong method */
5981 #if ENABLE_WRONG_METHOD_CHECK
5982 ppc_load (code, ppc_r0, (guint32)item->key);
5983 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5985 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5987 mips_lw (code, mips_t9, mips_t7,
5988 (sizeof (gpointer) * item->value.vtable_slot));
5989 mips_jr (code, mips_t9);
5992 #if ENABLE_WRONG_METHOD_CHECK
5993 ppc_patch (patch, code);
5999 mips_load_const (code, mips_temp, (gulong)item->key);
6000 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
6002 item->jmp_code = code;
6003 mips_beq (code, mips_temp, mips_zero, 0);
6007 /* patch the branches to get to the target items */
6008 for (i = 0; i < count; ++i) {
6009 MonoIMTCheckItem *item = imt_entries [i];
6010 if (item->jmp_code && item->check_target_idx) {
6011 mips_patch ((guint32 *)item->jmp_code,
6012 (guint32)imt_entries [item->check_target_idx]->code_target);
6017 mono_stats.imt_thunks_size += code - start;
6018 g_assert (code - start <= size);
6019 mono_arch_flush_icache (start, size);
6024 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6026 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6031 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6033 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6036 /* Soft Debug support */
6037 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6040 * mono_arch_set_breakpoint:
6042 * See mini-amd64.c for docs.
6045 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6048 guint32 addr = (guint32)bp_trigger_page;
6050 mips_load_const (code, mips_t9, addr);
6051 mips_lw (code, mips_t9, mips_t9, 0);
6053 mono_arch_flush_icache (ip, code - ip);
6057 * mono_arch_clear_breakpoint:
6059 * See mini-amd64.c for docs.
6062 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6070 mono_arch_flush_icache (ip, code - ip);
6074 * mono_arch_start_single_stepping:
6076 * See mini-amd64.c for docs.
6079 mono_arch_start_single_stepping (void)
6081 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6085 * mono_arch_stop_single_stepping:
6087 * See mini-amd64.c for docs.
6090 mono_arch_stop_single_stepping (void)
6092 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6096 * mono_arch_is_single_step_event:
6098 * See mini-amd64.c for docs.
6101 mono_arch_is_single_step_event (void *info, void *sigctx)
6103 siginfo_t* sinfo = (siginfo_t*) info;
6104 /* Sometimes the address is off by 4 */
6105 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6112 * mono_arch_is_breakpoint_event:
6114 * See mini-amd64.c for docs.
6117 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6119 siginfo_t* sinfo = (siginfo_t*) info;
6120 /* Sometimes the address is off by 4 */
6121 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6128 * mono_arch_skip_breakpoint:
6130 * See mini-amd64.c for docs.
6133 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6135 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6139 * mono_arch_skip_single_step:
6141 * See mini-amd64.c for docs.
6144 mono_arch_skip_single_step (MonoContext *ctx)
6146 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6150 * mono_arch_get_seq_point_info:
6152 * See mini-amd64.c for docs.
6155 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6161 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */