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>
21 #include <mono/utils/mono-hwcap-mips.h>
23 #include <mono/arch/mips/mips-codegen.h>
25 #include "mini-mips.h"
30 #define SAVE_FP_REGS 0
32 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
34 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
35 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
36 remember to update cpu-mips.md if you change this */
38 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
39 #define mips_call(c,D,v) do { \
40 guint32 _target = (guint32)(v); \
41 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
42 mips_load_const (c, D, _target); \
43 mips_jalr (c, D, mips_ra); \
46 mips_jumpl (c, _target >> 2); \
58 /* This mutex protects architecture specific caches */
59 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
60 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
61 static CRITICAL_SECTION mini_arch_mutex;
63 int mono_exc_esp_offset = 0;
64 static int tls_mode = TLS_MODE_DETECT;
65 static int lmf_pthread_key = -1;
66 static int monothread_key = -1;
67 static int monodomain_key = -1;
69 /* Whenever the host is little-endian */
70 static int little_endian;
71 /* Index of ms word/register */
72 static int ls_word_idx;
73 /* Index of ls word/register */
74 static int ms_word_idx;
75 /* Same for offsets */
76 static int ls_word_offset;
77 static int ms_word_offset;
80 * The code generated for sequence points reads from this location, which is
81 * made read-only when single stepping is enabled.
83 static gpointer ss_trigger_page;
85 /* Enabled breakpoints read from this trigger page */
86 static gpointer bp_trigger_page;
89 #define DEBUG(a) if (cfg->verbose_level > 1) a
95 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
97 code = mips_emit_exc_by_name (code, exc_name); \
98 cfg->bb_exit->max_offset += 16; \
102 #define emit_linuxthreads_tls(code,dreg,key) do {\
104 off1 = offsets_from_pthread_key ((key), &off2); \
105 g_assert_not_reached (); \
106 ppc_lwz ((code), (dreg), off1, ppc_r2); \
107 ppc_lwz ((code), (dreg), off2, (dreg)); \
111 #define emit_tls_access(code,dreg,key) do { \
112 switch (tls_mode) { \
113 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
114 default: g_assert_not_reached (); \
118 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
120 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
121 inst->type = STACK_R8; \
123 inst->inst_p0 = (void*)(addr); \
124 mono_bblock_add_inst (cfg->cbb, inst); \
127 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
128 || ((ins)->opcode == OP_ICOMPARE) \
129 || ((ins)->opcode == OP_LCOMPARE)))
130 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
131 || ((ins)->opcode == OP_ICOMPARE_IMM) \
132 || ((ins)->opcode == OP_LCOMPARE_IMM)))
134 #define INS_REWRITE(ins, op, _s1, _s2) do { \
137 ins->opcode = (op); \
142 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
144 ins->opcode = (op); \
146 ins->inst_imm = (_imm); \
150 typedef struct InstList InstList;
168 guint16 vtsize; /* in param area */
171 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
180 gboolean vtype_retaddr;
189 void patch_lui_addiu(guint32 *ip, guint32 val);
190 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
191 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
192 void mips_adjust_stackframe(MonoCompile *cfg);
193 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
194 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
197 /* Not defined in asm/cachectl.h */
198 int cacheflush(char *addr, int nbytes, int cache);
201 mono_arch_flush_icache (guint8 *code, gint size)
203 /* Linux/MIPS specific */
204 cacheflush ((char*)code, size, BCACHE);
208 mono_arch_flush_register_windows (void)
213 mono_arch_is_inst_imm (gint64 imm)
219 mips_emit_exc_by_name(guint8 *code, const char *name)
222 MonoClass *exc_class;
224 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
225 g_assert (exc_class);
227 mips_load_const (code, mips_a0, exc_class->type_token);
228 addr = mono_get_throw_corlib_exception ();
229 mips_call (code, mips_t9, addr);
235 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
237 if (mips_is_imm16 (v))
238 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
240 #if SIZEOF_REGISTER == 8
242 /* v is not a sign-extended 32-bit value */
243 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
244 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
245 mips_dsll (code, dreg, dreg, 16);
246 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
247 mips_dsll (code, dreg, dreg, 16);
248 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
252 if (((guint32)v) & (1 << 15)) {
253 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
256 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
258 if (((guint32)v) & 0xffff)
259 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
265 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
268 if (cfg->arch.long_branch) {
271 /* Invert test and emit branch around jump */
274 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
278 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
282 mips_bltz (code, ins->sreg1, br_offset);
286 mips_blez (code, ins->sreg1, br_offset);
290 mips_bgtz (code, ins->sreg1, br_offset);
294 mips_bgez (code, ins->sreg1, br_offset);
298 g_assert_not_reached ();
300 mono_add_patch_info (cfg, code - cfg->native_code,
301 MONO_PATCH_INFO_BB, ins->inst_true_bb);
302 mips_lui (code, mips_at, mips_zero, 0);
303 mips_addiu (code, mips_at, mips_at, 0);
304 mips_jr (code, mips_at);
308 mono_add_patch_info (cfg, code - cfg->native_code,
309 MONO_PATCH_INFO_BB, ins->inst_true_bb);
312 mips_beq (code, ins->sreg1, ins->sreg2, 0);
316 mips_bne (code, ins->sreg1, ins->sreg2, 0);
320 mips_bgez (code, ins->sreg1, 0);
324 mips_bgtz (code, ins->sreg1, 0);
328 mips_blez (code, ins->sreg1, 0);
332 mips_bltz (code, ins->sreg1, 0);
336 g_assert_not_reached ();
342 /* XXX - big-endian dependent? */
344 patch_lui_addiu(guint32 *ip, guint32 val)
346 guint16 *__lui_addiu = (guint16*)(void *)(ip);
349 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
350 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
353 if (((guint32)(val)) & (1 << 15))
354 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
356 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
357 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
358 mono_arch_flush_icache ((guint8 *)ip, 8);
363 mips_patch (guint32 *code, guint32 target)
366 guint32 op = ins >> 26;
367 guint32 diff, offset;
369 g_assert (trap_target != target);
370 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
372 case 0x00: /* jr ra */
373 if (ins == 0x3e00008)
375 g_assert_not_reached ();
379 g_assert (!(target & 0x03));
380 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
381 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
383 mono_arch_flush_icache ((guint8 *)code, 4);
385 case 0x01: /* BLTZ */
388 case 0x06: /* BLEZ */
389 case 0x07: /* BGTZ */
390 case 0x11: /* bc1t */
391 diff = target - (guint32)(code + 1);
392 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
393 g_assert (!(diff & 0x03));
394 offset = ((gint32)diff) >> 2;
395 if (((int)offset) != ((int)(short)offset))
396 g_assert (((int)offset) == ((int)(short)offset));
397 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
399 mono_arch_flush_icache ((guint8 *)code, 4);
401 case 0x0f: /* LUI / ADDIU pair */
402 g_assert ((code[1] >> 26) == 0x9);
403 patch_lui_addiu (code, target);
404 mono_arch_flush_icache ((guint8 *)code, 8);
408 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
409 g_assert_not_reached ();
415 offsets_from_pthread_key (guint32 key, int *offset2)
419 *offset2 = idx2 * sizeof (gpointer);
420 return 284 + idx1 * sizeof (gpointer);
424 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
427 mono_arch_regname (int reg) {
428 #if _MIPS_SIM == _ABIO32
429 static const char * rnames[] = {
430 "zero", "at", "v0", "v1",
431 "a0", "a1", "a2", "a3",
432 "t0", "t1", "t2", "t3",
433 "t4", "t5", "t6", "t7",
434 "s0", "s1", "s2", "s3",
435 "s4", "s5", "s6", "s7",
436 "t8", "t9", "k0", "k1",
437 "gp", "sp", "fp", "ra"
439 #elif _MIPS_SIM == _ABIN32
440 static const char * rnames[] = {
441 "zero", "at", "v0", "v1",
442 "a0", "a1", "a2", "a3",
443 "a4", "a5", "a6", "a7",
444 "t0", "t1", "t2", "t3",
445 "s0", "s1", "s2", "s3",
446 "s4", "s5", "s6", "s7",
447 "t8", "t9", "k0", "k1",
448 "gp", "sp", "fp", "ra"
451 if (reg >= 0 && reg < 32)
457 mono_arch_fregname (int reg) {
458 static const char * rnames[] = {
459 "f0", "f1", "f2", "f3",
460 "f4", "f5", "f6", "f7",
461 "f8", "f9", "f10", "f11",
462 "f12", "f13", "f14", "f15",
463 "f16", "f17", "f18", "f19",
464 "f20", "f21", "f22", "f23",
465 "f24", "f25", "f26", "f27",
466 "f28", "f29", "f30", "f31"
468 if (reg >= 0 && reg < 32)
473 /* this function overwrites at */
475 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
477 /* XXX write a loop, not an unrolled loop */
479 mips_lw (code, mips_at, sreg, soffset);
480 mips_sw (code, mips_at, dreg, doffset);
489 * mono_arch_get_argument_info:
490 * @csig: a method signature
491 * @param_count: the number of parameters to consider
492 * @arg_info: an array to store the result infos
494 * Gathers information on parameters such as size, alignment and
495 * padding. arg_info should be large enought to hold param_count + 1 entries.
497 * Returns the size of the activation frame.
500 mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
502 int k, frame_size = 0;
503 guint32 size, align, pad;
506 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
507 frame_size += sizeof (gpointer);
511 arg_info [0].offset = offset;
514 frame_size += sizeof (gpointer);
518 arg_info [0].size = frame_size;
520 for (k = 0; k < param_count; k++) {
521 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
523 /* ignore alignment for now */
526 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
527 arg_info [k].pad = pad;
529 arg_info [k + 1].pad = 0;
530 arg_info [k + 1].size = size;
532 arg_info [k + 1].offset = offset;
536 align = MONO_ARCH_FRAME_ALIGNMENT;
537 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
538 arg_info [k].pad = pad;
543 /* The delegate object plus 3 params */
544 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
547 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
549 guint8 *code, *start;
552 start = code = mono_global_codeman_reserve (16);
554 /* Replace the this argument with the target */
555 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
556 mips_lw (code, mips_a0, mips_a0, G_STRUCT_OFFSET (MonoDelegate, target));
557 mips_jr (code, mips_temp);
560 g_assert ((code - start) <= 16);
562 mono_arch_flush_icache (start, 16);
566 size = 16 + param_count * 4;
567 start = code = mono_global_codeman_reserve (size);
569 mips_lw (code, mips_temp, mips_a0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
570 /* slide down the arguments */
571 for (i = 0; i < param_count; ++i) {
572 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
574 mips_jr (code, mips_temp);
577 g_assert ((code - start) <= size);
579 mono_arch_flush_icache (start, size);
583 *code_size = code - start;
589 * mono_arch_get_delegate_invoke_impls:
591 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
595 mono_arch_get_delegate_invoke_impls (void)
603 code = get_delegate_invoke_impl (TRUE, 0, &code_len);
604 res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
606 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
607 code = get_delegate_invoke_impl (FALSE, i, &code_len);
608 tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
609 res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
617 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
619 guint8 *code, *start;
621 /* FIXME: Support more cases */
622 if (MONO_TYPE_ISSTRUCT (sig->ret))
626 static guint8* cached = NULL;
627 mono_mini_arch_lock ();
629 mono_mini_arch_unlock ();
634 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
636 start = get_delegate_invoke_impl (TRUE, 0, NULL);
638 mono_mini_arch_unlock ();
641 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
644 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
646 for (i = 0; i < sig->param_count; ++i)
647 if (!mono_is_regsize_var (sig->params [i]))
650 mono_mini_arch_lock ();
651 code = cache [sig->param_count];
653 mono_mini_arch_unlock ();
658 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
659 start = mono_aot_get_trampoline (name);
662 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
664 cache [sig->param_count] = start;
665 mono_mini_arch_unlock ();
673 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
676 return (gpointer)regs [mips_a0];
680 * Initialize the cpu to execute managed code.
683 mono_arch_cpu_init (void)
685 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
694 ls_word_offset = ls_word_idx * 4;
695 ms_word_offset = ms_word_idx * 4;
699 * Initialize architecture specific code.
702 mono_arch_init (void)
704 InitializeCriticalSection (&mini_arch_mutex);
706 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
707 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
708 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
712 * Cleanup architecture specific code.
715 mono_arch_cleanup (void)
717 DeleteCriticalSection (&mini_arch_mutex);
721 * This function returns the optimizations supported on this cpu.
724 mono_arch_cpu_optimizations (guint32 *exclude_mask)
728 /* no mips-specific optimizations yet */
734 * This function test for all SIMD functions supported.
736 * Returns a bitmask corresponding to all supported versions.
740 mono_arch_cpu_enumerate_simd_versions (void)
742 /* SIMD is currently unimplemented */
747 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
752 for (i = 0; i < cfg->num_varinfo; i++) {
753 MonoInst *ins = cfg->varinfo [i];
754 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
757 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
760 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
763 /* we can only allocate 32 bit values */
764 if (mono_is_regsize_var (ins->inst_vtype)) {
765 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
766 g_assert (i == vmv->idx);
767 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
775 mono_arch_get_global_int_regs (MonoCompile *cfg)
779 regs = g_list_prepend (regs, (gpointer)mips_s0);
780 regs = g_list_prepend (regs, (gpointer)mips_s1);
781 regs = g_list_prepend (regs, (gpointer)mips_s2);
782 regs = g_list_prepend (regs, (gpointer)mips_s3);
783 regs = g_list_prepend (regs, (gpointer)mips_s4);
784 //regs = g_list_prepend (regs, (gpointer)mips_s5);
785 regs = g_list_prepend (regs, (gpointer)mips_s6);
786 regs = g_list_prepend (regs, (gpointer)mips_s7);
792 * mono_arch_regalloc_cost:
794 * Return the cost, in number of memory references, of the action of
795 * allocating the variable VMV into a register during global register
799 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
806 args_onto_stack (CallInfo *info)
808 g_assert (!info->on_stack);
809 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
810 info->on_stack = TRUE;
811 info->stack_size = MIPS_STACK_PARAM_OFFSET;
814 #if _MIPS_SIM == _ABIO32
816 * O32 calling convention version
820 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
821 /* First, see if we need to drop onto the stack */
822 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
823 args_onto_stack (info);
825 /* Now, place the argument */
826 if (info->on_stack) {
827 ainfo->storage = ArgOnStack;
828 ainfo->reg = mips_sp; /* in the caller */
829 ainfo->offset = info->stack_size;
832 ainfo->storage = ArgInIReg;
833 ainfo->reg = info->gr;
835 info->gr_passed = TRUE;
837 info->stack_size += 4;
841 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
842 /* First, see if we need to drop onto the stack */
843 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
844 args_onto_stack (info);
846 /* Now, place the argument */
847 if (info->on_stack) {
848 g_assert (info->stack_size % 4 == 0);
849 info->stack_size += (info->stack_size % 8);
851 ainfo->storage = ArgOnStack;
852 ainfo->reg = mips_sp; /* in the caller */
853 ainfo->offset = info->stack_size;
856 // info->gr must be a0 or a2
857 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
858 g_assert(info->gr <= MIPS_LAST_ARG_REG);
860 ainfo->storage = ArgInIReg;
861 ainfo->reg = info->gr;
863 info->gr_passed = TRUE;
865 info->stack_size += 8;
869 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
870 /* First, see if we need to drop onto the stack */
871 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
872 args_onto_stack (info);
874 /* Now, place the argument */
875 if (info->on_stack) {
876 ainfo->storage = ArgOnStack;
877 ainfo->reg = mips_sp; /* in the caller */
878 ainfo->offset = info->stack_size;
881 /* Only use FP regs for args if no int args passed yet */
882 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
883 ainfo->storage = ArgInFReg;
884 ainfo->reg = info->fr;
885 /* Even though it's a single-precision float, it takes up two FP regs */
887 /* FP and GP slots do not overlap */
891 /* Passing single-precision float arg in a GP register
892 * such as: func (0, 1.0, 2, 3);
893 * In this case, only one 'gr' register is consumed.
895 ainfo->storage = ArgInIReg;
896 ainfo->reg = info->gr;
899 info->gr_passed = TRUE;
902 info->stack_size += 4;
906 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
907 /* First, see if we need to drop onto the stack */
908 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
909 args_onto_stack (info);
911 /* Now, place the argument */
912 if (info->on_stack) {
913 g_assert(info->stack_size % 4 == 0);
914 info->stack_size += (info->stack_size % 8);
916 ainfo->storage = ArgOnStack;
917 ainfo->reg = mips_sp; /* in the caller */
918 ainfo->offset = info->stack_size;
921 /* Only use FP regs for args if no int args passed yet */
922 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
923 ainfo->storage = ArgInFReg;
924 ainfo->reg = info->fr;
926 /* FP and GP slots do not overlap */
930 // info->gr must be a0 or a2
931 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
932 g_assert(info->gr <= MIPS_LAST_ARG_REG);
934 ainfo->storage = ArgInIReg;
935 ainfo->reg = info->gr;
937 info->gr_passed = TRUE;
940 info->stack_size += 8;
942 #elif _MIPS_SIM == _ABIN32
944 * N32 calling convention version
948 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
949 /* First, see if we need to drop onto the stack */
950 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
951 args_onto_stack (info);
953 /* Now, place the argument */
954 if (info->on_stack) {
955 ainfo->storage = ArgOnStack;
956 ainfo->reg = mips_sp; /* in the caller */
957 ainfo->offset = info->stack_size;
958 info->stack_size += SIZEOF_REGISTER;
961 ainfo->storage = ArgInIReg;
962 ainfo->reg = info->gr;
964 info->gr_passed = TRUE;
969 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
970 /* First, see if we need to drop onto the stack */
971 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
972 args_onto_stack (info);
974 /* Now, place the argument */
975 if (info->on_stack) {
976 g_assert (info->stack_size % 4 == 0);
977 info->stack_size += (info->stack_size % 8);
979 ainfo->storage = ArgOnStack;
980 ainfo->reg = mips_sp; /* in the caller */
981 ainfo->offset = info->stack_size;
982 info->stack_size += SIZEOF_REGISTER;
985 g_assert (info->gr <= MIPS_LAST_ARG_REG);
987 ainfo->storage = ArgInIReg;
988 ainfo->reg = info->gr;
990 info->gr_passed = TRUE;
995 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
996 /* First, see if we need to drop onto the stack */
997 if (!info->on_stack) {
998 if (info->gr > MIPS_LAST_ARG_REG)
999 args_onto_stack (info);
1000 else if (info->fr > MIPS_LAST_FPARG_REG)
1001 args_onto_stack (info);
1004 /* Now, place the argument */
1005 if (info->on_stack) {
1006 ainfo->storage = ArgOnStack;
1007 ainfo->reg = mips_sp; /* in the caller */
1008 ainfo->offset = info->stack_size;
1009 info->stack_size += FREG_SIZE;
1012 ainfo->storage = ArgInFReg;
1013 ainfo->reg = info->fr;
1015 /* FP and GP slots do not overlap */
1021 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1022 /* First, see if we need to drop onto the stack */
1023 if (!info->on_stack) {
1024 if (info->gr > MIPS_LAST_ARG_REG)
1025 args_onto_stack (info);
1026 else if (info->fr > MIPS_LAST_FPARG_REG)
1027 args_onto_stack (info);
1030 /* Now, place the argument */
1031 if (info->on_stack) {
1032 g_assert(info->stack_size % 4 == 0);
1033 info->stack_size += (info->stack_size % 8);
1035 ainfo->storage = ArgOnStack;
1036 ainfo->reg = mips_sp; /* in the caller */
1037 ainfo->offset = info->stack_size;
1038 info->stack_size += FREG_SIZE;
1041 ainfo->storage = ArgInFReg;
1042 ainfo->reg = info->fr;
1044 /* FP and GP slots do not overlap */
1051 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
1054 int n = sig->hasthis + sig->param_count;
1056 MonoType* simpletype;
1058 gboolean is_pinvoke = sig->pinvoke;
1061 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1063 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1065 cinfo->fr = MIPS_FIRST_FPARG_REG;
1066 cinfo->gr = MIPS_FIRST_ARG_REG;
1067 cinfo->stack_size = 0;
1069 DEBUG(printf("calculate_sizes\n"));
1071 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1075 /* handle returning a struct */
1076 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1077 cinfo->struct_ret = cinfo->gr;
1078 add_int32_arg (cinfo, &cinfo->ret);
1082 add_int32_arg (cinfo, cinfo->args + n);
1087 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1088 * the first argument, allowing 'this' to be always passed in the first arg reg.
1089 * Also do this if the first argument is a reference type, since virtual calls
1090 * are sometimes made using calli without sig->hasthis set, like in the delegate
1093 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]))))) {
1095 add_int32_arg (cinfo, cinfo->args + n);
1098 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1102 add_int32_arg (cinfo, &cinfo->ret);
1103 cinfo->struct_ret = cinfo->ret.reg;
1107 add_int32_arg (cinfo, cinfo->args + n);
1111 if (cinfo->vtype_retaddr) {
1112 add_int32_arg (cinfo, &cinfo->ret);
1113 cinfo->struct_ret = cinfo->ret.reg;
1118 DEBUG(printf("params: %d\n", sig->param_count));
1119 for (i = pstart; i < sig->param_count; ++i) {
1120 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1121 /* Prevent implicit arguments and sig_cookie from
1122 being passed in registers */
1123 args_onto_stack (cinfo);
1124 /* Emit the signature cookie just before the implicit arguments */
1125 add_int32_arg (cinfo, &cinfo->sig_cookie);
1127 DEBUG(printf("param %d: ", i));
1128 simpletype = mini_type_get_underlying_type (gsctx, sig->params [i]);
1129 switch (simpletype->type) {
1130 case MONO_TYPE_BOOLEAN:
1133 DEBUG(printf("1 byte\n"));
1134 cinfo->args [n].size = 1;
1135 add_int32_arg (cinfo, &cinfo->args[n]);
1138 case MONO_TYPE_CHAR:
1141 DEBUG(printf("2 bytes\n"));
1142 cinfo->args [n].size = 2;
1143 add_int32_arg (cinfo, &cinfo->args[n]);
1148 DEBUG(printf("4 bytes\n"));
1149 cinfo->args [n].size = 4;
1150 add_int32_arg (cinfo, &cinfo->args[n]);
1156 case MONO_TYPE_FNPTR:
1157 case MONO_TYPE_CLASS:
1158 case MONO_TYPE_OBJECT:
1159 case MONO_TYPE_STRING:
1160 case MONO_TYPE_SZARRAY:
1161 case MONO_TYPE_ARRAY:
1162 cinfo->args [n].size = sizeof (gpointer);
1163 add_int32_arg (cinfo, &cinfo->args[n]);
1166 case MONO_TYPE_GENERICINST:
1167 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1168 cinfo->args [n].size = sizeof (gpointer);
1169 add_int32_arg (cinfo, &cinfo->args[n]);
1174 case MONO_TYPE_TYPEDBYREF:
1175 case MONO_TYPE_VALUETYPE: {
1178 int has_offset = FALSE;
1180 gint size, alignment;
1183 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1184 size = sizeof (MonoTypedRef);
1185 alignment = sizeof (gpointer);
1187 klass = mono_class_from_mono_type (sig->params [i]);
1189 size = mono_class_native_size (klass, NULL);
1191 size = mono_class_value_size (klass, NULL);
1192 alignment = mono_class_min_align (klass);
1194 #if MIPS_PASS_STRUCTS_BY_VALUE
1195 /* Need to do alignment if struct contains long or double */
1196 if (alignment > 4) {
1197 /* Drop onto stack *before* looking at
1198 stack_size, if required. */
1199 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1200 args_onto_stack (cinfo);
1201 if (cinfo->stack_size & (alignment - 1)) {
1202 add_int32_arg (cinfo, &dummy_arg);
1204 g_assert (!(cinfo->stack_size & (alignment - 1)));
1208 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1209 mono_class_native_size (sig->params [i]->data.klass, NULL),
1210 cinfo->stack_size, alignment);
1212 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1213 g_assert (cinfo->args [n].size == 0);
1214 g_assert (cinfo->args [n].vtsize == 0);
1215 for (j = 0; j < nwords; ++j) {
1217 add_int32_arg (cinfo, &cinfo->args [n]);
1218 if (cinfo->on_stack)
1221 add_int32_arg (cinfo, &dummy_arg);
1222 if (!has_offset && cinfo->on_stack) {
1223 cinfo->args [n].offset = dummy_arg.offset;
1227 if (cinfo->on_stack)
1228 cinfo->args [n].vtsize += 1;
1230 cinfo->args [n].size += 1;
1232 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1233 cinfo->args [n].storage = ArgStructByVal;
1235 add_int32_arg (cinfo, &cinfo->args[n]);
1236 cinfo->args [n].storage = ArgStructByAddr;
1243 DEBUG(printf("8 bytes\n"));
1244 cinfo->args [n].size = 8;
1245 add_int64_arg (cinfo, &cinfo->args[n]);
1249 DEBUG(printf("R4\n"));
1250 cinfo->args [n].size = 4;
1251 add_float32_arg (cinfo, &cinfo->args[n]);
1255 DEBUG(printf("R8\n"));
1256 cinfo->args [n].size = 8;
1257 add_float64_arg (cinfo, &cinfo->args[n]);
1261 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1265 /* Handle the case where there are no implicit arguments */
1266 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1267 /* Prevent implicit arguments and sig_cookie from
1268 being passed in registers */
1269 args_onto_stack (cinfo);
1270 /* Emit the signature cookie just before the implicit arguments */
1271 add_int32_arg (cinfo, &cinfo->sig_cookie);
1275 simpletype = mini_type_get_underlying_type (gsctx, sig->ret);
1276 switch (simpletype->type) {
1277 case MONO_TYPE_BOOLEAN:
1282 case MONO_TYPE_CHAR:
1288 case MONO_TYPE_FNPTR:
1289 case MONO_TYPE_CLASS:
1290 case MONO_TYPE_OBJECT:
1291 case MONO_TYPE_SZARRAY:
1292 case MONO_TYPE_ARRAY:
1293 case MONO_TYPE_STRING:
1294 cinfo->ret.reg = mips_v0;
1298 cinfo->ret.reg = mips_v0;
1302 cinfo->ret.reg = mips_f0;
1303 cinfo->ret.storage = ArgInFReg;
1305 case MONO_TYPE_GENERICINST:
1306 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1307 cinfo->ret.reg = mips_v0;
1311 case MONO_TYPE_VALUETYPE:
1312 case MONO_TYPE_TYPEDBYREF:
1314 case MONO_TYPE_VOID:
1317 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1321 /* align stack size to 16 */
1322 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1324 cinfo->stack_usage = cinfo->stack_size;
1329 debug_omit_fp (void)
1332 return mono_debug_count ();
1339 * mono_arch_compute_omit_fp:
1341 * Determine whenever the frame pointer can be eliminated.
1344 mono_arch_compute_omit_fp (MonoCompile *cfg)
1346 MonoMethodSignature *sig;
1347 MonoMethodHeader *header;
1351 if (cfg->arch.omit_fp_computed)
1354 header = cfg->header;
1356 sig = mono_method_signature (cfg->method);
1358 if (!cfg->arch.cinfo)
1359 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1360 cinfo = cfg->arch.cinfo;
1363 * FIXME: Remove some of the restrictions.
1365 cfg->arch.omit_fp = TRUE;
1366 cfg->arch.omit_fp_computed = TRUE;
1368 if (cfg->disable_omit_fp)
1369 cfg->arch.omit_fp = FALSE;
1370 if (!debug_omit_fp ())
1371 cfg->arch.omit_fp = FALSE;
1372 if (cfg->method->save_lmf)
1373 cfg->arch.omit_fp = FALSE;
1374 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1375 cfg->arch.omit_fp = FALSE;
1376 if (header->num_clauses)
1377 cfg->arch.omit_fp = FALSE;
1378 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1379 cfg->arch.omit_fp = FALSE;
1380 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1381 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1382 cfg->arch.omit_fp = FALSE;
1384 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1385 * there are stack arguments.
1388 if (cinfo->stack_usage)
1389 cfg->arch.omit_fp = FALSE;
1393 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1394 MonoInst *ins = cfg->varinfo [i];
1397 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1400 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1404 * Set var information according to the calling convention. mips version.
1405 * The locals var stuff should most likely be split in another method.
1408 mono_arch_allocate_vars (MonoCompile *cfg)
1410 MonoMethodSignature *sig;
1411 MonoMethodHeader *header;
1413 int i, offset, size, align, curinst;
1414 int frame_reg = mips_sp;
1415 guint32 iregs_to_save = 0;
1417 guint32 fregs_to_restore;
1421 sig = mono_method_signature (cfg->method);
1423 if (!cfg->arch.cinfo)
1424 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1425 cinfo = cfg->arch.cinfo;
1427 mono_arch_compute_omit_fp (cfg);
1429 /* spill down, we'll fix it in a separate pass */
1430 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1432 /* allow room for the vararg method args: void* and long/double */
1433 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1434 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1436 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1437 * call convs needs to be handled this way.
1439 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1440 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1442 /* gtk-sharp and other broken code will dllimport vararg functions even with
1443 * non-varargs signatures. Since there is little hope people will get this right
1444 * we assume they won't.
1446 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1447 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1449 /* a0-a3 always present */
1450 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1452 header = cfg->header;
1454 if (cfg->arch.omit_fp)
1455 frame_reg = mips_sp;
1457 frame_reg = mips_fp;
1458 cfg->frame_reg = frame_reg;
1459 if (frame_reg != mips_sp) {
1460 cfg->used_int_regs |= 1 << frame_reg;
1465 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1466 /* FIXME: handle long and FP values */
1467 switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
1468 case MONO_TYPE_VOID:
1472 cfg->ret->opcode = OP_REGVAR;
1473 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1476 cfg->ret->opcode = OP_REGVAR;
1477 cfg->ret->inst_c0 = mips_v0;
1481 /* Space for outgoing parameters, including a0-a3 */
1482 offset += cfg->param_area;
1484 /* allow room to save the return value (if it's a struct) */
1485 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1488 /* Now handle the local variables */
1490 curinst = cfg->locals_start;
1491 for (i = curinst; i < cfg->num_varinfo; ++i) {
1492 inst = cfg->varinfo [i];
1493 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1496 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1497 * pinvoke wrappers when they call functions returning structure
1499 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1500 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1502 size = mono_type_size (inst->inst_vtype, &align);
1504 offset += align - 1;
1505 offset &= ~(align - 1);
1506 inst->inst_offset = offset;
1507 inst->opcode = OP_REGOFFSET;
1508 inst->inst_basereg = frame_reg;
1510 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1513 /* Space for LMF (if needed) */
1514 if (cfg->method->save_lmf) {
1515 /* align the offset to 16 bytes */
1516 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1517 cfg->arch.lmf_offset = offset;
1518 offset += sizeof (MonoLMF);
1521 if (sig->call_convention == MONO_CALL_VARARG) {
1525 /* Allocate a local slot to hold the sig cookie address */
1526 offset += align - 1;
1527 offset &= ~(align - 1);
1528 cfg->sig_cookie = offset;
1532 offset += SIZEOF_REGISTER - 1;
1533 offset &= ~(SIZEOF_REGISTER - 1);
1535 /* Space for saved registers */
1536 cfg->arch.iregs_offset = offset;
1537 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1538 if (iregs_to_save) {
1539 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1540 if (iregs_to_save & (1 << i)) {
1541 offset += SIZEOF_REGISTER;
1546 /* saved float registers */
1548 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1549 if (fregs_to_restore) {
1550 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1551 if (fregs_to_restore & (1 << i)) {
1552 offset += sizeof(double);
1558 #if _MIPS_SIM == _ABIO32
1559 /* Now add space for saving the ra */
1560 offset += SIZEOF_VOID_P;
1563 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1564 cfg->stack_offset = offset;
1565 cfg->arch.local_alloc_offset = cfg->stack_offset;
1569 * Now allocate stack slots for the int arg regs (a0 - a3)
1570 * On MIPS o32, these are just above the incoming stack pointer
1571 * Even if the arg has been assigned to a regvar, it gets a stack slot
1574 /* Return struct-by-value results in a hidden first argument */
1575 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1576 cfg->vret_addr->opcode = OP_REGOFFSET;
1577 cfg->vret_addr->inst_c0 = mips_a0;
1578 cfg->vret_addr->inst_offset = offset;
1579 cfg->vret_addr->inst_basereg = frame_reg;
1580 offset += SIZEOF_REGISTER;
1583 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1584 inst = cfg->args [i];
1585 if (inst->opcode != OP_REGVAR) {
1588 if (sig->hasthis && (i == 0))
1589 arg_type = &mono_defaults.object_class->byval_arg;
1591 arg_type = sig->params [i - sig->hasthis];
1593 inst->opcode = OP_REGOFFSET;
1594 size = mono_type_size (arg_type, &align);
1596 if (size < SIZEOF_REGISTER) {
1597 size = SIZEOF_REGISTER;
1598 align = SIZEOF_REGISTER;
1600 inst->inst_basereg = frame_reg;
1601 offset = (offset + align - 1) & ~(align - 1);
1602 inst->inst_offset = offset;
1604 if (cfg->verbose_level > 1)
1605 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1608 #if _MIPS_SIM == _ABIO32
1609 /* o32: Even a0-a3 get stack slots */
1610 size = SIZEOF_REGISTER;
1611 align = SIZEOF_REGISTER;
1612 inst->inst_basereg = frame_reg;
1613 offset = (offset + align - 1) & ~(align - 1);
1614 inst->inst_offset = offset;
1616 if (cfg->verbose_level > 1)
1617 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1621 #if _MIPS_SIM == _ABIN32
1622 /* Now add space for saving the ra */
1623 offset += SIZEOF_VOID_P;
1626 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1627 cfg->stack_offset = offset;
1628 cfg->arch.local_alloc_offset = cfg->stack_offset;
1633 mono_arch_create_vars (MonoCompile *cfg)
1635 MonoMethodSignature *sig;
1637 sig = mono_method_signature (cfg->method);
1639 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1640 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1641 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1642 printf ("vret_addr = ");
1643 mono_print_ins (cfg->vret_addr);
1648 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1649 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1653 * take the arguments and generate the arch-specific
1654 * instructions to properly call the function in call.
1655 * This includes pushing, moving arguments to the right register
1657 * Issue: who does the spilling if needed, and when?
1660 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1662 MonoMethodSignature *tmp_sig;
1665 if (call->tail_call)
1668 /* FIXME: Add support for signature tokens to AOT */
1669 cfg->disable_aot = TRUE;
1672 * mono_ArgIterator_Setup assumes the signature cookie is
1673 * passed first and all the arguments which were before it are
1674 * passed on the stack after the signature. So compensate by
1675 * passing a different signature.
1677 tmp_sig = mono_metadata_signature_dup (call->signature);
1678 tmp_sig->param_count -= call->signature->sentinelpos;
1679 tmp_sig->sentinelpos = 0;
1680 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1682 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1683 sig_arg->dreg = mono_alloc_ireg (cfg);
1684 sig_arg->inst_p0 = tmp_sig;
1685 MONO_ADD_INS (cfg->cbb, sig_arg);
1687 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1691 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1694 MonoMethodSignature *sig;
1699 sig = call->signature;
1700 n = sig->param_count + sig->hasthis;
1702 cinfo = get_call_info (NULL, cfg->mempool, sig);
1703 if (cinfo->struct_ret)
1704 call->used_iregs |= 1 << cinfo->struct_ret;
1706 for (i = 0; i < n; ++i) {
1707 ArgInfo *ainfo = cinfo->args + i;
1710 if (i >= sig->hasthis)
1711 t = sig->params [i - sig->hasthis];
1713 t = &mono_defaults.int_class->byval_arg;
1714 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1716 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1717 /* Emit the signature cookie just before the implicit arguments */
1718 emit_sig_cookie (cfg, call, cinfo);
1721 if (is_virtual && i == 0) {
1722 /* the argument will be attached to the call instrucion */
1723 in = call->args [i];
1724 call->used_iregs |= 1 << ainfo->reg;
1727 in = call->args [i];
1728 if (ainfo->storage == ArgInIReg) {
1729 #if SIZEOF_REGISTER == 4
1730 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1731 MONO_INST_NEW (cfg, ins, OP_MOVE);
1732 ins->dreg = mono_alloc_ireg (cfg);
1733 ins->sreg1 = in->dreg + 1;
1734 MONO_ADD_INS (cfg->cbb, ins);
1735 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1737 MONO_INST_NEW (cfg, ins, OP_MOVE);
1738 ins->dreg = mono_alloc_ireg (cfg);
1739 ins->sreg1 = in->dreg + 2;
1740 MONO_ADD_INS (cfg->cbb, ins);
1741 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1744 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1747 #if PROMOTE_R4_TO_R8
1748 /* ??? - convert to single first? */
1749 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1750 ins->dreg = mono_alloc_freg (cfg);
1751 ins->sreg1 = in->dreg;
1752 MONO_ADD_INS (cfg->cbb, ins);
1757 /* trying to load float value into int registers */
1758 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1759 ins->dreg = mono_alloc_ireg (cfg);
1761 MONO_ADD_INS (cfg->cbb, ins);
1762 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1763 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1764 /* trying to load float value into int registers */
1765 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1766 ins->dreg = mono_alloc_ireg (cfg);
1767 ins->sreg1 = in->dreg;
1768 MONO_ADD_INS (cfg->cbb, ins);
1769 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1771 MONO_INST_NEW (cfg, ins, OP_MOVE);
1772 ins->dreg = mono_alloc_ireg (cfg);
1773 ins->sreg1 = in->dreg;
1774 MONO_ADD_INS (cfg->cbb, ins);
1775 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1777 } else if (ainfo->storage == ArgStructByAddr) {
1778 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1779 ins->opcode = OP_OUTARG_VT;
1780 ins->sreg1 = in->dreg;
1781 ins->klass = in->klass;
1782 ins->inst_p0 = call;
1783 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1784 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1785 MONO_ADD_INS (cfg->cbb, ins);
1786 } else if (ainfo->storage == ArgStructByVal) {
1787 /* this is further handled in mono_arch_emit_outarg_vt () */
1788 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1789 ins->opcode = OP_OUTARG_VT;
1790 ins->sreg1 = in->dreg;
1791 ins->klass = in->klass;
1792 ins->inst_p0 = call;
1793 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1794 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1795 MONO_ADD_INS (cfg->cbb, ins);
1796 } else if (ainfo->storage == ArgOnStack) {
1797 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1798 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1799 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1800 if (t->type == MONO_TYPE_R8)
1801 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1803 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1805 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1807 } else if (ainfo->storage == ArgInFReg) {
1808 if (t->type == MONO_TYPE_VALUETYPE) {
1809 /* this is further handled in mono_arch_emit_outarg_vt () */
1810 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1811 ins->opcode = OP_OUTARG_VT;
1812 ins->sreg1 = in->dreg;
1813 ins->klass = in->klass;
1814 ins->inst_p0 = call;
1815 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1816 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1817 MONO_ADD_INS (cfg->cbb, ins);
1819 cfg->flags |= MONO_CFG_HAS_FPOUT;
1821 int dreg = mono_alloc_freg (cfg);
1823 if (ainfo->size == 4) {
1824 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1826 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1828 ins->sreg1 = in->dreg;
1829 MONO_ADD_INS (cfg->cbb, ins);
1832 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1833 cfg->flags |= MONO_CFG_HAS_FPOUT;
1836 g_assert_not_reached ();
1840 /* Handle the case where there are no implicit arguments */
1841 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1842 emit_sig_cookie (cfg, call, cinfo);
1844 if (cinfo->struct_ret) {
1847 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1848 vtarg->sreg1 = call->vret_var->dreg;
1849 vtarg->dreg = mono_alloc_preg (cfg);
1850 MONO_ADD_INS (cfg->cbb, vtarg);
1852 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1856 * Reverse the call->out_args list.
1859 MonoInst *prev = NULL, *list = call->out_args, *next;
1866 call->out_args = prev;
1869 call->stack_usage = cinfo->stack_usage;
1870 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1871 #if _MIPS_SIM == _ABIO32
1872 /* a0-a3 always present */
1873 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1875 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1876 cfg->flags |= MONO_CFG_HAS_CALLS;
1878 * should set more info in call, such as the stack space
1879 * used by the args that needs to be added back to esp
1884 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1886 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1887 ArgInfo *ainfo = ins->inst_p1;
1888 int ovf_size = ainfo->vtsize;
1889 int doffset = ainfo->offset;
1890 int i, soffset, dreg;
1892 if (ainfo->storage == ArgStructByVal) {
1894 if (cfg->verbose_level > 0) {
1895 char* nm = mono_method_full_name (cfg->method, TRUE);
1896 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1897 nm, doffset, ainfo->size, ovf_size);
1903 for (i = 0; i < ainfo->size; ++i) {
1904 dreg = mono_alloc_ireg (cfg);
1905 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1906 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1907 soffset += SIZEOF_REGISTER;
1909 if (ovf_size != 0) {
1910 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1912 } else if (ainfo->storage == ArgInFReg) {
1913 int tmpr = mono_alloc_freg (cfg);
1915 if (ainfo->size == 4)
1916 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1918 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1919 dreg = mono_alloc_freg (cfg);
1920 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1921 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1923 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1927 /* FIXME: alignment? */
1928 if (call->signature->pinvoke) {
1929 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1930 vtcopy->backend.is_pinvoke = 1;
1932 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1935 g_assert (ovf_size > 0);
1937 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1938 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1941 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1943 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1948 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1950 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1951 mono_method_signature (method)->ret);
1954 #if (SIZEOF_REGISTER == 4)
1955 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1958 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1959 ins->sreg1 = val->dreg + 1;
1960 ins->sreg2 = val->dreg + 2;
1961 MONO_ADD_INS (cfg->cbb, ins);
1965 if (ret->type == MONO_TYPE_R8) {
1966 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1969 if (ret->type == MONO_TYPE_R4) {
1970 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1974 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1978 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1980 MonoInst *ins, *n, *last_ins = NULL;
1982 if (cfg->verbose_level > 2)
1983 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1986 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1987 if (cfg->verbose_level > 2)
1988 mono_print_ins_index (0, ins);
1990 switch (ins->opcode) {
1992 case OP_LOAD_MEMBASE:
1993 case OP_LOADI4_MEMBASE:
1995 * OP_IADD reg2, reg1, const1
1996 * OP_LOAD_MEMBASE const2(reg2), reg3
1998 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
2000 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)){
2001 int const1 = last_ins->inst_imm;
2002 int const2 = ins->inst_offset;
2004 if (mips_is_imm16 (const1 + const2)) {
2005 ins->inst_basereg = last_ins->sreg1;
2006 ins->inst_offset = const1 + const2;
2016 bb->last_ins = last_ins;
2020 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2022 MonoInst *ins, *n, *last_ins = NULL;
2025 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2026 MonoInst *last_ins = ins->prev;
2028 switch (ins->opcode) {
2030 /* remove unnecessary multiplication with 1 */
2031 if (ins->inst_imm == 1) {
2032 if (ins->dreg != ins->sreg1) {
2033 ins->opcode = OP_MOVE;
2035 MONO_DELETE_INS (bb, ins);
2039 int power2 = mono_is_power_of_two (ins->inst_imm);
2041 ins->opcode = OP_SHL_IMM;
2042 ins->inst_imm = power2;
2046 case OP_LOAD_MEMBASE:
2047 case OP_LOADI4_MEMBASE:
2049 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2050 * OP_LOAD_MEMBASE offset(basereg), reg
2052 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2053 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2054 ins->inst_basereg == last_ins->inst_destbasereg &&
2055 ins->inst_offset == last_ins->inst_offset) {
2056 if (ins->dreg == last_ins->sreg1) {
2057 MONO_DELETE_INS (bb, ins);
2060 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2061 ins->opcode = OP_MOVE;
2062 ins->sreg1 = last_ins->sreg1;
2067 * Note: reg1 must be different from the basereg in the second load
2068 * OP_LOAD_MEMBASE offset(basereg), reg1
2069 * OP_LOAD_MEMBASE offset(basereg), reg2
2071 * OP_LOAD_MEMBASE offset(basereg), reg1
2072 * OP_MOVE reg1, reg2
2074 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2075 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2076 ins->inst_basereg != last_ins->dreg &&
2077 ins->inst_basereg == last_ins->inst_basereg &&
2078 ins->inst_offset == last_ins->inst_offset) {
2080 if (ins->dreg == last_ins->dreg) {
2081 MONO_DELETE_INS (bb, ins);
2084 ins->opcode = OP_MOVE;
2085 ins->sreg1 = last_ins->dreg;
2088 //g_assert_not_reached ();
2093 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2094 * OP_LOAD_MEMBASE offset(basereg), reg
2096 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2097 * OP_ICONST reg, imm
2099 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2100 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2101 ins->inst_basereg == last_ins->inst_destbasereg &&
2102 ins->inst_offset == last_ins->inst_offset) {
2103 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2104 ins->opcode = OP_ICONST;
2105 ins->inst_c0 = last_ins->inst_imm;
2106 g_assert_not_reached (); // check this rule
2111 case OP_LOADU1_MEMBASE:
2112 case OP_LOADI1_MEMBASE:
2113 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2114 ins->inst_basereg == last_ins->inst_destbasereg &&
2115 ins->inst_offset == last_ins->inst_offset) {
2116 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2117 ins->sreg1 = last_ins->sreg1;
2120 case OP_LOADU2_MEMBASE:
2121 case OP_LOADI2_MEMBASE:
2122 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2123 ins->inst_basereg == last_ins->inst_destbasereg &&
2124 ins->inst_offset == last_ins->inst_offset) {
2125 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2126 ins->sreg1 = last_ins->sreg1;
2129 case OP_ICONV_TO_I4:
2130 case OP_ICONV_TO_U4:
2132 ins->opcode = OP_MOVE;
2136 if (ins->dreg == ins->sreg1) {
2137 MONO_DELETE_INS (bb, ins);
2141 * OP_MOVE sreg, dreg
2142 * OP_MOVE dreg, sreg
2144 if (last_ins && last_ins->opcode == OP_MOVE &&
2145 ins->sreg1 == last_ins->dreg &&
2146 ins->dreg == last_ins->sreg1) {
2147 MONO_DELETE_INS (bb, ins);
2155 bb->last_ins = last_ins;
2159 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2167 switch (ins->opcode) {
2170 case OP_LCOMPARE_IMM:
2171 mono_print_ins (ins);
2172 g_assert_not_reached ();
2175 tmp1 = mono_alloc_ireg (cfg);
2176 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2177 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2178 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2179 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2184 tmp1 = mono_alloc_ireg (cfg);
2185 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2186 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2187 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2188 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2193 tmp1 = mono_alloc_ireg (cfg);
2194 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2195 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2196 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2197 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2202 tmp1 = mono_alloc_ireg (cfg);
2203 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2204 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2205 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2206 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2218 mono_print_ins (ins);
2219 g_assert_not_reached ();
2222 tmp1 = mono_alloc_ireg (cfg);
2223 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2224 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2225 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2226 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2234 case OP_LCONV_TO_I1:
2235 case OP_LCONV_TO_I2:
2236 case OP_LCONV_TO_I4:
2237 case OP_LCONV_TO_I8:
2238 case OP_LCONV_TO_R4:
2239 case OP_LCONV_TO_R8:
2240 case OP_LCONV_TO_U4:
2241 case OP_LCONV_TO_U8:
2242 case OP_LCONV_TO_U2:
2243 case OP_LCONV_TO_U1:
2245 case OP_LCONV_TO_OVF_I:
2246 case OP_LCONV_TO_OVF_U:
2248 mono_print_ins (ins);
2249 g_assert_not_reached ();
2252 tmp1 = mono_alloc_ireg (cfg);
2253 tmp2 = mono_alloc_ireg (cfg);
2254 tmp3 = mono_alloc_ireg (cfg);
2255 tmp4 = mono_alloc_ireg (cfg);
2256 tmp5 = mono_alloc_ireg (cfg);
2258 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2260 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2261 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2263 /* add the high 32-bits, and add in the carry from the low 32-bits */
2264 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2265 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2267 /* Overflow happens if
2268 * neg + neg = pos or
2270 * XOR of the high bits returns 0 if the signs match
2271 * XOR of that with the high bit of the result return 1 if overflow.
2274 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2275 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2277 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2278 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2279 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2281 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2282 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2283 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2285 /* Now, if (tmp4 == 0) then overflow */
2286 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2290 case OP_LADD_OVF_UN:
2291 tmp1 = mono_alloc_ireg (cfg);
2292 tmp2 = mono_alloc_ireg (cfg);
2294 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2295 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2296 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2297 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2298 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2299 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2304 case OP_LMUL_OVF_UN:
2305 mono_print_ins (ins);
2306 g_assert_not_reached ();
2309 tmp1 = mono_alloc_ireg (cfg);
2310 tmp2 = mono_alloc_ireg (cfg);
2311 tmp3 = mono_alloc_ireg (cfg);
2312 tmp4 = mono_alloc_ireg (cfg);
2313 tmp5 = mono_alloc_ireg (cfg);
2315 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2317 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2318 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2319 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2321 /* Overflow happens if
2322 * neg - pos = pos or
2324 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2326 * tmp1 = (lhs ^ rhs)
2327 * tmp2 = (lhs ^ result)
2328 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2331 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2332 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2333 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2334 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2336 /* Now, if (tmp4 == 1) then overflow */
2337 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2341 case OP_LSUB_OVF_UN:
2342 tmp1 = mono_alloc_ireg (cfg);
2343 tmp2 = mono_alloc_ireg (cfg);
2345 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2346 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2347 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2348 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2350 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2351 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2355 case OP_LCONV_TO_OVF_I1_UN:
2356 case OP_LCONV_TO_OVF_I2_UN:
2357 case OP_LCONV_TO_OVF_I4_UN:
2358 case OP_LCONV_TO_OVF_I8_UN:
2359 case OP_LCONV_TO_OVF_U1_UN:
2360 case OP_LCONV_TO_OVF_U2_UN:
2361 case OP_LCONV_TO_OVF_U4_UN:
2362 case OP_LCONV_TO_OVF_U8_UN:
2363 case OP_LCONV_TO_OVF_I_UN:
2364 case OP_LCONV_TO_OVF_U_UN:
2365 case OP_LCONV_TO_OVF_I1:
2366 case OP_LCONV_TO_OVF_U1:
2367 case OP_LCONV_TO_OVF_I2:
2368 case OP_LCONV_TO_OVF_U2:
2369 case OP_LCONV_TO_OVF_I4:
2370 case OP_LCONV_TO_OVF_U4:
2371 case OP_LCONV_TO_OVF_I8:
2372 case OP_LCONV_TO_OVF_U8:
2380 case OP_LCONV_TO_R_UN:
2386 case OP_LSHR_UN_IMM:
2388 case OP_LDIV_UN_IMM:
2390 case OP_LREM_UN_IMM:
2401 mono_print_ins (ins);
2402 g_assert_not_reached ();
2404 case OP_LCONV_TO_R8_2:
2405 case OP_LCONV_TO_R4_2:
2406 case OP_LCONV_TO_R_UN_2:
2408 case OP_LCONV_TO_OVF_I4_2:
2409 tmp1 = mono_alloc_ireg (cfg);
2411 /* Overflows if reg2 != sign extension of reg1 */
2412 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2413 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2414 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2422 mono_print_ins (ins);
2423 g_assert_not_reached ();
2431 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2439 switch (ins->opcode) {
2441 tmp1 = mono_alloc_ireg (cfg);
2442 tmp2 = mono_alloc_ireg (cfg);
2443 tmp3 = mono_alloc_ireg (cfg);
2444 tmp4 = mono_alloc_ireg (cfg);
2445 tmp5 = mono_alloc_ireg (cfg);
2447 /* add the operands */
2449 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2451 /* Overflow happens if
2452 * neg + neg = pos or
2455 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2456 * XOR of the high bit returns 0 if the signs match
2457 * XOR of that with the high bit of the result return 1 if overflow.
2460 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2461 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2463 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2464 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2465 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2467 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2468 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2470 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2472 /* Now, if (tmp5 == 0) then overflow */
2473 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2474 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2475 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2479 case OP_IADD_OVF_UN:
2480 tmp1 = mono_alloc_ireg (cfg);
2482 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2483 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2484 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2485 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2486 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2491 tmp1 = mono_alloc_ireg (cfg);
2492 tmp2 = mono_alloc_ireg (cfg);
2493 tmp3 = mono_alloc_ireg (cfg);
2494 tmp4 = mono_alloc_ireg (cfg);
2495 tmp5 = mono_alloc_ireg (cfg);
2497 /* add the operands */
2499 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2501 /* Overflow happens if
2502 * neg - pos = pos or
2504 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2506 * tmp1 = (lhs ^ rhs)
2507 * tmp2 = (lhs ^ result)
2508 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2511 /* tmp3 = 1 if the signs of the two inputs differ */
2512 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2513 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2514 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2515 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2516 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2518 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2519 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2520 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2524 case OP_ISUB_OVF_UN:
2525 tmp1 = mono_alloc_ireg (cfg);
2527 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2528 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2529 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2530 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2531 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2538 map_to_reg_reg_op (int op)
2547 case OP_COMPARE_IMM:
2549 case OP_ICOMPARE_IMM:
2551 case OP_LCOMPARE_IMM:
2567 case OP_LOAD_MEMBASE:
2568 return OP_LOAD_MEMINDEX;
2569 case OP_LOADI4_MEMBASE:
2570 return OP_LOADI4_MEMINDEX;
2571 case OP_LOADU4_MEMBASE:
2572 return OP_LOADU4_MEMINDEX;
2573 case OP_LOADU1_MEMBASE:
2574 return OP_LOADU1_MEMINDEX;
2575 case OP_LOADI2_MEMBASE:
2576 return OP_LOADI2_MEMINDEX;
2577 case OP_LOADU2_MEMBASE:
2578 return OP_LOADU2_MEMINDEX;
2579 case OP_LOADI1_MEMBASE:
2580 return OP_LOADI1_MEMINDEX;
2581 case OP_LOADR4_MEMBASE:
2582 return OP_LOADR4_MEMINDEX;
2583 case OP_LOADR8_MEMBASE:
2584 return OP_LOADR8_MEMINDEX;
2585 case OP_STOREI1_MEMBASE_REG:
2586 return OP_STOREI1_MEMINDEX;
2587 case OP_STOREI2_MEMBASE_REG:
2588 return OP_STOREI2_MEMINDEX;
2589 case OP_STOREI4_MEMBASE_REG:
2590 return OP_STOREI4_MEMINDEX;
2591 case OP_STORE_MEMBASE_REG:
2592 return OP_STORE_MEMINDEX;
2593 case OP_STORER4_MEMBASE_REG:
2594 return OP_STORER4_MEMINDEX;
2595 case OP_STORER8_MEMBASE_REG:
2596 return OP_STORER8_MEMINDEX;
2597 case OP_STORE_MEMBASE_IMM:
2598 return OP_STORE_MEMBASE_REG;
2599 case OP_STOREI1_MEMBASE_IMM:
2600 return OP_STOREI1_MEMBASE_REG;
2601 case OP_STOREI2_MEMBASE_IMM:
2602 return OP_STOREI2_MEMBASE_REG;
2603 case OP_STOREI4_MEMBASE_IMM:
2604 return OP_STOREI4_MEMBASE_REG;
2605 case OP_STOREI8_MEMBASE_IMM:
2606 return OP_STOREI8_MEMBASE_REG;
2608 return mono_op_imm_to_op (op);
2612 map_to_mips_op (int op)
2616 return OP_MIPS_FBEQ;
2618 return OP_MIPS_FBGE;
2620 return OP_MIPS_FBGT;
2622 return OP_MIPS_FBLE;
2624 return OP_MIPS_FBLT;
2626 return OP_MIPS_FBNE;
2628 return OP_MIPS_FBGE_UN;
2630 return OP_MIPS_FBGT_UN;
2632 return OP_MIPS_FBLE_UN;
2634 return OP_MIPS_FBLT_UN;
2642 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2643 g_assert_not_reached ();
2647 #define NEW_INS(cfg,after,dest,op) do { \
2648 MONO_INST_NEW((cfg), (dest), (op)); \
2649 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2652 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2654 MONO_INST_NEW(cfg, temp, (op)); \
2655 mono_bblock_insert_after_ins (bb, (pos), temp); \
2656 temp->dreg = (_dreg); \
2657 temp->sreg1 = (_sreg1); \
2658 temp->sreg2 = (_sreg2); \
2662 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2664 MONO_INST_NEW(cfg, temp, (op)); \
2665 mono_bblock_insert_after_ins (bb, (pos), temp); \
2666 temp->dreg = (_dreg); \
2667 temp->sreg1 = (_sreg1); \
2668 temp->inst_c0 = (_imm); \
2673 * Remove from the instruction list the instructions that can't be
2674 * represented with very simple instructions with no register
2678 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2680 MonoInst *ins, *next, *temp, *last_ins = NULL;
2684 if (cfg->verbose_level > 2) {
2687 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2688 MONO_BB_FOR_EACH_INS (bb, ins) {
2689 mono_print_ins_index (idx++, ins);
2695 MONO_BB_FOR_EACH_INS (bb, ins) {
2697 switch (ins->opcode) {
2702 /* Branch opts can eliminate the branch */
2703 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2709 case OP_COMPARE_IMM:
2710 case OP_ICOMPARE_IMM:
2711 case OP_LCOMPARE_IMM:
2713 /* Branch opts can eliminate the branch */
2714 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2718 if (ins->inst_imm) {
2719 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2720 temp->inst_c0 = ins->inst_imm;
2721 temp->dreg = mono_alloc_ireg (cfg);
2722 ins->sreg2 = temp->dreg;
2726 ins->sreg2 = mips_zero;
2728 if (ins->opcode == OP_COMPARE_IMM)
2729 ins->opcode = OP_COMPARE;
2730 else if (ins->opcode == OP_ICOMPARE_IMM)
2731 ins->opcode = OP_ICOMPARE;
2732 else if (ins->opcode == OP_LCOMPARE_IMM)
2733 ins->opcode = OP_LCOMPARE;
2736 case OP_IDIV_UN_IMM:
2739 case OP_IREM_UN_IMM:
2740 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2741 temp->inst_c0 = ins->inst_imm;
2742 temp->dreg = mono_alloc_ireg (cfg);
2743 ins->sreg2 = temp->dreg;
2744 if (ins->opcode == OP_IDIV_IMM)
2745 ins->opcode = OP_IDIV;
2746 else if (ins->opcode == OP_IREM_IMM)
2747 ins->opcode = OP_IREM;
2748 else if (ins->opcode == OP_IDIV_UN_IMM)
2749 ins->opcode = OP_IDIV_UN;
2750 else if (ins->opcode == OP_IREM_UN_IMM)
2751 ins->opcode = OP_IREM_UN;
2753 /* handle rem separately */
2760 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2761 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2762 temp->inst_c0 = ins->inst_imm;
2763 temp->dreg = mono_alloc_ireg (cfg);
2764 ins->sreg2 = temp->dreg;
2765 ins->opcode = map_to_reg_reg_op (ins->opcode);
2775 /* unsigned 16 bit immediate */
2776 if (ins->inst_imm & 0xffff0000) {
2777 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2778 temp->inst_c0 = ins->inst_imm;
2779 temp->dreg = mono_alloc_ireg (cfg);
2780 ins->sreg2 = temp->dreg;
2781 ins->opcode = map_to_reg_reg_op (ins->opcode);
2788 /* signed 16 bit immediate */
2789 if (!mips_is_imm16 (ins->inst_imm)) {
2790 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2791 temp->inst_c0 = ins->inst_imm;
2792 temp->dreg = mono_alloc_ireg (cfg);
2793 ins->sreg2 = temp->dreg;
2794 ins->opcode = map_to_reg_reg_op (ins->opcode);
2800 if (!mips_is_imm16 (-ins->inst_imm)) {
2801 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2802 temp->inst_c0 = ins->inst_imm;
2803 temp->dreg = mono_alloc_ireg (cfg);
2804 ins->sreg2 = temp->dreg;
2805 ins->opcode = map_to_reg_reg_op (ins->opcode);
2811 if (ins->inst_imm == 1) {
2812 ins->opcode = OP_MOVE;
2815 if (ins->inst_imm == 0) {
2816 ins->opcode = OP_ICONST;
2820 imm = mono_is_power_of_two (ins->inst_imm);
2822 ins->opcode = OP_SHL_IMM;
2823 ins->inst_imm = imm;
2826 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2827 temp->inst_c0 = ins->inst_imm;
2828 temp->dreg = mono_alloc_ireg (cfg);
2829 ins->sreg2 = temp->dreg;
2830 ins->opcode = map_to_reg_reg_op (ins->opcode);
2833 case OP_LOCALLOC_IMM:
2834 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2835 temp->inst_c0 = ins->inst_imm;
2836 temp->dreg = mono_alloc_ireg (cfg);
2837 ins->sreg1 = temp->dreg;
2838 ins->opcode = OP_LOCALLOC;
2841 case OP_LOADR4_MEMBASE:
2842 case OP_STORER4_MEMBASE_REG:
2843 /* we can do two things: load the immed in a register
2844 * and use an indexed load, or see if the immed can be
2845 * represented as an ad_imm + a load with a smaller offset
2846 * that fits. We just do the first for now, optimize later.
2848 if (mips_is_imm16 (ins->inst_offset))
2850 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2851 temp->inst_c0 = ins->inst_offset;
2852 temp->dreg = mono_alloc_ireg (cfg);
2853 ins->sreg2 = temp->dreg;
2854 ins->opcode = map_to_reg_reg_op (ins->opcode);
2857 case OP_STORE_MEMBASE_IMM:
2858 case OP_STOREI1_MEMBASE_IMM:
2859 case OP_STOREI2_MEMBASE_IMM:
2860 case OP_STOREI4_MEMBASE_IMM:
2861 case OP_STOREI8_MEMBASE_IMM:
2862 if (!ins->inst_imm) {
2863 ins->sreg1 = mips_zero;
2864 ins->opcode = map_to_reg_reg_op (ins->opcode);
2867 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2868 temp->inst_c0 = ins->inst_imm;
2869 temp->dreg = mono_alloc_ireg (cfg);
2870 ins->sreg1 = temp->dreg;
2871 ins->opcode = map_to_reg_reg_op (ins->opcode);
2873 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2879 /* Branch opts can eliminate the branch */
2880 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2887 * remap compare/branch and compare/set
2888 * to MIPS specific opcodes.
2890 next->opcode = map_to_mips_op (next->opcode);
2891 next->sreg1 = ins->sreg1;
2892 next->sreg2 = ins->sreg2;
2899 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2900 temp->inst_c0 = (guint32)ins->inst_p0;
2901 temp->dreg = mono_alloc_ireg (cfg);
2902 ins->inst_basereg = temp->dreg;
2903 ins->inst_offset = 0;
2904 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2906 /* make it handle the possibly big ins->inst_offset
2907 * later optimize to use lis + load_membase
2912 g_assert (ins_is_compare(last_ins));
2913 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2914 NULLIFY_INS(last_ins);
2918 g_assert (ins_is_compare(last_ins));
2919 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2920 NULLIFY_INS(last_ins);
2924 g_assert (ins_is_compare(last_ins));
2925 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2926 last_ins->dreg = mono_alloc_ireg (cfg);
2927 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2931 g_assert (ins_is_compare(last_ins));
2932 INS_REWRITE(last_ins, OP_MIPS_SLTU, 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_SLT, last_ins->sreg1, last_ins->sreg2);
2940 last_ins->dreg = mono_alloc_ireg (cfg);
2941 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2945 g_assert (ins_is_compare(last_ins));
2946 INS_REWRITE(last_ins, OP_MIPS_SLTU, 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_SLT, last_ins->sreg2, last_ins->sreg1);
2954 last_ins->dreg = mono_alloc_ireg (cfg);
2955 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2959 g_assert (ins_is_compare(last_ins));
2960 INS_REWRITE(last_ins, OP_MIPS_SLTU, 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_SLT, last_ins->sreg2, last_ins->sreg1);
2968 last_ins->dreg = mono_alloc_ireg (cfg);
2969 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2973 g_assert (ins_is_compare(last_ins));
2974 INS_REWRITE(last_ins, OP_MIPS_SLTU, 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);
2981 g_assert (ins_is_compare(last_ins));
2982 last_ins->opcode = OP_IXOR;
2983 last_ins->dreg = mono_alloc_ireg(cfg);
2984 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2989 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2990 NULLIFY_INS(last_ins);
2996 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2997 NULLIFY_INS(last_ins);
3002 g_assert (ins_is_compare(last_ins));
3003 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
3004 MONO_DELETE_INS(bb, last_ins);
3009 g_assert (ins_is_compare(last_ins));
3010 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3011 MONO_DELETE_INS(bb, last_ins);
3014 case OP_COND_EXC_EQ:
3015 case OP_COND_EXC_IEQ:
3016 g_assert (ins_is_compare(last_ins));
3017 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3018 MONO_DELETE_INS(bb, last_ins);
3021 case OP_COND_EXC_GE:
3022 case OP_COND_EXC_IGE:
3023 g_assert (ins_is_compare(last_ins));
3024 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3025 MONO_DELETE_INS(bb, last_ins);
3028 case OP_COND_EXC_GT:
3029 case OP_COND_EXC_IGT:
3030 g_assert (ins_is_compare(last_ins));
3031 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3032 MONO_DELETE_INS(bb, last_ins);
3035 case OP_COND_EXC_LE:
3036 case OP_COND_EXC_ILE:
3037 g_assert (ins_is_compare(last_ins));
3038 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3039 MONO_DELETE_INS(bb, last_ins);
3042 case OP_COND_EXC_LT:
3043 case OP_COND_EXC_ILT:
3044 g_assert (ins_is_compare(last_ins));
3045 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3046 MONO_DELETE_INS(bb, last_ins);
3049 case OP_COND_EXC_NE_UN:
3050 case OP_COND_EXC_INE_UN:
3051 g_assert (ins_is_compare(last_ins));
3052 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3053 MONO_DELETE_INS(bb, last_ins);
3056 case OP_COND_EXC_GE_UN:
3057 case OP_COND_EXC_IGE_UN:
3058 g_assert (ins_is_compare(last_ins));
3059 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3060 MONO_DELETE_INS(bb, last_ins);
3063 case OP_COND_EXC_GT_UN:
3064 case OP_COND_EXC_IGT_UN:
3065 g_assert (ins_is_compare(last_ins));
3066 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3067 MONO_DELETE_INS(bb, last_ins);
3070 case OP_COND_EXC_LE_UN:
3071 case OP_COND_EXC_ILE_UN:
3072 g_assert (ins_is_compare(last_ins));
3073 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3074 MONO_DELETE_INS(bb, last_ins);
3077 case OP_COND_EXC_LT_UN:
3078 case OP_COND_EXC_ILT_UN:
3079 g_assert (ins_is_compare(last_ins));
3080 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3081 MONO_DELETE_INS(bb, last_ins);
3084 case OP_COND_EXC_OV:
3085 case OP_COND_EXC_IOV: {
3086 int tmp1, tmp2, tmp3, tmp4, tmp5;
3087 MonoInst *pos = last_ins;
3089 /* Overflow happens if
3090 * neg + neg = pos or
3093 * (bit31s of operands match) AND (bit31 of operand
3094 * != bit31 of result)
3095 * XOR of the high bit returns 0 if the signs match
3096 * XOR of that with the high bit of the result return 1
3099 g_assert (last_ins->opcode == OP_IADC);
3101 tmp1 = mono_alloc_ireg (cfg);
3102 tmp2 = mono_alloc_ireg (cfg);
3103 tmp3 = mono_alloc_ireg (cfg);
3104 tmp4 = mono_alloc_ireg (cfg);
3105 tmp5 = mono_alloc_ireg (cfg);
3107 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3108 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3110 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3111 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3112 INS (pos, OP_INOT, tmp3, tmp2, -1);
3114 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3115 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3116 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3118 /* Now, if (tmp5 == 0) then overflow */
3119 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3124 case OP_COND_EXC_NO:
3125 case OP_COND_EXC_INO:
3126 g_assert_not_reached ();
3130 case OP_COND_EXC_IC:
3131 g_assert_not_reached ();
3134 case OP_COND_EXC_NC:
3135 case OP_COND_EXC_INC:
3136 g_assert_not_reached ();
3142 bb->last_ins = last_ins;
3143 bb->max_vreg = cfg->next_vreg;
3146 if (cfg->verbose_level > 2) {
3149 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3150 MONO_BB_FOR_EACH_INS (bb, ins) {
3151 mono_print_ins_index (idx++, ins);
3160 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3162 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3164 mips_truncwd (code, mips_ftemp, sreg);
3166 mips_cvtwd (code, mips_ftemp, sreg);
3168 mips_mfc1 (code, dreg, mips_ftemp);
3171 mips_andi (code, dreg, dreg, 0xff);
3172 else if (size == 2) {
3173 mips_sll (code, dreg, dreg, 16);
3174 mips_srl (code, dreg, dreg, 16);
3178 mips_sll (code, dreg, dreg, 24);
3179 mips_sra (code, dreg, dreg, 24);
3181 else if (size == 2) {
3182 mips_sll (code, dreg, dreg, 16);
3183 mips_sra (code, dreg, dreg, 16);
3190 * emit_load_volatile_arguments:
3192 * Load volatile arguments from the stack to the original input registers.
3193 * Required before a tail call.
3196 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3198 MonoMethod *method = cfg->method;
3199 MonoMethodSignature *sig;
3204 sig = mono_method_signature (method);
3206 if (!cfg->arch.cinfo)
3207 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
3208 cinfo = cfg->arch.cinfo;
3210 if (cinfo->struct_ret) {
3211 ArgInfo *ainfo = &cinfo->ret;
3212 inst = cfg->vret_addr;
3213 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3216 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3217 ArgInfo *ainfo = cinfo->args + i;
3218 inst = cfg->args [i];
3219 if (inst->opcode == OP_REGVAR) {
3220 if (ainfo->storage == ArgInIReg)
3221 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3222 else if (ainfo->storage == ArgInFReg)
3223 g_assert_not_reached();
3224 else if (ainfo->storage == ArgOnStack) {
3227 g_assert_not_reached ();
3229 if (ainfo->storage == ArgInIReg) {
3230 g_assert (mips_is_imm16 (inst->inst_offset));
3231 switch (ainfo->size) {
3233 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3236 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3240 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3243 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3244 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3247 g_assert_not_reached ();
3250 } else if (ainfo->storage == ArgOnStack) {
3252 } else if (ainfo->storage == ArgInFReg) {
3253 g_assert (mips_is_imm16 (inst->inst_offset));
3254 if (ainfo->size == 8) {
3255 #if _MIPS_SIM == _ABIO32
3256 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3257 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3258 #elif _MIPS_SIM == _ABIN32
3259 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3262 else if (ainfo->size == 4)
3263 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3265 g_assert_not_reached ();
3266 } else if (ainfo->storage == ArgStructByVal) {
3268 int doffset = inst->inst_offset;
3270 g_assert (mips_is_imm16 (inst->inst_offset));
3271 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3272 for (i = 0; i < ainfo->size; ++i) {
3273 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3274 doffset += SIZEOF_REGISTER;
3276 } else if (ainfo->storage == ArgStructByAddr) {
3277 g_assert (mips_is_imm16 (inst->inst_offset));
3278 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3280 g_assert_not_reached ();
3288 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3290 int size = cfg->param_area;
3292 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3293 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3298 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3299 if (ppc_is_imm16 (-size)) {
3300 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3302 ppc_load (code, ppc_r11, -size);
3303 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3310 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3312 int size = cfg->param_area;
3314 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3315 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3320 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3321 if (ppc_is_imm16 (size)) {
3322 ppc_stwu (code, ppc_r0, size, ppc_sp);
3324 ppc_load (code, ppc_r11, size);
3325 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3332 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3337 guint8 *code = cfg->native_code + cfg->code_len;
3338 MonoInst *last_ins = NULL;
3339 guint last_offset = 0;
3343 /* we don't align basic blocks of loops on mips */
3345 if (cfg->verbose_level > 2)
3346 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3348 cpos = bb->max_offset;
3351 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3352 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3353 g_assert (!mono_compile_aot);
3356 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3357 /* this is not thread save, but good enough */
3358 /* fixme: howto handle overflows? */
3359 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3360 mips_lw (code, mips_temp, mips_at, 0);
3361 mips_addiu (code, mips_temp, mips_temp, 1);
3362 mips_sw (code, mips_temp, mips_at, 0);
3365 MONO_BB_FOR_EACH_INS (bb, ins) {
3366 offset = code - cfg->native_code;
3368 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3370 if (offset > (cfg->code_size - max_len - 16)) {
3371 cfg->code_size *= 2;
3372 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3373 code = cfg->native_code + offset;
3375 mono_debug_record_line_number (cfg, ins, offset);
3376 if (cfg->verbose_level > 2) {
3377 g_print (" @ 0x%x\t", offset);
3378 mono_print_ins_index (ins_cnt++, ins);
3380 /* Check for virtual regs that snuck by */
3381 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3383 switch (ins->opcode) {
3384 case OP_RELAXED_NOP:
3387 case OP_DUMMY_STORE:
3388 case OP_NOT_REACHED:
3391 case OP_SEQ_POINT: {
3392 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3393 guint32 addr = (guint32)ss_trigger_page;
3395 mips_load_const (code, mips_t9, addr);
3396 mips_lw (code, mips_t9, mips_t9, 0);
3399 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3402 * A placeholder for a possible breakpoint inserted by
3403 * mono_arch_set_breakpoint ().
3405 /* mips_load_const () + mips_lw */
3412 g_assert_not_reached();
3414 emit_tls_access (code, ins->dreg, ins->inst_offset);
3418 mips_mult (code, ins->sreg1, ins->sreg2);
3419 mips_mflo (code, ins->dreg);
3420 mips_mfhi (code, ins->dreg+1);
3423 mips_multu (code, ins->sreg1, ins->sreg2);
3424 mips_mflo (code, ins->dreg);
3425 mips_mfhi (code, ins->dreg+1);
3427 case OP_MEMORY_BARRIER:
3432 case OP_STOREI1_MEMBASE_IMM:
3433 mips_load_const (code, mips_temp, ins->inst_imm);
3434 if (mips_is_imm16 (ins->inst_offset)) {
3435 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3437 mips_load_const (code, mips_at, ins->inst_offset);
3438 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3441 case OP_STOREI2_MEMBASE_IMM:
3442 mips_load_const (code, mips_temp, ins->inst_imm);
3443 if (mips_is_imm16 (ins->inst_offset)) {
3444 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3446 mips_load_const (code, mips_at, ins->inst_offset);
3447 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3450 case OP_STOREI8_MEMBASE_IMM:
3451 mips_load_const (code, mips_temp, ins->inst_imm);
3452 if (mips_is_imm16 (ins->inst_offset)) {
3453 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3455 mips_load_const (code, mips_at, ins->inst_offset);
3456 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3459 case OP_STORE_MEMBASE_IMM:
3460 case OP_STOREI4_MEMBASE_IMM:
3461 mips_load_const (code, mips_temp, ins->inst_imm);
3462 if (mips_is_imm16 (ins->inst_offset)) {
3463 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3465 mips_load_const (code, mips_at, ins->inst_offset);
3466 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3469 case OP_STOREI1_MEMBASE_REG:
3470 if (mips_is_imm16 (ins->inst_offset)) {
3471 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3473 mips_load_const (code, mips_at, ins->inst_offset);
3474 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3475 mips_sb (code, ins->sreg1, mips_at, 0);
3478 case OP_STOREI2_MEMBASE_REG:
3479 if (mips_is_imm16 (ins->inst_offset)) {
3480 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3482 mips_load_const (code, mips_at, ins->inst_offset);
3483 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3484 mips_sh (code, ins->sreg1, mips_at, 0);
3487 case OP_STORE_MEMBASE_REG:
3488 case OP_STOREI4_MEMBASE_REG:
3489 if (mips_is_imm16 (ins->inst_offset)) {
3490 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3492 mips_load_const (code, mips_at, ins->inst_offset);
3493 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3494 mips_sw (code, ins->sreg1, mips_at, 0);
3497 case OP_STOREI8_MEMBASE_REG:
3498 if (mips_is_imm16 (ins->inst_offset)) {
3499 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3501 mips_load_const (code, mips_at, ins->inst_offset);
3502 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3503 mips_sd (code, ins->sreg1, mips_at, 0);
3507 g_assert_not_reached ();
3508 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3509 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3511 case OP_LOADI8_MEMBASE:
3512 if (mips_is_imm16 (ins->inst_offset)) {
3513 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3515 mips_load_const (code, mips_at, ins->inst_offset);
3516 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3517 mips_ld (code, ins->dreg, mips_at, 0);
3520 case OP_LOAD_MEMBASE:
3521 case OP_LOADI4_MEMBASE:
3522 case OP_LOADU4_MEMBASE:
3523 g_assert (ins->dreg != -1);
3524 if (mips_is_imm16 (ins->inst_offset)) {
3525 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3527 mips_load_const (code, mips_at, ins->inst_offset);
3528 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3529 mips_lw (code, ins->dreg, mips_at, 0);
3532 case OP_LOADI1_MEMBASE:
3533 if (mips_is_imm16 (ins->inst_offset)) {
3534 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3536 mips_load_const (code, mips_at, ins->inst_offset);
3537 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3538 mips_lb (code, ins->dreg, mips_at, 0);
3541 case OP_LOADU1_MEMBASE:
3542 if (mips_is_imm16 (ins->inst_offset)) {
3543 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3545 mips_load_const (code, mips_at, ins->inst_offset);
3546 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3547 mips_lbu (code, ins->dreg, mips_at, 0);
3550 case OP_LOADI2_MEMBASE:
3551 if (mips_is_imm16 (ins->inst_offset)) {
3552 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3554 mips_load_const (code, mips_at, ins->inst_offset);
3555 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3556 mips_lh (code, ins->dreg, mips_at, 0);
3559 case OP_LOADU2_MEMBASE:
3560 if (mips_is_imm16 (ins->inst_offset)) {
3561 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3563 mips_load_const (code, mips_at, ins->inst_offset);
3564 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3565 mips_lhu (code, ins->dreg, mips_at, 0);
3568 case OP_ICONV_TO_I1:
3569 mips_sll (code, mips_at, ins->sreg1, 24);
3570 mips_sra (code, ins->dreg, mips_at, 24);
3572 case OP_ICONV_TO_I2:
3573 mips_sll (code, mips_at, ins->sreg1, 16);
3574 mips_sra (code, ins->dreg, mips_at, 16);
3576 case OP_ICONV_TO_U1:
3577 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3579 case OP_ICONV_TO_U2:
3580 mips_sll (code, mips_at, ins->sreg1, 16);
3581 mips_srl (code, ins->dreg, mips_at, 16);
3584 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3587 g_assert (mips_is_imm16 (ins->inst_imm));
3588 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3591 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3594 g_assert (mips_is_imm16 (ins->inst_imm));
3595 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3599 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3600 * So instead of emitting a trap, we emit a call a C function and place a
3603 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3604 (gpointer)"mono_break");
3605 mips_load (code, mips_t9, 0x1f1f1f1f);
3606 mips_jalr (code, mips_t9, mips_ra);
3610 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3613 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3618 g_assert (mips_is_imm16 (ins->inst_imm));
3619 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3622 g_assert (mips_is_imm16 (ins->inst_imm));
3623 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3627 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3630 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3635 // we add the negated value
3636 g_assert (mips_is_imm16 (-ins->inst_imm));
3637 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3641 // we add the negated value
3642 g_assert (mips_is_imm16 (-ins->inst_imm));
3643 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3648 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3654 g_assert (!(ins->inst_imm & 0xffff0000));
3655 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3660 guint32 *divisor_is_m1;
3661 guint32 *dividend_is_minvalue;
3662 guint32 *divisor_is_zero;
3664 mips_load_const (code, mips_at, -1);
3665 divisor_is_m1 = (guint32 *)(void *)code;
3666 mips_bne (code, ins->sreg2, mips_at, 0);
3667 mips_lui (code, mips_at, mips_zero, 0x8000);
3668 dividend_is_minvalue = (guint32 *)(void *)code;
3669 mips_bne (code, ins->sreg1, mips_at, 0);
3672 /* Divide Int32.MinValue by -1 -- throw exception */
3673 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3675 mips_patch (divisor_is_m1, (guint32)code);
3676 mips_patch (dividend_is_minvalue, (guint32)code);
3678 /* Put divide in branch delay slot (NOT YET) */
3679 divisor_is_zero = (guint32 *)(void *)code;
3680 mips_bne (code, ins->sreg2, mips_zero, 0);
3683 /* Divide by zero -- throw exception */
3684 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3686 mips_patch (divisor_is_zero, (guint32)code);
3687 mips_div (code, ins->sreg1, ins->sreg2);
3688 if (ins->opcode == OP_IDIV)
3689 mips_mflo (code, ins->dreg);
3691 mips_mfhi (code, ins->dreg);
3696 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3698 /* Put divide in branch delay slot (NOT YET) */
3699 mips_bne (code, ins->sreg2, mips_zero, 0);
3702 /* Divide by zero -- throw exception */
3703 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3705 mips_patch (divisor_is_zero, (guint32)code);
3706 mips_divu (code, ins->sreg1, ins->sreg2);
3707 if (ins->opcode == OP_IDIV_UN)
3708 mips_mflo (code, ins->dreg);
3710 mips_mfhi (code, ins->dreg);
3714 g_assert_not_reached ();
3716 ppc_load (code, ppc_r11, ins->inst_imm);
3717 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3718 ppc_mfspr (code, ppc_r0, ppc_xer);
3719 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3720 /* FIXME: use OverflowException for 0x80000000/-1 */
3721 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3723 g_assert_not_reached();
3726 g_assert_not_reached ();
3728 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3732 g_assert (!(ins->inst_imm & 0xffff0000));
3733 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3736 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3740 /* unsigned 16-bit immediate */
3741 g_assert (!(ins->inst_imm & 0xffff0000));
3742 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3745 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3749 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3752 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3755 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3759 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3762 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3765 case OP_ISHR_UN_IMM:
3766 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3768 case OP_LSHR_UN_IMM:
3769 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3772 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3775 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3779 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3782 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3785 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3789 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3791 mips_mult (code, ins->sreg1, ins->sreg2);
3792 mips_mflo (code, ins->dreg);
3797 #if SIZEOF_REGISTER == 8
3799 mips_dmult (code, ins->sreg1, ins->sreg2);
3800 mips_mflo (code, ins->dreg);
3805 mips_mult (code, ins->sreg1, ins->sreg2);
3806 mips_mflo (code, ins->dreg);
3807 mips_mfhi (code, mips_at);
3810 mips_sra (code, mips_temp, ins->dreg, 31);
3811 patch = (guint32 *)(void *)code;
3812 mips_beq (code, mips_temp, mips_at, 0);
3814 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3815 mips_patch (patch, (guint32)code);
3818 case OP_IMUL_OVF_UN: {
3820 mips_mult (code, ins->sreg1, ins->sreg2);
3821 mips_mflo (code, ins->dreg);
3822 mips_mfhi (code, mips_at);
3825 patch = (guint32 *)(void *)code;
3826 mips_beq (code, mips_at, mips_zero, 0);
3828 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3829 mips_patch (patch, (guint32)code);
3833 mips_load_const (code, ins->dreg, ins->inst_c0);
3835 #if SIZEOF_REGISTER == 8
3837 mips_load_const (code, ins->dreg, ins->inst_c0);
3841 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3842 mips_load (code, ins->dreg, 0);
3846 mips_mtc1 (code, ins->dreg, ins->sreg1);
3848 case OP_MIPS_MTC1S_2:
3849 mips_mtc1 (code, ins->dreg, ins->sreg1);
3850 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3853 mips_mfc1 (code, ins->dreg, ins->sreg1);
3856 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3860 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3862 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3863 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3867 case OP_ICONV_TO_I4:
3868 case OP_ICONV_TO_U4:
3870 if (ins->dreg != ins->sreg1)
3871 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3873 #if SIZEOF_REGISTER == 8
3875 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3876 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3879 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3880 mips_dsra (code, ins->dreg, ins->dreg, 32);
3884 int lsreg = mips_v0 + ls_word_idx;
3885 int msreg = mips_v0 + ms_word_idx;
3887 /* Get sreg1 into lsreg, sreg2 into msreg */
3889 if (ins->sreg1 == msreg) {
3890 if (ins->sreg1 != mips_at)
3891 MIPS_MOVE (code, mips_at, ins->sreg1);
3892 if (ins->sreg2 != msreg)
3893 MIPS_MOVE (code, msreg, ins->sreg2);
3894 MIPS_MOVE (code, lsreg, mips_at);
3897 if (ins->sreg2 != msreg)
3898 MIPS_MOVE (code, msreg, ins->sreg2);
3899 if (ins->sreg1 != lsreg)
3900 MIPS_MOVE (code, lsreg, ins->sreg1);
3905 if (ins->dreg != ins->sreg1) {
3906 mips_fmovd (code, ins->dreg, ins->sreg1);
3910 /* Convert from double to float and leave it there */
3911 mips_cvtsd (code, ins->dreg, ins->sreg1);
3913 case OP_FCONV_TO_R4:
3915 mips_cvtsd (code, ins->dreg, ins->sreg1);
3917 /* Just a move, no precision change */
3918 if (ins->dreg != ins->sreg1) {
3919 mips_fmovd (code, ins->dreg, ins->sreg1);
3924 code = emit_load_volatile_arguments(cfg, code);
3927 * Pop our stack, then jump to specified method (tail-call)
3928 * Keep in sync with mono_arch_emit_epilog
3930 code = mono_arch_emit_epilog_sub (cfg, code);
3932 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3933 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3934 mips_load (code, mips_t9, 0);
3935 mips_jr (code, mips_t9);
3939 /* ensure ins->sreg1 is not NULL */
3940 mips_lw (code, mips_zero, ins->sreg1, 0);
3943 g_assert (mips_is_imm16 (cfg->sig_cookie));
3944 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3945 mips_sw (code, mips_at, ins->sreg1, 0);
3958 case OP_VOIDCALL_REG:
3960 case OP_FCALL_MEMBASE:
3961 case OP_LCALL_MEMBASE:
3962 case OP_VCALL_MEMBASE:
3963 case OP_VCALL2_MEMBASE:
3964 case OP_VOIDCALL_MEMBASE:
3965 case OP_CALL_MEMBASE:
3966 call = (MonoCallInst*)ins;
3967 switch (ins->opcode) {
3974 if (ins->flags & MONO_INST_HAS_METHOD) {
3975 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3976 mips_load (code, mips_t9, call->method);
3979 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3980 mips_load (code, mips_t9, call->fptr);
3982 mips_jalr (code, mips_t9, mips_ra);
3989 case OP_VOIDCALL_REG:
3991 MIPS_MOVE (code, mips_t9, ins->sreg1);
3992 mips_jalr (code, mips_t9, mips_ra);
3995 case OP_FCALL_MEMBASE:
3996 case OP_LCALL_MEMBASE:
3997 case OP_VCALL_MEMBASE:
3998 case OP_VCALL2_MEMBASE:
3999 case OP_VOIDCALL_MEMBASE:
4000 case OP_CALL_MEMBASE:
4001 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
4002 mips_jalr (code, mips_t9, mips_ra);
4006 #if PROMOTE_R4_TO_R8
4007 /* returned an FP R4 (single), promote to R8 (double) in place */
4008 switch (ins->opcode) {
4011 case OP_FCALL_MEMBASE:
4012 if (call->signature->ret->type == MONO_TYPE_R4)
4013 mips_cvtds (code, mips_f0, mips_f0);
4021 int area_offset = cfg->param_area;
4023 /* Round up ins->sreg1, mips_at ends up holding size */
4024 mips_addiu (code, mips_at, ins->sreg1, 31);
4025 mips_addiu (code, mips_temp, mips_zero, ~31);
4026 mips_and (code, mips_at, mips_at, mips_temp);
4028 mips_subu (code, mips_sp, mips_sp, mips_at);
4029 g_assert (mips_is_imm16 (area_offset));
4030 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4032 if (ins->flags & MONO_INST_INIT) {
4035 buf = (guint32*)(void*)code;
4036 mips_beq (code, mips_at, mips_zero, 0);
4039 mips_move (code, mips_temp, ins->dreg);
4040 mips_sb (code, mips_zero, mips_temp, 0);
4041 mips_addiu (code, mips_at, mips_at, -1);
4042 mips_bne (code, mips_at, mips_zero, -3);
4043 mips_addiu (code, mips_temp, mips_temp, 1);
4045 mips_patch (buf, (guint32)code);
4050 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4051 mips_move (code, mips_a0, ins->sreg1);
4052 mips_call (code, mips_t9, addr);
4053 mips_break (code, 0xfc);
4057 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4058 mips_move (code, mips_a0, ins->sreg1);
4059 mips_call (code, mips_t9, addr);
4060 mips_break (code, 0xfb);
4063 case OP_START_HANDLER: {
4065 * The START_HANDLER instruction marks the beginning of
4066 * a handler block. It is called using a call
4067 * instruction, so mips_ra contains the return address.
4068 * Since the handler executes in the same stack frame
4069 * as the method itself, we can't use save/restore to
4070 * save the return address. Instead, we save it into
4071 * a dedicated variable.
4073 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4074 g_assert (spvar->inst_basereg != mips_sp);
4075 code = emit_reserve_param_area (cfg, code);
4077 if (mips_is_imm16 (spvar->inst_offset)) {
4078 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4080 mips_load_const (code, mips_at, spvar->inst_offset);
4081 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4082 mips_sw (code, mips_ra, mips_at, 0);
4086 case OP_ENDFILTER: {
4087 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4088 g_assert (spvar->inst_basereg != mips_sp);
4089 code = emit_unreserve_param_area (cfg, code);
4091 if (ins->sreg1 != mips_v0)
4092 MIPS_MOVE (code, mips_v0, ins->sreg1);
4093 if (mips_is_imm16 (spvar->inst_offset)) {
4094 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4096 mips_load_const (code, mips_at, spvar->inst_offset);
4097 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4098 mips_lw (code, mips_ra, mips_at, 0);
4100 mips_jr (code, mips_ra);
4104 case OP_ENDFINALLY: {
4105 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4106 g_assert (spvar->inst_basereg != mips_sp);
4107 code = emit_unreserve_param_area (cfg, code);
4108 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4109 mips_jalr (code, mips_t9, mips_ra);
4113 case OP_CALL_HANDLER:
4114 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4115 mips_lui (code, mips_t9, mips_zero, 0);
4116 mips_addiu (code, mips_t9, mips_t9, 0);
4117 mips_jalr (code, mips_t9, mips_ra);
4119 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4120 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4123 ins->inst_c0 = code - cfg->native_code;
4126 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4127 if (cfg->arch.long_branch) {
4128 mips_lui (code, mips_at, mips_zero, 0);
4129 mips_addiu (code, mips_at, mips_at, 0);
4130 mips_jr (code, mips_at);
4134 mips_beq (code, mips_zero, mips_zero, 0);
4139 mips_jr (code, ins->sreg1);
4145 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4146 if (offset > (cfg->code_size - max_len - 16)) {
4147 cfg->code_size += max_len;
4148 cfg->code_size *= 2;
4149 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4150 code = cfg->native_code + offset;
4152 g_assert (ins->sreg1 != -1);
4153 mips_sll (code, mips_at, ins->sreg1, 2);
4154 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4155 MIPS_MOVE (code, mips_t8, mips_ra);
4156 mips_bgezal (code, mips_zero, 1); /* bal */
4158 mips_addu (code, mips_t9, mips_ra, mips_at);
4159 /* Table is 16 or 20 bytes from target of bal above */
4160 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4161 MIPS_MOVE (code, mips_ra, mips_t8);
4162 mips_lw (code, mips_t9, mips_t9, 20);
4165 mips_lw (code, mips_t9, mips_t9, 16);
4166 mips_jalr (code, mips_t9, mips_t8);
4168 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4169 mips_emit32 (code, 0xfefefefe);
4174 mips_addiu (code, ins->dreg, mips_zero, 1);
4175 mips_beq (code, mips_at, mips_zero, 2);
4177 MIPS_MOVE (code, ins->dreg, mips_zero);
4183 mips_addiu (code, ins->dreg, mips_zero, 1);
4184 mips_bltz (code, mips_at, 2);
4186 MIPS_MOVE (code, ins->dreg, mips_zero);
4192 mips_addiu (code, ins->dreg, mips_zero, 1);
4193 mips_bgtz (code, mips_at, 2);
4195 MIPS_MOVE (code, ins->dreg, mips_zero);
4198 case OP_MIPS_COND_EXC_EQ:
4199 case OP_MIPS_COND_EXC_GE:
4200 case OP_MIPS_COND_EXC_GT:
4201 case OP_MIPS_COND_EXC_LE:
4202 case OP_MIPS_COND_EXC_LT:
4203 case OP_MIPS_COND_EXC_NE_UN:
4204 case OP_MIPS_COND_EXC_GE_UN:
4205 case OP_MIPS_COND_EXC_GT_UN:
4206 case OP_MIPS_COND_EXC_LE_UN:
4207 case OP_MIPS_COND_EXC_LT_UN:
4209 case OP_MIPS_COND_EXC_OV:
4210 case OP_MIPS_COND_EXC_NO:
4211 case OP_MIPS_COND_EXC_C:
4212 case OP_MIPS_COND_EXC_NC:
4214 case OP_MIPS_COND_EXC_IEQ:
4215 case OP_MIPS_COND_EXC_IGE:
4216 case OP_MIPS_COND_EXC_IGT:
4217 case OP_MIPS_COND_EXC_ILE:
4218 case OP_MIPS_COND_EXC_ILT:
4219 case OP_MIPS_COND_EXC_INE_UN:
4220 case OP_MIPS_COND_EXC_IGE_UN:
4221 case OP_MIPS_COND_EXC_IGT_UN:
4222 case OP_MIPS_COND_EXC_ILE_UN:
4223 case OP_MIPS_COND_EXC_ILT_UN:
4225 case OP_MIPS_COND_EXC_IOV:
4226 case OP_MIPS_COND_EXC_INO:
4227 case OP_MIPS_COND_EXC_IC:
4228 case OP_MIPS_COND_EXC_INC: {
4232 /* If the condition is true, raise the exception */
4234 /* need to reverse test to skip around exception raising */
4236 /* For the moment, branch around a branch to avoid reversing
4239 /* Remember, an unpatched branch to 0 branches to the delay slot */
4240 switch (ins->opcode) {
4241 case OP_MIPS_COND_EXC_EQ:
4242 throw = (guint32 *)(void *)code;
4243 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4247 case OP_MIPS_COND_EXC_NE_UN:
4248 throw = (guint32 *)(void *)code;
4249 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4253 case OP_MIPS_COND_EXC_LE_UN:
4254 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4255 throw = (guint32 *)(void *)code;
4256 mips_beq (code, mips_at, mips_zero, 0);
4260 case OP_MIPS_COND_EXC_GT:
4261 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4262 throw = (guint32 *)(void *)code;
4263 mips_bne (code, mips_at, mips_zero, 0);
4267 case OP_MIPS_COND_EXC_GT_UN:
4268 mips_sltu (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_LT:
4275 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4276 throw = (guint32 *)(void *)code;
4277 mips_bne (code, mips_at, mips_zero, 0);
4281 case OP_MIPS_COND_EXC_LT_UN:
4282 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4283 throw = (guint32 *)(void *)code;
4284 mips_bne (code, mips_at, mips_zero, 0);
4289 /* Not yet implemented */
4290 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4291 g_assert_not_reached ();
4293 skip = (guint32 *)(void *)code;
4294 mips_beq (code, mips_zero, mips_zero, 0);
4296 mips_patch (throw, (guint32)code);
4297 code = mips_emit_exc_by_name (code, ins->inst_p1);
4298 mips_patch (skip, (guint32)code);
4299 cfg->bb_exit->max_offset += 24;
4308 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4311 /* floating point opcodes */
4314 if (((guint32)ins->inst_p0) & (1 << 15))
4315 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4317 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4318 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4320 mips_load_const (code, mips_at, ins->inst_p0);
4321 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4322 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4326 if (((guint32)ins->inst_p0) & (1 << 15))
4327 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4329 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4330 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4331 #if PROMOTE_R4_TO_R8
4332 mips_cvtds (code, ins->dreg, ins->dreg);
4335 case OP_STORER8_MEMBASE_REG:
4336 if (mips_is_imm16 (ins->inst_offset)) {
4337 #if _MIPS_SIM == _ABIO32
4338 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4339 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4340 #elif _MIPS_SIM == _ABIN32
4341 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4344 mips_load_const (code, mips_at, ins->inst_offset);
4345 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4346 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4347 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4350 case OP_LOADR8_MEMBASE:
4351 if (mips_is_imm16 (ins->inst_offset)) {
4352 #if _MIPS_SIM == _ABIO32
4353 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4354 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4355 #elif _MIPS_SIM == _ABIN32
4356 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4359 mips_load_const (code, mips_at, ins->inst_offset);
4360 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4361 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4362 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4365 case OP_STORER4_MEMBASE_REG:
4366 g_assert (mips_is_imm16 (ins->inst_offset));
4367 #if PROMOTE_R4_TO_R8
4368 /* Need to convert ins->sreg1 to single-precision first */
4369 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4370 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4372 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4376 g_assert (mips_is_imm16 (ins->inst_offset));
4377 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4379 case OP_LOADR4_MEMBASE:
4380 g_assert (mips_is_imm16 (ins->inst_offset));
4381 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4382 #if PROMOTE_R4_TO_R8
4383 /* Convert to double precision in place */
4384 mips_cvtds (code, ins->dreg, ins->dreg);
4387 case OP_LOADR4_MEMINDEX:
4388 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4389 mips_lwc1 (code, ins->dreg, mips_at, 0);
4391 case OP_LOADR8_MEMINDEX:
4392 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4393 #if _MIPS_SIM == _ABIO32
4394 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4395 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4396 #elif _MIPS_SIM == _ABIN32
4397 mips_ldc1 (code, ins->dreg, mips_at, 0);
4400 case OP_STORER4_MEMINDEX:
4401 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4402 #if PROMOTE_R4_TO_R8
4403 /* Need to convert ins->sreg1 to single-precision first */
4404 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4405 mips_swc1 (code, mips_ftemp, mips_at, 0);
4407 mips_swc1 (code, ins->sreg1, mips_at, 0);
4410 case OP_STORER8_MEMINDEX:
4411 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4412 #if _MIPS_SIM == _ABIO32
4413 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4414 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4415 #elif _MIPS_SIM == _ABIN32
4416 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4419 case OP_ICONV_TO_R_UN: {
4420 static const guint64 adjust_val = 0x41F0000000000000ULL;
4422 /* convert unsigned int to double */
4423 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4424 mips_bgez (code, ins->sreg1, 5);
4425 mips_cvtdw (code, ins->dreg, mips_ftemp);
4427 mips_load (code, mips_at, (guint32) &adjust_val);
4428 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4429 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4430 /* target is here */
4433 case OP_ICONV_TO_R4:
4434 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4435 mips_cvtsw (code, ins->dreg, mips_ftemp);
4436 mips_cvtds (code, ins->dreg, ins->dreg);
4438 case OP_ICONV_TO_R8:
4439 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4440 mips_cvtdw (code, ins->dreg, mips_ftemp);
4442 case OP_FCONV_TO_I1:
4443 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4445 case OP_FCONV_TO_U1:
4446 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4448 case OP_FCONV_TO_I2:
4449 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4451 case OP_FCONV_TO_U2:
4452 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4454 case OP_FCONV_TO_I4:
4456 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4458 case OP_FCONV_TO_U4:
4460 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4463 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4466 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4469 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4472 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4475 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4478 mips_fnegd (code, ins->dreg, ins->sreg1);
4481 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4482 mips_addiu (code, ins->dreg, mips_zero, 1);
4483 mips_fbtrue (code, 2);
4485 MIPS_MOVE (code, ins->dreg, mips_zero);
4488 mips_fcmpd (code, MIPS_FPU_LT, 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 /* Less than, or Unordered */
4496 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4497 mips_addiu (code, ins->dreg, mips_zero, 1);
4498 mips_fbtrue (code, 2);
4500 MIPS_MOVE (code, ins->dreg, mips_zero);
4503 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4504 MIPS_MOVE (code, ins->dreg, mips_zero);
4505 mips_fbtrue (code, 2);
4507 mips_addiu (code, ins->dreg, mips_zero, 1);
4510 /* Greater than, or Unordered */
4511 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4512 MIPS_MOVE (code, ins->dreg, mips_zero);
4513 mips_fbtrue (code, 2);
4515 mips_addiu (code, ins->dreg, mips_zero, 1);
4520 case OP_MIPS_FBLT_UN:
4522 case OP_MIPS_FBGT_UN:
4524 case OP_MIPS_FBGE_UN:
4526 case OP_MIPS_FBLE_UN: {
4528 gboolean is_true = TRUE, is_ordered = FALSE;
4529 guint32 *buf = NULL;
4531 switch (ins->opcode) {
4545 case OP_MIPS_FBLT_UN:
4546 cond = MIPS_FPU_ULT;
4554 case OP_MIPS_FBGT_UN:
4555 cond = MIPS_FPU_OLE;
4563 case OP_MIPS_FBGE_UN:
4564 cond = MIPS_FPU_OLT;
4568 cond = MIPS_FPU_OLE;
4572 case OP_MIPS_FBLE_UN:
4573 cond = MIPS_FPU_ULE;
4577 g_assert_not_reached ();
4581 /* Skip the check if unordered */
4582 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4584 buf = (guint32*)code;
4585 mips_fbtrue (code, 0);
4589 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4591 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4593 mips_fbtrue (code, 0);
4595 mips_fbfalse (code, 0);
4599 mips_patch (buf, (guint32)code);
4603 guint32 *branch_patch;
4605 mips_mfc1 (code, mips_at, ins->sreg1+1);
4606 mips_srl (code, mips_at, mips_at, 16+4);
4607 mips_andi (code, mips_at, mips_at, 2047);
4608 mips_addiu (code, mips_at, mips_at, -2047);
4610 branch_patch = (guint32 *)(void *)code;
4611 mips_bne (code, mips_at, mips_zero, 0);
4614 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4615 mips_patch (branch_patch, (guint32)code);
4616 mips_fmovd (code, ins->dreg, ins->sreg1);
4620 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4621 mips_load (code, ins->dreg, 0x0f0f0f0f);
4626 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4627 g_assert_not_reached ();
4630 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4631 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4632 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4633 g_assert_not_reached ();
4639 last_offset = offset;
4642 cfg->code_len = code - cfg->native_code;
4646 mono_arch_register_lowlevel_calls (void)
4651 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4653 MonoJumpInfo *patch_info;
4655 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4656 unsigned char *ip = patch_info->ip.i + code;
4657 const unsigned char *target = NULL;
4659 switch (patch_info->type) {
4660 case MONO_PATCH_INFO_IP:
4661 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4663 case MONO_PATCH_INFO_SWITCH: {
4664 gpointer *table = (gpointer *)patch_info->data.table->table;
4667 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4669 for (i = 0; i < patch_info->data.table->table_size; i++) {
4670 table [i] = (int)patch_info->data.table->table [i] + code;
4674 case MONO_PATCH_INFO_METHODCONST:
4675 case MONO_PATCH_INFO_CLASS:
4676 case MONO_PATCH_INFO_IMAGE:
4677 case MONO_PATCH_INFO_FIELD:
4678 case MONO_PATCH_INFO_VTABLE:
4679 case MONO_PATCH_INFO_IID:
4680 case MONO_PATCH_INFO_SFLDA:
4681 case MONO_PATCH_INFO_LDSTR:
4682 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4683 case MONO_PATCH_INFO_LDTOKEN:
4684 case MONO_PATCH_INFO_R4:
4685 case MONO_PATCH_INFO_R8:
4686 /* from OP_AOTCONST : lui + addiu */
4687 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4688 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4691 case MONO_PATCH_INFO_EXC_NAME:
4692 g_assert_not_reached ();
4693 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4696 case MONO_PATCH_INFO_NONE:
4697 /* everything is dealt with at epilog output time */
4700 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4701 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4708 * Allow tracing to work with this interface (with an optional argument)
4710 * This code is expected to be inserted just after the 'real' prolog code,
4711 * and before the first basic block. We need to allocate a 2nd, temporary
4712 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4716 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4719 int offset = cfg->arch.tracing_offset;
4725 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4726 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4727 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4728 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4729 #if _MIPS_SIM == _ABIN32
4731 /* FIXME: Need a separate region for these */
4732 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4733 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4734 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4735 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4739 mips_load_const (code, mips_a0, cfg->method);
4740 mips_addiu (code, mips_a1, mips_sp, offset);
4741 mips_call (code, mips_t9, func);
4744 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4745 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4746 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4747 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4748 #if _MIPS_SIM == _ABIN32
4751 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4752 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4753 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4754 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4765 mips_adjust_stackframe(MonoCompile *cfg)
4768 int delta, threshold, i;
4769 MonoMethodSignature *sig;
4772 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4775 /* adjust cfg->stack_offset for account for down-spilling */
4776 cfg->stack_offset += SIZEOF_REGISTER;
4778 /* re-align cfg->stack_offset if needed (due to var spilling) */
4779 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4780 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4781 if (cfg->verbose_level > 2) {
4782 g_print ("mips_adjust_stackframe:\n");
4783 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4785 threshold = cfg->arch.local_alloc_offset;
4786 ra_offset = cfg->stack_offset - sizeof(gpointer);
4787 if (cfg->verbose_level > 2) {
4788 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4791 sig = mono_method_signature (cfg->method);
4792 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4793 cfg->vret_addr->inst_offset += delta;
4795 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4796 MonoInst *inst = cfg->args [i];
4798 inst->inst_offset += delta;
4802 * loads and stores based off the frame reg that (used to) lie
4803 * above the spill var area need to be increased by 'delta'
4804 * to make room for the spill vars.
4806 /* Need to find loads and stores to adjust that
4807 * are above where the spillvars were inserted, but
4808 * which are not the spillvar references themselves.
4810 * Idea - since all offsets from fp are positive, make
4811 * spillvar offsets negative to begin with so we can spot
4816 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4820 if (cfg->verbose_level > 2) {
4821 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4823 MONO_BB_FOR_EACH_INS (bb, ins) {
4827 if (cfg->verbose_level > 2) {
4828 mono_print_ins_index (ins_cnt, ins);
4830 /* The == mips_sp tests catch FP spills */
4831 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4832 (ins->inst_basereg == mips_sp))) {
4833 switch (ins->opcode) {
4834 case OP_LOADI8_MEMBASE:
4835 case OP_LOADR8_MEMBASE:
4842 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4843 (ins->dreg == mips_sp))) {
4844 switch (ins->opcode) {
4845 case OP_STOREI8_MEMBASE_REG:
4846 case OP_STORER8_MEMBASE_REG:
4847 case OP_STOREI8_MEMBASE_IMM:
4855 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4858 if (ins->inst_c0 >= threshold) {
4859 ins->inst_c0 += delta;
4860 if (cfg->verbose_level > 2) {
4862 mono_print_ins_index (ins_cnt, ins);
4865 else if (ins->inst_c0 < 0) {
4866 /* Adj_c0 holds the size of the datatype. */
4867 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4868 if (cfg->verbose_level > 2) {
4870 mono_print_ins_index (ins_cnt, ins);
4873 g_assert (ins->inst_c0 != ra_offset);
4876 if (ins->inst_imm >= threshold) {
4877 ins->inst_imm += delta;
4878 if (cfg->verbose_level > 2) {
4880 mono_print_ins_index (ins_cnt, ins);
4883 g_assert (ins->inst_c0 != ra_offset);
4893 * Stack frame layout:
4895 * ------------------- sp + cfg->stack_usage + cfg->param_area
4896 * param area incoming
4897 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4899 * ------------------- sp + cfg->stack_usage
4901 * ------------------- sp + cfg->stack_usage-4
4903 * ------------------- sp +
4904 * MonoLMF structure optional
4905 * ------------------- sp + cfg->arch.lmf_offset
4906 * saved registers s0-s8
4907 * ------------------- sp + cfg->arch.iregs_offset
4909 * ------------------- sp + cfg->param_area
4910 * param area outgoing
4911 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4913 * ------------------- sp
4917 mono_arch_emit_prolog (MonoCompile *cfg)
4919 MonoMethod *method = cfg->method;
4920 MonoMethodSignature *sig;
4922 int alloc_size, pos, i, max_offset;
4923 int alloc2_size = 0;
4927 guint32 iregs_to_save = 0;
4929 guint32 fregs_to_save = 0;
4931 /* lmf_offset is the offset of the LMF from our stack pointer. */
4932 guint32 lmf_offset = cfg->arch.lmf_offset;
4936 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4940 cfg->flags |= MONO_CFG_HAS_CALLS;
4942 sig = mono_method_signature (method);
4943 cfg->code_size = 768 + sig->param_count * 20;
4944 code = cfg->native_code = g_malloc (cfg->code_size);
4947 * compute max_offset in order to use short forward jumps.
4950 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4951 MonoInst *ins = bb->code;
4952 bb->max_offset = max_offset;
4954 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4957 MONO_BB_FOR_EACH_INS (bb, ins)
4958 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4960 if (max_offset > 0xffff)
4961 cfg->arch.long_branch = TRUE;
4964 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4965 * This means that we have to adjust the offsets inside instructions which reference
4966 * arguments received on the stack, since the initial offset doesn't take into
4967 * account spill slots.
4969 mips_adjust_stackframe (cfg);
4971 /* Offset between current sp and the CFA */
4973 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4975 /* stack_offset should not be changed here. */
4976 alloc_size = cfg->stack_offset;
4977 cfg->stack_usage = alloc_size;
4979 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4982 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4984 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4985 fregs_to_save |= (fregs_to_save << 1);
4988 /* If the stack size is too big, save 1024 bytes to start with
4989 * so the prologue can use imm16(reg) addressing, then allocate
4990 * the rest of the frame.
4992 if (alloc_size > ((1 << 15) - 1024)) {
4993 alloc2_size = alloc_size - 1024;
4997 g_assert (mips_is_imm16 (-alloc_size));
4998 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4999 cfa_offset = alloc_size;
5000 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5003 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5004 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5005 if (mips_is_imm16(offset))
5006 mips_sw (code, mips_ra, mips_sp, offset);
5008 g_assert_not_reached ();
5010 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5011 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5014 /* XXX - optimize this later to not save all regs if LMF constructed */
5015 pos = cfg->arch.iregs_offset - alloc2_size;
5017 if (iregs_to_save) {
5018 /* save used registers in own stack frame (at pos) */
5019 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5020 if (iregs_to_save & (1 << i)) {
5021 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5022 g_assert (mips_is_imm16(pos));
5023 MIPS_SW (code, i, mips_sp, pos);
5024 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5025 pos += SIZEOF_REGISTER;
5030 // FIXME: Don't save registers twice if there is an LMF
5031 // s8 has to be special cased since it is overwritten with the updated value
5033 if (method->save_lmf) {
5034 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5035 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5036 g_assert (mips_is_imm16(offset));
5037 if (MIPS_LMF_IREGMASK & (1 << i))
5038 MIPS_SW (code, i, mips_sp, offset);
5043 /* Save float registers */
5044 if (fregs_to_save) {
5045 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5046 if (fregs_to_save & (1 << i)) {
5047 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5048 g_assert (mips_is_imm16(pos));
5049 mips_swc1 (code, i, mips_sp, pos);
5050 pos += sizeof (gulong);
5055 if (method->save_lmf) {
5056 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5057 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5058 g_assert (mips_is_imm16(offset));
5059 mips_swc1 (code, i, mips_sp, offset);
5064 if (cfg->frame_reg != mips_sp) {
5065 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5066 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5068 if (method->save_lmf) {
5069 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5070 g_assert (mips_is_imm16(offset));
5071 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5075 /* store runtime generic context */
5076 if (cfg->rgctx_var) {
5077 MonoInst *ins = cfg->rgctx_var;
5079 g_assert (ins->opcode == OP_REGOFFSET);
5081 g_assert (mips_is_imm16 (ins->inst_offset));
5082 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5085 /* load arguments allocated to register from the stack */
5088 if (!cfg->arch.cinfo)
5089 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
5090 cinfo = cfg->arch.cinfo;
5092 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5093 ArgInfo *ainfo = &cinfo->ret;
5094 inst = cfg->vret_addr;
5095 if (inst->opcode == OP_REGVAR)
5096 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5097 else if (mips_is_imm16 (inst->inst_offset)) {
5098 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5100 mips_load_const (code, mips_at, inst->inst_offset);
5101 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5102 mips_sw (code, ainfo->reg, mips_at, 0);
5106 if (sig->call_convention == MONO_CALL_VARARG) {
5107 ArgInfo *cookie = &cinfo->sig_cookie;
5108 int offset = alloc_size + cookie->offset;
5110 /* Save the sig cookie address */
5111 g_assert (cookie->storage == ArgOnStack);
5113 g_assert (mips_is_imm16(offset));
5114 mips_addi (code, mips_at, cfg->frame_reg, offset);
5115 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5118 /* Keep this in sync with emit_load_volatile_arguments */
5119 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5120 ArgInfo *ainfo = cinfo->args + i;
5121 inst = cfg->args [pos];
5123 if (cfg->verbose_level > 2)
5124 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5125 if (inst->opcode == OP_REGVAR) {
5126 /* Argument ends up in a register */
5127 if (ainfo->storage == ArgInIReg)
5128 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5129 else if (ainfo->storage == ArgInFReg) {
5130 g_assert_not_reached();
5132 ppc_fmr (code, inst->dreg, ainfo->reg);
5135 else if (ainfo->storage == ArgOnStack) {
5136 int offset = cfg->stack_usage + ainfo->offset;
5137 g_assert (mips_is_imm16(offset));
5138 mips_lw (code, inst->dreg, mips_sp, offset);
5140 g_assert_not_reached ();
5142 if (cfg->verbose_level > 2)
5143 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5145 /* Argument ends up on the stack */
5146 if (ainfo->storage == ArgInIReg) {
5148 /* Incoming parameters should be above this frame */
5149 if (cfg->verbose_level > 2)
5150 g_print ("stack slot at %d of %d+%d\n",
5151 inst->inst_offset, alloc_size, alloc2_size);
5152 /* g_assert (inst->inst_offset >= alloc_size); */
5153 g_assert (inst->inst_basereg == cfg->frame_reg);
5154 basereg_offset = inst->inst_offset - alloc2_size;
5155 g_assert (mips_is_imm16 (basereg_offset));
5156 switch (ainfo->size) {
5158 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5161 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5165 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5168 #if (SIZEOF_REGISTER == 4)
5169 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5170 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5171 #elif (SIZEOF_REGISTER == 8)
5172 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5176 g_assert_not_reached ();
5179 } else if (ainfo->storage == ArgOnStack) {
5181 * Argument comes in on the stack, and ends up on the stack
5182 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5183 * 8 and 16 bit quantities. Shorten them in place.
5185 g_assert (mips_is_imm16 (inst->inst_offset));
5186 switch (ainfo->size) {
5188 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5189 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5192 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5193 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5200 g_assert_not_reached ();
5202 } else if (ainfo->storage == ArgInFReg) {
5203 g_assert (mips_is_imm16 (inst->inst_offset));
5204 g_assert (mips_is_imm16 (inst->inst_offset+4));
5205 if (ainfo->size == 8) {
5206 #if _MIPS_SIM == _ABIO32
5207 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5208 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5209 #elif _MIPS_SIM == _ABIN32
5210 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5213 else if (ainfo->size == 4)
5214 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5216 g_assert_not_reached ();
5217 } else if (ainfo->storage == ArgStructByVal) {
5219 int doffset = inst->inst_offset;
5221 g_assert (mips_is_imm16 (inst->inst_offset));
5222 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5223 /* Push the argument registers into their stack slots */
5224 for (i = 0; i < ainfo->size; ++i) {
5225 g_assert (mips_is_imm16(doffset));
5226 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5227 doffset += SIZEOF_REGISTER;
5229 } else if (ainfo->storage == ArgStructByAddr) {
5230 g_assert (mips_is_imm16 (inst->inst_offset));
5231 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5232 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5234 g_assert_not_reached ();
5239 if (method->save_lmf) {
5240 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5241 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5243 if (lmf_pthread_key != -1) {
5244 g_assert_not_reached();
5246 emit_tls_access (code, mips_temp, lmf_pthread_key);
5248 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5249 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5250 g_assert (mips_is_imm16(offset));
5251 mips_addiu (code, mips_a0, mips_temp, offset);
5254 /* This can/will clobber the a0-a3 registers */
5255 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5258 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5259 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5260 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5261 /* new_lmf->previous_lmf = *lmf_addr */
5262 mips_lw (code, mips_at, mips_v0, 0);
5263 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5264 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5265 /* *(lmf_addr) = sp + lmf_offset */
5266 g_assert (mips_is_imm16(lmf_offset));
5267 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5268 mips_sw (code, mips_at, mips_v0, 0);
5270 /* save method info */
5271 mips_load_const (code, mips_at, method);
5272 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5273 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5275 /* save the current IP */
5276 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5277 mips_load_const (code, mips_at, 0x01010101);
5278 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5282 if (mips_is_imm16 (-alloc2_size)) {
5283 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5286 mips_load_const (code, mips_at, -alloc2_size);
5287 mips_addu (code, mips_sp, mips_sp, mips_at);
5289 alloc_size += alloc2_size;
5290 cfa_offset += alloc2_size;
5291 if (cfg->frame_reg != mips_sp)
5292 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5294 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5298 #if _MIPS_SIM == _ABIO32
5299 cfg->arch.tracing_offset = cfg->stack_offset;
5300 #elif _MIPS_SIM == _ABIN32
5301 /* no stack slots by default for argument regs, reserve a special block */
5302 g_assert_not_reached ();
5304 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5307 cfg->code_len = code - cfg->native_code;
5308 g_assert (cfg->code_len < cfg->code_size);
5322 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5325 int save_mode = SAVE_NONE;
5327 MonoMethod *method = cfg->method;
5328 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type;
5329 int save_offset = MIPS_STACK_PARAM_OFFSET;
5331 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5333 offset = code - cfg->native_code;
5334 /* we need about 16 instructions */
5335 if (offset > (cfg->code_size - 16 * 4)) {
5336 cfg->code_size *= 2;
5337 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5338 code = cfg->native_code + offset;
5343 case MONO_TYPE_VOID:
5344 /* special case string .ctor icall */
5345 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5346 save_mode = SAVE_ONE;
5348 save_mode = SAVE_NONE;
5352 save_mode = SAVE_FP;
5354 case MONO_TYPE_VALUETYPE:
5355 save_mode = SAVE_STRUCT;
5359 #if SIZEOF_REGISTER == 4
5360 save_mode = SAVE_TWO;
5361 #elif SIZEOF_REGISTER == 8
5362 save_mode = SAVE_ONE;
5366 save_mode = SAVE_ONE;
5370 mips_addiu (code, mips_sp, mips_sp, -32);
5371 g_assert (mips_is_imm16(save_offset));
5372 switch (save_mode) {
5374 mips_sw (code, mips_v0, mips_sp, save_offset);
5375 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5376 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5377 if (enable_arguments) {
5378 MIPS_MOVE (code, mips_a1, mips_v0);
5379 MIPS_MOVE (code, mips_a2, mips_v1);
5383 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5384 if (enable_arguments) {
5385 MIPS_MOVE (code, mips_a1, mips_v0);
5389 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5390 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5391 mips_lw (code, mips_a0, mips_sp, save_offset);
5392 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5393 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5400 mips_load_const (code, mips_a0, cfg->method);
5401 mips_call (code, mips_t9, func);
5403 switch (save_mode) {
5405 mips_lw (code, mips_v0, mips_sp, save_offset);
5406 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5407 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5410 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5413 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5420 mips_addiu (code, mips_sp, mips_sp, 32);
5427 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5429 MonoMethod *method = cfg->method;
5431 int max_epilog_size = 16 + 20*4;
5432 int alloc2_size = 0;
5433 guint32 iregs_to_restore;
5435 guint32 fregs_to_restore;
5438 if (cfg->method->save_lmf)
5439 max_epilog_size += 128;
5441 if (mono_jit_trace_calls != NULL)
5442 max_epilog_size += 50;
5444 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5445 max_epilog_size += 50;
5448 pos = code - cfg->native_code;
5449 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5450 cfg->code_size *= 2;
5451 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5452 cfg->stat_code_reallocs++;
5456 * Keep in sync with OP_JMP
5459 code = cfg->native_code + pos;
5461 code = cfg->native_code + cfg->code_len;
5463 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5464 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5466 if (cfg->frame_reg != mips_sp) {
5467 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5469 /* If the stack frame is really large, deconstruct it in two steps */
5470 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5471 alloc2_size = cfg->stack_usage - 1024;
5472 /* partially deconstruct the stack */
5473 mips_load_const (code, mips_at, alloc2_size);
5474 mips_addu (code, mips_sp, mips_sp, mips_at);
5476 pos = cfg->arch.iregs_offset - alloc2_size;
5477 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5478 if (iregs_to_restore) {
5479 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5480 if (iregs_to_restore & (1 << i)) {
5481 g_assert (mips_is_imm16(pos));
5482 MIPS_LW (code, i, mips_sp, pos);
5483 pos += SIZEOF_REGISTER;
5490 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5492 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5493 fregs_to_restore |= (fregs_to_restore << 1);
5495 if (fregs_to_restore) {
5496 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5497 if (fregs_to_restore & (1 << i)) {
5498 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5499 g_assert (mips_is_imm16(pos));
5500 mips_lwc1 (code, i, mips_sp, pos);
5507 /* Unlink the LMF if necessary */
5508 if (method->save_lmf) {
5509 int lmf_offset = cfg->arch.lmf_offset;
5511 /* t0 = current_lmf->previous_lmf */
5512 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5513 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5515 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5516 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5517 /* (*lmf_addr) = previous_lmf */
5518 mips_sw (code, mips_temp, mips_t1, 0);
5522 /* Restore the fp */
5523 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5526 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5527 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5528 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5530 /* Restore the stack pointer */
5531 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5532 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5534 /* Caller will emit either return or tail-call sequence */
5536 cfg->code_len = code - cfg->native_code;
5538 g_assert (cfg->code_len < cfg->code_size);
5543 mono_arch_emit_epilog (MonoCompile *cfg)
5547 code = mono_arch_emit_epilog_sub (cfg, NULL);
5549 mips_jr (code, mips_ra);
5552 cfg->code_len = code - cfg->native_code;
5554 g_assert (cfg->code_len < cfg->code_size);
5557 /* remove once throw_exception_by_name is eliminated */
5560 exception_id_by_name (const char *name)
5562 if (strcmp (name, "IndexOutOfRangeException") == 0)
5563 return MONO_EXC_INDEX_OUT_OF_RANGE;
5564 if (strcmp (name, "OverflowException") == 0)
5565 return MONO_EXC_OVERFLOW;
5566 if (strcmp (name, "ArithmeticException") == 0)
5567 return MONO_EXC_ARITHMETIC;
5568 if (strcmp (name, "DivideByZeroException") == 0)
5569 return MONO_EXC_DIVIDE_BY_ZERO;
5570 if (strcmp (name, "InvalidCastException") == 0)
5571 return MONO_EXC_INVALID_CAST;
5572 if (strcmp (name, "NullReferenceException") == 0)
5573 return MONO_EXC_NULL_REF;
5574 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5575 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5576 if (strcmp (name, "ArgumentException") == 0)
5577 return MONO_EXC_ARGUMENT;
5578 g_error ("Unknown intrinsic exception %s\n", name);
5584 mono_arch_emit_exceptions (MonoCompile *cfg)
5587 MonoJumpInfo *patch_info;
5590 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5591 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5592 int max_epilog_size = 50;
5594 /* count the number of exception infos */
5597 * make sure we have enough space for exceptions
5598 * 24 is the simulated call to throw_exception_by_name
5600 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5602 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5603 i = exception_id_by_name (patch_info->data.target);
5604 g_assert (i < MONO_EXC_INTRINS_NUM);
5605 if (!exc_throw_found [i]) {
5606 max_epilog_size += 12;
5607 exc_throw_found [i] = TRUE;
5613 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5614 cfg->code_size *= 2;
5615 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5616 cfg->stat_code_reallocs++;
5619 code = cfg->native_code + cfg->code_len;
5621 /* add code to raise exceptions */
5622 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5623 switch (patch_info->type) {
5624 case MONO_PATCH_INFO_EXC: {
5626 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5628 i = exception_id_by_name (patch_info->data.target);
5629 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5630 if (!exc_throw_pos [i]) {
5633 exc_throw_pos [i] = code;
5634 //g_print ("exc: writing stub at %p\n", code);
5635 mips_load_const (code, mips_a0, patch_info->data.target);
5636 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5637 mips_load_const (code, mips_t9, addr);
5638 mips_jr (code, mips_t9);
5641 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5643 /* Turn into a Relative patch, pointing at code stub */
5644 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5645 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5647 g_assert_not_reached();
5657 cfg->code_len = code - cfg->native_code;
5659 g_assert (cfg->code_len < cfg->code_size);
5664 * Thread local storage support
5667 setup_tls_access (void)
5670 //guint32 *ins, *code;
5672 if (tls_mode == TLS_MODE_FAILED)
5675 if (g_getenv ("MONO_NO_TLS")) {
5676 tls_mode = TLS_MODE_FAILED;
5680 if (tls_mode == TLS_MODE_DETECT) {
5682 tls_mode = TLS_MODE_FAILED;
5686 ins = (guint32*)pthread_getspecific;
5687 /* uncond branch to the real method */
5688 if ((*ins >> 26) == 18) {
5690 val = (*ins & ~3) << 6;
5694 ins = (guint32*)val;
5696 ins = (guint32*) ((char*)ins + val);
5699 code = &cmplwi_1023;
5700 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5702 ppc_li (code, ppc_r4, 0x48);
5705 if (*ins == cmplwi_1023) {
5706 int found_lwz_284 = 0;
5707 for (ptk = 0; ptk < 20; ++ptk) {
5709 if (!*ins || *ins == blr_ins)
5711 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5716 if (!found_lwz_284) {
5717 tls_mode = TLS_MODE_FAILED;
5720 tls_mode = TLS_MODE_LTHREADS;
5721 } else if (*ins == li_0x48) {
5723 /* uncond branch to the real method */
5724 if ((*ins >> 26) == 18) {
5726 val = (*ins & ~3) << 6;
5730 ins = (guint32*)val;
5732 ins = (guint32*) ((char*)ins + val);
5735 ppc_li (code, ppc_r0, 0x7FF2);
5736 if (ins [1] == val) {
5737 /* Darwin on G4, implement */
5738 tls_mode = TLS_MODE_FAILED;
5742 ppc_mfspr (code, ppc_r3, 104);
5743 if (ins [1] != val) {
5744 tls_mode = TLS_MODE_FAILED;
5747 tls_mode = TLS_MODE_DARWIN_G5;
5750 tls_mode = TLS_MODE_FAILED;
5754 tls_mode = TLS_MODE_FAILED;
5759 if (monodomain_key == -1) {
5760 ptk = mono_domain_get_tls_key ();
5762 monodomain_key = ptk;
5764 if (lmf_pthread_key == -1) {
5765 ptk = mono_jit_tls_id;
5767 /*g_print ("MonoLMF at: %d\n", ptk);*/
5768 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5769 init_tls_failed = 1;
5772 lmf_pthread_key = ptk;
5775 if (monothread_key == -1) {
5776 ptk = mono_thread_get_tls_key ();
5778 monothread_key = ptk;
5779 /*g_print ("thread inited: %d\n", ptk);*/
5781 /*g_print ("thread not inited yet %d\n", ptk);*/
5787 mono_arch_finish_init (void)
5789 setup_tls_access ();
5793 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5798 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5800 int this_dreg = mips_a0;
5803 this_dreg = mips_a1;
5805 /* add the this argument */
5806 if (this_reg != -1) {
5808 MONO_INST_NEW (cfg, this, OP_MOVE);
5809 this->type = this_type;
5810 this->sreg1 = this_reg;
5811 this->dreg = mono_alloc_ireg (cfg);
5812 mono_bblock_add_inst (cfg->cbb, this);
5813 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5818 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5819 vtarg->type = STACK_MP;
5820 vtarg->sreg1 = vt_reg;
5821 vtarg->dreg = mono_alloc_ireg (cfg);
5822 mono_bblock_add_inst (cfg->cbb, vtarg);
5823 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5828 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5830 MonoInst *ins = NULL;
5836 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5842 mono_arch_print_tree (MonoInst *tree, int arity)
5847 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5851 setup_tls_access ();
5852 if (monodomain_key == -1)
5855 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5856 ins->inst_offset = monodomain_key;
5861 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5863 return ctx->sc_regs [reg];
5866 #ifdef MONO_ARCH_HAVE_IMT
5868 #define ENABLE_WRONG_METHOD_CHECK 0
5870 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5871 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5873 #define LOADSTORE_SIZE 4
5874 #define JUMP_IMM_SIZE 16
5875 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5876 #define LOAD_CONST_SIZE 8
5877 #define JUMP_JR_SIZE 8
5880 * LOCKING: called with the domain lock held
5883 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5884 gpointer fail_tramp)
5888 guint8 *code, *start, *patch;
5890 for (i = 0; i < count; ++i) {
5891 MonoIMTCheckItem *item = imt_entries [i];
5893 if (item->is_equals) {
5894 if (item->check_target_idx) {
5895 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5896 if (item->has_target_code)
5897 item->chunk_size += LOAD_CONST_SIZE;
5899 item->chunk_size += LOADSTORE_SIZE;
5902 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5903 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5904 if (!item->has_target_code)
5905 item->chunk_size += LOADSTORE_SIZE;
5907 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5908 #if ENABLE_WRONG_METHOD_CHECK
5909 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5914 item->chunk_size += CMP_SIZE + BR_SIZE;
5915 imt_entries [item->check_target_idx]->compare_done = TRUE;
5917 size += item->chunk_size;
5919 /* the initial load of the vtable address */
5920 size += MIPS_LOAD_SEQUENCE_LENGTH;
5922 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5924 code = mono_domain_code_reserve (domain, size);
5928 /* t7 points to the vtable */
5929 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5931 for (i = 0; i < count; ++i) {
5932 MonoIMTCheckItem *item = imt_entries [i];
5934 item->code_target = code;
5935 if (item->is_equals) {
5936 if (item->check_target_idx) {
5937 mips_load_const (code, mips_temp, (gsize)item->key);
5938 item->jmp_code = code;
5939 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5941 if (item->has_target_code) {
5942 mips_load_const (code, mips_t9,
5943 item->value.target_code);
5946 mips_lw (code, mips_t9, mips_t7,
5947 (sizeof (gpointer) * item->value.vtable_slot));
5949 mips_jr (code, mips_t9);
5953 mips_load_const (code, mips_temp, (gsize)item->key);
5955 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5957 if (item->has_target_code) {
5958 mips_load_const (code, mips_t9,
5959 item->value.target_code);
5962 mips_load_const (code, mips_at,
5963 & (vtable->vtable [item->value.vtable_slot]));
5964 mips_lw (code, mips_t9, mips_at, 0);
5966 mips_jr (code, mips_t9);
5968 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5969 mips_load_const (code, mips_t9, fail_tramp);
5970 mips_jr (code, mips_t9);
5973 /* enable the commented code to assert on wrong method */
5974 #if ENABLE_WRONG_METHOD_CHECK
5975 ppc_load (code, ppc_r0, (guint32)item->key);
5976 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5978 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5980 mips_lw (code, mips_t9, mips_t7,
5981 (sizeof (gpointer) * item->value.vtable_slot));
5982 mips_jr (code, mips_t9);
5985 #if ENABLE_WRONG_METHOD_CHECK
5986 ppc_patch (patch, code);
5992 mips_load_const (code, mips_temp, (gulong)item->key);
5993 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5995 item->jmp_code = code;
5996 mips_beq (code, mips_temp, mips_zero, 0);
6000 /* patch the branches to get to the target items */
6001 for (i = 0; i < count; ++i) {
6002 MonoIMTCheckItem *item = imt_entries [i];
6003 if (item->jmp_code && item->check_target_idx) {
6004 mips_patch ((guint32 *)item->jmp_code,
6005 (guint32)imt_entries [item->check_target_idx]->code_target);
6010 mono_stats.imt_thunks_size += code - start;
6011 g_assert (code - start <= size);
6012 mono_arch_flush_icache (start, size);
6017 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6019 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6024 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6026 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6029 /* Soft Debug support */
6030 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6033 * mono_arch_set_breakpoint:
6035 * See mini-amd64.c for docs.
6038 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6041 guint32 addr = (guint32)bp_trigger_page;
6043 mips_load_const (code, mips_t9, addr);
6044 mips_lw (code, mips_t9, mips_t9, 0);
6046 mono_arch_flush_icache (ip, code - ip);
6050 * mono_arch_clear_breakpoint:
6052 * See mini-amd64.c for docs.
6055 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6063 mono_arch_flush_icache (ip, code - ip);
6067 * mono_arch_start_single_stepping:
6069 * See mini-amd64.c for docs.
6072 mono_arch_start_single_stepping (void)
6074 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6078 * mono_arch_stop_single_stepping:
6080 * See mini-amd64.c for docs.
6083 mono_arch_stop_single_stepping (void)
6085 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6089 * mono_arch_is_single_step_event:
6091 * See mini-amd64.c for docs.
6094 mono_arch_is_single_step_event (void *info, void *sigctx)
6096 siginfo_t* sinfo = (siginfo_t*) info;
6097 /* Sometimes the address is off by 4 */
6098 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6105 * mono_arch_is_breakpoint_event:
6107 * See mini-amd64.c for docs.
6110 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6112 siginfo_t* sinfo = (siginfo_t*) info;
6113 /* Sometimes the address is off by 4 */
6114 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6121 * mono_arch_skip_breakpoint:
6123 * See mini-amd64.c for docs.
6126 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6128 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6132 * mono_arch_skip_single_step:
6134 * See mini-amd64.c for docs.
6137 mono_arch_skip_single_step (MonoContext *ctx)
6139 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6143 * mono_arch_get_seq_point_info:
6145 * See mini-amd64.c for docs.
6148 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6154 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */