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/abi-details.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/utils/mono-mmap.h>
22 #include <mono/utils/mono-hwcap-mips.h>
24 #include <mono/arch/mips/mips-codegen.h>
26 #include "mini-mips.h"
31 #define SAVE_FP_REGS 0
33 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
35 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
36 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
37 remember to update cpu-mips.md if you change this */
39 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
40 #define mips_call(c,D,v) do { \
41 guint32 _target = (guint32)(v); \
42 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
43 mips_load_const (c, D, _target); \
44 mips_jalr (c, D, mips_ra); \
47 mips_jumpl (c, _target >> 2); \
59 /* This mutex protects architecture specific caches */
60 #define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
61 #define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
62 static mono_mutex_t mini_arch_mutex;
64 int mono_exc_esp_offset = 0;
65 static int tls_mode = TLS_MODE_DETECT;
66 static int lmf_pthread_key = -1;
67 static int monothread_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 (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 (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, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
556 mips_lw (code, mips_a0, mips_a0, MONO_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, MONO_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_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
679 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
682 return (gpointer)regs [mips_a0];
686 * Initialize the cpu to execute managed code.
689 mono_arch_cpu_init (void)
691 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
700 ls_word_offset = ls_word_idx * 4;
701 ms_word_offset = ms_word_idx * 4;
705 * Initialize architecture specific code.
708 mono_arch_init (void)
710 mono_mutex_init_recursive (&mini_arch_mutex);
712 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
713 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
714 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
718 * Cleanup architecture specific code.
721 mono_arch_cleanup (void)
723 mono_mutex_destroy (&mini_arch_mutex);
727 * This function returns the optimizations supported on this cpu.
730 mono_arch_cpu_optimizations (guint32 *exclude_mask)
734 /* no mips-specific optimizations yet */
740 * This function test for all SIMD functions supported.
742 * Returns a bitmask corresponding to all supported versions.
746 mono_arch_cpu_enumerate_simd_versions (void)
748 /* SIMD is currently unimplemented */
753 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
758 for (i = 0; i < cfg->num_varinfo; i++) {
759 MonoInst *ins = cfg->varinfo [i];
760 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
763 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
766 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
769 /* we can only allocate 32 bit values */
770 if (mono_is_regsize_var (ins->inst_vtype)) {
771 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
772 g_assert (i == vmv->idx);
773 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
781 mono_arch_get_global_int_regs (MonoCompile *cfg)
785 regs = g_list_prepend (regs, (gpointer)mips_s0);
786 regs = g_list_prepend (regs, (gpointer)mips_s1);
787 regs = g_list_prepend (regs, (gpointer)mips_s2);
788 regs = g_list_prepend (regs, (gpointer)mips_s3);
789 regs = g_list_prepend (regs, (gpointer)mips_s4);
790 //regs = g_list_prepend (regs, (gpointer)mips_s5);
791 regs = g_list_prepend (regs, (gpointer)mips_s6);
792 regs = g_list_prepend (regs, (gpointer)mips_s7);
798 * mono_arch_regalloc_cost:
800 * Return the cost, in number of memory references, of the action of
801 * allocating the variable VMV into a register during global register
805 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
812 args_onto_stack (CallInfo *info)
814 g_assert (!info->on_stack);
815 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
816 info->on_stack = TRUE;
817 info->stack_size = MIPS_STACK_PARAM_OFFSET;
820 #if _MIPS_SIM == _ABIO32
822 * O32 calling convention version
826 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
827 /* First, see if we need to drop onto the stack */
828 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
829 args_onto_stack (info);
831 /* Now, place the argument */
832 if (info->on_stack) {
833 ainfo->storage = ArgOnStack;
834 ainfo->reg = mips_sp; /* in the caller */
835 ainfo->offset = info->stack_size;
838 ainfo->storage = ArgInIReg;
839 ainfo->reg = info->gr;
841 info->gr_passed = TRUE;
843 info->stack_size += 4;
847 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
848 /* First, see if we need to drop onto the stack */
849 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
850 args_onto_stack (info);
852 /* Now, place the argument */
853 if (info->on_stack) {
854 g_assert (info->stack_size % 4 == 0);
855 info->stack_size += (info->stack_size % 8);
857 ainfo->storage = ArgOnStack;
858 ainfo->reg = mips_sp; /* in the caller */
859 ainfo->offset = info->stack_size;
862 // info->gr must be a0 or a2
863 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
864 g_assert(info->gr <= MIPS_LAST_ARG_REG);
866 ainfo->storage = ArgInIReg;
867 ainfo->reg = info->gr;
869 info->gr_passed = TRUE;
871 info->stack_size += 8;
875 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
876 /* First, see if we need to drop onto the stack */
877 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
878 args_onto_stack (info);
880 /* Now, place the argument */
881 if (info->on_stack) {
882 ainfo->storage = ArgOnStack;
883 ainfo->reg = mips_sp; /* in the caller */
884 ainfo->offset = info->stack_size;
887 /* Only use FP regs for args if no int args passed yet */
888 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
889 ainfo->storage = ArgInFReg;
890 ainfo->reg = info->fr;
891 /* Even though it's a single-precision float, it takes up two FP regs */
893 /* FP and GP slots do not overlap */
897 /* Passing single-precision float arg in a GP register
898 * such as: func (0, 1.0, 2, 3);
899 * In this case, only one 'gr' register is consumed.
901 ainfo->storage = ArgInIReg;
902 ainfo->reg = info->gr;
905 info->gr_passed = TRUE;
908 info->stack_size += 4;
912 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
913 /* First, see if we need to drop onto the stack */
914 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
915 args_onto_stack (info);
917 /* Now, place the argument */
918 if (info->on_stack) {
919 g_assert(info->stack_size % 4 == 0);
920 info->stack_size += (info->stack_size % 8);
922 ainfo->storage = ArgOnStack;
923 ainfo->reg = mips_sp; /* in the caller */
924 ainfo->offset = info->stack_size;
927 /* Only use FP regs for args if no int args passed yet */
928 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
929 ainfo->storage = ArgInFReg;
930 ainfo->reg = info->fr;
932 /* FP and GP slots do not overlap */
936 // info->gr must be a0 or a2
937 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
938 g_assert(info->gr <= MIPS_LAST_ARG_REG);
940 ainfo->storage = ArgInIReg;
941 ainfo->reg = info->gr;
943 info->gr_passed = TRUE;
946 info->stack_size += 8;
948 #elif _MIPS_SIM == _ABIN32
950 * N32 calling convention version
954 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
955 /* First, see if we need to drop onto the stack */
956 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
957 args_onto_stack (info);
959 /* Now, place the argument */
960 if (info->on_stack) {
961 ainfo->storage = ArgOnStack;
962 ainfo->reg = mips_sp; /* in the caller */
963 ainfo->offset = info->stack_size;
964 info->stack_size += SIZEOF_REGISTER;
967 ainfo->storage = ArgInIReg;
968 ainfo->reg = info->gr;
970 info->gr_passed = TRUE;
975 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
976 /* First, see if we need to drop onto the stack */
977 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
978 args_onto_stack (info);
980 /* Now, place the argument */
981 if (info->on_stack) {
982 g_assert (info->stack_size % 4 == 0);
983 info->stack_size += (info->stack_size % 8);
985 ainfo->storage = ArgOnStack;
986 ainfo->reg = mips_sp; /* in the caller */
987 ainfo->offset = info->stack_size;
988 info->stack_size += SIZEOF_REGISTER;
991 g_assert (info->gr <= MIPS_LAST_ARG_REG);
993 ainfo->storage = ArgInIReg;
994 ainfo->reg = info->gr;
996 info->gr_passed = TRUE;
1001 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
1002 /* First, see if we need to drop onto the stack */
1003 if (!info->on_stack) {
1004 if (info->gr > MIPS_LAST_ARG_REG)
1005 args_onto_stack (info);
1006 else if (info->fr > MIPS_LAST_FPARG_REG)
1007 args_onto_stack (info);
1010 /* Now, place the argument */
1011 if (info->on_stack) {
1012 ainfo->storage = ArgOnStack;
1013 ainfo->reg = mips_sp; /* in the caller */
1014 ainfo->offset = info->stack_size;
1015 info->stack_size += FREG_SIZE;
1018 ainfo->storage = ArgInFReg;
1019 ainfo->reg = info->fr;
1021 /* FP and GP slots do not overlap */
1027 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1028 /* First, see if we need to drop onto the stack */
1029 if (!info->on_stack) {
1030 if (info->gr > MIPS_LAST_ARG_REG)
1031 args_onto_stack (info);
1032 else if (info->fr > MIPS_LAST_FPARG_REG)
1033 args_onto_stack (info);
1036 /* Now, place the argument */
1037 if (info->on_stack) {
1038 g_assert(info->stack_size % 4 == 0);
1039 info->stack_size += (info->stack_size % 8);
1041 ainfo->storage = ArgOnStack;
1042 ainfo->reg = mips_sp; /* in the caller */
1043 ainfo->offset = info->stack_size;
1044 info->stack_size += FREG_SIZE;
1047 ainfo->storage = ArgInFReg;
1048 ainfo->reg = info->fr;
1050 /* FP and GP slots do not overlap */
1057 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1060 int n = sig->hasthis + sig->param_count;
1062 MonoType* simpletype;
1064 gboolean is_pinvoke = sig->pinvoke;
1067 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1069 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1071 cinfo->fr = MIPS_FIRST_FPARG_REG;
1072 cinfo->gr = MIPS_FIRST_ARG_REG;
1073 cinfo->stack_size = 0;
1075 DEBUG(printf("calculate_sizes\n"));
1077 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1081 /* handle returning a struct */
1082 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1083 cinfo->struct_ret = cinfo->gr;
1084 add_int32_arg (cinfo, &cinfo->ret);
1088 add_int32_arg (cinfo, cinfo->args + n);
1093 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1094 * the first argument, allowing 'this' to be always passed in the first arg reg.
1095 * Also do this if the first argument is a reference type, since virtual calls
1096 * are sometimes made using calli without sig->hasthis set, like in the delegate
1099 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1101 add_int32_arg (cinfo, cinfo->args + n);
1104 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1108 add_int32_arg (cinfo, &cinfo->ret);
1109 cinfo->struct_ret = cinfo->ret.reg;
1113 add_int32_arg (cinfo, cinfo->args + n);
1117 if (cinfo->vtype_retaddr) {
1118 add_int32_arg (cinfo, &cinfo->ret);
1119 cinfo->struct_ret = cinfo->ret.reg;
1124 DEBUG(printf("params: %d\n", sig->param_count));
1125 for (i = pstart; i < sig->param_count; ++i) {
1126 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1127 /* Prevent implicit arguments and sig_cookie from
1128 being passed in registers */
1129 args_onto_stack (cinfo);
1130 /* Emit the signature cookie just before the implicit arguments */
1131 add_int32_arg (cinfo, &cinfo->sig_cookie);
1133 DEBUG(printf("param %d: ", i));
1134 simpletype = mini_get_underlying_type (sig->params [i]);
1135 switch (simpletype->type) {
1136 case MONO_TYPE_BOOLEAN:
1139 DEBUG(printf("1 byte\n"));
1140 cinfo->args [n].size = 1;
1141 add_int32_arg (cinfo, &cinfo->args[n]);
1144 case MONO_TYPE_CHAR:
1147 DEBUG(printf("2 bytes\n"));
1148 cinfo->args [n].size = 2;
1149 add_int32_arg (cinfo, &cinfo->args[n]);
1154 DEBUG(printf("4 bytes\n"));
1155 cinfo->args [n].size = 4;
1156 add_int32_arg (cinfo, &cinfo->args[n]);
1162 case MONO_TYPE_FNPTR:
1163 case MONO_TYPE_CLASS:
1164 case MONO_TYPE_OBJECT:
1165 case MONO_TYPE_STRING:
1166 case MONO_TYPE_SZARRAY:
1167 case MONO_TYPE_ARRAY:
1168 cinfo->args [n].size = sizeof (gpointer);
1169 add_int32_arg (cinfo, &cinfo->args[n]);
1172 case MONO_TYPE_GENERICINST:
1173 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1174 cinfo->args [n].size = sizeof (gpointer);
1175 add_int32_arg (cinfo, &cinfo->args[n]);
1180 case MONO_TYPE_TYPEDBYREF:
1181 case MONO_TYPE_VALUETYPE: {
1184 int has_offset = FALSE;
1186 gint size, alignment;
1189 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1190 size = sizeof (MonoTypedRef);
1191 alignment = sizeof (gpointer);
1193 klass = mono_class_from_mono_type (sig->params [i]);
1195 size = mono_class_native_size (klass, NULL);
1197 size = mono_class_value_size (klass, NULL);
1198 alignment = mono_class_min_align (klass);
1200 #if MIPS_PASS_STRUCTS_BY_VALUE
1201 /* Need to do alignment if struct contains long or double */
1202 if (alignment > 4) {
1203 /* Drop onto stack *before* looking at
1204 stack_size, if required. */
1205 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1206 args_onto_stack (cinfo);
1207 if (cinfo->stack_size & (alignment - 1)) {
1208 add_int32_arg (cinfo, &dummy_arg);
1210 g_assert (!(cinfo->stack_size & (alignment - 1)));
1214 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1215 mono_class_native_size (sig->params [i]->data.klass, NULL),
1216 cinfo->stack_size, alignment);
1218 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1219 g_assert (cinfo->args [n].size == 0);
1220 g_assert (cinfo->args [n].vtsize == 0);
1221 for (j = 0; j < nwords; ++j) {
1223 add_int32_arg (cinfo, &cinfo->args [n]);
1224 if (cinfo->on_stack)
1227 add_int32_arg (cinfo, &dummy_arg);
1228 if (!has_offset && cinfo->on_stack) {
1229 cinfo->args [n].offset = dummy_arg.offset;
1233 if (cinfo->on_stack)
1234 cinfo->args [n].vtsize += 1;
1236 cinfo->args [n].size += 1;
1238 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1239 cinfo->args [n].storage = ArgStructByVal;
1241 add_int32_arg (cinfo, &cinfo->args[n]);
1242 cinfo->args [n].storage = ArgStructByAddr;
1249 DEBUG(printf("8 bytes\n"));
1250 cinfo->args [n].size = 8;
1251 add_int64_arg (cinfo, &cinfo->args[n]);
1255 DEBUG(printf("R4\n"));
1256 cinfo->args [n].size = 4;
1257 add_float32_arg (cinfo, &cinfo->args[n]);
1261 DEBUG(printf("R8\n"));
1262 cinfo->args [n].size = 8;
1263 add_float64_arg (cinfo, &cinfo->args[n]);
1267 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1271 /* Handle the case where there are no implicit arguments */
1272 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1273 /* Prevent implicit arguments and sig_cookie from
1274 being passed in registers */
1275 args_onto_stack (cinfo);
1276 /* Emit the signature cookie just before the implicit arguments */
1277 add_int32_arg (cinfo, &cinfo->sig_cookie);
1281 simpletype = mini_get_underlying_type (sig->ret);
1282 switch (simpletype->type) {
1283 case MONO_TYPE_BOOLEAN:
1288 case MONO_TYPE_CHAR:
1294 case MONO_TYPE_FNPTR:
1295 case MONO_TYPE_CLASS:
1296 case MONO_TYPE_OBJECT:
1297 case MONO_TYPE_SZARRAY:
1298 case MONO_TYPE_ARRAY:
1299 case MONO_TYPE_STRING:
1300 cinfo->ret.reg = mips_v0;
1304 cinfo->ret.reg = mips_v0;
1308 cinfo->ret.reg = mips_f0;
1309 cinfo->ret.storage = ArgInFReg;
1311 case MONO_TYPE_GENERICINST:
1312 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1313 cinfo->ret.reg = mips_v0;
1317 case MONO_TYPE_VALUETYPE:
1318 case MONO_TYPE_TYPEDBYREF:
1320 case MONO_TYPE_VOID:
1323 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1327 /* align stack size to 16 */
1328 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1330 cinfo->stack_usage = cinfo->stack_size;
1335 debug_omit_fp (void)
1338 return mono_debug_count ();
1345 * mono_arch_compute_omit_fp:
1347 * Determine whenever the frame pointer can be eliminated.
1350 mono_arch_compute_omit_fp (MonoCompile *cfg)
1352 MonoMethodSignature *sig;
1353 MonoMethodHeader *header;
1357 if (cfg->arch.omit_fp_computed)
1360 header = cfg->header;
1362 sig = mono_method_signature (cfg->method);
1364 if (!cfg->arch.cinfo)
1365 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1366 cinfo = cfg->arch.cinfo;
1369 * FIXME: Remove some of the restrictions.
1371 cfg->arch.omit_fp = TRUE;
1372 cfg->arch.omit_fp_computed = TRUE;
1374 if (cfg->disable_omit_fp)
1375 cfg->arch.omit_fp = FALSE;
1376 if (!debug_omit_fp ())
1377 cfg->arch.omit_fp = FALSE;
1378 if (cfg->method->save_lmf)
1379 cfg->arch.omit_fp = FALSE;
1380 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1381 cfg->arch.omit_fp = FALSE;
1382 if (header->num_clauses)
1383 cfg->arch.omit_fp = FALSE;
1384 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1385 cfg->arch.omit_fp = FALSE;
1386 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1387 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1388 cfg->arch.omit_fp = FALSE;
1390 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1391 * there are stack arguments.
1394 if (cinfo->stack_usage)
1395 cfg->arch.omit_fp = FALSE;
1399 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1400 MonoInst *ins = cfg->varinfo [i];
1403 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1406 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1410 * Set var information according to the calling convention. mips version.
1411 * The locals var stuff should most likely be split in another method.
1414 mono_arch_allocate_vars (MonoCompile *cfg)
1416 MonoMethodSignature *sig;
1417 MonoMethodHeader *header;
1419 int i, offset, size, align, curinst;
1420 int frame_reg = mips_sp;
1421 guint32 iregs_to_save = 0;
1423 guint32 fregs_to_restore;
1427 sig = mono_method_signature (cfg->method);
1429 if (!cfg->arch.cinfo)
1430 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1431 cinfo = cfg->arch.cinfo;
1433 mono_arch_compute_omit_fp (cfg);
1435 /* spill down, we'll fix it in a separate pass */
1436 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1438 /* allow room for the vararg method args: void* and long/double */
1439 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1440 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1442 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1443 * call convs needs to be handled this way.
1445 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1446 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1448 /* gtk-sharp and other broken code will dllimport vararg functions even with
1449 * non-varargs signatures. Since there is little hope people will get this right
1450 * we assume they won't.
1452 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1453 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1455 /* a0-a3 always present */
1456 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1458 header = cfg->header;
1460 if (cfg->arch.omit_fp)
1461 frame_reg = mips_sp;
1463 frame_reg = mips_fp;
1464 cfg->frame_reg = frame_reg;
1465 if (frame_reg != mips_sp) {
1466 cfg->used_int_regs |= 1 << frame_reg;
1471 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1472 /* FIXME: handle long and FP values */
1473 switch (mini_get_underlying_type (sig->ret)->type) {
1474 case MONO_TYPE_VOID:
1478 cfg->ret->opcode = OP_REGVAR;
1479 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1482 cfg->ret->opcode = OP_REGVAR;
1483 cfg->ret->inst_c0 = mips_v0;
1487 /* Space for outgoing parameters, including a0-a3 */
1488 offset += cfg->param_area;
1490 /* allow room to save the return value (if it's a struct) */
1491 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1494 /* Now handle the local variables */
1496 curinst = cfg->locals_start;
1497 for (i = curinst; i < cfg->num_varinfo; ++i) {
1498 inst = cfg->varinfo [i];
1499 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1502 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1503 * pinvoke wrappers when they call functions returning structure
1505 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1506 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1508 size = mono_type_size (inst->inst_vtype, &align);
1510 offset += align - 1;
1511 offset &= ~(align - 1);
1512 inst->inst_offset = offset;
1513 inst->opcode = OP_REGOFFSET;
1514 inst->inst_basereg = frame_reg;
1516 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1519 /* Space for LMF (if needed) */
1520 if (cfg->method->save_lmf) {
1521 /* align the offset to 16 bytes */
1522 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1523 cfg->arch.lmf_offset = offset;
1524 offset += sizeof (MonoLMF);
1527 if (sig->call_convention == MONO_CALL_VARARG) {
1531 /* Allocate a local slot to hold the sig cookie address */
1532 offset += align - 1;
1533 offset &= ~(align - 1);
1534 cfg->sig_cookie = offset;
1538 offset += SIZEOF_REGISTER - 1;
1539 offset &= ~(SIZEOF_REGISTER - 1);
1541 /* Space for saved registers */
1542 cfg->arch.iregs_offset = offset;
1543 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1544 if (iregs_to_save) {
1545 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1546 if (iregs_to_save & (1 << i)) {
1547 offset += SIZEOF_REGISTER;
1552 /* saved float registers */
1554 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1555 if (fregs_to_restore) {
1556 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1557 if (fregs_to_restore & (1 << i)) {
1558 offset += sizeof(double);
1564 #if _MIPS_SIM == _ABIO32
1565 /* Now add space for saving the ra */
1566 offset += SIZEOF_VOID_P;
1569 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1570 cfg->stack_offset = offset;
1571 cfg->arch.local_alloc_offset = cfg->stack_offset;
1575 * Now allocate stack slots for the int arg regs (a0 - a3)
1576 * On MIPS o32, these are just above the incoming stack pointer
1577 * Even if the arg has been assigned to a regvar, it gets a stack slot
1580 /* Return struct-by-value results in a hidden first argument */
1581 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1582 cfg->vret_addr->opcode = OP_REGOFFSET;
1583 cfg->vret_addr->inst_c0 = mips_a0;
1584 cfg->vret_addr->inst_offset = offset;
1585 cfg->vret_addr->inst_basereg = frame_reg;
1586 offset += SIZEOF_REGISTER;
1589 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1590 inst = cfg->args [i];
1591 if (inst->opcode != OP_REGVAR) {
1594 if (sig->hasthis && (i == 0))
1595 arg_type = &mono_defaults.object_class->byval_arg;
1597 arg_type = sig->params [i - sig->hasthis];
1599 inst->opcode = OP_REGOFFSET;
1600 size = mono_type_size (arg_type, &align);
1602 if (size < SIZEOF_REGISTER) {
1603 size = SIZEOF_REGISTER;
1604 align = SIZEOF_REGISTER;
1606 inst->inst_basereg = frame_reg;
1607 offset = (offset + align - 1) & ~(align - 1);
1608 inst->inst_offset = offset;
1610 if (cfg->verbose_level > 1)
1611 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1614 #if _MIPS_SIM == _ABIO32
1615 /* o32: Even a0-a3 get stack slots */
1616 size = SIZEOF_REGISTER;
1617 align = SIZEOF_REGISTER;
1618 inst->inst_basereg = frame_reg;
1619 offset = (offset + align - 1) & ~(align - 1);
1620 inst->inst_offset = offset;
1622 if (cfg->verbose_level > 1)
1623 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1627 #if _MIPS_SIM == _ABIN32
1628 /* Now add space for saving the ra */
1629 offset += SIZEOF_VOID_P;
1632 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1633 cfg->stack_offset = offset;
1634 cfg->arch.local_alloc_offset = cfg->stack_offset;
1639 mono_arch_create_vars (MonoCompile *cfg)
1641 MonoMethodSignature *sig;
1643 sig = mono_method_signature (cfg->method);
1645 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1646 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1647 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1648 printf ("vret_addr = ");
1649 mono_print_ins (cfg->vret_addr);
1654 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1655 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1659 * take the arguments and generate the arch-specific
1660 * instructions to properly call the function in call.
1661 * This includes pushing, moving arguments to the right register
1663 * Issue: who does the spilling if needed, and when?
1666 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1668 MonoMethodSignature *tmp_sig;
1671 if (call->tail_call)
1674 /* FIXME: Add support for signature tokens to AOT */
1675 cfg->disable_aot = TRUE;
1678 * mono_ArgIterator_Setup assumes the signature cookie is
1679 * passed first and all the arguments which were before it are
1680 * passed on the stack after the signature. So compensate by
1681 * passing a different signature.
1683 tmp_sig = mono_metadata_signature_dup (call->signature);
1684 tmp_sig->param_count -= call->signature->sentinelpos;
1685 tmp_sig->sentinelpos = 0;
1686 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1688 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1689 sig_arg->dreg = mono_alloc_ireg (cfg);
1690 sig_arg->inst_p0 = tmp_sig;
1691 MONO_ADD_INS (cfg->cbb, sig_arg);
1693 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1697 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1700 MonoMethodSignature *sig;
1705 sig = call->signature;
1706 n = sig->param_count + sig->hasthis;
1708 cinfo = get_call_info (cfg->mempool, sig);
1709 if (cinfo->struct_ret)
1710 call->used_iregs |= 1 << cinfo->struct_ret;
1712 for (i = 0; i < n; ++i) {
1713 ArgInfo *ainfo = cinfo->args + i;
1716 if (i >= sig->hasthis)
1717 t = sig->params [i - sig->hasthis];
1719 t = &mono_defaults.int_class->byval_arg;
1720 t = mini_get_underlying_type (t);
1722 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1723 /* Emit the signature cookie just before the implicit arguments */
1724 emit_sig_cookie (cfg, call, cinfo);
1727 if (is_virtual && i == 0) {
1728 /* the argument will be attached to the call instrucion */
1729 in = call->args [i];
1730 call->used_iregs |= 1 << ainfo->reg;
1733 in = call->args [i];
1734 if (ainfo->storage == ArgInIReg) {
1735 #if SIZEOF_REGISTER == 4
1736 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1737 MONO_INST_NEW (cfg, ins, OP_MOVE);
1738 ins->dreg = mono_alloc_ireg (cfg);
1739 ins->sreg1 = in->dreg + 1;
1740 MONO_ADD_INS (cfg->cbb, ins);
1741 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1743 MONO_INST_NEW (cfg, ins, OP_MOVE);
1744 ins->dreg = mono_alloc_ireg (cfg);
1745 ins->sreg1 = in->dreg + 2;
1746 MONO_ADD_INS (cfg->cbb, ins);
1747 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1750 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1753 #if PROMOTE_R4_TO_R8
1754 /* ??? - convert to single first? */
1755 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1756 ins->dreg = mono_alloc_freg (cfg);
1757 ins->sreg1 = in->dreg;
1758 MONO_ADD_INS (cfg->cbb, ins);
1763 /* trying to load float value into int registers */
1764 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1765 ins->dreg = mono_alloc_ireg (cfg);
1767 MONO_ADD_INS (cfg->cbb, ins);
1768 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1769 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1770 /* trying to load float value into int registers */
1771 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
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 MONO_INST_NEW (cfg, ins, OP_MOVE);
1778 ins->dreg = mono_alloc_ireg (cfg);
1779 ins->sreg1 = in->dreg;
1780 MONO_ADD_INS (cfg->cbb, ins);
1781 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1783 } else if (ainfo->storage == ArgStructByAddr) {
1784 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1785 ins->opcode = OP_OUTARG_VT;
1786 ins->sreg1 = in->dreg;
1787 ins->klass = in->klass;
1788 ins->inst_p0 = call;
1789 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1790 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1791 MONO_ADD_INS (cfg->cbb, ins);
1792 } else if (ainfo->storage == ArgStructByVal) {
1793 /* this is further handled in mono_arch_emit_outarg_vt () */
1794 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1795 ins->opcode = OP_OUTARG_VT;
1796 ins->sreg1 = in->dreg;
1797 ins->klass = in->klass;
1798 ins->inst_p0 = call;
1799 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1800 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1801 MONO_ADD_INS (cfg->cbb, ins);
1802 } else if (ainfo->storage == ArgOnStack) {
1803 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1804 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1805 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1806 if (t->type == MONO_TYPE_R8)
1807 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1809 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1811 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1813 } else if (ainfo->storage == ArgInFReg) {
1814 if (t->type == MONO_TYPE_VALUETYPE) {
1815 /* this is further handled in mono_arch_emit_outarg_vt () */
1816 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1817 ins->opcode = OP_OUTARG_VT;
1818 ins->sreg1 = in->dreg;
1819 ins->klass = in->klass;
1820 ins->inst_p0 = call;
1821 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1822 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1823 MONO_ADD_INS (cfg->cbb, ins);
1825 cfg->flags |= MONO_CFG_HAS_FPOUT;
1827 int dreg = mono_alloc_freg (cfg);
1829 if (ainfo->size == 4) {
1830 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1832 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1834 ins->sreg1 = in->dreg;
1835 MONO_ADD_INS (cfg->cbb, ins);
1838 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1839 cfg->flags |= MONO_CFG_HAS_FPOUT;
1842 g_assert_not_reached ();
1846 /* Handle the case where there are no implicit arguments */
1847 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1848 emit_sig_cookie (cfg, call, cinfo);
1850 if (cinfo->struct_ret) {
1853 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1854 vtarg->sreg1 = call->vret_var->dreg;
1855 vtarg->dreg = mono_alloc_preg (cfg);
1856 MONO_ADD_INS (cfg->cbb, vtarg);
1858 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1862 * Reverse the call->out_args list.
1865 MonoInst *prev = NULL, *list = call->out_args, *next;
1872 call->out_args = prev;
1875 call->stack_usage = cinfo->stack_usage;
1876 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1877 #if _MIPS_SIM == _ABIO32
1878 /* a0-a3 always present */
1879 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1881 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1882 cfg->flags |= MONO_CFG_HAS_CALLS;
1884 * should set more info in call, such as the stack space
1885 * used by the args that needs to be added back to esp
1890 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1892 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1893 ArgInfo *ainfo = ins->inst_p1;
1894 int ovf_size = ainfo->vtsize;
1895 int doffset = ainfo->offset;
1896 int i, soffset, dreg;
1898 if (ainfo->storage == ArgStructByVal) {
1900 if (cfg->verbose_level > 0) {
1901 char* nm = mono_method_full_name (cfg->method, TRUE);
1902 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1903 nm, doffset, ainfo->size, ovf_size);
1909 for (i = 0; i < ainfo->size; ++i) {
1910 dreg = mono_alloc_ireg (cfg);
1911 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1912 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1913 soffset += SIZEOF_REGISTER;
1915 if (ovf_size != 0) {
1916 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1918 } else if (ainfo->storage == ArgInFReg) {
1919 int tmpr = mono_alloc_freg (cfg);
1921 if (ainfo->size == 4)
1922 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1924 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1925 dreg = mono_alloc_freg (cfg);
1926 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1927 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1929 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1933 /* FIXME: alignment? */
1934 if (call->signature->pinvoke) {
1935 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1936 vtcopy->backend.is_pinvoke = 1;
1938 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1941 g_assert (ovf_size > 0);
1943 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1944 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1947 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1949 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1954 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1956 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1959 #if (SIZEOF_REGISTER == 4)
1960 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1963 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1964 ins->sreg1 = val->dreg + 1;
1965 ins->sreg2 = val->dreg + 2;
1966 MONO_ADD_INS (cfg->cbb, ins);
1970 if (ret->type == MONO_TYPE_R8) {
1971 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1974 if (ret->type == MONO_TYPE_R4) {
1975 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1979 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1983 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1985 MonoInst *ins, *n, *last_ins = NULL;
1987 if (cfg->verbose_level > 2)
1988 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1991 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1992 if (cfg->verbose_level > 2)
1993 mono_print_ins_index (0, ins);
1995 switch (ins->opcode) {
1997 case OP_LOAD_MEMBASE:
1998 case OP_LOADI4_MEMBASE:
2000 * OP_IADD reg2, reg1, const1
2001 * OP_LOAD_MEMBASE const2(reg2), reg3
2003 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
2005 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)){
2006 int const1 = last_ins->inst_imm;
2007 int const2 = ins->inst_offset;
2009 if (mips_is_imm16 (const1 + const2)) {
2010 ins->inst_basereg = last_ins->sreg1;
2011 ins->inst_offset = const1 + const2;
2021 bb->last_ins = last_ins;
2025 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2027 MonoInst *ins, *n, *last_ins = NULL;
2030 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2031 MonoInst *last_ins = ins->prev;
2033 switch (ins->opcode) {
2035 /* remove unnecessary multiplication with 1 */
2036 if (ins->inst_imm == 1) {
2037 if (ins->dreg != ins->sreg1) {
2038 ins->opcode = OP_MOVE;
2040 MONO_DELETE_INS (bb, ins);
2044 int power2 = mono_is_power_of_two (ins->inst_imm);
2046 ins->opcode = OP_SHL_IMM;
2047 ins->inst_imm = power2;
2051 case OP_LOAD_MEMBASE:
2052 case OP_LOADI4_MEMBASE:
2054 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2055 * OP_LOAD_MEMBASE offset(basereg), reg
2057 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2058 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2059 ins->inst_basereg == last_ins->inst_destbasereg &&
2060 ins->inst_offset == last_ins->inst_offset) {
2061 if (ins->dreg == last_ins->sreg1) {
2062 MONO_DELETE_INS (bb, ins);
2065 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2066 ins->opcode = OP_MOVE;
2067 ins->sreg1 = last_ins->sreg1;
2072 * Note: reg1 must be different from the basereg in the second load
2073 * OP_LOAD_MEMBASE offset(basereg), reg1
2074 * OP_LOAD_MEMBASE offset(basereg), reg2
2076 * OP_LOAD_MEMBASE offset(basereg), reg1
2077 * OP_MOVE reg1, reg2
2079 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2080 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2081 ins->inst_basereg != last_ins->dreg &&
2082 ins->inst_basereg == last_ins->inst_basereg &&
2083 ins->inst_offset == last_ins->inst_offset) {
2085 if (ins->dreg == last_ins->dreg) {
2086 MONO_DELETE_INS (bb, ins);
2089 ins->opcode = OP_MOVE;
2090 ins->sreg1 = last_ins->dreg;
2093 //g_assert_not_reached ();
2098 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2099 * OP_LOAD_MEMBASE offset(basereg), reg
2101 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2102 * OP_ICONST reg, imm
2104 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2105 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2106 ins->inst_basereg == last_ins->inst_destbasereg &&
2107 ins->inst_offset == last_ins->inst_offset) {
2108 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2109 ins->opcode = OP_ICONST;
2110 ins->inst_c0 = last_ins->inst_imm;
2111 g_assert_not_reached (); // check this rule
2116 case OP_LOADU1_MEMBASE:
2117 case OP_LOADI1_MEMBASE:
2118 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2119 ins->inst_basereg == last_ins->inst_destbasereg &&
2120 ins->inst_offset == last_ins->inst_offset) {
2121 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2122 ins->sreg1 = last_ins->sreg1;
2125 case OP_LOADU2_MEMBASE:
2126 case OP_LOADI2_MEMBASE:
2127 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2128 ins->inst_basereg == last_ins->inst_destbasereg &&
2129 ins->inst_offset == last_ins->inst_offset) {
2130 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2131 ins->sreg1 = last_ins->sreg1;
2134 case OP_ICONV_TO_I4:
2135 case OP_ICONV_TO_U4:
2137 ins->opcode = OP_MOVE;
2141 if (ins->dreg == ins->sreg1) {
2142 MONO_DELETE_INS (bb, ins);
2146 * OP_MOVE sreg, dreg
2147 * OP_MOVE dreg, sreg
2149 if (last_ins && last_ins->opcode == OP_MOVE &&
2150 ins->sreg1 == last_ins->dreg &&
2151 ins->dreg == last_ins->sreg1) {
2152 MONO_DELETE_INS (bb, ins);
2160 bb->last_ins = last_ins;
2164 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2172 switch (ins->opcode) {
2175 case OP_LCOMPARE_IMM:
2176 mono_print_ins (ins);
2177 g_assert_not_reached ();
2180 tmp1 = mono_alloc_ireg (cfg);
2181 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2182 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2183 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2184 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2189 tmp1 = mono_alloc_ireg (cfg);
2190 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2191 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2192 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2193 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2198 tmp1 = mono_alloc_ireg (cfg);
2199 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2200 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2201 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2202 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2207 tmp1 = mono_alloc_ireg (cfg);
2208 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2209 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2210 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2211 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2223 mono_print_ins (ins);
2224 g_assert_not_reached ();
2227 tmp1 = mono_alloc_ireg (cfg);
2228 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2229 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2230 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2231 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2239 case OP_LCONV_TO_I1:
2240 case OP_LCONV_TO_I2:
2241 case OP_LCONV_TO_I4:
2242 case OP_LCONV_TO_I8:
2243 case OP_LCONV_TO_R4:
2244 case OP_LCONV_TO_R8:
2245 case OP_LCONV_TO_U4:
2246 case OP_LCONV_TO_U8:
2247 case OP_LCONV_TO_U2:
2248 case OP_LCONV_TO_U1:
2250 case OP_LCONV_TO_OVF_I:
2251 case OP_LCONV_TO_OVF_U:
2253 mono_print_ins (ins);
2254 g_assert_not_reached ();
2257 tmp1 = mono_alloc_ireg (cfg);
2258 tmp2 = mono_alloc_ireg (cfg);
2259 tmp3 = mono_alloc_ireg (cfg);
2260 tmp4 = mono_alloc_ireg (cfg);
2261 tmp5 = mono_alloc_ireg (cfg);
2263 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2265 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2266 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2268 /* add the high 32-bits, and add in the carry from the low 32-bits */
2269 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2270 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2272 /* Overflow happens if
2273 * neg + neg = pos or
2275 * XOR of the high bits returns 0 if the signs match
2276 * XOR of that with the high bit of the result return 1 if overflow.
2279 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2280 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2282 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2283 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2284 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2286 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2287 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2288 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2290 /* Now, if (tmp4 == 0) then overflow */
2291 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2295 case OP_LADD_OVF_UN:
2296 tmp1 = mono_alloc_ireg (cfg);
2297 tmp2 = mono_alloc_ireg (cfg);
2299 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2300 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2301 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2302 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2303 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2304 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2309 case OP_LMUL_OVF_UN:
2310 mono_print_ins (ins);
2311 g_assert_not_reached ();
2314 tmp1 = mono_alloc_ireg (cfg);
2315 tmp2 = mono_alloc_ireg (cfg);
2316 tmp3 = mono_alloc_ireg (cfg);
2317 tmp4 = mono_alloc_ireg (cfg);
2318 tmp5 = mono_alloc_ireg (cfg);
2320 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2322 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2323 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2324 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2326 /* Overflow happens if
2327 * neg - pos = pos or
2329 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2331 * tmp1 = (lhs ^ rhs)
2332 * tmp2 = (lhs ^ result)
2333 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2336 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2337 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2338 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2339 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2341 /* Now, if (tmp4 == 1) then overflow */
2342 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2346 case OP_LSUB_OVF_UN:
2347 tmp1 = mono_alloc_ireg (cfg);
2348 tmp2 = mono_alloc_ireg (cfg);
2350 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2351 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2352 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2353 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2355 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2356 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2360 case OP_LCONV_TO_OVF_I1_UN:
2361 case OP_LCONV_TO_OVF_I2_UN:
2362 case OP_LCONV_TO_OVF_I4_UN:
2363 case OP_LCONV_TO_OVF_I8_UN:
2364 case OP_LCONV_TO_OVF_U1_UN:
2365 case OP_LCONV_TO_OVF_U2_UN:
2366 case OP_LCONV_TO_OVF_U4_UN:
2367 case OP_LCONV_TO_OVF_U8_UN:
2368 case OP_LCONV_TO_OVF_I_UN:
2369 case OP_LCONV_TO_OVF_U_UN:
2370 case OP_LCONV_TO_OVF_I1:
2371 case OP_LCONV_TO_OVF_U1:
2372 case OP_LCONV_TO_OVF_I2:
2373 case OP_LCONV_TO_OVF_U2:
2374 case OP_LCONV_TO_OVF_I4:
2375 case OP_LCONV_TO_OVF_U4:
2376 case OP_LCONV_TO_OVF_I8:
2377 case OP_LCONV_TO_OVF_U8:
2385 case OP_LCONV_TO_R_UN:
2391 case OP_LSHR_UN_IMM:
2393 case OP_LDIV_UN_IMM:
2395 case OP_LREM_UN_IMM:
2406 mono_print_ins (ins);
2407 g_assert_not_reached ();
2409 case OP_LCONV_TO_R8_2:
2410 case OP_LCONV_TO_R4_2:
2411 case OP_LCONV_TO_R_UN_2:
2413 case OP_LCONV_TO_OVF_I4_2:
2414 tmp1 = mono_alloc_ireg (cfg);
2416 /* Overflows if reg2 != sign extension of reg1 */
2417 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2418 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2419 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2427 mono_print_ins (ins);
2428 g_assert_not_reached ();
2436 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2444 switch (ins->opcode) {
2446 tmp1 = mono_alloc_ireg (cfg);
2447 tmp2 = mono_alloc_ireg (cfg);
2448 tmp3 = mono_alloc_ireg (cfg);
2449 tmp4 = mono_alloc_ireg (cfg);
2450 tmp5 = mono_alloc_ireg (cfg);
2452 /* add the operands */
2454 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2456 /* Overflow happens if
2457 * neg + neg = pos or
2460 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2461 * XOR of the high bit returns 0 if the signs match
2462 * XOR of that with the high bit of the result return 1 if overflow.
2465 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2466 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2468 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2469 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2470 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2472 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2473 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2475 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2477 /* Now, if (tmp5 == 0) then overflow */
2478 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2479 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2480 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2484 case OP_IADD_OVF_UN:
2485 tmp1 = mono_alloc_ireg (cfg);
2487 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2488 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2489 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2490 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2491 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2496 tmp1 = mono_alloc_ireg (cfg);
2497 tmp2 = mono_alloc_ireg (cfg);
2498 tmp3 = mono_alloc_ireg (cfg);
2499 tmp4 = mono_alloc_ireg (cfg);
2500 tmp5 = mono_alloc_ireg (cfg);
2502 /* add the operands */
2504 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2506 /* Overflow happens if
2507 * neg - pos = pos or
2509 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2511 * tmp1 = (lhs ^ rhs)
2512 * tmp2 = (lhs ^ result)
2513 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2516 /* tmp3 = 1 if the signs of the two inputs differ */
2517 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2518 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2519 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2520 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2521 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2523 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2524 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2525 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2529 case OP_ISUB_OVF_UN:
2530 tmp1 = mono_alloc_ireg (cfg);
2532 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2533 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2534 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2535 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2536 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2543 map_to_reg_reg_op (int op)
2552 case OP_COMPARE_IMM:
2554 case OP_ICOMPARE_IMM:
2556 case OP_LCOMPARE_IMM:
2572 case OP_LOAD_MEMBASE:
2573 return OP_LOAD_MEMINDEX;
2574 case OP_LOADI4_MEMBASE:
2575 return OP_LOADI4_MEMINDEX;
2576 case OP_LOADU4_MEMBASE:
2577 return OP_LOADU4_MEMINDEX;
2578 case OP_LOADU1_MEMBASE:
2579 return OP_LOADU1_MEMINDEX;
2580 case OP_LOADI2_MEMBASE:
2581 return OP_LOADI2_MEMINDEX;
2582 case OP_LOADU2_MEMBASE:
2583 return OP_LOADU2_MEMINDEX;
2584 case OP_LOADI1_MEMBASE:
2585 return OP_LOADI1_MEMINDEX;
2586 case OP_LOADR4_MEMBASE:
2587 return OP_LOADR4_MEMINDEX;
2588 case OP_LOADR8_MEMBASE:
2589 return OP_LOADR8_MEMINDEX;
2590 case OP_STOREI1_MEMBASE_REG:
2591 return OP_STOREI1_MEMINDEX;
2592 case OP_STOREI2_MEMBASE_REG:
2593 return OP_STOREI2_MEMINDEX;
2594 case OP_STOREI4_MEMBASE_REG:
2595 return OP_STOREI4_MEMINDEX;
2596 case OP_STORE_MEMBASE_REG:
2597 return OP_STORE_MEMINDEX;
2598 case OP_STORER4_MEMBASE_REG:
2599 return OP_STORER4_MEMINDEX;
2600 case OP_STORER8_MEMBASE_REG:
2601 return OP_STORER8_MEMINDEX;
2602 case OP_STORE_MEMBASE_IMM:
2603 return OP_STORE_MEMBASE_REG;
2604 case OP_STOREI1_MEMBASE_IMM:
2605 return OP_STOREI1_MEMBASE_REG;
2606 case OP_STOREI2_MEMBASE_IMM:
2607 return OP_STOREI2_MEMBASE_REG;
2608 case OP_STOREI4_MEMBASE_IMM:
2609 return OP_STOREI4_MEMBASE_REG;
2610 case OP_STOREI8_MEMBASE_IMM:
2611 return OP_STOREI8_MEMBASE_REG;
2613 return mono_op_imm_to_op (op);
2617 map_to_mips_op (int op)
2621 return OP_MIPS_FBEQ;
2623 return OP_MIPS_FBGE;
2625 return OP_MIPS_FBGT;
2627 return OP_MIPS_FBLE;
2629 return OP_MIPS_FBLT;
2631 return OP_MIPS_FBNE;
2633 return OP_MIPS_FBGE_UN;
2635 return OP_MIPS_FBGT_UN;
2637 return OP_MIPS_FBLE_UN;
2639 return OP_MIPS_FBLT_UN;
2647 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2648 g_assert_not_reached ();
2652 #define NEW_INS(cfg,after,dest,op) do { \
2653 MONO_INST_NEW((cfg), (dest), (op)); \
2654 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2657 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2659 MONO_INST_NEW(cfg, temp, (op)); \
2660 mono_bblock_insert_after_ins (bb, (pos), temp); \
2661 temp->dreg = (_dreg); \
2662 temp->sreg1 = (_sreg1); \
2663 temp->sreg2 = (_sreg2); \
2667 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2669 MONO_INST_NEW(cfg, temp, (op)); \
2670 mono_bblock_insert_after_ins (bb, (pos), temp); \
2671 temp->dreg = (_dreg); \
2672 temp->sreg1 = (_sreg1); \
2673 temp->inst_c0 = (_imm); \
2678 * Remove from the instruction list the instructions that can't be
2679 * represented with very simple instructions with no register
2683 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2685 MonoInst *ins, *next, *temp, *last_ins = NULL;
2689 if (cfg->verbose_level > 2) {
2692 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2693 MONO_BB_FOR_EACH_INS (bb, ins) {
2694 mono_print_ins_index (idx++, ins);
2700 MONO_BB_FOR_EACH_INS (bb, ins) {
2702 switch (ins->opcode) {
2707 /* Branch opts can eliminate the branch */
2708 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2714 case OP_COMPARE_IMM:
2715 case OP_ICOMPARE_IMM:
2716 case OP_LCOMPARE_IMM:
2718 /* Branch opts can eliminate the branch */
2719 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2723 if (ins->inst_imm) {
2724 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2725 temp->inst_c0 = ins->inst_imm;
2726 temp->dreg = mono_alloc_ireg (cfg);
2727 ins->sreg2 = temp->dreg;
2731 ins->sreg2 = mips_zero;
2733 if (ins->opcode == OP_COMPARE_IMM)
2734 ins->opcode = OP_COMPARE;
2735 else if (ins->opcode == OP_ICOMPARE_IMM)
2736 ins->opcode = OP_ICOMPARE;
2737 else if (ins->opcode == OP_LCOMPARE_IMM)
2738 ins->opcode = OP_LCOMPARE;
2741 case OP_IDIV_UN_IMM:
2744 case OP_IREM_UN_IMM:
2745 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2746 temp->inst_c0 = ins->inst_imm;
2747 temp->dreg = mono_alloc_ireg (cfg);
2748 ins->sreg2 = temp->dreg;
2749 if (ins->opcode == OP_IDIV_IMM)
2750 ins->opcode = OP_IDIV;
2751 else if (ins->opcode == OP_IREM_IMM)
2752 ins->opcode = OP_IREM;
2753 else if (ins->opcode == OP_IDIV_UN_IMM)
2754 ins->opcode = OP_IDIV_UN;
2755 else if (ins->opcode == OP_IREM_UN_IMM)
2756 ins->opcode = OP_IREM_UN;
2758 /* handle rem separately */
2765 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2766 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2767 temp->inst_c0 = ins->inst_imm;
2768 temp->dreg = mono_alloc_ireg (cfg);
2769 ins->sreg2 = temp->dreg;
2770 ins->opcode = map_to_reg_reg_op (ins->opcode);
2780 /* unsigned 16 bit immediate */
2781 if (ins->inst_imm & 0xffff0000) {
2782 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2783 temp->inst_c0 = ins->inst_imm;
2784 temp->dreg = mono_alloc_ireg (cfg);
2785 ins->sreg2 = temp->dreg;
2786 ins->opcode = map_to_reg_reg_op (ins->opcode);
2793 /* signed 16 bit immediate */
2794 if (!mips_is_imm16 (ins->inst_imm)) {
2795 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2796 temp->inst_c0 = ins->inst_imm;
2797 temp->dreg = mono_alloc_ireg (cfg);
2798 ins->sreg2 = temp->dreg;
2799 ins->opcode = map_to_reg_reg_op (ins->opcode);
2805 if (!mips_is_imm16 (-ins->inst_imm)) {
2806 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2807 temp->inst_c0 = ins->inst_imm;
2808 temp->dreg = mono_alloc_ireg (cfg);
2809 ins->sreg2 = temp->dreg;
2810 ins->opcode = map_to_reg_reg_op (ins->opcode);
2816 if (ins->inst_imm == 1) {
2817 ins->opcode = OP_MOVE;
2820 if (ins->inst_imm == 0) {
2821 ins->opcode = OP_ICONST;
2825 imm = mono_is_power_of_two (ins->inst_imm);
2827 ins->opcode = OP_SHL_IMM;
2828 ins->inst_imm = imm;
2831 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2832 temp->inst_c0 = ins->inst_imm;
2833 temp->dreg = mono_alloc_ireg (cfg);
2834 ins->sreg2 = temp->dreg;
2835 ins->opcode = map_to_reg_reg_op (ins->opcode);
2838 case OP_LOCALLOC_IMM:
2839 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2840 temp->inst_c0 = ins->inst_imm;
2841 temp->dreg = mono_alloc_ireg (cfg);
2842 ins->sreg1 = temp->dreg;
2843 ins->opcode = OP_LOCALLOC;
2846 case OP_LOADR4_MEMBASE:
2847 case OP_STORER4_MEMBASE_REG:
2848 /* we can do two things: load the immed in a register
2849 * and use an indexed load, or see if the immed can be
2850 * represented as an ad_imm + a load with a smaller offset
2851 * that fits. We just do the first for now, optimize later.
2853 if (mips_is_imm16 (ins->inst_offset))
2855 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2856 temp->inst_c0 = ins->inst_offset;
2857 temp->dreg = mono_alloc_ireg (cfg);
2858 ins->sreg2 = temp->dreg;
2859 ins->opcode = map_to_reg_reg_op (ins->opcode);
2862 case OP_STORE_MEMBASE_IMM:
2863 case OP_STOREI1_MEMBASE_IMM:
2864 case OP_STOREI2_MEMBASE_IMM:
2865 case OP_STOREI4_MEMBASE_IMM:
2866 case OP_STOREI8_MEMBASE_IMM:
2867 if (!ins->inst_imm) {
2868 ins->sreg1 = mips_zero;
2869 ins->opcode = map_to_reg_reg_op (ins->opcode);
2872 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2873 temp->inst_c0 = ins->inst_imm;
2874 temp->dreg = mono_alloc_ireg (cfg);
2875 ins->sreg1 = temp->dreg;
2876 ins->opcode = map_to_reg_reg_op (ins->opcode);
2878 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2884 /* Branch opts can eliminate the branch */
2885 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2892 * remap compare/branch and compare/set
2893 * to MIPS specific opcodes.
2895 next->opcode = map_to_mips_op (next->opcode);
2896 next->sreg1 = ins->sreg1;
2897 next->sreg2 = ins->sreg2;
2904 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2905 temp->inst_c0 = (guint32)ins->inst_p0;
2906 temp->dreg = mono_alloc_ireg (cfg);
2907 ins->inst_basereg = temp->dreg;
2908 ins->inst_offset = 0;
2909 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2911 /* make it handle the possibly big ins->inst_offset
2912 * later optimize to use lis + load_membase
2917 g_assert (ins_is_compare(last_ins));
2918 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2919 NULLIFY_INS(last_ins);
2923 g_assert (ins_is_compare(last_ins));
2924 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2925 NULLIFY_INS(last_ins);
2929 g_assert (ins_is_compare(last_ins));
2930 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2931 last_ins->dreg = mono_alloc_ireg (cfg);
2932 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2936 g_assert (ins_is_compare(last_ins));
2937 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2938 last_ins->dreg = mono_alloc_ireg (cfg);
2939 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2943 g_assert (ins_is_compare(last_ins));
2944 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2945 last_ins->dreg = mono_alloc_ireg (cfg);
2946 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2950 g_assert (ins_is_compare(last_ins));
2951 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2952 last_ins->dreg = mono_alloc_ireg (cfg);
2953 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2957 g_assert (ins_is_compare(last_ins));
2958 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2959 last_ins->dreg = mono_alloc_ireg (cfg);
2960 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2964 g_assert (ins_is_compare(last_ins));
2965 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2966 last_ins->dreg = mono_alloc_ireg (cfg);
2967 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2971 g_assert (ins_is_compare(last_ins));
2972 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2973 last_ins->dreg = mono_alloc_ireg (cfg);
2974 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2978 g_assert (ins_is_compare(last_ins));
2979 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2980 last_ins->dreg = mono_alloc_ireg (cfg);
2981 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2986 g_assert (ins_is_compare(last_ins));
2987 last_ins->opcode = OP_IXOR;
2988 last_ins->dreg = mono_alloc_ireg(cfg);
2989 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2994 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2995 NULLIFY_INS(last_ins);
3001 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
3002 NULLIFY_INS(last_ins);
3007 g_assert (ins_is_compare(last_ins));
3008 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
3009 MONO_DELETE_INS(bb, last_ins);
3014 g_assert (ins_is_compare(last_ins));
3015 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3016 MONO_DELETE_INS(bb, last_ins);
3019 case OP_COND_EXC_EQ:
3020 case OP_COND_EXC_IEQ:
3021 g_assert (ins_is_compare(last_ins));
3022 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3023 MONO_DELETE_INS(bb, last_ins);
3026 case OP_COND_EXC_GE:
3027 case OP_COND_EXC_IGE:
3028 g_assert (ins_is_compare(last_ins));
3029 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3030 MONO_DELETE_INS(bb, last_ins);
3033 case OP_COND_EXC_GT:
3034 case OP_COND_EXC_IGT:
3035 g_assert (ins_is_compare(last_ins));
3036 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3037 MONO_DELETE_INS(bb, last_ins);
3040 case OP_COND_EXC_LE:
3041 case OP_COND_EXC_ILE:
3042 g_assert (ins_is_compare(last_ins));
3043 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3044 MONO_DELETE_INS(bb, last_ins);
3047 case OP_COND_EXC_LT:
3048 case OP_COND_EXC_ILT:
3049 g_assert (ins_is_compare(last_ins));
3050 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3051 MONO_DELETE_INS(bb, last_ins);
3054 case OP_COND_EXC_NE_UN:
3055 case OP_COND_EXC_INE_UN:
3056 g_assert (ins_is_compare(last_ins));
3057 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3058 MONO_DELETE_INS(bb, last_ins);
3061 case OP_COND_EXC_GE_UN:
3062 case OP_COND_EXC_IGE_UN:
3063 g_assert (ins_is_compare(last_ins));
3064 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3065 MONO_DELETE_INS(bb, last_ins);
3068 case OP_COND_EXC_GT_UN:
3069 case OP_COND_EXC_IGT_UN:
3070 g_assert (ins_is_compare(last_ins));
3071 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3072 MONO_DELETE_INS(bb, last_ins);
3075 case OP_COND_EXC_LE_UN:
3076 case OP_COND_EXC_ILE_UN:
3077 g_assert (ins_is_compare(last_ins));
3078 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3079 MONO_DELETE_INS(bb, last_ins);
3082 case OP_COND_EXC_LT_UN:
3083 case OP_COND_EXC_ILT_UN:
3084 g_assert (ins_is_compare(last_ins));
3085 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3086 MONO_DELETE_INS(bb, last_ins);
3089 case OP_COND_EXC_OV:
3090 case OP_COND_EXC_IOV: {
3091 int tmp1, tmp2, tmp3, tmp4, tmp5;
3092 MonoInst *pos = last_ins;
3094 /* Overflow happens if
3095 * neg + neg = pos or
3098 * (bit31s of operands match) AND (bit31 of operand
3099 * != bit31 of result)
3100 * XOR of the high bit returns 0 if the signs match
3101 * XOR of that with the high bit of the result return 1
3104 g_assert (last_ins->opcode == OP_IADC);
3106 tmp1 = mono_alloc_ireg (cfg);
3107 tmp2 = mono_alloc_ireg (cfg);
3108 tmp3 = mono_alloc_ireg (cfg);
3109 tmp4 = mono_alloc_ireg (cfg);
3110 tmp5 = mono_alloc_ireg (cfg);
3112 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3113 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3115 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3116 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3117 INS (pos, OP_INOT, tmp3, tmp2, -1);
3119 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3120 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3121 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3123 /* Now, if (tmp5 == 0) then overflow */
3124 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3129 case OP_COND_EXC_NO:
3130 case OP_COND_EXC_INO:
3131 g_assert_not_reached ();
3135 case OP_COND_EXC_IC:
3136 g_assert_not_reached ();
3139 case OP_COND_EXC_NC:
3140 case OP_COND_EXC_INC:
3141 g_assert_not_reached ();
3147 bb->last_ins = last_ins;
3148 bb->max_vreg = cfg->next_vreg;
3151 if (cfg->verbose_level > 2) {
3154 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3155 MONO_BB_FOR_EACH_INS (bb, ins) {
3156 mono_print_ins_index (idx++, ins);
3165 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3167 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3169 mips_truncwd (code, mips_ftemp, sreg);
3171 mips_cvtwd (code, mips_ftemp, sreg);
3173 mips_mfc1 (code, dreg, mips_ftemp);
3176 mips_andi (code, dreg, dreg, 0xff);
3177 else if (size == 2) {
3178 mips_sll (code, dreg, dreg, 16);
3179 mips_srl (code, dreg, dreg, 16);
3183 mips_sll (code, dreg, dreg, 24);
3184 mips_sra (code, dreg, dreg, 24);
3186 else if (size == 2) {
3187 mips_sll (code, dreg, dreg, 16);
3188 mips_sra (code, dreg, dreg, 16);
3195 * emit_load_volatile_arguments:
3197 * Load volatile arguments from the stack to the original input registers.
3198 * Required before a tail call.
3201 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3203 MonoMethod *method = cfg->method;
3204 MonoMethodSignature *sig;
3209 sig = mono_method_signature (method);
3211 if (!cfg->arch.cinfo)
3212 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3213 cinfo = cfg->arch.cinfo;
3215 if (cinfo->struct_ret) {
3216 ArgInfo *ainfo = &cinfo->ret;
3217 inst = cfg->vret_addr;
3218 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3221 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3222 ArgInfo *ainfo = cinfo->args + i;
3223 inst = cfg->args [i];
3224 if (inst->opcode == OP_REGVAR) {
3225 if (ainfo->storage == ArgInIReg)
3226 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3227 else if (ainfo->storage == ArgInFReg)
3228 g_assert_not_reached();
3229 else if (ainfo->storage == ArgOnStack) {
3232 g_assert_not_reached ();
3234 if (ainfo->storage == ArgInIReg) {
3235 g_assert (mips_is_imm16 (inst->inst_offset));
3236 switch (ainfo->size) {
3238 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3241 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3245 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3248 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3249 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3252 g_assert_not_reached ();
3255 } else if (ainfo->storage == ArgOnStack) {
3257 } else if (ainfo->storage == ArgInFReg) {
3258 g_assert (mips_is_imm16 (inst->inst_offset));
3259 if (ainfo->size == 8) {
3260 #if _MIPS_SIM == _ABIO32
3261 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3262 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3263 #elif _MIPS_SIM == _ABIN32
3264 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3267 else if (ainfo->size == 4)
3268 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3270 g_assert_not_reached ();
3271 } else if (ainfo->storage == ArgStructByVal) {
3273 int doffset = inst->inst_offset;
3275 g_assert (mips_is_imm16 (inst->inst_offset));
3276 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3277 for (i = 0; i < ainfo->size; ++i) {
3278 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3279 doffset += SIZEOF_REGISTER;
3281 } else if (ainfo->storage == ArgStructByAddr) {
3282 g_assert (mips_is_imm16 (inst->inst_offset));
3283 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3285 g_assert_not_reached ();
3293 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3295 int size = cfg->param_area;
3297 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3298 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3303 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3304 if (ppc_is_imm16 (-size)) {
3305 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3307 ppc_load (code, ppc_r12, -size);
3308 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3315 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3317 int size = cfg->param_area;
3319 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3320 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3325 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3326 if (ppc_is_imm16 (size)) {
3327 ppc_stwu (code, ppc_r0, size, ppc_sp);
3329 ppc_load (code, ppc_r12, size);
3330 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3337 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3342 guint8 *code = cfg->native_code + cfg->code_len;
3343 MonoInst *last_ins = NULL;
3344 guint last_offset = 0;
3348 /* we don't align basic blocks of loops on mips */
3350 if (cfg->verbose_level > 2)
3351 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3353 cpos = bb->max_offset;
3356 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3357 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3358 g_assert (!mono_compile_aot);
3361 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3362 /* this is not thread save, but good enough */
3363 /* fixme: howto handle overflows? */
3364 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3365 mips_lw (code, mips_temp, mips_at, 0);
3366 mips_addiu (code, mips_temp, mips_temp, 1);
3367 mips_sw (code, mips_temp, mips_at, 0);
3370 MONO_BB_FOR_EACH_INS (bb, ins) {
3371 offset = code - cfg->native_code;
3373 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3375 if (offset > (cfg->code_size - max_len - 16)) {
3376 cfg->code_size *= 2;
3377 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3378 code = cfg->native_code + offset;
3380 mono_debug_record_line_number (cfg, ins, offset);
3381 if (cfg->verbose_level > 2) {
3382 g_print (" @ 0x%x\t", offset);
3383 mono_print_ins_index (ins_cnt++, ins);
3385 /* Check for virtual regs that snuck by */
3386 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3388 switch (ins->opcode) {
3389 case OP_RELAXED_NOP:
3392 case OP_DUMMY_STORE:
3393 case OP_NOT_REACHED:
3396 case OP_IL_SEQ_POINT:
3397 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3399 case OP_SEQ_POINT: {
3400 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3401 guint32 addr = (guint32)ss_trigger_page;
3403 mips_load_const (code, mips_t9, addr);
3404 mips_lw (code, mips_t9, mips_t9, 0);
3407 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3410 * A placeholder for a possible breakpoint inserted by
3411 * mono_arch_set_breakpoint ().
3413 /* mips_load_const () + mips_lw */
3420 g_assert_not_reached();
3422 emit_tls_access (code, ins->dreg, ins->inst_offset);
3426 mips_mult (code, ins->sreg1, ins->sreg2);
3427 mips_mflo (code, ins->dreg);
3428 mips_mfhi (code, ins->dreg+1);
3431 mips_multu (code, ins->sreg1, ins->sreg2);
3432 mips_mflo (code, ins->dreg);
3433 mips_mfhi (code, ins->dreg+1);
3435 case OP_MEMORY_BARRIER:
3436 mips_sync (code, 0);
3438 case OP_STOREI1_MEMBASE_IMM:
3439 mips_load_const (code, mips_temp, ins->inst_imm);
3440 if (mips_is_imm16 (ins->inst_offset)) {
3441 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3443 mips_load_const (code, mips_at, ins->inst_offset);
3444 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3447 case OP_STOREI2_MEMBASE_IMM:
3448 mips_load_const (code, mips_temp, ins->inst_imm);
3449 if (mips_is_imm16 (ins->inst_offset)) {
3450 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3452 mips_load_const (code, mips_at, ins->inst_offset);
3453 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3456 case OP_STOREI8_MEMBASE_IMM:
3457 mips_load_const (code, mips_temp, ins->inst_imm);
3458 if (mips_is_imm16 (ins->inst_offset)) {
3459 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3461 mips_load_const (code, mips_at, ins->inst_offset);
3462 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3465 case OP_STORE_MEMBASE_IMM:
3466 case OP_STOREI4_MEMBASE_IMM:
3467 mips_load_const (code, mips_temp, ins->inst_imm);
3468 if (mips_is_imm16 (ins->inst_offset)) {
3469 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3471 mips_load_const (code, mips_at, ins->inst_offset);
3472 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3475 case OP_STOREI1_MEMBASE_REG:
3476 if (mips_is_imm16 (ins->inst_offset)) {
3477 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3479 mips_load_const (code, mips_at, ins->inst_offset);
3480 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3481 mips_sb (code, ins->sreg1, mips_at, 0);
3484 case OP_STOREI2_MEMBASE_REG:
3485 if (mips_is_imm16 (ins->inst_offset)) {
3486 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3488 mips_load_const (code, mips_at, ins->inst_offset);
3489 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3490 mips_sh (code, ins->sreg1, mips_at, 0);
3493 case OP_STORE_MEMBASE_REG:
3494 case OP_STOREI4_MEMBASE_REG:
3495 if (mips_is_imm16 (ins->inst_offset)) {
3496 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3498 mips_load_const (code, mips_at, ins->inst_offset);
3499 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3500 mips_sw (code, ins->sreg1, mips_at, 0);
3503 case OP_STOREI8_MEMBASE_REG:
3504 if (mips_is_imm16 (ins->inst_offset)) {
3505 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3507 mips_load_const (code, mips_at, ins->inst_offset);
3508 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3509 mips_sd (code, ins->sreg1, mips_at, 0);
3513 g_assert_not_reached ();
3514 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3515 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3517 case OP_LOADI8_MEMBASE:
3518 if (mips_is_imm16 (ins->inst_offset)) {
3519 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3521 mips_load_const (code, mips_at, ins->inst_offset);
3522 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3523 mips_ld (code, ins->dreg, mips_at, 0);
3526 case OP_LOAD_MEMBASE:
3527 case OP_LOADI4_MEMBASE:
3528 case OP_LOADU4_MEMBASE:
3529 g_assert (ins->dreg != -1);
3530 if (mips_is_imm16 (ins->inst_offset)) {
3531 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3533 mips_load_const (code, mips_at, ins->inst_offset);
3534 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3535 mips_lw (code, ins->dreg, mips_at, 0);
3538 case OP_LOADI1_MEMBASE:
3539 if (mips_is_imm16 (ins->inst_offset)) {
3540 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3542 mips_load_const (code, mips_at, ins->inst_offset);
3543 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3544 mips_lb (code, ins->dreg, mips_at, 0);
3547 case OP_LOADU1_MEMBASE:
3548 if (mips_is_imm16 (ins->inst_offset)) {
3549 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3551 mips_load_const (code, mips_at, ins->inst_offset);
3552 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3553 mips_lbu (code, ins->dreg, mips_at, 0);
3556 case OP_LOADI2_MEMBASE:
3557 if (mips_is_imm16 (ins->inst_offset)) {
3558 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3560 mips_load_const (code, mips_at, ins->inst_offset);
3561 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3562 mips_lh (code, ins->dreg, mips_at, 0);
3565 case OP_LOADU2_MEMBASE:
3566 if (mips_is_imm16 (ins->inst_offset)) {
3567 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3569 mips_load_const (code, mips_at, ins->inst_offset);
3570 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3571 mips_lhu (code, ins->dreg, mips_at, 0);
3574 case OP_ICONV_TO_I1:
3575 mips_sll (code, mips_at, ins->sreg1, 24);
3576 mips_sra (code, ins->dreg, mips_at, 24);
3578 case OP_ICONV_TO_I2:
3579 mips_sll (code, mips_at, ins->sreg1, 16);
3580 mips_sra (code, ins->dreg, mips_at, 16);
3582 case OP_ICONV_TO_U1:
3583 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3585 case OP_ICONV_TO_U2:
3586 mips_sll (code, mips_at, ins->sreg1, 16);
3587 mips_srl (code, ins->dreg, mips_at, 16);
3590 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3593 g_assert (mips_is_imm16 (ins->inst_imm));
3594 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3597 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3600 g_assert (mips_is_imm16 (ins->inst_imm));
3601 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3605 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3606 * So instead of emitting a trap, we emit a call a C function and place a
3609 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3610 (gpointer)"mono_break");
3611 mips_load (code, mips_t9, 0x1f1f1f1f);
3612 mips_jalr (code, mips_t9, mips_ra);
3616 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3619 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3624 g_assert (mips_is_imm16 (ins->inst_imm));
3625 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3628 g_assert (mips_is_imm16 (ins->inst_imm));
3629 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3633 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3636 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3641 // we add the negated value
3642 g_assert (mips_is_imm16 (-ins->inst_imm));
3643 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3647 // we add the negated value
3648 g_assert (mips_is_imm16 (-ins->inst_imm));
3649 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3654 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3660 g_assert (!(ins->inst_imm & 0xffff0000));
3661 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3666 guint32 *divisor_is_m1;
3667 guint32 *dividend_is_minvalue;
3668 guint32 *divisor_is_zero;
3670 mips_load_const (code, mips_at, -1);
3671 divisor_is_m1 = (guint32 *)(void *)code;
3672 mips_bne (code, ins->sreg2, mips_at, 0);
3673 mips_lui (code, mips_at, mips_zero, 0x8000);
3674 dividend_is_minvalue = (guint32 *)(void *)code;
3675 mips_bne (code, ins->sreg1, mips_at, 0);
3678 /* Divide Int32.MinValue by -1 -- throw exception */
3679 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3681 mips_patch (divisor_is_m1, (guint32)code);
3682 mips_patch (dividend_is_minvalue, (guint32)code);
3684 /* Put divide in branch delay slot (NOT YET) */
3685 divisor_is_zero = (guint32 *)(void *)code;
3686 mips_bne (code, ins->sreg2, mips_zero, 0);
3689 /* Divide by zero -- throw exception */
3690 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3692 mips_patch (divisor_is_zero, (guint32)code);
3693 mips_div (code, ins->sreg1, ins->sreg2);
3694 if (ins->opcode == OP_IDIV)
3695 mips_mflo (code, ins->dreg);
3697 mips_mfhi (code, ins->dreg);
3702 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3704 /* Put divide in branch delay slot (NOT YET) */
3705 mips_bne (code, ins->sreg2, mips_zero, 0);
3708 /* Divide by zero -- throw exception */
3709 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3711 mips_patch (divisor_is_zero, (guint32)code);
3712 mips_divu (code, ins->sreg1, ins->sreg2);
3713 if (ins->opcode == OP_IDIV_UN)
3714 mips_mflo (code, ins->dreg);
3716 mips_mfhi (code, ins->dreg);
3720 g_assert_not_reached ();
3722 ppc_load (code, ppc_r12, ins->inst_imm);
3723 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3724 ppc_mfspr (code, ppc_r0, ppc_xer);
3725 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3726 /* FIXME: use OverflowException for 0x80000000/-1 */
3727 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3729 g_assert_not_reached();
3732 g_assert_not_reached ();
3734 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3738 g_assert (!(ins->inst_imm & 0xffff0000));
3739 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3742 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3746 /* unsigned 16-bit immediate */
3747 g_assert (!(ins->inst_imm & 0xffff0000));
3748 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3751 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3755 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3758 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3761 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3765 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3768 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3771 case OP_ISHR_UN_IMM:
3772 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3774 case OP_LSHR_UN_IMM:
3775 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3778 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3781 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3785 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3788 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3791 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3795 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3797 mips_mult (code, ins->sreg1, ins->sreg2);
3798 mips_mflo (code, ins->dreg);
3803 #if SIZEOF_REGISTER == 8
3805 mips_dmult (code, ins->sreg1, ins->sreg2);
3806 mips_mflo (code, ins->dreg);
3811 mips_mult (code, ins->sreg1, ins->sreg2);
3812 mips_mflo (code, ins->dreg);
3813 mips_mfhi (code, mips_at);
3816 mips_sra (code, mips_temp, ins->dreg, 31);
3817 patch = (guint32 *)(void *)code;
3818 mips_beq (code, mips_temp, mips_at, 0);
3820 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3821 mips_patch (patch, (guint32)code);
3824 case OP_IMUL_OVF_UN: {
3826 mips_mult (code, ins->sreg1, ins->sreg2);
3827 mips_mflo (code, ins->dreg);
3828 mips_mfhi (code, mips_at);
3831 patch = (guint32 *)(void *)code;
3832 mips_beq (code, mips_at, mips_zero, 0);
3834 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3835 mips_patch (patch, (guint32)code);
3839 mips_load_const (code, ins->dreg, ins->inst_c0);
3841 #if SIZEOF_REGISTER == 8
3843 mips_load_const (code, ins->dreg, ins->inst_c0);
3847 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3848 mips_load (code, ins->dreg, 0);
3852 mips_mtc1 (code, ins->dreg, ins->sreg1);
3854 case OP_MIPS_MTC1S_2:
3855 mips_mtc1 (code, ins->dreg, ins->sreg1);
3856 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3859 mips_mfc1 (code, ins->dreg, ins->sreg1);
3862 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3866 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3868 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3869 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3873 case OP_ICONV_TO_I4:
3874 case OP_ICONV_TO_U4:
3876 if (ins->dreg != ins->sreg1)
3877 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3879 #if SIZEOF_REGISTER == 8
3881 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3882 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3885 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3886 mips_dsra (code, ins->dreg, ins->dreg, 32);
3890 int lsreg = mips_v0 + ls_word_idx;
3891 int msreg = mips_v0 + ms_word_idx;
3893 /* Get sreg1 into lsreg, sreg2 into msreg */
3895 if (ins->sreg1 == msreg) {
3896 if (ins->sreg1 != mips_at)
3897 MIPS_MOVE (code, mips_at, ins->sreg1);
3898 if (ins->sreg2 != msreg)
3899 MIPS_MOVE (code, msreg, ins->sreg2);
3900 MIPS_MOVE (code, lsreg, mips_at);
3903 if (ins->sreg2 != msreg)
3904 MIPS_MOVE (code, msreg, ins->sreg2);
3905 if (ins->sreg1 != lsreg)
3906 MIPS_MOVE (code, lsreg, ins->sreg1);
3911 if (ins->dreg != ins->sreg1) {
3912 mips_fmovd (code, ins->dreg, ins->sreg1);
3915 case OP_MOVE_F_TO_I4:
3916 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3917 mips_mfc1 (code, ins->dreg, mips_ftemp);
3919 case OP_MOVE_I4_TO_F:
3920 mips_mtc1 (code, ins->dreg, ins->sreg1);
3921 mips_cvtds (code, ins->dreg, ins->dreg);
3924 /* Convert from double to float and leave it there */
3925 mips_cvtsd (code, ins->dreg, ins->sreg1);
3927 case OP_FCONV_TO_R4:
3929 mips_cvtsd (code, ins->dreg, ins->sreg1);
3931 /* Just a move, no precision change */
3932 if (ins->dreg != ins->sreg1) {
3933 mips_fmovd (code, ins->dreg, ins->sreg1);
3938 code = emit_load_volatile_arguments(cfg, code);
3941 * Pop our stack, then jump to specified method (tail-call)
3942 * Keep in sync with mono_arch_emit_epilog
3944 code = mono_arch_emit_epilog_sub (cfg, code);
3946 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3947 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3948 mips_load (code, mips_t9, 0);
3949 mips_jr (code, mips_t9);
3953 /* ensure ins->sreg1 is not NULL */
3954 mips_lw (code, mips_zero, ins->sreg1, 0);
3957 g_assert (mips_is_imm16 (cfg->sig_cookie));
3958 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3959 mips_sw (code, mips_at, ins->sreg1, 0);
3972 case OP_VOIDCALL_REG:
3974 case OP_FCALL_MEMBASE:
3975 case OP_LCALL_MEMBASE:
3976 case OP_VCALL_MEMBASE:
3977 case OP_VCALL2_MEMBASE:
3978 case OP_VOIDCALL_MEMBASE:
3979 case OP_CALL_MEMBASE:
3980 call = (MonoCallInst*)ins;
3981 switch (ins->opcode) {
3988 if (ins->flags & MONO_INST_HAS_METHOD) {
3989 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3990 mips_load (code, mips_t9, call->method);
3993 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3994 mips_load (code, mips_t9, call->fptr);
3996 mips_jalr (code, mips_t9, mips_ra);
4003 case OP_VOIDCALL_REG:
4005 MIPS_MOVE (code, mips_t9, ins->sreg1);
4006 mips_jalr (code, mips_t9, mips_ra);
4009 case OP_FCALL_MEMBASE:
4010 case OP_LCALL_MEMBASE:
4011 case OP_VCALL_MEMBASE:
4012 case OP_VCALL2_MEMBASE:
4013 case OP_VOIDCALL_MEMBASE:
4014 case OP_CALL_MEMBASE:
4015 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
4016 mips_jalr (code, mips_t9, mips_ra);
4020 #if PROMOTE_R4_TO_R8
4021 /* returned an FP R4 (single), promote to R8 (double) in place */
4022 switch (ins->opcode) {
4025 case OP_FCALL_MEMBASE:
4026 if (call->signature->ret->type == MONO_TYPE_R4)
4027 mips_cvtds (code, mips_f0, mips_f0);
4035 int area_offset = cfg->param_area;
4037 /* Round up ins->sreg1, mips_at ends up holding size */
4038 mips_addiu (code, mips_at, ins->sreg1, 31);
4039 mips_addiu (code, mips_temp, mips_zero, ~31);
4040 mips_and (code, mips_at, mips_at, mips_temp);
4042 mips_subu (code, mips_sp, mips_sp, mips_at);
4043 g_assert (mips_is_imm16 (area_offset));
4044 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4046 if (ins->flags & MONO_INST_INIT) {
4049 buf = (guint32*)(void*)code;
4050 mips_beq (code, mips_at, mips_zero, 0);
4053 mips_move (code, mips_temp, ins->dreg);
4054 mips_sb (code, mips_zero, mips_temp, 0);
4055 mips_addiu (code, mips_at, mips_at, -1);
4056 mips_bne (code, mips_at, mips_zero, -3);
4057 mips_addiu (code, mips_temp, mips_temp, 1);
4059 mips_patch (buf, (guint32)code);
4064 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4065 mips_move (code, mips_a0, ins->sreg1);
4066 mips_call (code, mips_t9, addr);
4067 mips_break (code, 0xfc);
4071 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4072 mips_move (code, mips_a0, ins->sreg1);
4073 mips_call (code, mips_t9, addr);
4074 mips_break (code, 0xfb);
4077 case OP_START_HANDLER: {
4079 * The START_HANDLER instruction marks the beginning of
4080 * a handler block. It is called using a call
4081 * instruction, so mips_ra contains the return address.
4082 * Since the handler executes in the same stack frame
4083 * as the method itself, we can't use save/restore to
4084 * save the return address. Instead, we save it into
4085 * a dedicated variable.
4087 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4088 g_assert (spvar->inst_basereg != mips_sp);
4089 code = emit_reserve_param_area (cfg, code);
4091 if (mips_is_imm16 (spvar->inst_offset)) {
4092 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4094 mips_load_const (code, mips_at, spvar->inst_offset);
4095 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4096 mips_sw (code, mips_ra, mips_at, 0);
4100 case OP_ENDFILTER: {
4101 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4102 g_assert (spvar->inst_basereg != mips_sp);
4103 code = emit_unreserve_param_area (cfg, code);
4105 if (ins->sreg1 != mips_v0)
4106 MIPS_MOVE (code, mips_v0, ins->sreg1);
4107 if (mips_is_imm16 (spvar->inst_offset)) {
4108 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4110 mips_load_const (code, mips_at, spvar->inst_offset);
4111 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4112 mips_lw (code, mips_ra, mips_at, 0);
4114 mips_jr (code, mips_ra);
4118 case OP_ENDFINALLY: {
4119 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4120 g_assert (spvar->inst_basereg != mips_sp);
4121 code = emit_unreserve_param_area (cfg, code);
4122 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4123 mips_jalr (code, mips_t9, mips_ra);
4127 case OP_CALL_HANDLER:
4128 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4129 mips_lui (code, mips_t9, mips_zero, 0);
4130 mips_addiu (code, mips_t9, mips_t9, 0);
4131 mips_jalr (code, mips_t9, mips_ra);
4133 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4134 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4137 ins->inst_c0 = code - cfg->native_code;
4140 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4141 if (cfg->arch.long_branch) {
4142 mips_lui (code, mips_at, mips_zero, 0);
4143 mips_addiu (code, mips_at, mips_at, 0);
4144 mips_jr (code, mips_at);
4148 mips_beq (code, mips_zero, mips_zero, 0);
4153 mips_jr (code, ins->sreg1);
4159 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4160 if (offset > (cfg->code_size - max_len - 16)) {
4161 cfg->code_size += max_len;
4162 cfg->code_size *= 2;
4163 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4164 code = cfg->native_code + offset;
4166 g_assert (ins->sreg1 != -1);
4167 mips_sll (code, mips_at, ins->sreg1, 2);
4168 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4169 MIPS_MOVE (code, mips_t8, mips_ra);
4170 mips_bgezal (code, mips_zero, 1); /* bal */
4172 mips_addu (code, mips_t9, mips_ra, mips_at);
4173 /* Table is 16 or 20 bytes from target of bal above */
4174 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4175 MIPS_MOVE (code, mips_ra, mips_t8);
4176 mips_lw (code, mips_t9, mips_t9, 20);
4179 mips_lw (code, mips_t9, mips_t9, 16);
4180 mips_jalr (code, mips_t9, mips_t8);
4182 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4183 mips_emit32 (code, 0xfefefefe);
4188 mips_addiu (code, ins->dreg, mips_zero, 1);
4189 mips_beq (code, mips_at, mips_zero, 2);
4191 MIPS_MOVE (code, ins->dreg, mips_zero);
4197 mips_addiu (code, ins->dreg, mips_zero, 1);
4198 mips_bltz (code, mips_at, 2);
4200 MIPS_MOVE (code, ins->dreg, mips_zero);
4206 mips_addiu (code, ins->dreg, mips_zero, 1);
4207 mips_bgtz (code, mips_at, 2);
4209 MIPS_MOVE (code, ins->dreg, mips_zero);
4212 case OP_MIPS_COND_EXC_EQ:
4213 case OP_MIPS_COND_EXC_GE:
4214 case OP_MIPS_COND_EXC_GT:
4215 case OP_MIPS_COND_EXC_LE:
4216 case OP_MIPS_COND_EXC_LT:
4217 case OP_MIPS_COND_EXC_NE_UN:
4218 case OP_MIPS_COND_EXC_GE_UN:
4219 case OP_MIPS_COND_EXC_GT_UN:
4220 case OP_MIPS_COND_EXC_LE_UN:
4221 case OP_MIPS_COND_EXC_LT_UN:
4223 case OP_MIPS_COND_EXC_OV:
4224 case OP_MIPS_COND_EXC_NO:
4225 case OP_MIPS_COND_EXC_C:
4226 case OP_MIPS_COND_EXC_NC:
4228 case OP_MIPS_COND_EXC_IEQ:
4229 case OP_MIPS_COND_EXC_IGE:
4230 case OP_MIPS_COND_EXC_IGT:
4231 case OP_MIPS_COND_EXC_ILE:
4232 case OP_MIPS_COND_EXC_ILT:
4233 case OP_MIPS_COND_EXC_INE_UN:
4234 case OP_MIPS_COND_EXC_IGE_UN:
4235 case OP_MIPS_COND_EXC_IGT_UN:
4236 case OP_MIPS_COND_EXC_ILE_UN:
4237 case OP_MIPS_COND_EXC_ILT_UN:
4239 case OP_MIPS_COND_EXC_IOV:
4240 case OP_MIPS_COND_EXC_INO:
4241 case OP_MIPS_COND_EXC_IC:
4242 case OP_MIPS_COND_EXC_INC: {
4246 /* If the condition is true, raise the exception */
4248 /* need to reverse test to skip around exception raising */
4250 /* For the moment, branch around a branch to avoid reversing
4253 /* Remember, an unpatched branch to 0 branches to the delay slot */
4254 switch (ins->opcode) {
4255 case OP_MIPS_COND_EXC_EQ:
4256 throw = (guint32 *)(void *)code;
4257 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4261 case OP_MIPS_COND_EXC_NE_UN:
4262 throw = (guint32 *)(void *)code;
4263 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4267 case OP_MIPS_COND_EXC_LE_UN:
4268 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4269 throw = (guint32 *)(void *)code;
4270 mips_beq (code, mips_at, mips_zero, 0);
4274 case OP_MIPS_COND_EXC_GT:
4275 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4276 throw = (guint32 *)(void *)code;
4277 mips_bne (code, mips_at, mips_zero, 0);
4281 case OP_MIPS_COND_EXC_GT_UN:
4282 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4283 throw = (guint32 *)(void *)code;
4284 mips_bne (code, mips_at, mips_zero, 0);
4288 case OP_MIPS_COND_EXC_LT:
4289 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4290 throw = (guint32 *)(void *)code;
4291 mips_bne (code, mips_at, mips_zero, 0);
4295 case OP_MIPS_COND_EXC_LT_UN:
4296 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4297 throw = (guint32 *)(void *)code;
4298 mips_bne (code, mips_at, mips_zero, 0);
4303 /* Not yet implemented */
4304 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4305 g_assert_not_reached ();
4307 skip = (guint32 *)(void *)code;
4308 mips_beq (code, mips_zero, mips_zero, 0);
4310 mips_patch (throw, (guint32)code);
4311 code = mips_emit_exc_by_name (code, ins->inst_p1);
4312 mips_patch (skip, (guint32)code);
4313 cfg->bb_exit->max_offset += 24;
4322 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4325 /* floating point opcodes */
4328 if (((guint32)ins->inst_p0) & (1 << 15))
4329 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4331 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4332 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4334 mips_load_const (code, mips_at, ins->inst_p0);
4335 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4336 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4340 if (((guint32)ins->inst_p0) & (1 << 15))
4341 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4343 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4344 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4345 #if PROMOTE_R4_TO_R8
4346 mips_cvtds (code, ins->dreg, ins->dreg);
4349 case OP_STORER8_MEMBASE_REG:
4350 if (mips_is_imm16 (ins->inst_offset)) {
4351 #if _MIPS_SIM == _ABIO32
4352 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4353 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4354 #elif _MIPS_SIM == _ABIN32
4355 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4358 mips_load_const (code, mips_at, ins->inst_offset);
4359 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4360 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4361 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4364 case OP_LOADR8_MEMBASE:
4365 if (mips_is_imm16 (ins->inst_offset)) {
4366 #if _MIPS_SIM == _ABIO32
4367 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4368 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4369 #elif _MIPS_SIM == _ABIN32
4370 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4373 mips_load_const (code, mips_at, ins->inst_offset);
4374 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4375 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4376 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4379 case OP_STORER4_MEMBASE_REG:
4380 g_assert (mips_is_imm16 (ins->inst_offset));
4381 #if PROMOTE_R4_TO_R8
4382 /* Need to convert ins->sreg1 to single-precision first */
4383 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4384 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4386 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4390 g_assert (mips_is_imm16 (ins->inst_offset));
4391 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4393 case OP_LOADR4_MEMBASE:
4394 g_assert (mips_is_imm16 (ins->inst_offset));
4395 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4396 #if PROMOTE_R4_TO_R8
4397 /* Convert to double precision in place */
4398 mips_cvtds (code, ins->dreg, ins->dreg);
4401 case OP_LOADR4_MEMINDEX:
4402 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4403 mips_lwc1 (code, ins->dreg, mips_at, 0);
4405 case OP_LOADR8_MEMINDEX:
4406 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4407 #if _MIPS_SIM == _ABIO32
4408 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4409 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4410 #elif _MIPS_SIM == _ABIN32
4411 mips_ldc1 (code, ins->dreg, mips_at, 0);
4414 case OP_STORER4_MEMINDEX:
4415 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4416 #if PROMOTE_R4_TO_R8
4417 /* Need to convert ins->sreg1 to single-precision first */
4418 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4419 mips_swc1 (code, mips_ftemp, mips_at, 0);
4421 mips_swc1 (code, ins->sreg1, mips_at, 0);
4424 case OP_STORER8_MEMINDEX:
4425 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4426 #if _MIPS_SIM == _ABIO32
4427 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4428 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4429 #elif _MIPS_SIM == _ABIN32
4430 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4433 case OP_ICONV_TO_R_UN: {
4434 static const guint64 adjust_val = 0x41F0000000000000ULL;
4436 /* convert unsigned int to double */
4437 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4438 mips_bgez (code, ins->sreg1, 5);
4439 mips_cvtdw (code, ins->dreg, mips_ftemp);
4441 mips_load (code, mips_at, (guint32) &adjust_val);
4442 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4443 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4444 /* target is here */
4447 case OP_ICONV_TO_R4:
4448 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4449 mips_cvtsw (code, ins->dreg, mips_ftemp);
4450 mips_cvtds (code, ins->dreg, ins->dreg);
4452 case OP_ICONV_TO_R8:
4453 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4454 mips_cvtdw (code, ins->dreg, mips_ftemp);
4456 case OP_FCONV_TO_I1:
4457 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4459 case OP_FCONV_TO_U1:
4460 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4462 case OP_FCONV_TO_I2:
4463 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4465 case OP_FCONV_TO_U2:
4466 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4468 case OP_FCONV_TO_I4:
4470 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4472 case OP_FCONV_TO_U4:
4474 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4477 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4480 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4483 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4486 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4489 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4492 mips_fnegd (code, ins->dreg, ins->sreg1);
4495 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4496 mips_addiu (code, ins->dreg, mips_zero, 1);
4497 mips_fbtrue (code, 2);
4499 MIPS_MOVE (code, ins->dreg, mips_zero);
4502 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4503 mips_addiu (code, ins->dreg, mips_zero, 1);
4504 mips_fbtrue (code, 2);
4506 MIPS_MOVE (code, ins->dreg, mips_zero);
4509 /* Less than, or Unordered */
4510 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4511 mips_addiu (code, ins->dreg, mips_zero, 1);
4512 mips_fbtrue (code, 2);
4514 MIPS_MOVE (code, ins->dreg, mips_zero);
4517 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4518 MIPS_MOVE (code, ins->dreg, mips_zero);
4519 mips_fbtrue (code, 2);
4521 mips_addiu (code, ins->dreg, mips_zero, 1);
4524 /* Greater than, or Unordered */
4525 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4526 MIPS_MOVE (code, ins->dreg, mips_zero);
4527 mips_fbtrue (code, 2);
4529 mips_addiu (code, ins->dreg, mips_zero, 1);
4534 case OP_MIPS_FBLT_UN:
4536 case OP_MIPS_FBGT_UN:
4538 case OP_MIPS_FBGE_UN:
4540 case OP_MIPS_FBLE_UN: {
4542 gboolean is_true = TRUE, is_ordered = FALSE;
4543 guint32 *buf = NULL;
4545 switch (ins->opcode) {
4559 case OP_MIPS_FBLT_UN:
4560 cond = MIPS_FPU_ULT;
4568 case OP_MIPS_FBGT_UN:
4569 cond = MIPS_FPU_OLE;
4577 case OP_MIPS_FBGE_UN:
4578 cond = MIPS_FPU_OLT;
4582 cond = MIPS_FPU_OLE;
4586 case OP_MIPS_FBLE_UN:
4587 cond = MIPS_FPU_ULE;
4591 g_assert_not_reached ();
4595 /* Skip the check if unordered */
4596 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4598 buf = (guint32*)code;
4599 mips_fbtrue (code, 0);
4603 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4605 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4607 mips_fbtrue (code, 0);
4609 mips_fbfalse (code, 0);
4613 mips_patch (buf, (guint32)code);
4617 guint32 *branch_patch;
4619 mips_mfc1 (code, mips_at, ins->sreg1+1);
4620 mips_srl (code, mips_at, mips_at, 16+4);
4621 mips_andi (code, mips_at, mips_at, 2047);
4622 mips_addiu (code, mips_at, mips_at, -2047);
4624 branch_patch = (guint32 *)(void *)code;
4625 mips_bne (code, mips_at, mips_zero, 0);
4628 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4629 mips_patch (branch_patch, (guint32)code);
4630 mips_fmovd (code, ins->dreg, ins->sreg1);
4634 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4635 mips_load (code, ins->dreg, 0x0f0f0f0f);
4640 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4641 g_assert_not_reached ();
4644 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4645 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4646 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4647 g_assert_not_reached ();
4653 last_offset = offset;
4656 cfg->code_len = code - cfg->native_code;
4660 mono_arch_register_lowlevel_calls (void)
4665 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4667 MonoJumpInfo *patch_info;
4669 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4670 unsigned char *ip = patch_info->ip.i + code;
4671 const unsigned char *target = NULL;
4673 switch (patch_info->type) {
4674 case MONO_PATCH_INFO_IP:
4675 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4677 case MONO_PATCH_INFO_SWITCH: {
4678 gpointer *table = (gpointer *)patch_info->data.table->table;
4681 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4683 for (i = 0; i < patch_info->data.table->table_size; i++) {
4684 table [i] = (int)patch_info->data.table->table [i] + code;
4688 case MONO_PATCH_INFO_METHODCONST:
4689 case MONO_PATCH_INFO_CLASS:
4690 case MONO_PATCH_INFO_IMAGE:
4691 case MONO_PATCH_INFO_FIELD:
4692 case MONO_PATCH_INFO_VTABLE:
4693 case MONO_PATCH_INFO_IID:
4694 case MONO_PATCH_INFO_SFLDA:
4695 case MONO_PATCH_INFO_LDSTR:
4696 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4697 case MONO_PATCH_INFO_LDTOKEN:
4698 case MONO_PATCH_INFO_R4:
4699 case MONO_PATCH_INFO_R8:
4700 /* from OP_AOTCONST : lui + addiu */
4701 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4702 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4705 case MONO_PATCH_INFO_EXC_NAME:
4706 g_assert_not_reached ();
4707 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4710 case MONO_PATCH_INFO_NONE:
4711 /* everything is dealt with at epilog output time */
4714 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4715 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4722 * Allow tracing to work with this interface (with an optional argument)
4724 * This code is expected to be inserted just after the 'real' prolog code,
4725 * and before the first basic block. We need to allocate a 2nd, temporary
4726 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4730 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4733 int offset = cfg->arch.tracing_offset;
4739 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4740 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4741 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4742 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4743 #if _MIPS_SIM == _ABIN32
4745 /* FIXME: Need a separate region for these */
4746 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4747 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4748 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4749 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4753 mips_load_const (code, mips_a0, cfg->method);
4754 mips_addiu (code, mips_a1, mips_sp, offset);
4755 mips_call (code, mips_t9, func);
4758 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4759 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4760 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4761 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4762 #if _MIPS_SIM == _ABIN32
4765 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4766 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4767 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4768 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4779 mips_adjust_stackframe(MonoCompile *cfg)
4782 int delta, threshold, i;
4783 MonoMethodSignature *sig;
4786 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4789 /* adjust cfg->stack_offset for account for down-spilling */
4790 cfg->stack_offset += SIZEOF_REGISTER;
4792 /* re-align cfg->stack_offset if needed (due to var spilling) */
4793 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4794 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4795 if (cfg->verbose_level > 2) {
4796 g_print ("mips_adjust_stackframe:\n");
4797 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4799 threshold = cfg->arch.local_alloc_offset;
4800 ra_offset = cfg->stack_offset - sizeof(gpointer);
4801 if (cfg->verbose_level > 2) {
4802 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4805 sig = mono_method_signature (cfg->method);
4806 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4807 cfg->vret_addr->inst_offset += delta;
4809 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4810 MonoInst *inst = cfg->args [i];
4812 inst->inst_offset += delta;
4816 * loads and stores based off the frame reg that (used to) lie
4817 * above the spill var area need to be increased by 'delta'
4818 * to make room for the spill vars.
4820 /* Need to find loads and stores to adjust that
4821 * are above where the spillvars were inserted, but
4822 * which are not the spillvar references themselves.
4824 * Idea - since all offsets from fp are positive, make
4825 * spillvar offsets negative to begin with so we can spot
4830 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4834 if (cfg->verbose_level > 2) {
4835 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4837 MONO_BB_FOR_EACH_INS (bb, ins) {
4841 if (cfg->verbose_level > 2) {
4842 mono_print_ins_index (ins_cnt, ins);
4844 /* The == mips_sp tests catch FP spills */
4845 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4846 (ins->inst_basereg == mips_sp))) {
4847 switch (ins->opcode) {
4848 case OP_LOADI8_MEMBASE:
4849 case OP_LOADR8_MEMBASE:
4856 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4857 (ins->dreg == mips_sp))) {
4858 switch (ins->opcode) {
4859 case OP_STOREI8_MEMBASE_REG:
4860 case OP_STORER8_MEMBASE_REG:
4861 case OP_STOREI8_MEMBASE_IMM:
4869 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4872 if (ins->inst_c0 >= threshold) {
4873 ins->inst_c0 += delta;
4874 if (cfg->verbose_level > 2) {
4876 mono_print_ins_index (ins_cnt, ins);
4879 else if (ins->inst_c0 < 0) {
4880 /* Adj_c0 holds the size of the datatype. */
4881 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4882 if (cfg->verbose_level > 2) {
4884 mono_print_ins_index (ins_cnt, ins);
4887 g_assert (ins->inst_c0 != ra_offset);
4890 if (ins->inst_imm >= threshold) {
4891 ins->inst_imm += delta;
4892 if (cfg->verbose_level > 2) {
4894 mono_print_ins_index (ins_cnt, ins);
4897 g_assert (ins->inst_c0 != ra_offset);
4907 * Stack frame layout:
4909 * ------------------- sp + cfg->stack_usage + cfg->param_area
4910 * param area incoming
4911 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4913 * ------------------- sp + cfg->stack_usage
4915 * ------------------- sp + cfg->stack_usage-4
4917 * ------------------- sp +
4918 * MonoLMF structure optional
4919 * ------------------- sp + cfg->arch.lmf_offset
4920 * saved registers s0-s8
4921 * ------------------- sp + cfg->arch.iregs_offset
4923 * ------------------- sp + cfg->param_area
4924 * param area outgoing
4925 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4927 * ------------------- sp
4931 mono_arch_emit_prolog (MonoCompile *cfg)
4933 MonoMethod *method = cfg->method;
4934 MonoMethodSignature *sig;
4936 int alloc_size, pos, i, max_offset;
4937 int alloc2_size = 0;
4941 guint32 iregs_to_save = 0;
4943 guint32 fregs_to_save = 0;
4945 /* lmf_offset is the offset of the LMF from our stack pointer. */
4946 guint32 lmf_offset = cfg->arch.lmf_offset;
4950 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4954 cfg->flags |= MONO_CFG_HAS_CALLS;
4956 sig = mono_method_signature (method);
4957 cfg->code_size = 768 + sig->param_count * 20;
4958 code = cfg->native_code = g_malloc (cfg->code_size);
4961 * compute max_offset in order to use short forward jumps.
4964 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4965 MonoInst *ins = bb->code;
4966 bb->max_offset = max_offset;
4968 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4971 MONO_BB_FOR_EACH_INS (bb, ins)
4972 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4974 if (max_offset > 0xffff)
4975 cfg->arch.long_branch = TRUE;
4978 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4979 * This means that we have to adjust the offsets inside instructions which reference
4980 * arguments received on the stack, since the initial offset doesn't take into
4981 * account spill slots.
4983 mips_adjust_stackframe (cfg);
4985 /* Offset between current sp and the CFA */
4987 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4989 /* stack_offset should not be changed here. */
4990 alloc_size = cfg->stack_offset;
4991 cfg->stack_usage = alloc_size;
4993 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4996 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4998 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4999 fregs_to_save |= (fregs_to_save << 1);
5002 /* If the stack size is too big, save 1024 bytes to start with
5003 * so the prologue can use imm16(reg) addressing, then allocate
5004 * the rest of the frame.
5006 if (alloc_size > ((1 << 15) - 1024)) {
5007 alloc2_size = alloc_size - 1024;
5011 g_assert (mips_is_imm16 (-alloc_size));
5012 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
5013 cfa_offset = alloc_size;
5014 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5017 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5018 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5019 if (mips_is_imm16(offset))
5020 mips_sw (code, mips_ra, mips_sp, offset);
5022 g_assert_not_reached ();
5024 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5025 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5028 /* XXX - optimize this later to not save all regs if LMF constructed */
5029 pos = cfg->arch.iregs_offset - alloc2_size;
5031 if (iregs_to_save) {
5032 /* save used registers in own stack frame (at pos) */
5033 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5034 if (iregs_to_save & (1 << i)) {
5035 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5036 g_assert (mips_is_imm16(pos));
5037 MIPS_SW (code, i, mips_sp, pos);
5038 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5039 pos += SIZEOF_REGISTER;
5044 // FIXME: Don't save registers twice if there is an LMF
5045 // s8 has to be special cased since it is overwritten with the updated value
5047 if (method->save_lmf) {
5048 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5049 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5050 g_assert (mips_is_imm16(offset));
5051 if (MIPS_LMF_IREGMASK & (1 << i))
5052 MIPS_SW (code, i, mips_sp, offset);
5057 /* Save float registers */
5058 if (fregs_to_save) {
5059 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5060 if (fregs_to_save & (1 << i)) {
5061 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5062 g_assert (mips_is_imm16(pos));
5063 mips_swc1 (code, i, mips_sp, pos);
5064 pos += sizeof (gulong);
5069 if (method->save_lmf) {
5070 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5071 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5072 g_assert (mips_is_imm16(offset));
5073 mips_swc1 (code, i, mips_sp, offset);
5078 if (cfg->frame_reg != mips_sp) {
5079 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5080 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5082 if (method->save_lmf) {
5083 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5084 g_assert (mips_is_imm16(offset));
5085 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5089 /* store runtime generic context */
5090 if (cfg->rgctx_var) {
5091 MonoInst *ins = cfg->rgctx_var;
5093 g_assert (ins->opcode == OP_REGOFFSET);
5095 g_assert (mips_is_imm16 (ins->inst_offset));
5096 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5099 /* load arguments allocated to register from the stack */
5102 if (!cfg->arch.cinfo)
5103 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
5104 cinfo = cfg->arch.cinfo;
5106 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5107 ArgInfo *ainfo = &cinfo->ret;
5108 inst = cfg->vret_addr;
5109 if (inst->opcode == OP_REGVAR)
5110 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5111 else if (mips_is_imm16 (inst->inst_offset)) {
5112 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5114 mips_load_const (code, mips_at, inst->inst_offset);
5115 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5116 mips_sw (code, ainfo->reg, mips_at, 0);
5120 if (sig->call_convention == MONO_CALL_VARARG) {
5121 ArgInfo *cookie = &cinfo->sig_cookie;
5122 int offset = alloc_size + cookie->offset;
5124 /* Save the sig cookie address */
5125 g_assert (cookie->storage == ArgOnStack);
5127 g_assert (mips_is_imm16(offset));
5128 mips_addi (code, mips_at, cfg->frame_reg, offset);
5129 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5132 /* Keep this in sync with emit_load_volatile_arguments */
5133 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5134 ArgInfo *ainfo = cinfo->args + i;
5135 inst = cfg->args [pos];
5137 if (cfg->verbose_level > 2)
5138 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5139 if (inst->opcode == OP_REGVAR) {
5140 /* Argument ends up in a register */
5141 if (ainfo->storage == ArgInIReg)
5142 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5143 else if (ainfo->storage == ArgInFReg) {
5144 g_assert_not_reached();
5146 ppc_fmr (code, inst->dreg, ainfo->reg);
5149 else if (ainfo->storage == ArgOnStack) {
5150 int offset = cfg->stack_usage + ainfo->offset;
5151 g_assert (mips_is_imm16(offset));
5152 mips_lw (code, inst->dreg, mips_sp, offset);
5154 g_assert_not_reached ();
5156 if (cfg->verbose_level > 2)
5157 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5159 /* Argument ends up on the stack */
5160 if (ainfo->storage == ArgInIReg) {
5162 /* Incoming parameters should be above this frame */
5163 if (cfg->verbose_level > 2)
5164 g_print ("stack slot at %d of %d+%d\n",
5165 inst->inst_offset, alloc_size, alloc2_size);
5166 /* g_assert (inst->inst_offset >= alloc_size); */
5167 g_assert (inst->inst_basereg == cfg->frame_reg);
5168 basereg_offset = inst->inst_offset - alloc2_size;
5169 g_assert (mips_is_imm16 (basereg_offset));
5170 switch (ainfo->size) {
5172 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5175 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5179 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5182 #if (SIZEOF_REGISTER == 4)
5183 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5184 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5185 #elif (SIZEOF_REGISTER == 8)
5186 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5190 g_assert_not_reached ();
5193 } else if (ainfo->storage == ArgOnStack) {
5195 * Argument comes in on the stack, and ends up on the stack
5196 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5197 * 8 and 16 bit quantities. Shorten them in place.
5199 g_assert (mips_is_imm16 (inst->inst_offset));
5200 switch (ainfo->size) {
5202 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5203 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5206 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5207 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5214 g_assert_not_reached ();
5216 } else if (ainfo->storage == ArgInFReg) {
5217 g_assert (mips_is_imm16 (inst->inst_offset));
5218 g_assert (mips_is_imm16 (inst->inst_offset+4));
5219 if (ainfo->size == 8) {
5220 #if _MIPS_SIM == _ABIO32
5221 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5222 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5223 #elif _MIPS_SIM == _ABIN32
5224 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5227 else if (ainfo->size == 4)
5228 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5230 g_assert_not_reached ();
5231 } else if (ainfo->storage == ArgStructByVal) {
5233 int doffset = inst->inst_offset;
5235 g_assert (mips_is_imm16 (inst->inst_offset));
5236 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5237 /* Push the argument registers into their stack slots */
5238 for (i = 0; i < ainfo->size; ++i) {
5239 g_assert (mips_is_imm16(doffset));
5240 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5241 doffset += SIZEOF_REGISTER;
5243 } else if (ainfo->storage == ArgStructByAddr) {
5244 g_assert (mips_is_imm16 (inst->inst_offset));
5245 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5246 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5248 g_assert_not_reached ();
5253 if (method->save_lmf) {
5254 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5255 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5257 if (lmf_pthread_key != -1) {
5258 g_assert_not_reached();
5260 emit_tls_access (code, mips_temp, lmf_pthread_key);
5262 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5263 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5264 g_assert (mips_is_imm16(offset));
5265 mips_addiu (code, mips_a0, mips_temp, offset);
5268 /* This can/will clobber the a0-a3 registers */
5269 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5272 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5273 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5274 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5275 /* new_lmf->previous_lmf = *lmf_addr */
5276 mips_lw (code, mips_at, mips_v0, 0);
5277 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5278 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5279 /* *(lmf_addr) = sp + lmf_offset */
5280 g_assert (mips_is_imm16(lmf_offset));
5281 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5282 mips_sw (code, mips_at, mips_v0, 0);
5284 /* save method info */
5285 mips_load_const (code, mips_at, method);
5286 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5287 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5289 /* save the current IP */
5290 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5291 mips_load_const (code, mips_at, 0x01010101);
5292 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5296 if (mips_is_imm16 (-alloc2_size)) {
5297 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5300 mips_load_const (code, mips_at, -alloc2_size);
5301 mips_addu (code, mips_sp, mips_sp, mips_at);
5303 alloc_size += alloc2_size;
5304 cfa_offset += alloc2_size;
5305 if (cfg->frame_reg != mips_sp)
5306 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5308 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5312 #if _MIPS_SIM == _ABIO32
5313 cfg->arch.tracing_offset = cfg->stack_offset;
5314 #elif _MIPS_SIM == _ABIN32
5315 /* no stack slots by default for argument regs, reserve a special block */
5316 g_assert_not_reached ();
5318 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5321 cfg->code_len = code - cfg->native_code;
5322 g_assert (cfg->code_len < cfg->code_size);
5336 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5339 int save_mode = SAVE_NONE;
5341 MonoMethod *method = cfg->method;
5342 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5343 int save_offset = MIPS_STACK_PARAM_OFFSET;
5345 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5347 offset = code - cfg->native_code;
5348 /* we need about 16 instructions */
5349 if (offset > (cfg->code_size - 16 * 4)) {
5350 cfg->code_size *= 2;
5351 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5352 code = cfg->native_code + offset;
5357 case MONO_TYPE_VOID:
5358 /* special case string .ctor icall */
5359 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5360 save_mode = SAVE_ONE;
5362 save_mode = SAVE_NONE;
5366 save_mode = SAVE_FP;
5368 case MONO_TYPE_VALUETYPE:
5369 save_mode = SAVE_STRUCT;
5373 #if SIZEOF_REGISTER == 4
5374 save_mode = SAVE_TWO;
5375 #elif SIZEOF_REGISTER == 8
5376 save_mode = SAVE_ONE;
5380 save_mode = SAVE_ONE;
5384 mips_addiu (code, mips_sp, mips_sp, -32);
5385 g_assert (mips_is_imm16(save_offset));
5386 switch (save_mode) {
5388 mips_sw (code, mips_v0, mips_sp, save_offset);
5389 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5390 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5391 if (enable_arguments) {
5392 MIPS_MOVE (code, mips_a1, mips_v0);
5393 MIPS_MOVE (code, mips_a2, mips_v1);
5397 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5398 if (enable_arguments) {
5399 MIPS_MOVE (code, mips_a1, mips_v0);
5403 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5404 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5405 mips_lw (code, mips_a0, mips_sp, save_offset);
5406 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5407 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5414 mips_load_const (code, mips_a0, cfg->method);
5415 mips_call (code, mips_t9, func);
5417 switch (save_mode) {
5419 mips_lw (code, mips_v0, mips_sp, save_offset);
5420 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5421 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5424 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5427 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5434 mips_addiu (code, mips_sp, mips_sp, 32);
5441 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5443 MonoMethod *method = cfg->method;
5445 int max_epilog_size = 16 + 20*4;
5446 int alloc2_size = 0;
5447 guint32 iregs_to_restore;
5449 guint32 fregs_to_restore;
5452 if (cfg->method->save_lmf)
5453 max_epilog_size += 128;
5455 if (mono_jit_trace_calls != NULL)
5456 max_epilog_size += 50;
5458 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5459 max_epilog_size += 50;
5462 pos = code - cfg->native_code;
5463 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5464 cfg->code_size *= 2;
5465 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5466 cfg->stat_code_reallocs++;
5470 * Keep in sync with OP_JMP
5473 code = cfg->native_code + pos;
5475 code = cfg->native_code + cfg->code_len;
5477 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5478 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5480 if (cfg->frame_reg != mips_sp) {
5481 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5483 /* If the stack frame is really large, deconstruct it in two steps */
5484 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5485 alloc2_size = cfg->stack_usage - 1024;
5486 /* partially deconstruct the stack */
5487 mips_load_const (code, mips_at, alloc2_size);
5488 mips_addu (code, mips_sp, mips_sp, mips_at);
5490 pos = cfg->arch.iregs_offset - alloc2_size;
5491 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5492 if (iregs_to_restore) {
5493 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5494 if (iregs_to_restore & (1 << i)) {
5495 g_assert (mips_is_imm16(pos));
5496 MIPS_LW (code, i, mips_sp, pos);
5497 pos += SIZEOF_REGISTER;
5504 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5506 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5507 fregs_to_restore |= (fregs_to_restore << 1);
5509 if (fregs_to_restore) {
5510 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5511 if (fregs_to_restore & (1 << i)) {
5512 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5513 g_assert (mips_is_imm16(pos));
5514 mips_lwc1 (code, i, mips_sp, pos);
5521 /* Unlink the LMF if necessary */
5522 if (method->save_lmf) {
5523 int lmf_offset = cfg->arch.lmf_offset;
5525 /* t0 = current_lmf->previous_lmf */
5526 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5527 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5529 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5530 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5531 /* (*lmf_addr) = previous_lmf */
5532 mips_sw (code, mips_temp, mips_t1, 0);
5536 /* Restore the fp */
5537 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5540 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5541 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5542 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5544 /* Restore the stack pointer */
5545 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5546 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5548 /* Caller will emit either return or tail-call sequence */
5550 cfg->code_len = code - cfg->native_code;
5552 g_assert (cfg->code_len < cfg->code_size);
5557 mono_arch_emit_epilog (MonoCompile *cfg)
5561 code = mono_arch_emit_epilog_sub (cfg, NULL);
5563 mips_jr (code, mips_ra);
5566 cfg->code_len = code - cfg->native_code;
5568 g_assert (cfg->code_len < cfg->code_size);
5571 /* remove once throw_exception_by_name is eliminated */
5574 exception_id_by_name (const char *name)
5576 if (strcmp (name, "IndexOutOfRangeException") == 0)
5577 return MONO_EXC_INDEX_OUT_OF_RANGE;
5578 if (strcmp (name, "OverflowException") == 0)
5579 return MONO_EXC_OVERFLOW;
5580 if (strcmp (name, "ArithmeticException") == 0)
5581 return MONO_EXC_ARITHMETIC;
5582 if (strcmp (name, "DivideByZeroException") == 0)
5583 return MONO_EXC_DIVIDE_BY_ZERO;
5584 if (strcmp (name, "InvalidCastException") == 0)
5585 return MONO_EXC_INVALID_CAST;
5586 if (strcmp (name, "NullReferenceException") == 0)
5587 return MONO_EXC_NULL_REF;
5588 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5589 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5590 if (strcmp (name, "ArgumentException") == 0)
5591 return MONO_EXC_ARGUMENT;
5592 g_error ("Unknown intrinsic exception %s\n", name);
5598 mono_arch_emit_exceptions (MonoCompile *cfg)
5601 MonoJumpInfo *patch_info;
5604 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5605 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5606 int max_epilog_size = 50;
5608 /* count the number of exception infos */
5611 * make sure we have enough space for exceptions
5612 * 24 is the simulated call to throw_exception_by_name
5614 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5616 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5617 i = exception_id_by_name (patch_info->data.target);
5618 g_assert (i < MONO_EXC_INTRINS_NUM);
5619 if (!exc_throw_found [i]) {
5620 max_epilog_size += 12;
5621 exc_throw_found [i] = TRUE;
5627 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5628 cfg->code_size *= 2;
5629 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5630 cfg->stat_code_reallocs++;
5633 code = cfg->native_code + cfg->code_len;
5635 /* add code to raise exceptions */
5636 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5637 switch (patch_info->type) {
5638 case MONO_PATCH_INFO_EXC: {
5640 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5642 i = exception_id_by_name (patch_info->data.target);
5643 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5644 if (!exc_throw_pos [i]) {
5647 exc_throw_pos [i] = code;
5648 //g_print ("exc: writing stub at %p\n", code);
5649 mips_load_const (code, mips_a0, patch_info->data.target);
5650 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5651 mips_load_const (code, mips_t9, addr);
5652 mips_jr (code, mips_t9);
5655 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5657 /* Turn into a Relative patch, pointing at code stub */
5658 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5659 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5661 g_assert_not_reached();
5671 cfg->code_len = code - cfg->native_code;
5673 g_assert (cfg->code_len < cfg->code_size);
5678 * Thread local storage support
5681 setup_tls_access (void)
5684 //guint32 *ins, *code;
5686 if (tls_mode == TLS_MODE_FAILED)
5689 if (g_getenv ("MONO_NO_TLS")) {
5690 tls_mode = TLS_MODE_FAILED;
5694 if (tls_mode == TLS_MODE_DETECT) {
5696 tls_mode = TLS_MODE_FAILED;
5700 ins = (guint32*)pthread_getspecific;
5701 /* uncond branch to the real method */
5702 if ((*ins >> 26) == 18) {
5704 val = (*ins & ~3) << 6;
5708 ins = (guint32*)val;
5710 ins = (guint32*) ((char*)ins + val);
5713 code = &cmplwi_1023;
5714 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5716 ppc_li (code, ppc_r4, 0x48);
5719 if (*ins == cmplwi_1023) {
5720 int found_lwz_284 = 0;
5721 for (ptk = 0; ptk < 20; ++ptk) {
5723 if (!*ins || *ins == blr_ins)
5725 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5730 if (!found_lwz_284) {
5731 tls_mode = TLS_MODE_FAILED;
5734 tls_mode = TLS_MODE_LTHREADS;
5735 } else if (*ins == li_0x48) {
5737 /* uncond branch to the real method */
5738 if ((*ins >> 26) == 18) {
5740 val = (*ins & ~3) << 6;
5744 ins = (guint32*)val;
5746 ins = (guint32*) ((char*)ins + val);
5749 ppc_li (code, ppc_r0, 0x7FF2);
5750 if (ins [1] == val) {
5751 /* Darwin on G4, implement */
5752 tls_mode = TLS_MODE_FAILED;
5756 ppc_mfspr (code, ppc_r3, 104);
5757 if (ins [1] != val) {
5758 tls_mode = TLS_MODE_FAILED;
5761 tls_mode = TLS_MODE_DARWIN_G5;
5764 tls_mode = TLS_MODE_FAILED;
5768 tls_mode = TLS_MODE_FAILED;
5773 if (lmf_pthread_key == -1) {
5774 ptk = mono_jit_tls_id;
5776 /*g_print ("MonoLMF at: %d\n", ptk);*/
5777 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5778 init_tls_failed = 1;
5781 lmf_pthread_key = ptk;
5784 if (monothread_key == -1) {
5785 ptk = mono_thread_get_tls_key ();
5787 monothread_key = ptk;
5788 /*g_print ("thread inited: %d\n", ptk);*/
5790 /*g_print ("thread not inited yet %d\n", ptk);*/
5796 mono_arch_finish_init (void)
5798 setup_tls_access ();
5802 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5807 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5809 int this_dreg = mips_a0;
5812 this_dreg = mips_a1;
5814 /* add the this argument */
5815 if (this_reg != -1) {
5817 MONO_INST_NEW (cfg, this, OP_MOVE);
5818 this->type = this_type;
5819 this->sreg1 = this_reg;
5820 this->dreg = mono_alloc_ireg (cfg);
5821 mono_bblock_add_inst (cfg->cbb, this);
5822 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5827 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5828 vtarg->type = STACK_MP;
5829 vtarg->sreg1 = vt_reg;
5830 vtarg->dreg = mono_alloc_ireg (cfg);
5831 mono_bblock_add_inst (cfg->cbb, vtarg);
5832 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5837 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5839 MonoInst *ins = NULL;
5845 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5851 mono_arch_print_tree (MonoInst *tree, int arity)
5857 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5859 return ctx->sc_regs [reg];
5862 #define ENABLE_WRONG_METHOD_CHECK 0
5864 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5865 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5867 #define LOADSTORE_SIZE 4
5868 #define JUMP_IMM_SIZE 16
5869 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5870 #define LOAD_CONST_SIZE 8
5871 #define JUMP_JR_SIZE 8
5874 * LOCKING: called with the domain lock held
5877 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5878 gpointer fail_tramp)
5882 guint8 *code, *start, *patch;
5884 for (i = 0; i < count; ++i) {
5885 MonoIMTCheckItem *item = imt_entries [i];
5887 if (item->is_equals) {
5888 if (item->check_target_idx) {
5889 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5890 if (item->has_target_code)
5891 item->chunk_size += LOAD_CONST_SIZE;
5893 item->chunk_size += LOADSTORE_SIZE;
5896 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5897 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5898 if (!item->has_target_code)
5899 item->chunk_size += LOADSTORE_SIZE;
5901 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5902 #if ENABLE_WRONG_METHOD_CHECK
5903 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5908 item->chunk_size += CMP_SIZE + BR_SIZE;
5909 imt_entries [item->check_target_idx]->compare_done = TRUE;
5911 size += item->chunk_size;
5913 /* the initial load of the vtable address */
5914 size += MIPS_LOAD_SEQUENCE_LENGTH;
5916 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5918 code = mono_domain_code_reserve (domain, size);
5922 /* t7 points to the vtable */
5923 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5925 for (i = 0; i < count; ++i) {
5926 MonoIMTCheckItem *item = imt_entries [i];
5928 item->code_target = code;
5929 if (item->is_equals) {
5930 if (item->check_target_idx) {
5931 mips_load_const (code, mips_temp, (gsize)item->key);
5932 item->jmp_code = code;
5933 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5935 if (item->has_target_code) {
5936 mips_load_const (code, mips_t9,
5937 item->value.target_code);
5940 mips_lw (code, mips_t9, mips_t7,
5941 (sizeof (gpointer) * item->value.vtable_slot));
5943 mips_jr (code, mips_t9);
5947 mips_load_const (code, mips_temp, (gsize)item->key);
5949 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5951 if (item->has_target_code) {
5952 mips_load_const (code, mips_t9,
5953 item->value.target_code);
5956 mips_load_const (code, mips_at,
5957 & (vtable->vtable [item->value.vtable_slot]));
5958 mips_lw (code, mips_t9, mips_at, 0);
5960 mips_jr (code, mips_t9);
5962 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5963 mips_load_const (code, mips_t9, fail_tramp);
5964 mips_jr (code, mips_t9);
5967 /* enable the commented code to assert on wrong method */
5968 #if ENABLE_WRONG_METHOD_CHECK
5969 ppc_load (code, ppc_r0, (guint32)item->key);
5970 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5972 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5974 mips_lw (code, mips_t9, mips_t7,
5975 (sizeof (gpointer) * item->value.vtable_slot));
5976 mips_jr (code, mips_t9);
5979 #if ENABLE_WRONG_METHOD_CHECK
5980 ppc_patch (patch, code);
5986 mips_load_const (code, mips_temp, (gulong)item->key);
5987 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5989 item->jmp_code = code;
5990 mips_beq (code, mips_temp, mips_zero, 0);
5994 /* patch the branches to get to the target items */
5995 for (i = 0; i < count; ++i) {
5996 MonoIMTCheckItem *item = imt_entries [i];
5997 if (item->jmp_code && item->check_target_idx) {
5998 mips_patch ((guint32 *)item->jmp_code,
5999 (guint32)imt_entries [item->check_target_idx]->code_target);
6004 mono_stats.imt_thunks_size += code - start;
6005 g_assert (code - start <= size);
6006 mono_arch_flush_icache (start, size);
6011 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6013 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6017 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6019 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6022 /* Soft Debug support */
6023 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6026 * mono_arch_set_breakpoint:
6028 * See mini-amd64.c for docs.
6031 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6034 guint32 addr = (guint32)bp_trigger_page;
6036 mips_load_const (code, mips_t9, addr);
6037 mips_lw (code, mips_t9, mips_t9, 0);
6039 mono_arch_flush_icache (ip, code - ip);
6043 * mono_arch_clear_breakpoint:
6045 * See mini-amd64.c for docs.
6048 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6056 mono_arch_flush_icache (ip, code - ip);
6060 * mono_arch_start_single_stepping:
6062 * See mini-amd64.c for docs.
6065 mono_arch_start_single_stepping (void)
6067 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6071 * mono_arch_stop_single_stepping:
6073 * See mini-amd64.c for docs.
6076 mono_arch_stop_single_stepping (void)
6078 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6082 * mono_arch_is_single_step_event:
6084 * See mini-amd64.c for docs.
6087 mono_arch_is_single_step_event (void *info, void *sigctx)
6089 siginfo_t* sinfo = (siginfo_t*) info;
6090 /* Sometimes the address is off by 4 */
6091 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6098 * mono_arch_is_breakpoint_event:
6100 * See mini-amd64.c for docs.
6103 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6105 siginfo_t* sinfo = (siginfo_t*) info;
6106 /* Sometimes the address is off by 4 */
6107 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6114 * mono_arch_skip_breakpoint:
6116 * See mini-amd64.c for docs.
6119 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6121 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6125 * mono_arch_skip_single_step:
6127 * See mini-amd64.c for docs.
6130 mono_arch_skip_single_step (MonoContext *ctx)
6132 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6136 * mono_arch_get_seq_point_info:
6138 * See mini-amd64.c for docs.
6141 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6148 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6150 ext->lmf.previous_lmf = prev_lmf;
6151 /* Mark that this is a MonoLMFExt */
6152 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6153 ext->lmf.iregs [mips_sp] = (gssize)ext;
6156 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
6159 mono_arch_opcode_supported (int opcode)