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 (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
502 int k, frame_size = 0;
503 guint32 size, align, pad;
506 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
507 frame_size += sizeof (gpointer);
511 arg_info [0].offset = offset;
514 frame_size += sizeof (gpointer);
518 arg_info [0].size = frame_size;
520 for (k = 0; k < param_count; k++) {
521 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
523 /* ignore alignment for now */
526 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
527 arg_info [k].pad = pad;
529 arg_info [k + 1].pad = 0;
530 arg_info [k + 1].size = size;
532 arg_info [k + 1].offset = offset;
536 align = MONO_ARCH_FRAME_ALIGNMENT;
537 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
538 arg_info [k].pad = pad;
543 /* The delegate object plus 3 params */
544 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
547 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
549 guint8 *code, *start;
552 start = code = mono_global_codeman_reserve (16);
554 /* Replace the this argument with the target */
555 mips_lw (code, mips_temp, mips_a0, 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 (MonoGenericSharingContext *gsctx, 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_type_get_underlying_type (gsctx, 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_type_get_underlying_type (gsctx, 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_type_get_underlying_type (gsctx, 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->generic_sharing_context, 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->generic_sharing_context, 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_type_get_underlying_type (cfg->generic_sharing_context, 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 (NULL, 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_type_get_underlying_type (cfg->generic_sharing_context, 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 (cfg->generic_sharing_context, &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_type_get_underlying_type (cfg->generic_sharing_context,
1957 mono_method_signature (method)->ret);
1960 #if (SIZEOF_REGISTER == 4)
1961 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1964 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1965 ins->sreg1 = val->dreg + 1;
1966 ins->sreg2 = val->dreg + 2;
1967 MONO_ADD_INS (cfg->cbb, ins);
1971 if (ret->type == MONO_TYPE_R8) {
1972 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1975 if (ret->type == MONO_TYPE_R4) {
1976 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1980 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1984 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1986 MonoInst *ins, *n, *last_ins = NULL;
1988 if (cfg->verbose_level > 2)
1989 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1992 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1993 if (cfg->verbose_level > 2)
1994 mono_print_ins_index (0, ins);
1996 switch (ins->opcode) {
1998 case OP_LOAD_MEMBASE:
1999 case OP_LOADI4_MEMBASE:
2001 * OP_IADD reg2, reg1, const1
2002 * OP_LOAD_MEMBASE const2(reg2), reg3
2004 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
2006 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)){
2007 int const1 = last_ins->inst_imm;
2008 int const2 = ins->inst_offset;
2010 if (mips_is_imm16 (const1 + const2)) {
2011 ins->inst_basereg = last_ins->sreg1;
2012 ins->inst_offset = const1 + const2;
2022 bb->last_ins = last_ins;
2026 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2028 MonoInst *ins, *n, *last_ins = NULL;
2031 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2032 MonoInst *last_ins = ins->prev;
2034 switch (ins->opcode) {
2036 /* remove unnecessary multiplication with 1 */
2037 if (ins->inst_imm == 1) {
2038 if (ins->dreg != ins->sreg1) {
2039 ins->opcode = OP_MOVE;
2041 MONO_DELETE_INS (bb, ins);
2045 int power2 = mono_is_power_of_two (ins->inst_imm);
2047 ins->opcode = OP_SHL_IMM;
2048 ins->inst_imm = power2;
2052 case OP_LOAD_MEMBASE:
2053 case OP_LOADI4_MEMBASE:
2055 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2056 * OP_LOAD_MEMBASE offset(basereg), reg
2058 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2059 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2060 ins->inst_basereg == last_ins->inst_destbasereg &&
2061 ins->inst_offset == last_ins->inst_offset) {
2062 if (ins->dreg == last_ins->sreg1) {
2063 MONO_DELETE_INS (bb, ins);
2066 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2067 ins->opcode = OP_MOVE;
2068 ins->sreg1 = last_ins->sreg1;
2073 * Note: reg1 must be different from the basereg in the second load
2074 * OP_LOAD_MEMBASE offset(basereg), reg1
2075 * OP_LOAD_MEMBASE offset(basereg), reg2
2077 * OP_LOAD_MEMBASE offset(basereg), reg1
2078 * OP_MOVE reg1, reg2
2080 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2081 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2082 ins->inst_basereg != last_ins->dreg &&
2083 ins->inst_basereg == last_ins->inst_basereg &&
2084 ins->inst_offset == last_ins->inst_offset) {
2086 if (ins->dreg == last_ins->dreg) {
2087 MONO_DELETE_INS (bb, ins);
2090 ins->opcode = OP_MOVE;
2091 ins->sreg1 = last_ins->dreg;
2094 //g_assert_not_reached ();
2099 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2100 * OP_LOAD_MEMBASE offset(basereg), reg
2102 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2103 * OP_ICONST reg, imm
2105 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2106 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2107 ins->inst_basereg == last_ins->inst_destbasereg &&
2108 ins->inst_offset == last_ins->inst_offset) {
2109 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2110 ins->opcode = OP_ICONST;
2111 ins->inst_c0 = last_ins->inst_imm;
2112 g_assert_not_reached (); // check this rule
2117 case OP_LOADU1_MEMBASE:
2118 case OP_LOADI1_MEMBASE:
2119 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2120 ins->inst_basereg == last_ins->inst_destbasereg &&
2121 ins->inst_offset == last_ins->inst_offset) {
2122 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2123 ins->sreg1 = last_ins->sreg1;
2126 case OP_LOADU2_MEMBASE:
2127 case OP_LOADI2_MEMBASE:
2128 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2129 ins->inst_basereg == last_ins->inst_destbasereg &&
2130 ins->inst_offset == last_ins->inst_offset) {
2131 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2132 ins->sreg1 = last_ins->sreg1;
2135 case OP_ICONV_TO_I4:
2136 case OP_ICONV_TO_U4:
2138 ins->opcode = OP_MOVE;
2142 if (ins->dreg == ins->sreg1) {
2143 MONO_DELETE_INS (bb, ins);
2147 * OP_MOVE sreg, dreg
2148 * OP_MOVE dreg, sreg
2150 if (last_ins && last_ins->opcode == OP_MOVE &&
2151 ins->sreg1 == last_ins->dreg &&
2152 ins->dreg == last_ins->sreg1) {
2153 MONO_DELETE_INS (bb, ins);
2161 bb->last_ins = last_ins;
2165 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2173 switch (ins->opcode) {
2176 case OP_LCOMPARE_IMM:
2177 mono_print_ins (ins);
2178 g_assert_not_reached ();
2181 tmp1 = mono_alloc_ireg (cfg);
2182 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2183 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2184 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2185 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2190 tmp1 = mono_alloc_ireg (cfg);
2191 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2192 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2193 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2194 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2199 tmp1 = mono_alloc_ireg (cfg);
2200 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2201 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2202 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2203 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2208 tmp1 = mono_alloc_ireg (cfg);
2209 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2210 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2211 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2212 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2224 mono_print_ins (ins);
2225 g_assert_not_reached ();
2228 tmp1 = mono_alloc_ireg (cfg);
2229 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2230 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2231 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2232 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2240 case OP_LCONV_TO_I1:
2241 case OP_LCONV_TO_I2:
2242 case OP_LCONV_TO_I4:
2243 case OP_LCONV_TO_I8:
2244 case OP_LCONV_TO_R4:
2245 case OP_LCONV_TO_R8:
2246 case OP_LCONV_TO_U4:
2247 case OP_LCONV_TO_U8:
2248 case OP_LCONV_TO_U2:
2249 case OP_LCONV_TO_U1:
2251 case OP_LCONV_TO_OVF_I:
2252 case OP_LCONV_TO_OVF_U:
2254 mono_print_ins (ins);
2255 g_assert_not_reached ();
2258 tmp1 = mono_alloc_ireg (cfg);
2259 tmp2 = mono_alloc_ireg (cfg);
2260 tmp3 = mono_alloc_ireg (cfg);
2261 tmp4 = mono_alloc_ireg (cfg);
2262 tmp5 = mono_alloc_ireg (cfg);
2264 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2266 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2267 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2269 /* add the high 32-bits, and add in the carry from the low 32-bits */
2270 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2271 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2273 /* Overflow happens if
2274 * neg + neg = pos or
2276 * XOR of the high bits returns 0 if the signs match
2277 * XOR of that with the high bit of the result return 1 if overflow.
2280 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2281 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2283 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2284 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2285 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2287 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2288 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2289 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2291 /* Now, if (tmp4 == 0) then overflow */
2292 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2296 case OP_LADD_OVF_UN:
2297 tmp1 = mono_alloc_ireg (cfg);
2298 tmp2 = mono_alloc_ireg (cfg);
2300 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2301 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2302 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2303 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2304 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2305 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2310 case OP_LMUL_OVF_UN:
2311 mono_print_ins (ins);
2312 g_assert_not_reached ();
2315 tmp1 = mono_alloc_ireg (cfg);
2316 tmp2 = mono_alloc_ireg (cfg);
2317 tmp3 = mono_alloc_ireg (cfg);
2318 tmp4 = mono_alloc_ireg (cfg);
2319 tmp5 = mono_alloc_ireg (cfg);
2321 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2323 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2324 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2325 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2327 /* Overflow happens if
2328 * neg - pos = pos or
2330 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2332 * tmp1 = (lhs ^ rhs)
2333 * tmp2 = (lhs ^ result)
2334 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2337 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2338 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2339 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2340 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2342 /* Now, if (tmp4 == 1) then overflow */
2343 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2347 case OP_LSUB_OVF_UN:
2348 tmp1 = mono_alloc_ireg (cfg);
2349 tmp2 = mono_alloc_ireg (cfg);
2351 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2352 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2353 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2354 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2356 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2357 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2361 case OP_LCONV_TO_OVF_I1_UN:
2362 case OP_LCONV_TO_OVF_I2_UN:
2363 case OP_LCONV_TO_OVF_I4_UN:
2364 case OP_LCONV_TO_OVF_I8_UN:
2365 case OP_LCONV_TO_OVF_U1_UN:
2366 case OP_LCONV_TO_OVF_U2_UN:
2367 case OP_LCONV_TO_OVF_U4_UN:
2368 case OP_LCONV_TO_OVF_U8_UN:
2369 case OP_LCONV_TO_OVF_I_UN:
2370 case OP_LCONV_TO_OVF_U_UN:
2371 case OP_LCONV_TO_OVF_I1:
2372 case OP_LCONV_TO_OVF_U1:
2373 case OP_LCONV_TO_OVF_I2:
2374 case OP_LCONV_TO_OVF_U2:
2375 case OP_LCONV_TO_OVF_I4:
2376 case OP_LCONV_TO_OVF_U4:
2377 case OP_LCONV_TO_OVF_I8:
2378 case OP_LCONV_TO_OVF_U8:
2386 case OP_LCONV_TO_R_UN:
2392 case OP_LSHR_UN_IMM:
2394 case OP_LDIV_UN_IMM:
2396 case OP_LREM_UN_IMM:
2407 mono_print_ins (ins);
2408 g_assert_not_reached ();
2410 case OP_LCONV_TO_R8_2:
2411 case OP_LCONV_TO_R4_2:
2412 case OP_LCONV_TO_R_UN_2:
2414 case OP_LCONV_TO_OVF_I4_2:
2415 tmp1 = mono_alloc_ireg (cfg);
2417 /* Overflows if reg2 != sign extension of reg1 */
2418 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2419 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2420 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2428 mono_print_ins (ins);
2429 g_assert_not_reached ();
2437 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2445 switch (ins->opcode) {
2447 tmp1 = mono_alloc_ireg (cfg);
2448 tmp2 = mono_alloc_ireg (cfg);
2449 tmp3 = mono_alloc_ireg (cfg);
2450 tmp4 = mono_alloc_ireg (cfg);
2451 tmp5 = mono_alloc_ireg (cfg);
2453 /* add the operands */
2455 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2457 /* Overflow happens if
2458 * neg + neg = pos or
2461 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2462 * XOR of the high bit returns 0 if the signs match
2463 * XOR of that with the high bit of the result return 1 if overflow.
2466 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2467 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2469 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2470 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2471 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2473 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2474 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2476 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2478 /* Now, if (tmp5 == 0) then overflow */
2479 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2480 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2481 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2485 case OP_IADD_OVF_UN:
2486 tmp1 = mono_alloc_ireg (cfg);
2488 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2489 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2490 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2491 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2492 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2497 tmp1 = mono_alloc_ireg (cfg);
2498 tmp2 = mono_alloc_ireg (cfg);
2499 tmp3 = mono_alloc_ireg (cfg);
2500 tmp4 = mono_alloc_ireg (cfg);
2501 tmp5 = mono_alloc_ireg (cfg);
2503 /* add the operands */
2505 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2507 /* Overflow happens if
2508 * neg - pos = pos or
2510 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2512 * tmp1 = (lhs ^ rhs)
2513 * tmp2 = (lhs ^ result)
2514 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2517 /* tmp3 = 1 if the signs of the two inputs differ */
2518 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2519 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2520 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2521 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2522 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2524 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2525 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2526 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2530 case OP_ISUB_OVF_UN:
2531 tmp1 = mono_alloc_ireg (cfg);
2533 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2534 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2535 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2536 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2537 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2544 map_to_reg_reg_op (int op)
2553 case OP_COMPARE_IMM:
2555 case OP_ICOMPARE_IMM:
2557 case OP_LCOMPARE_IMM:
2573 case OP_LOAD_MEMBASE:
2574 return OP_LOAD_MEMINDEX;
2575 case OP_LOADI4_MEMBASE:
2576 return OP_LOADI4_MEMINDEX;
2577 case OP_LOADU4_MEMBASE:
2578 return OP_LOADU4_MEMINDEX;
2579 case OP_LOADU1_MEMBASE:
2580 return OP_LOADU1_MEMINDEX;
2581 case OP_LOADI2_MEMBASE:
2582 return OP_LOADI2_MEMINDEX;
2583 case OP_LOADU2_MEMBASE:
2584 return OP_LOADU2_MEMINDEX;
2585 case OP_LOADI1_MEMBASE:
2586 return OP_LOADI1_MEMINDEX;
2587 case OP_LOADR4_MEMBASE:
2588 return OP_LOADR4_MEMINDEX;
2589 case OP_LOADR8_MEMBASE:
2590 return OP_LOADR8_MEMINDEX;
2591 case OP_STOREI1_MEMBASE_REG:
2592 return OP_STOREI1_MEMINDEX;
2593 case OP_STOREI2_MEMBASE_REG:
2594 return OP_STOREI2_MEMINDEX;
2595 case OP_STOREI4_MEMBASE_REG:
2596 return OP_STOREI4_MEMINDEX;
2597 case OP_STORE_MEMBASE_REG:
2598 return OP_STORE_MEMINDEX;
2599 case OP_STORER4_MEMBASE_REG:
2600 return OP_STORER4_MEMINDEX;
2601 case OP_STORER8_MEMBASE_REG:
2602 return OP_STORER8_MEMINDEX;
2603 case OP_STORE_MEMBASE_IMM:
2604 return OP_STORE_MEMBASE_REG;
2605 case OP_STOREI1_MEMBASE_IMM:
2606 return OP_STOREI1_MEMBASE_REG;
2607 case OP_STOREI2_MEMBASE_IMM:
2608 return OP_STOREI2_MEMBASE_REG;
2609 case OP_STOREI4_MEMBASE_IMM:
2610 return OP_STOREI4_MEMBASE_REG;
2611 case OP_STOREI8_MEMBASE_IMM:
2612 return OP_STOREI8_MEMBASE_REG;
2614 return mono_op_imm_to_op (op);
2618 map_to_mips_op (int op)
2622 return OP_MIPS_FBEQ;
2624 return OP_MIPS_FBGE;
2626 return OP_MIPS_FBGT;
2628 return OP_MIPS_FBLE;
2630 return OP_MIPS_FBLT;
2632 return OP_MIPS_FBNE;
2634 return OP_MIPS_FBGE_UN;
2636 return OP_MIPS_FBGT_UN;
2638 return OP_MIPS_FBLE_UN;
2640 return OP_MIPS_FBLT_UN;
2648 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2649 g_assert_not_reached ();
2653 #define NEW_INS(cfg,after,dest,op) do { \
2654 MONO_INST_NEW((cfg), (dest), (op)); \
2655 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2658 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2660 MONO_INST_NEW(cfg, temp, (op)); \
2661 mono_bblock_insert_after_ins (bb, (pos), temp); \
2662 temp->dreg = (_dreg); \
2663 temp->sreg1 = (_sreg1); \
2664 temp->sreg2 = (_sreg2); \
2668 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2670 MONO_INST_NEW(cfg, temp, (op)); \
2671 mono_bblock_insert_after_ins (bb, (pos), temp); \
2672 temp->dreg = (_dreg); \
2673 temp->sreg1 = (_sreg1); \
2674 temp->inst_c0 = (_imm); \
2679 * Remove from the instruction list the instructions that can't be
2680 * represented with very simple instructions with no register
2684 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2686 MonoInst *ins, *next, *temp, *last_ins = NULL;
2690 if (cfg->verbose_level > 2) {
2693 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2694 MONO_BB_FOR_EACH_INS (bb, ins) {
2695 mono_print_ins_index (idx++, ins);
2701 MONO_BB_FOR_EACH_INS (bb, ins) {
2703 switch (ins->opcode) {
2708 /* Branch opts can eliminate the branch */
2709 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2715 case OP_COMPARE_IMM:
2716 case OP_ICOMPARE_IMM:
2717 case OP_LCOMPARE_IMM:
2719 /* Branch opts can eliminate the branch */
2720 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2724 if (ins->inst_imm) {
2725 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2726 temp->inst_c0 = ins->inst_imm;
2727 temp->dreg = mono_alloc_ireg (cfg);
2728 ins->sreg2 = temp->dreg;
2732 ins->sreg2 = mips_zero;
2734 if (ins->opcode == OP_COMPARE_IMM)
2735 ins->opcode = OP_COMPARE;
2736 else if (ins->opcode == OP_ICOMPARE_IMM)
2737 ins->opcode = OP_ICOMPARE;
2738 else if (ins->opcode == OP_LCOMPARE_IMM)
2739 ins->opcode = OP_LCOMPARE;
2742 case OP_IDIV_UN_IMM:
2745 case OP_IREM_UN_IMM:
2746 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2747 temp->inst_c0 = ins->inst_imm;
2748 temp->dreg = mono_alloc_ireg (cfg);
2749 ins->sreg2 = temp->dreg;
2750 if (ins->opcode == OP_IDIV_IMM)
2751 ins->opcode = OP_IDIV;
2752 else if (ins->opcode == OP_IREM_IMM)
2753 ins->opcode = OP_IREM;
2754 else if (ins->opcode == OP_IDIV_UN_IMM)
2755 ins->opcode = OP_IDIV_UN;
2756 else if (ins->opcode == OP_IREM_UN_IMM)
2757 ins->opcode = OP_IREM_UN;
2759 /* handle rem separately */
2766 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2767 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2768 temp->inst_c0 = ins->inst_imm;
2769 temp->dreg = mono_alloc_ireg (cfg);
2770 ins->sreg2 = temp->dreg;
2771 ins->opcode = map_to_reg_reg_op (ins->opcode);
2781 /* unsigned 16 bit immediate */
2782 if (ins->inst_imm & 0xffff0000) {
2783 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2784 temp->inst_c0 = ins->inst_imm;
2785 temp->dreg = mono_alloc_ireg (cfg);
2786 ins->sreg2 = temp->dreg;
2787 ins->opcode = map_to_reg_reg_op (ins->opcode);
2794 /* signed 16 bit immediate */
2795 if (!mips_is_imm16 (ins->inst_imm)) {
2796 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2797 temp->inst_c0 = ins->inst_imm;
2798 temp->dreg = mono_alloc_ireg (cfg);
2799 ins->sreg2 = temp->dreg;
2800 ins->opcode = map_to_reg_reg_op (ins->opcode);
2806 if (!mips_is_imm16 (-ins->inst_imm)) {
2807 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2808 temp->inst_c0 = ins->inst_imm;
2809 temp->dreg = mono_alloc_ireg (cfg);
2810 ins->sreg2 = temp->dreg;
2811 ins->opcode = map_to_reg_reg_op (ins->opcode);
2817 if (ins->inst_imm == 1) {
2818 ins->opcode = OP_MOVE;
2821 if (ins->inst_imm == 0) {
2822 ins->opcode = OP_ICONST;
2826 imm = mono_is_power_of_two (ins->inst_imm);
2828 ins->opcode = OP_SHL_IMM;
2829 ins->inst_imm = imm;
2832 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2833 temp->inst_c0 = ins->inst_imm;
2834 temp->dreg = mono_alloc_ireg (cfg);
2835 ins->sreg2 = temp->dreg;
2836 ins->opcode = map_to_reg_reg_op (ins->opcode);
2839 case OP_LOCALLOC_IMM:
2840 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2841 temp->inst_c0 = ins->inst_imm;
2842 temp->dreg = mono_alloc_ireg (cfg);
2843 ins->sreg1 = temp->dreg;
2844 ins->opcode = OP_LOCALLOC;
2847 case OP_LOADR4_MEMBASE:
2848 case OP_STORER4_MEMBASE_REG:
2849 /* we can do two things: load the immed in a register
2850 * and use an indexed load, or see if the immed can be
2851 * represented as an ad_imm + a load with a smaller offset
2852 * that fits. We just do the first for now, optimize later.
2854 if (mips_is_imm16 (ins->inst_offset))
2856 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2857 temp->inst_c0 = ins->inst_offset;
2858 temp->dreg = mono_alloc_ireg (cfg);
2859 ins->sreg2 = temp->dreg;
2860 ins->opcode = map_to_reg_reg_op (ins->opcode);
2863 case OP_STORE_MEMBASE_IMM:
2864 case OP_STOREI1_MEMBASE_IMM:
2865 case OP_STOREI2_MEMBASE_IMM:
2866 case OP_STOREI4_MEMBASE_IMM:
2867 case OP_STOREI8_MEMBASE_IMM:
2868 if (!ins->inst_imm) {
2869 ins->sreg1 = mips_zero;
2870 ins->opcode = map_to_reg_reg_op (ins->opcode);
2873 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2874 temp->inst_c0 = ins->inst_imm;
2875 temp->dreg = mono_alloc_ireg (cfg);
2876 ins->sreg1 = temp->dreg;
2877 ins->opcode = map_to_reg_reg_op (ins->opcode);
2879 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2885 /* Branch opts can eliminate the branch */
2886 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2893 * remap compare/branch and compare/set
2894 * to MIPS specific opcodes.
2896 next->opcode = map_to_mips_op (next->opcode);
2897 next->sreg1 = ins->sreg1;
2898 next->sreg2 = ins->sreg2;
2905 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2906 temp->inst_c0 = (guint32)ins->inst_p0;
2907 temp->dreg = mono_alloc_ireg (cfg);
2908 ins->inst_basereg = temp->dreg;
2909 ins->inst_offset = 0;
2910 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2912 /* make it handle the possibly big ins->inst_offset
2913 * later optimize to use lis + load_membase
2918 g_assert (ins_is_compare(last_ins));
2919 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2920 NULLIFY_INS(last_ins);
2924 g_assert (ins_is_compare(last_ins));
2925 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2926 NULLIFY_INS(last_ins);
2930 g_assert (ins_is_compare(last_ins));
2931 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2932 last_ins->dreg = mono_alloc_ireg (cfg);
2933 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2937 g_assert (ins_is_compare(last_ins));
2938 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2939 last_ins->dreg = mono_alloc_ireg (cfg);
2940 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2944 g_assert (ins_is_compare(last_ins));
2945 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2946 last_ins->dreg = mono_alloc_ireg (cfg);
2947 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2951 g_assert (ins_is_compare(last_ins));
2952 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2953 last_ins->dreg = mono_alloc_ireg (cfg);
2954 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2958 g_assert (ins_is_compare(last_ins));
2959 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2960 last_ins->dreg = mono_alloc_ireg (cfg);
2961 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2965 g_assert (ins_is_compare(last_ins));
2966 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2967 last_ins->dreg = mono_alloc_ireg (cfg);
2968 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2972 g_assert (ins_is_compare(last_ins));
2973 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2974 last_ins->dreg = mono_alloc_ireg (cfg);
2975 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2979 g_assert (ins_is_compare(last_ins));
2980 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2981 last_ins->dreg = mono_alloc_ireg (cfg);
2982 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2987 g_assert (ins_is_compare(last_ins));
2988 last_ins->opcode = OP_IXOR;
2989 last_ins->dreg = mono_alloc_ireg(cfg);
2990 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2995 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2996 NULLIFY_INS(last_ins);
3002 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
3003 NULLIFY_INS(last_ins);
3008 g_assert (ins_is_compare(last_ins));
3009 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
3010 MONO_DELETE_INS(bb, last_ins);
3015 g_assert (ins_is_compare(last_ins));
3016 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3017 MONO_DELETE_INS(bb, last_ins);
3020 case OP_COND_EXC_EQ:
3021 case OP_COND_EXC_IEQ:
3022 g_assert (ins_is_compare(last_ins));
3023 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3024 MONO_DELETE_INS(bb, last_ins);
3027 case OP_COND_EXC_GE:
3028 case OP_COND_EXC_IGE:
3029 g_assert (ins_is_compare(last_ins));
3030 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3031 MONO_DELETE_INS(bb, last_ins);
3034 case OP_COND_EXC_GT:
3035 case OP_COND_EXC_IGT:
3036 g_assert (ins_is_compare(last_ins));
3037 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3038 MONO_DELETE_INS(bb, last_ins);
3041 case OP_COND_EXC_LE:
3042 case OP_COND_EXC_ILE:
3043 g_assert (ins_is_compare(last_ins));
3044 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3045 MONO_DELETE_INS(bb, last_ins);
3048 case OP_COND_EXC_LT:
3049 case OP_COND_EXC_ILT:
3050 g_assert (ins_is_compare(last_ins));
3051 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3052 MONO_DELETE_INS(bb, last_ins);
3055 case OP_COND_EXC_NE_UN:
3056 case OP_COND_EXC_INE_UN:
3057 g_assert (ins_is_compare(last_ins));
3058 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3059 MONO_DELETE_INS(bb, last_ins);
3062 case OP_COND_EXC_GE_UN:
3063 case OP_COND_EXC_IGE_UN:
3064 g_assert (ins_is_compare(last_ins));
3065 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3066 MONO_DELETE_INS(bb, last_ins);
3069 case OP_COND_EXC_GT_UN:
3070 case OP_COND_EXC_IGT_UN:
3071 g_assert (ins_is_compare(last_ins));
3072 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3073 MONO_DELETE_INS(bb, last_ins);
3076 case OP_COND_EXC_LE_UN:
3077 case OP_COND_EXC_ILE_UN:
3078 g_assert (ins_is_compare(last_ins));
3079 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3080 MONO_DELETE_INS(bb, last_ins);
3083 case OP_COND_EXC_LT_UN:
3084 case OP_COND_EXC_ILT_UN:
3085 g_assert (ins_is_compare(last_ins));
3086 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3087 MONO_DELETE_INS(bb, last_ins);
3090 case OP_COND_EXC_OV:
3091 case OP_COND_EXC_IOV: {
3092 int tmp1, tmp2, tmp3, tmp4, tmp5;
3093 MonoInst *pos = last_ins;
3095 /* Overflow happens if
3096 * neg + neg = pos or
3099 * (bit31s of operands match) AND (bit31 of operand
3100 * != bit31 of result)
3101 * XOR of the high bit returns 0 if the signs match
3102 * XOR of that with the high bit of the result return 1
3105 g_assert (last_ins->opcode == OP_IADC);
3107 tmp1 = mono_alloc_ireg (cfg);
3108 tmp2 = mono_alloc_ireg (cfg);
3109 tmp3 = mono_alloc_ireg (cfg);
3110 tmp4 = mono_alloc_ireg (cfg);
3111 tmp5 = mono_alloc_ireg (cfg);
3113 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3114 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3116 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3117 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3118 INS (pos, OP_INOT, tmp3, tmp2, -1);
3120 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3121 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3122 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3124 /* Now, if (tmp5 == 0) then overflow */
3125 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3130 case OP_COND_EXC_NO:
3131 case OP_COND_EXC_INO:
3132 g_assert_not_reached ();
3136 case OP_COND_EXC_IC:
3137 g_assert_not_reached ();
3140 case OP_COND_EXC_NC:
3141 case OP_COND_EXC_INC:
3142 g_assert_not_reached ();
3148 bb->last_ins = last_ins;
3149 bb->max_vreg = cfg->next_vreg;
3152 if (cfg->verbose_level > 2) {
3155 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3156 MONO_BB_FOR_EACH_INS (bb, ins) {
3157 mono_print_ins_index (idx++, ins);
3166 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3168 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3170 mips_truncwd (code, mips_ftemp, sreg);
3172 mips_cvtwd (code, mips_ftemp, sreg);
3174 mips_mfc1 (code, dreg, mips_ftemp);
3177 mips_andi (code, dreg, dreg, 0xff);
3178 else if (size == 2) {
3179 mips_sll (code, dreg, dreg, 16);
3180 mips_srl (code, dreg, dreg, 16);
3184 mips_sll (code, dreg, dreg, 24);
3185 mips_sra (code, dreg, dreg, 24);
3187 else if (size == 2) {
3188 mips_sll (code, dreg, dreg, 16);
3189 mips_sra (code, dreg, dreg, 16);
3196 * emit_load_volatile_arguments:
3198 * Load volatile arguments from the stack to the original input registers.
3199 * Required before a tail call.
3202 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3204 MonoMethod *method = cfg->method;
3205 MonoMethodSignature *sig;
3210 sig = mono_method_signature (method);
3212 if (!cfg->arch.cinfo)
3213 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
3214 cinfo = cfg->arch.cinfo;
3216 if (cinfo->struct_ret) {
3217 ArgInfo *ainfo = &cinfo->ret;
3218 inst = cfg->vret_addr;
3219 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3222 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3223 ArgInfo *ainfo = cinfo->args + i;
3224 inst = cfg->args [i];
3225 if (inst->opcode == OP_REGVAR) {
3226 if (ainfo->storage == ArgInIReg)
3227 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3228 else if (ainfo->storage == ArgInFReg)
3229 g_assert_not_reached();
3230 else if (ainfo->storage == ArgOnStack) {
3233 g_assert_not_reached ();
3235 if (ainfo->storage == ArgInIReg) {
3236 g_assert (mips_is_imm16 (inst->inst_offset));
3237 switch (ainfo->size) {
3239 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3242 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3246 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3249 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3250 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3253 g_assert_not_reached ();
3256 } else if (ainfo->storage == ArgOnStack) {
3258 } else if (ainfo->storage == ArgInFReg) {
3259 g_assert (mips_is_imm16 (inst->inst_offset));
3260 if (ainfo->size == 8) {
3261 #if _MIPS_SIM == _ABIO32
3262 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3263 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3264 #elif _MIPS_SIM == _ABIN32
3265 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3268 else if (ainfo->size == 4)
3269 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3271 g_assert_not_reached ();
3272 } else if (ainfo->storage == ArgStructByVal) {
3274 int doffset = inst->inst_offset;
3276 g_assert (mips_is_imm16 (inst->inst_offset));
3277 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3278 for (i = 0; i < ainfo->size; ++i) {
3279 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3280 doffset += SIZEOF_REGISTER;
3282 } else if (ainfo->storage == ArgStructByAddr) {
3283 g_assert (mips_is_imm16 (inst->inst_offset));
3284 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3286 g_assert_not_reached ();
3294 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3296 int size = cfg->param_area;
3298 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3299 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3304 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3305 if (ppc_is_imm16 (-size)) {
3306 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3308 ppc_load (code, ppc_r12, -size);
3309 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3316 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3318 int size = cfg->param_area;
3320 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3321 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3326 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3327 if (ppc_is_imm16 (size)) {
3328 ppc_stwu (code, ppc_r0, size, ppc_sp);
3330 ppc_load (code, ppc_r12, size);
3331 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3338 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3343 guint8 *code = cfg->native_code + cfg->code_len;
3344 MonoInst *last_ins = NULL;
3345 guint last_offset = 0;
3349 /* we don't align basic blocks of loops on mips */
3351 if (cfg->verbose_level > 2)
3352 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3354 cpos = bb->max_offset;
3357 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3358 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3359 g_assert (!mono_compile_aot);
3362 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3363 /* this is not thread save, but good enough */
3364 /* fixme: howto handle overflows? */
3365 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3366 mips_lw (code, mips_temp, mips_at, 0);
3367 mips_addiu (code, mips_temp, mips_temp, 1);
3368 mips_sw (code, mips_temp, mips_at, 0);
3371 MONO_BB_FOR_EACH_INS (bb, ins) {
3372 offset = code - cfg->native_code;
3374 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3376 if (offset > (cfg->code_size - max_len - 16)) {
3377 cfg->code_size *= 2;
3378 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3379 code = cfg->native_code + offset;
3381 mono_debug_record_line_number (cfg, ins, offset);
3382 if (cfg->verbose_level > 2) {
3383 g_print (" @ 0x%x\t", offset);
3384 mono_print_ins_index (ins_cnt++, ins);
3386 /* Check for virtual regs that snuck by */
3387 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3389 switch (ins->opcode) {
3390 case OP_RELAXED_NOP:
3393 case OP_DUMMY_STORE:
3394 case OP_NOT_REACHED:
3397 case OP_IL_SEQ_POINT:
3398 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3400 case OP_SEQ_POINT: {
3401 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3402 guint32 addr = (guint32)ss_trigger_page;
3404 mips_load_const (code, mips_t9, addr);
3405 mips_lw (code, mips_t9, mips_t9, 0);
3408 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3411 * A placeholder for a possible breakpoint inserted by
3412 * mono_arch_set_breakpoint ().
3414 /* mips_load_const () + mips_lw */
3421 g_assert_not_reached();
3423 emit_tls_access (code, ins->dreg, ins->inst_offset);
3427 mips_mult (code, ins->sreg1, ins->sreg2);
3428 mips_mflo (code, ins->dreg);
3429 mips_mfhi (code, ins->dreg+1);
3432 mips_multu (code, ins->sreg1, ins->sreg2);
3433 mips_mflo (code, ins->dreg);
3434 mips_mfhi (code, ins->dreg+1);
3436 case OP_MEMORY_BARRIER:
3437 mips_sync (code, 0);
3439 case OP_STOREI1_MEMBASE_IMM:
3440 mips_load_const (code, mips_temp, ins->inst_imm);
3441 if (mips_is_imm16 (ins->inst_offset)) {
3442 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3444 mips_load_const (code, mips_at, ins->inst_offset);
3445 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3448 case OP_STOREI2_MEMBASE_IMM:
3449 mips_load_const (code, mips_temp, ins->inst_imm);
3450 if (mips_is_imm16 (ins->inst_offset)) {
3451 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3453 mips_load_const (code, mips_at, ins->inst_offset);
3454 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3457 case OP_STOREI8_MEMBASE_IMM:
3458 mips_load_const (code, mips_temp, ins->inst_imm);
3459 if (mips_is_imm16 (ins->inst_offset)) {
3460 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3462 mips_load_const (code, mips_at, ins->inst_offset);
3463 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3466 case OP_STORE_MEMBASE_IMM:
3467 case OP_STOREI4_MEMBASE_IMM:
3468 mips_load_const (code, mips_temp, ins->inst_imm);
3469 if (mips_is_imm16 (ins->inst_offset)) {
3470 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3472 mips_load_const (code, mips_at, ins->inst_offset);
3473 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3476 case OP_STOREI1_MEMBASE_REG:
3477 if (mips_is_imm16 (ins->inst_offset)) {
3478 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3480 mips_load_const (code, mips_at, ins->inst_offset);
3481 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3482 mips_sb (code, ins->sreg1, mips_at, 0);
3485 case OP_STOREI2_MEMBASE_REG:
3486 if (mips_is_imm16 (ins->inst_offset)) {
3487 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3489 mips_load_const (code, mips_at, ins->inst_offset);
3490 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3491 mips_sh (code, ins->sreg1, mips_at, 0);
3494 case OP_STORE_MEMBASE_REG:
3495 case OP_STOREI4_MEMBASE_REG:
3496 if (mips_is_imm16 (ins->inst_offset)) {
3497 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3499 mips_load_const (code, mips_at, ins->inst_offset);
3500 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3501 mips_sw (code, ins->sreg1, mips_at, 0);
3504 case OP_STOREI8_MEMBASE_REG:
3505 if (mips_is_imm16 (ins->inst_offset)) {
3506 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3508 mips_load_const (code, mips_at, ins->inst_offset);
3509 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3510 mips_sd (code, ins->sreg1, mips_at, 0);
3514 g_assert_not_reached ();
3515 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3516 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3518 case OP_LOADI8_MEMBASE:
3519 if (mips_is_imm16 (ins->inst_offset)) {
3520 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3522 mips_load_const (code, mips_at, ins->inst_offset);
3523 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3524 mips_ld (code, ins->dreg, mips_at, 0);
3527 case OP_LOAD_MEMBASE:
3528 case OP_LOADI4_MEMBASE:
3529 case OP_LOADU4_MEMBASE:
3530 g_assert (ins->dreg != -1);
3531 if (mips_is_imm16 (ins->inst_offset)) {
3532 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3534 mips_load_const (code, mips_at, ins->inst_offset);
3535 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3536 mips_lw (code, ins->dreg, mips_at, 0);
3539 case OP_LOADI1_MEMBASE:
3540 if (mips_is_imm16 (ins->inst_offset)) {
3541 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3543 mips_load_const (code, mips_at, ins->inst_offset);
3544 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3545 mips_lb (code, ins->dreg, mips_at, 0);
3548 case OP_LOADU1_MEMBASE:
3549 if (mips_is_imm16 (ins->inst_offset)) {
3550 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3552 mips_load_const (code, mips_at, ins->inst_offset);
3553 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3554 mips_lbu (code, ins->dreg, mips_at, 0);
3557 case OP_LOADI2_MEMBASE:
3558 if (mips_is_imm16 (ins->inst_offset)) {
3559 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3561 mips_load_const (code, mips_at, ins->inst_offset);
3562 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3563 mips_lh (code, ins->dreg, mips_at, 0);
3566 case OP_LOADU2_MEMBASE:
3567 if (mips_is_imm16 (ins->inst_offset)) {
3568 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3570 mips_load_const (code, mips_at, ins->inst_offset);
3571 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3572 mips_lhu (code, ins->dreg, mips_at, 0);
3575 case OP_ICONV_TO_I1:
3576 mips_sll (code, mips_at, ins->sreg1, 24);
3577 mips_sra (code, ins->dreg, mips_at, 24);
3579 case OP_ICONV_TO_I2:
3580 mips_sll (code, mips_at, ins->sreg1, 16);
3581 mips_sra (code, ins->dreg, mips_at, 16);
3583 case OP_ICONV_TO_U1:
3584 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3586 case OP_ICONV_TO_U2:
3587 mips_sll (code, mips_at, ins->sreg1, 16);
3588 mips_srl (code, ins->dreg, mips_at, 16);
3591 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3594 g_assert (mips_is_imm16 (ins->inst_imm));
3595 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3598 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3601 g_assert (mips_is_imm16 (ins->inst_imm));
3602 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3606 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3607 * So instead of emitting a trap, we emit a call a C function and place a
3610 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3611 (gpointer)"mono_break");
3612 mips_load (code, mips_t9, 0x1f1f1f1f);
3613 mips_jalr (code, mips_t9, mips_ra);
3617 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3620 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3625 g_assert (mips_is_imm16 (ins->inst_imm));
3626 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3629 g_assert (mips_is_imm16 (ins->inst_imm));
3630 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3634 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3637 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3642 // we add the negated value
3643 g_assert (mips_is_imm16 (-ins->inst_imm));
3644 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3648 // we add the negated value
3649 g_assert (mips_is_imm16 (-ins->inst_imm));
3650 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3655 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3661 g_assert (!(ins->inst_imm & 0xffff0000));
3662 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3667 guint32 *divisor_is_m1;
3668 guint32 *dividend_is_minvalue;
3669 guint32 *divisor_is_zero;
3671 mips_load_const (code, mips_at, -1);
3672 divisor_is_m1 = (guint32 *)(void *)code;
3673 mips_bne (code, ins->sreg2, mips_at, 0);
3674 mips_lui (code, mips_at, mips_zero, 0x8000);
3675 dividend_is_minvalue = (guint32 *)(void *)code;
3676 mips_bne (code, ins->sreg1, mips_at, 0);
3679 /* Divide Int32.MinValue by -1 -- throw exception */
3680 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3682 mips_patch (divisor_is_m1, (guint32)code);
3683 mips_patch (dividend_is_minvalue, (guint32)code);
3685 /* Put divide in branch delay slot (NOT YET) */
3686 divisor_is_zero = (guint32 *)(void *)code;
3687 mips_bne (code, ins->sreg2, mips_zero, 0);
3690 /* Divide by zero -- throw exception */
3691 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3693 mips_patch (divisor_is_zero, (guint32)code);
3694 mips_div (code, ins->sreg1, ins->sreg2);
3695 if (ins->opcode == OP_IDIV)
3696 mips_mflo (code, ins->dreg);
3698 mips_mfhi (code, ins->dreg);
3703 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3705 /* Put divide in branch delay slot (NOT YET) */
3706 mips_bne (code, ins->sreg2, mips_zero, 0);
3709 /* Divide by zero -- throw exception */
3710 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3712 mips_patch (divisor_is_zero, (guint32)code);
3713 mips_divu (code, ins->sreg1, ins->sreg2);
3714 if (ins->opcode == OP_IDIV_UN)
3715 mips_mflo (code, ins->dreg);
3717 mips_mfhi (code, ins->dreg);
3721 g_assert_not_reached ();
3723 ppc_load (code, ppc_r12, ins->inst_imm);
3724 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3725 ppc_mfspr (code, ppc_r0, ppc_xer);
3726 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3727 /* FIXME: use OverflowException for 0x80000000/-1 */
3728 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3730 g_assert_not_reached();
3733 g_assert_not_reached ();
3735 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3739 g_assert (!(ins->inst_imm & 0xffff0000));
3740 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3743 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3747 /* unsigned 16-bit immediate */
3748 g_assert (!(ins->inst_imm & 0xffff0000));
3749 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3752 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3756 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3759 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3762 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3766 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3769 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3772 case OP_ISHR_UN_IMM:
3773 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3775 case OP_LSHR_UN_IMM:
3776 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3779 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3782 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3786 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3789 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3792 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3796 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3798 mips_mult (code, ins->sreg1, ins->sreg2);
3799 mips_mflo (code, ins->dreg);
3804 #if SIZEOF_REGISTER == 8
3806 mips_dmult (code, ins->sreg1, ins->sreg2);
3807 mips_mflo (code, ins->dreg);
3812 mips_mult (code, ins->sreg1, ins->sreg2);
3813 mips_mflo (code, ins->dreg);
3814 mips_mfhi (code, mips_at);
3817 mips_sra (code, mips_temp, ins->dreg, 31);
3818 patch = (guint32 *)(void *)code;
3819 mips_beq (code, mips_temp, mips_at, 0);
3821 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3822 mips_patch (patch, (guint32)code);
3825 case OP_IMUL_OVF_UN: {
3827 mips_mult (code, ins->sreg1, ins->sreg2);
3828 mips_mflo (code, ins->dreg);
3829 mips_mfhi (code, mips_at);
3832 patch = (guint32 *)(void *)code;
3833 mips_beq (code, mips_at, mips_zero, 0);
3835 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3836 mips_patch (patch, (guint32)code);
3840 mips_load_const (code, ins->dreg, ins->inst_c0);
3842 #if SIZEOF_REGISTER == 8
3844 mips_load_const (code, ins->dreg, ins->inst_c0);
3848 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3849 mips_load (code, ins->dreg, 0);
3853 mips_mtc1 (code, ins->dreg, ins->sreg1);
3855 case OP_MIPS_MTC1S_2:
3856 mips_mtc1 (code, ins->dreg, ins->sreg1);
3857 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3860 mips_mfc1 (code, ins->dreg, ins->sreg1);
3863 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3867 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3869 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3870 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3874 case OP_ICONV_TO_I4:
3875 case OP_ICONV_TO_U4:
3877 if (ins->dreg != ins->sreg1)
3878 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3880 #if SIZEOF_REGISTER == 8
3882 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3883 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3886 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3887 mips_dsra (code, ins->dreg, ins->dreg, 32);
3891 int lsreg = mips_v0 + ls_word_idx;
3892 int msreg = mips_v0 + ms_word_idx;
3894 /* Get sreg1 into lsreg, sreg2 into msreg */
3896 if (ins->sreg1 == msreg) {
3897 if (ins->sreg1 != mips_at)
3898 MIPS_MOVE (code, mips_at, ins->sreg1);
3899 if (ins->sreg2 != msreg)
3900 MIPS_MOVE (code, msreg, ins->sreg2);
3901 MIPS_MOVE (code, lsreg, mips_at);
3904 if (ins->sreg2 != msreg)
3905 MIPS_MOVE (code, msreg, ins->sreg2);
3906 if (ins->sreg1 != lsreg)
3907 MIPS_MOVE (code, lsreg, ins->sreg1);
3912 if (ins->dreg != ins->sreg1) {
3913 mips_fmovd (code, ins->dreg, ins->sreg1);
3916 case OP_MOVE_F_TO_I4:
3917 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3918 mips_mfc1 (code, ins->dreg, mips_ftemp);
3920 case OP_MOVE_I4_TO_F:
3921 mips_mtc1 (code, ins->dreg, ins->sreg1);
3922 mips_cvtds (code, ins->dreg, ins->dreg);
3925 /* Convert from double to float and leave it there */
3926 mips_cvtsd (code, ins->dreg, ins->sreg1);
3928 case OP_FCONV_TO_R4:
3930 mips_cvtsd (code, ins->dreg, ins->sreg1);
3932 /* Just a move, no precision change */
3933 if (ins->dreg != ins->sreg1) {
3934 mips_fmovd (code, ins->dreg, ins->sreg1);
3939 code = emit_load_volatile_arguments(cfg, code);
3942 * Pop our stack, then jump to specified method (tail-call)
3943 * Keep in sync with mono_arch_emit_epilog
3945 code = mono_arch_emit_epilog_sub (cfg, code);
3947 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3948 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3949 mips_load (code, mips_t9, 0);
3950 mips_jr (code, mips_t9);
3954 /* ensure ins->sreg1 is not NULL */
3955 mips_lw (code, mips_zero, ins->sreg1, 0);
3958 g_assert (mips_is_imm16 (cfg->sig_cookie));
3959 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3960 mips_sw (code, mips_at, ins->sreg1, 0);
3973 case OP_VOIDCALL_REG:
3975 case OP_FCALL_MEMBASE:
3976 case OP_LCALL_MEMBASE:
3977 case OP_VCALL_MEMBASE:
3978 case OP_VCALL2_MEMBASE:
3979 case OP_VOIDCALL_MEMBASE:
3980 case OP_CALL_MEMBASE:
3981 call = (MonoCallInst*)ins;
3982 switch (ins->opcode) {
3989 if (ins->flags & MONO_INST_HAS_METHOD) {
3990 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3991 mips_load (code, mips_t9, call->method);
3994 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3995 mips_load (code, mips_t9, call->fptr);
3997 mips_jalr (code, mips_t9, mips_ra);
4004 case OP_VOIDCALL_REG:
4006 MIPS_MOVE (code, mips_t9, ins->sreg1);
4007 mips_jalr (code, mips_t9, mips_ra);
4010 case OP_FCALL_MEMBASE:
4011 case OP_LCALL_MEMBASE:
4012 case OP_VCALL_MEMBASE:
4013 case OP_VCALL2_MEMBASE:
4014 case OP_VOIDCALL_MEMBASE:
4015 case OP_CALL_MEMBASE:
4016 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
4017 mips_jalr (code, mips_t9, mips_ra);
4021 #if PROMOTE_R4_TO_R8
4022 /* returned an FP R4 (single), promote to R8 (double) in place */
4023 switch (ins->opcode) {
4026 case OP_FCALL_MEMBASE:
4027 if (call->signature->ret->type == MONO_TYPE_R4)
4028 mips_cvtds (code, mips_f0, mips_f0);
4036 int area_offset = cfg->param_area;
4038 /* Round up ins->sreg1, mips_at ends up holding size */
4039 mips_addiu (code, mips_at, ins->sreg1, 31);
4040 mips_addiu (code, mips_temp, mips_zero, ~31);
4041 mips_and (code, mips_at, mips_at, mips_temp);
4043 mips_subu (code, mips_sp, mips_sp, mips_at);
4044 g_assert (mips_is_imm16 (area_offset));
4045 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4047 if (ins->flags & MONO_INST_INIT) {
4050 buf = (guint32*)(void*)code;
4051 mips_beq (code, mips_at, mips_zero, 0);
4054 mips_move (code, mips_temp, ins->dreg);
4055 mips_sb (code, mips_zero, mips_temp, 0);
4056 mips_addiu (code, mips_at, mips_at, -1);
4057 mips_bne (code, mips_at, mips_zero, -3);
4058 mips_addiu (code, mips_temp, mips_temp, 1);
4060 mips_patch (buf, (guint32)code);
4065 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4066 mips_move (code, mips_a0, ins->sreg1);
4067 mips_call (code, mips_t9, addr);
4068 mips_break (code, 0xfc);
4072 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4073 mips_move (code, mips_a0, ins->sreg1);
4074 mips_call (code, mips_t9, addr);
4075 mips_break (code, 0xfb);
4078 case OP_START_HANDLER: {
4080 * The START_HANDLER instruction marks the beginning of
4081 * a handler block. It is called using a call
4082 * instruction, so mips_ra contains the return address.
4083 * Since the handler executes in the same stack frame
4084 * as the method itself, we can't use save/restore to
4085 * save the return address. Instead, we save it into
4086 * a dedicated variable.
4088 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4089 g_assert (spvar->inst_basereg != mips_sp);
4090 code = emit_reserve_param_area (cfg, code);
4092 if (mips_is_imm16 (spvar->inst_offset)) {
4093 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4095 mips_load_const (code, mips_at, spvar->inst_offset);
4096 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4097 mips_sw (code, mips_ra, mips_at, 0);
4101 case OP_ENDFILTER: {
4102 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4103 g_assert (spvar->inst_basereg != mips_sp);
4104 code = emit_unreserve_param_area (cfg, code);
4106 if (ins->sreg1 != mips_v0)
4107 MIPS_MOVE (code, mips_v0, ins->sreg1);
4108 if (mips_is_imm16 (spvar->inst_offset)) {
4109 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4111 mips_load_const (code, mips_at, spvar->inst_offset);
4112 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4113 mips_lw (code, mips_ra, mips_at, 0);
4115 mips_jr (code, mips_ra);
4119 case OP_ENDFINALLY: {
4120 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4121 g_assert (spvar->inst_basereg != mips_sp);
4122 code = emit_unreserve_param_area (cfg, code);
4123 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4124 mips_jalr (code, mips_t9, mips_ra);
4128 case OP_CALL_HANDLER:
4129 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4130 mips_lui (code, mips_t9, mips_zero, 0);
4131 mips_addiu (code, mips_t9, mips_t9, 0);
4132 mips_jalr (code, mips_t9, mips_ra);
4134 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4135 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4138 ins->inst_c0 = code - cfg->native_code;
4141 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4142 if (cfg->arch.long_branch) {
4143 mips_lui (code, mips_at, mips_zero, 0);
4144 mips_addiu (code, mips_at, mips_at, 0);
4145 mips_jr (code, mips_at);
4149 mips_beq (code, mips_zero, mips_zero, 0);
4154 mips_jr (code, ins->sreg1);
4160 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4161 if (offset > (cfg->code_size - max_len - 16)) {
4162 cfg->code_size += max_len;
4163 cfg->code_size *= 2;
4164 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4165 code = cfg->native_code + offset;
4167 g_assert (ins->sreg1 != -1);
4168 mips_sll (code, mips_at, ins->sreg1, 2);
4169 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4170 MIPS_MOVE (code, mips_t8, mips_ra);
4171 mips_bgezal (code, mips_zero, 1); /* bal */
4173 mips_addu (code, mips_t9, mips_ra, mips_at);
4174 /* Table is 16 or 20 bytes from target of bal above */
4175 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4176 MIPS_MOVE (code, mips_ra, mips_t8);
4177 mips_lw (code, mips_t9, mips_t9, 20);
4180 mips_lw (code, mips_t9, mips_t9, 16);
4181 mips_jalr (code, mips_t9, mips_t8);
4183 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4184 mips_emit32 (code, 0xfefefefe);
4189 mips_addiu (code, ins->dreg, mips_zero, 1);
4190 mips_beq (code, mips_at, mips_zero, 2);
4192 MIPS_MOVE (code, ins->dreg, mips_zero);
4198 mips_addiu (code, ins->dreg, mips_zero, 1);
4199 mips_bltz (code, mips_at, 2);
4201 MIPS_MOVE (code, ins->dreg, mips_zero);
4207 mips_addiu (code, ins->dreg, mips_zero, 1);
4208 mips_bgtz (code, mips_at, 2);
4210 MIPS_MOVE (code, ins->dreg, mips_zero);
4213 case OP_MIPS_COND_EXC_EQ:
4214 case OP_MIPS_COND_EXC_GE:
4215 case OP_MIPS_COND_EXC_GT:
4216 case OP_MIPS_COND_EXC_LE:
4217 case OP_MIPS_COND_EXC_LT:
4218 case OP_MIPS_COND_EXC_NE_UN:
4219 case OP_MIPS_COND_EXC_GE_UN:
4220 case OP_MIPS_COND_EXC_GT_UN:
4221 case OP_MIPS_COND_EXC_LE_UN:
4222 case OP_MIPS_COND_EXC_LT_UN:
4224 case OP_MIPS_COND_EXC_OV:
4225 case OP_MIPS_COND_EXC_NO:
4226 case OP_MIPS_COND_EXC_C:
4227 case OP_MIPS_COND_EXC_NC:
4229 case OP_MIPS_COND_EXC_IEQ:
4230 case OP_MIPS_COND_EXC_IGE:
4231 case OP_MIPS_COND_EXC_IGT:
4232 case OP_MIPS_COND_EXC_ILE:
4233 case OP_MIPS_COND_EXC_ILT:
4234 case OP_MIPS_COND_EXC_INE_UN:
4235 case OP_MIPS_COND_EXC_IGE_UN:
4236 case OP_MIPS_COND_EXC_IGT_UN:
4237 case OP_MIPS_COND_EXC_ILE_UN:
4238 case OP_MIPS_COND_EXC_ILT_UN:
4240 case OP_MIPS_COND_EXC_IOV:
4241 case OP_MIPS_COND_EXC_INO:
4242 case OP_MIPS_COND_EXC_IC:
4243 case OP_MIPS_COND_EXC_INC: {
4247 /* If the condition is true, raise the exception */
4249 /* need to reverse test to skip around exception raising */
4251 /* For the moment, branch around a branch to avoid reversing
4254 /* Remember, an unpatched branch to 0 branches to the delay slot */
4255 switch (ins->opcode) {
4256 case OP_MIPS_COND_EXC_EQ:
4257 throw = (guint32 *)(void *)code;
4258 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4262 case OP_MIPS_COND_EXC_NE_UN:
4263 throw = (guint32 *)(void *)code;
4264 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4268 case OP_MIPS_COND_EXC_LE_UN:
4269 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4270 throw = (guint32 *)(void *)code;
4271 mips_beq (code, mips_at, mips_zero, 0);
4275 case OP_MIPS_COND_EXC_GT:
4276 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4277 throw = (guint32 *)(void *)code;
4278 mips_bne (code, mips_at, mips_zero, 0);
4282 case OP_MIPS_COND_EXC_GT_UN:
4283 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4284 throw = (guint32 *)(void *)code;
4285 mips_bne (code, mips_at, mips_zero, 0);
4289 case OP_MIPS_COND_EXC_LT:
4290 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4291 throw = (guint32 *)(void *)code;
4292 mips_bne (code, mips_at, mips_zero, 0);
4296 case OP_MIPS_COND_EXC_LT_UN:
4297 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4298 throw = (guint32 *)(void *)code;
4299 mips_bne (code, mips_at, mips_zero, 0);
4304 /* Not yet implemented */
4305 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4306 g_assert_not_reached ();
4308 skip = (guint32 *)(void *)code;
4309 mips_beq (code, mips_zero, mips_zero, 0);
4311 mips_patch (throw, (guint32)code);
4312 code = mips_emit_exc_by_name (code, ins->inst_p1);
4313 mips_patch (skip, (guint32)code);
4314 cfg->bb_exit->max_offset += 24;
4323 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4326 /* floating point opcodes */
4329 if (((guint32)ins->inst_p0) & (1 << 15))
4330 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4332 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4333 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4335 mips_load_const (code, mips_at, ins->inst_p0);
4336 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4337 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4341 if (((guint32)ins->inst_p0) & (1 << 15))
4342 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4344 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4345 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4346 #if PROMOTE_R4_TO_R8
4347 mips_cvtds (code, ins->dreg, ins->dreg);
4350 case OP_STORER8_MEMBASE_REG:
4351 if (mips_is_imm16 (ins->inst_offset)) {
4352 #if _MIPS_SIM == _ABIO32
4353 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4354 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4355 #elif _MIPS_SIM == _ABIN32
4356 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4359 mips_load_const (code, mips_at, ins->inst_offset);
4360 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4361 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4362 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4365 case OP_LOADR8_MEMBASE:
4366 if (mips_is_imm16 (ins->inst_offset)) {
4367 #if _MIPS_SIM == _ABIO32
4368 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4369 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4370 #elif _MIPS_SIM == _ABIN32
4371 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4374 mips_load_const (code, mips_at, ins->inst_offset);
4375 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4376 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4377 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4380 case OP_STORER4_MEMBASE_REG:
4381 g_assert (mips_is_imm16 (ins->inst_offset));
4382 #if PROMOTE_R4_TO_R8
4383 /* Need to convert ins->sreg1 to single-precision first */
4384 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4385 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4387 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4391 g_assert (mips_is_imm16 (ins->inst_offset));
4392 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4394 case OP_LOADR4_MEMBASE:
4395 g_assert (mips_is_imm16 (ins->inst_offset));
4396 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4397 #if PROMOTE_R4_TO_R8
4398 /* Convert to double precision in place */
4399 mips_cvtds (code, ins->dreg, ins->dreg);
4402 case OP_LOADR4_MEMINDEX:
4403 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4404 mips_lwc1 (code, ins->dreg, mips_at, 0);
4406 case OP_LOADR8_MEMINDEX:
4407 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4408 #if _MIPS_SIM == _ABIO32
4409 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4410 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4411 #elif _MIPS_SIM == _ABIN32
4412 mips_ldc1 (code, ins->dreg, mips_at, 0);
4415 case OP_STORER4_MEMINDEX:
4416 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4417 #if PROMOTE_R4_TO_R8
4418 /* Need to convert ins->sreg1 to single-precision first */
4419 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4420 mips_swc1 (code, mips_ftemp, mips_at, 0);
4422 mips_swc1 (code, ins->sreg1, mips_at, 0);
4425 case OP_STORER8_MEMINDEX:
4426 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4427 #if _MIPS_SIM == _ABIO32
4428 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4429 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4430 #elif _MIPS_SIM == _ABIN32
4431 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4434 case OP_ICONV_TO_R_UN: {
4435 static const guint64 adjust_val = 0x41F0000000000000ULL;
4437 /* convert unsigned int to double */
4438 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4439 mips_bgez (code, ins->sreg1, 5);
4440 mips_cvtdw (code, ins->dreg, mips_ftemp);
4442 mips_load (code, mips_at, (guint32) &adjust_val);
4443 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4444 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4445 /* target is here */
4448 case OP_ICONV_TO_R4:
4449 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4450 mips_cvtsw (code, ins->dreg, mips_ftemp);
4451 mips_cvtds (code, ins->dreg, ins->dreg);
4453 case OP_ICONV_TO_R8:
4454 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4455 mips_cvtdw (code, ins->dreg, mips_ftemp);
4457 case OP_FCONV_TO_I1:
4458 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4460 case OP_FCONV_TO_U1:
4461 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4463 case OP_FCONV_TO_I2:
4464 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4466 case OP_FCONV_TO_U2:
4467 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4469 case OP_FCONV_TO_I4:
4471 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4473 case OP_FCONV_TO_U4:
4475 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4478 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4481 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4484 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4487 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4490 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4493 mips_fnegd (code, ins->dreg, ins->sreg1);
4496 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4497 mips_addiu (code, ins->dreg, mips_zero, 1);
4498 mips_fbtrue (code, 2);
4500 MIPS_MOVE (code, ins->dreg, mips_zero);
4503 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4504 mips_addiu (code, ins->dreg, mips_zero, 1);
4505 mips_fbtrue (code, 2);
4507 MIPS_MOVE (code, ins->dreg, mips_zero);
4510 /* Less than, or Unordered */
4511 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4512 mips_addiu (code, ins->dreg, mips_zero, 1);
4513 mips_fbtrue (code, 2);
4515 MIPS_MOVE (code, ins->dreg, mips_zero);
4518 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4519 MIPS_MOVE (code, ins->dreg, mips_zero);
4520 mips_fbtrue (code, 2);
4522 mips_addiu (code, ins->dreg, mips_zero, 1);
4525 /* Greater than, or Unordered */
4526 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4527 MIPS_MOVE (code, ins->dreg, mips_zero);
4528 mips_fbtrue (code, 2);
4530 mips_addiu (code, ins->dreg, mips_zero, 1);
4535 case OP_MIPS_FBLT_UN:
4537 case OP_MIPS_FBGT_UN:
4539 case OP_MIPS_FBGE_UN:
4541 case OP_MIPS_FBLE_UN: {
4543 gboolean is_true = TRUE, is_ordered = FALSE;
4544 guint32 *buf = NULL;
4546 switch (ins->opcode) {
4560 case OP_MIPS_FBLT_UN:
4561 cond = MIPS_FPU_ULT;
4569 case OP_MIPS_FBGT_UN:
4570 cond = MIPS_FPU_OLE;
4578 case OP_MIPS_FBGE_UN:
4579 cond = MIPS_FPU_OLT;
4583 cond = MIPS_FPU_OLE;
4587 case OP_MIPS_FBLE_UN:
4588 cond = MIPS_FPU_ULE;
4592 g_assert_not_reached ();
4596 /* Skip the check if unordered */
4597 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4599 buf = (guint32*)code;
4600 mips_fbtrue (code, 0);
4604 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4606 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4608 mips_fbtrue (code, 0);
4610 mips_fbfalse (code, 0);
4614 mips_patch (buf, (guint32)code);
4618 guint32 *branch_patch;
4620 mips_mfc1 (code, mips_at, ins->sreg1+1);
4621 mips_srl (code, mips_at, mips_at, 16+4);
4622 mips_andi (code, mips_at, mips_at, 2047);
4623 mips_addiu (code, mips_at, mips_at, -2047);
4625 branch_patch = (guint32 *)(void *)code;
4626 mips_bne (code, mips_at, mips_zero, 0);
4629 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4630 mips_patch (branch_patch, (guint32)code);
4631 mips_fmovd (code, ins->dreg, ins->sreg1);
4635 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4636 mips_load (code, ins->dreg, 0x0f0f0f0f);
4641 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4642 g_assert_not_reached ();
4645 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4646 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4647 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4648 g_assert_not_reached ();
4654 last_offset = offset;
4657 cfg->code_len = code - cfg->native_code;
4661 mono_arch_register_lowlevel_calls (void)
4666 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4668 MonoJumpInfo *patch_info;
4670 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4671 unsigned char *ip = patch_info->ip.i + code;
4672 const unsigned char *target = NULL;
4674 switch (patch_info->type) {
4675 case MONO_PATCH_INFO_IP:
4676 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4678 case MONO_PATCH_INFO_SWITCH: {
4679 gpointer *table = (gpointer *)patch_info->data.table->table;
4682 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4684 for (i = 0; i < patch_info->data.table->table_size; i++) {
4685 table [i] = (int)patch_info->data.table->table [i] + code;
4689 case MONO_PATCH_INFO_METHODCONST:
4690 case MONO_PATCH_INFO_CLASS:
4691 case MONO_PATCH_INFO_IMAGE:
4692 case MONO_PATCH_INFO_FIELD:
4693 case MONO_PATCH_INFO_VTABLE:
4694 case MONO_PATCH_INFO_IID:
4695 case MONO_PATCH_INFO_SFLDA:
4696 case MONO_PATCH_INFO_LDSTR:
4697 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4698 case MONO_PATCH_INFO_LDTOKEN:
4699 case MONO_PATCH_INFO_R4:
4700 case MONO_PATCH_INFO_R8:
4701 /* from OP_AOTCONST : lui + addiu */
4702 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4703 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4706 case MONO_PATCH_INFO_EXC_NAME:
4707 g_assert_not_reached ();
4708 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4711 case MONO_PATCH_INFO_NONE:
4712 /* everything is dealt with at epilog output time */
4715 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4716 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4723 * Allow tracing to work with this interface (with an optional argument)
4725 * This code is expected to be inserted just after the 'real' prolog code,
4726 * and before the first basic block. We need to allocate a 2nd, temporary
4727 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4731 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4734 int offset = cfg->arch.tracing_offset;
4740 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4741 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4742 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4743 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4744 #if _MIPS_SIM == _ABIN32
4746 /* FIXME: Need a separate region for these */
4747 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4748 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4749 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4750 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4754 mips_load_const (code, mips_a0, cfg->method);
4755 mips_addiu (code, mips_a1, mips_sp, offset);
4756 mips_call (code, mips_t9, func);
4759 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4760 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4761 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4762 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4763 #if _MIPS_SIM == _ABIN32
4766 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4767 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4768 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4769 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4780 mips_adjust_stackframe(MonoCompile *cfg)
4783 int delta, threshold, i;
4784 MonoMethodSignature *sig;
4787 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4790 /* adjust cfg->stack_offset for account for down-spilling */
4791 cfg->stack_offset += SIZEOF_REGISTER;
4793 /* re-align cfg->stack_offset if needed (due to var spilling) */
4794 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4795 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4796 if (cfg->verbose_level > 2) {
4797 g_print ("mips_adjust_stackframe:\n");
4798 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4800 threshold = cfg->arch.local_alloc_offset;
4801 ra_offset = cfg->stack_offset - sizeof(gpointer);
4802 if (cfg->verbose_level > 2) {
4803 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4806 sig = mono_method_signature (cfg->method);
4807 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4808 cfg->vret_addr->inst_offset += delta;
4810 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4811 MonoInst *inst = cfg->args [i];
4813 inst->inst_offset += delta;
4817 * loads and stores based off the frame reg that (used to) lie
4818 * above the spill var area need to be increased by 'delta'
4819 * to make room for the spill vars.
4821 /* Need to find loads and stores to adjust that
4822 * are above where the spillvars were inserted, but
4823 * which are not the spillvar references themselves.
4825 * Idea - since all offsets from fp are positive, make
4826 * spillvar offsets negative to begin with so we can spot
4831 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4835 if (cfg->verbose_level > 2) {
4836 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4838 MONO_BB_FOR_EACH_INS (bb, ins) {
4842 if (cfg->verbose_level > 2) {
4843 mono_print_ins_index (ins_cnt, ins);
4845 /* The == mips_sp tests catch FP spills */
4846 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4847 (ins->inst_basereg == mips_sp))) {
4848 switch (ins->opcode) {
4849 case OP_LOADI8_MEMBASE:
4850 case OP_LOADR8_MEMBASE:
4857 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4858 (ins->dreg == mips_sp))) {
4859 switch (ins->opcode) {
4860 case OP_STOREI8_MEMBASE_REG:
4861 case OP_STORER8_MEMBASE_REG:
4862 case OP_STOREI8_MEMBASE_IMM:
4870 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4873 if (ins->inst_c0 >= threshold) {
4874 ins->inst_c0 += delta;
4875 if (cfg->verbose_level > 2) {
4877 mono_print_ins_index (ins_cnt, ins);
4880 else if (ins->inst_c0 < 0) {
4881 /* Adj_c0 holds the size of the datatype. */
4882 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4883 if (cfg->verbose_level > 2) {
4885 mono_print_ins_index (ins_cnt, ins);
4888 g_assert (ins->inst_c0 != ra_offset);
4891 if (ins->inst_imm >= threshold) {
4892 ins->inst_imm += delta;
4893 if (cfg->verbose_level > 2) {
4895 mono_print_ins_index (ins_cnt, ins);
4898 g_assert (ins->inst_c0 != ra_offset);
4908 * Stack frame layout:
4910 * ------------------- sp + cfg->stack_usage + cfg->param_area
4911 * param area incoming
4912 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4914 * ------------------- sp + cfg->stack_usage
4916 * ------------------- sp + cfg->stack_usage-4
4918 * ------------------- sp +
4919 * MonoLMF structure optional
4920 * ------------------- sp + cfg->arch.lmf_offset
4921 * saved registers s0-s8
4922 * ------------------- sp + cfg->arch.iregs_offset
4924 * ------------------- sp + cfg->param_area
4925 * param area outgoing
4926 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4928 * ------------------- sp
4932 mono_arch_emit_prolog (MonoCompile *cfg)
4934 MonoMethod *method = cfg->method;
4935 MonoMethodSignature *sig;
4937 int alloc_size, pos, i, max_offset;
4938 int alloc2_size = 0;
4942 guint32 iregs_to_save = 0;
4944 guint32 fregs_to_save = 0;
4946 /* lmf_offset is the offset of the LMF from our stack pointer. */
4947 guint32 lmf_offset = cfg->arch.lmf_offset;
4951 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4955 cfg->flags |= MONO_CFG_HAS_CALLS;
4957 sig = mono_method_signature (method);
4958 cfg->code_size = 768 + sig->param_count * 20;
4959 code = cfg->native_code = g_malloc (cfg->code_size);
4962 * compute max_offset in order to use short forward jumps.
4965 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4966 MonoInst *ins = bb->code;
4967 bb->max_offset = max_offset;
4969 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4972 MONO_BB_FOR_EACH_INS (bb, ins)
4973 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4975 if (max_offset > 0xffff)
4976 cfg->arch.long_branch = TRUE;
4979 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4980 * This means that we have to adjust the offsets inside instructions which reference
4981 * arguments received on the stack, since the initial offset doesn't take into
4982 * account spill slots.
4984 mips_adjust_stackframe (cfg);
4986 /* Offset between current sp and the CFA */
4988 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4990 /* stack_offset should not be changed here. */
4991 alloc_size = cfg->stack_offset;
4992 cfg->stack_usage = alloc_size;
4994 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4997 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4999 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
5000 fregs_to_save |= (fregs_to_save << 1);
5003 /* If the stack size is too big, save 1024 bytes to start with
5004 * so the prologue can use imm16(reg) addressing, then allocate
5005 * the rest of the frame.
5007 if (alloc_size > ((1 << 15) - 1024)) {
5008 alloc2_size = alloc_size - 1024;
5012 g_assert (mips_is_imm16 (-alloc_size));
5013 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
5014 cfa_offset = alloc_size;
5015 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5018 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5019 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5020 if (mips_is_imm16(offset))
5021 mips_sw (code, mips_ra, mips_sp, offset);
5023 g_assert_not_reached ();
5025 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5026 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5029 /* XXX - optimize this later to not save all regs if LMF constructed */
5030 pos = cfg->arch.iregs_offset - alloc2_size;
5032 if (iregs_to_save) {
5033 /* save used registers in own stack frame (at pos) */
5034 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5035 if (iregs_to_save & (1 << i)) {
5036 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5037 g_assert (mips_is_imm16(pos));
5038 MIPS_SW (code, i, mips_sp, pos);
5039 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5040 pos += SIZEOF_REGISTER;
5045 // FIXME: Don't save registers twice if there is an LMF
5046 // s8 has to be special cased since it is overwritten with the updated value
5048 if (method->save_lmf) {
5049 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5050 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5051 g_assert (mips_is_imm16(offset));
5052 if (MIPS_LMF_IREGMASK & (1 << i))
5053 MIPS_SW (code, i, mips_sp, offset);
5058 /* Save float registers */
5059 if (fregs_to_save) {
5060 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5061 if (fregs_to_save & (1 << i)) {
5062 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5063 g_assert (mips_is_imm16(pos));
5064 mips_swc1 (code, i, mips_sp, pos);
5065 pos += sizeof (gulong);
5070 if (method->save_lmf) {
5071 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5072 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5073 g_assert (mips_is_imm16(offset));
5074 mips_swc1 (code, i, mips_sp, offset);
5079 if (cfg->frame_reg != mips_sp) {
5080 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5081 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5083 if (method->save_lmf) {
5084 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5085 g_assert (mips_is_imm16(offset));
5086 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5090 /* store runtime generic context */
5091 if (cfg->rgctx_var) {
5092 MonoInst *ins = cfg->rgctx_var;
5094 g_assert (ins->opcode == OP_REGOFFSET);
5096 g_assert (mips_is_imm16 (ins->inst_offset));
5097 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5100 /* load arguments allocated to register from the stack */
5103 if (!cfg->arch.cinfo)
5104 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
5105 cinfo = cfg->arch.cinfo;
5107 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5108 ArgInfo *ainfo = &cinfo->ret;
5109 inst = cfg->vret_addr;
5110 if (inst->opcode == OP_REGVAR)
5111 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5112 else if (mips_is_imm16 (inst->inst_offset)) {
5113 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5115 mips_load_const (code, mips_at, inst->inst_offset);
5116 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5117 mips_sw (code, ainfo->reg, mips_at, 0);
5121 if (sig->call_convention == MONO_CALL_VARARG) {
5122 ArgInfo *cookie = &cinfo->sig_cookie;
5123 int offset = alloc_size + cookie->offset;
5125 /* Save the sig cookie address */
5126 g_assert (cookie->storage == ArgOnStack);
5128 g_assert (mips_is_imm16(offset));
5129 mips_addi (code, mips_at, cfg->frame_reg, offset);
5130 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5133 /* Keep this in sync with emit_load_volatile_arguments */
5134 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5135 ArgInfo *ainfo = cinfo->args + i;
5136 inst = cfg->args [pos];
5138 if (cfg->verbose_level > 2)
5139 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5140 if (inst->opcode == OP_REGVAR) {
5141 /* Argument ends up in a register */
5142 if (ainfo->storage == ArgInIReg)
5143 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5144 else if (ainfo->storage == ArgInFReg) {
5145 g_assert_not_reached();
5147 ppc_fmr (code, inst->dreg, ainfo->reg);
5150 else if (ainfo->storage == ArgOnStack) {
5151 int offset = cfg->stack_usage + ainfo->offset;
5152 g_assert (mips_is_imm16(offset));
5153 mips_lw (code, inst->dreg, mips_sp, offset);
5155 g_assert_not_reached ();
5157 if (cfg->verbose_level > 2)
5158 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5160 /* Argument ends up on the stack */
5161 if (ainfo->storage == ArgInIReg) {
5163 /* Incoming parameters should be above this frame */
5164 if (cfg->verbose_level > 2)
5165 g_print ("stack slot at %d of %d+%d\n",
5166 inst->inst_offset, alloc_size, alloc2_size);
5167 /* g_assert (inst->inst_offset >= alloc_size); */
5168 g_assert (inst->inst_basereg == cfg->frame_reg);
5169 basereg_offset = inst->inst_offset - alloc2_size;
5170 g_assert (mips_is_imm16 (basereg_offset));
5171 switch (ainfo->size) {
5173 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5176 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5180 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5183 #if (SIZEOF_REGISTER == 4)
5184 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5185 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5186 #elif (SIZEOF_REGISTER == 8)
5187 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5191 g_assert_not_reached ();
5194 } else if (ainfo->storage == ArgOnStack) {
5196 * Argument comes in on the stack, and ends up on the stack
5197 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5198 * 8 and 16 bit quantities. Shorten them in place.
5200 g_assert (mips_is_imm16 (inst->inst_offset));
5201 switch (ainfo->size) {
5203 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5204 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5207 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5208 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5215 g_assert_not_reached ();
5217 } else if (ainfo->storage == ArgInFReg) {
5218 g_assert (mips_is_imm16 (inst->inst_offset));
5219 g_assert (mips_is_imm16 (inst->inst_offset+4));
5220 if (ainfo->size == 8) {
5221 #if _MIPS_SIM == _ABIO32
5222 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5223 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5224 #elif _MIPS_SIM == _ABIN32
5225 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5228 else if (ainfo->size == 4)
5229 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5231 g_assert_not_reached ();
5232 } else if (ainfo->storage == ArgStructByVal) {
5234 int doffset = inst->inst_offset;
5236 g_assert (mips_is_imm16 (inst->inst_offset));
5237 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5238 /* Push the argument registers into their stack slots */
5239 for (i = 0; i < ainfo->size; ++i) {
5240 g_assert (mips_is_imm16(doffset));
5241 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5242 doffset += SIZEOF_REGISTER;
5244 } else if (ainfo->storage == ArgStructByAddr) {
5245 g_assert (mips_is_imm16 (inst->inst_offset));
5246 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5247 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5249 g_assert_not_reached ();
5254 if (method->save_lmf) {
5255 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5256 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5258 if (lmf_pthread_key != -1) {
5259 g_assert_not_reached();
5261 emit_tls_access (code, mips_temp, lmf_pthread_key);
5263 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5264 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5265 g_assert (mips_is_imm16(offset));
5266 mips_addiu (code, mips_a0, mips_temp, offset);
5269 /* This can/will clobber the a0-a3 registers */
5270 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5273 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5274 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5275 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5276 /* new_lmf->previous_lmf = *lmf_addr */
5277 mips_lw (code, mips_at, mips_v0, 0);
5278 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5279 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5280 /* *(lmf_addr) = sp + lmf_offset */
5281 g_assert (mips_is_imm16(lmf_offset));
5282 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5283 mips_sw (code, mips_at, mips_v0, 0);
5285 /* save method info */
5286 mips_load_const (code, mips_at, method);
5287 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5288 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5290 /* save the current IP */
5291 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5292 mips_load_const (code, mips_at, 0x01010101);
5293 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5297 if (mips_is_imm16 (-alloc2_size)) {
5298 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5301 mips_load_const (code, mips_at, -alloc2_size);
5302 mips_addu (code, mips_sp, mips_sp, mips_at);
5304 alloc_size += alloc2_size;
5305 cfa_offset += alloc2_size;
5306 if (cfg->frame_reg != mips_sp)
5307 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5309 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5313 #if _MIPS_SIM == _ABIO32
5314 cfg->arch.tracing_offset = cfg->stack_offset;
5315 #elif _MIPS_SIM == _ABIN32
5316 /* no stack slots by default for argument regs, reserve a special block */
5317 g_assert_not_reached ();
5319 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5322 cfg->code_len = code - cfg->native_code;
5323 g_assert (cfg->code_len < cfg->code_size);
5337 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5340 int save_mode = SAVE_NONE;
5342 MonoMethod *method = cfg->method;
5343 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type;
5344 int save_offset = MIPS_STACK_PARAM_OFFSET;
5346 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5348 offset = code - cfg->native_code;
5349 /* we need about 16 instructions */
5350 if (offset > (cfg->code_size - 16 * 4)) {
5351 cfg->code_size *= 2;
5352 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5353 code = cfg->native_code + offset;
5358 case MONO_TYPE_VOID:
5359 /* special case string .ctor icall */
5360 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5361 save_mode = SAVE_ONE;
5363 save_mode = SAVE_NONE;
5367 save_mode = SAVE_FP;
5369 case MONO_TYPE_VALUETYPE:
5370 save_mode = SAVE_STRUCT;
5374 #if SIZEOF_REGISTER == 4
5375 save_mode = SAVE_TWO;
5376 #elif SIZEOF_REGISTER == 8
5377 save_mode = SAVE_ONE;
5381 save_mode = SAVE_ONE;
5385 mips_addiu (code, mips_sp, mips_sp, -32);
5386 g_assert (mips_is_imm16(save_offset));
5387 switch (save_mode) {
5389 mips_sw (code, mips_v0, mips_sp, save_offset);
5390 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5391 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5392 if (enable_arguments) {
5393 MIPS_MOVE (code, mips_a1, mips_v0);
5394 MIPS_MOVE (code, mips_a2, mips_v1);
5398 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5399 if (enable_arguments) {
5400 MIPS_MOVE (code, mips_a1, mips_v0);
5404 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5405 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5406 mips_lw (code, mips_a0, mips_sp, save_offset);
5407 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5408 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5415 mips_load_const (code, mips_a0, cfg->method);
5416 mips_call (code, mips_t9, func);
5418 switch (save_mode) {
5420 mips_lw (code, mips_v0, mips_sp, save_offset);
5421 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5422 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5425 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5428 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5435 mips_addiu (code, mips_sp, mips_sp, 32);
5442 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5444 MonoMethod *method = cfg->method;
5446 int max_epilog_size = 16 + 20*4;
5447 int alloc2_size = 0;
5448 guint32 iregs_to_restore;
5450 guint32 fregs_to_restore;
5453 if (cfg->method->save_lmf)
5454 max_epilog_size += 128;
5456 if (mono_jit_trace_calls != NULL)
5457 max_epilog_size += 50;
5459 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5460 max_epilog_size += 50;
5463 pos = code - cfg->native_code;
5464 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5465 cfg->code_size *= 2;
5466 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5467 cfg->stat_code_reallocs++;
5471 * Keep in sync with OP_JMP
5474 code = cfg->native_code + pos;
5476 code = cfg->native_code + cfg->code_len;
5478 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5479 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5481 if (cfg->frame_reg != mips_sp) {
5482 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5484 /* If the stack frame is really large, deconstruct it in two steps */
5485 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5486 alloc2_size = cfg->stack_usage - 1024;
5487 /* partially deconstruct the stack */
5488 mips_load_const (code, mips_at, alloc2_size);
5489 mips_addu (code, mips_sp, mips_sp, mips_at);
5491 pos = cfg->arch.iregs_offset - alloc2_size;
5492 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5493 if (iregs_to_restore) {
5494 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5495 if (iregs_to_restore & (1 << i)) {
5496 g_assert (mips_is_imm16(pos));
5497 MIPS_LW (code, i, mips_sp, pos);
5498 pos += SIZEOF_REGISTER;
5505 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5507 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5508 fregs_to_restore |= (fregs_to_restore << 1);
5510 if (fregs_to_restore) {
5511 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5512 if (fregs_to_restore & (1 << i)) {
5513 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5514 g_assert (mips_is_imm16(pos));
5515 mips_lwc1 (code, i, mips_sp, pos);
5522 /* Unlink the LMF if necessary */
5523 if (method->save_lmf) {
5524 int lmf_offset = cfg->arch.lmf_offset;
5526 /* t0 = current_lmf->previous_lmf */
5527 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5528 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5530 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5531 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5532 /* (*lmf_addr) = previous_lmf */
5533 mips_sw (code, mips_temp, mips_t1, 0);
5537 /* Restore the fp */
5538 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5541 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5542 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5543 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5545 /* Restore the stack pointer */
5546 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5547 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5549 /* Caller will emit either return or tail-call sequence */
5551 cfg->code_len = code - cfg->native_code;
5553 g_assert (cfg->code_len < cfg->code_size);
5558 mono_arch_emit_epilog (MonoCompile *cfg)
5562 code = mono_arch_emit_epilog_sub (cfg, NULL);
5564 mips_jr (code, mips_ra);
5567 cfg->code_len = code - cfg->native_code;
5569 g_assert (cfg->code_len < cfg->code_size);
5572 /* remove once throw_exception_by_name is eliminated */
5575 exception_id_by_name (const char *name)
5577 if (strcmp (name, "IndexOutOfRangeException") == 0)
5578 return MONO_EXC_INDEX_OUT_OF_RANGE;
5579 if (strcmp (name, "OverflowException") == 0)
5580 return MONO_EXC_OVERFLOW;
5581 if (strcmp (name, "ArithmeticException") == 0)
5582 return MONO_EXC_ARITHMETIC;
5583 if (strcmp (name, "DivideByZeroException") == 0)
5584 return MONO_EXC_DIVIDE_BY_ZERO;
5585 if (strcmp (name, "InvalidCastException") == 0)
5586 return MONO_EXC_INVALID_CAST;
5587 if (strcmp (name, "NullReferenceException") == 0)
5588 return MONO_EXC_NULL_REF;
5589 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5590 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5591 if (strcmp (name, "ArgumentException") == 0)
5592 return MONO_EXC_ARGUMENT;
5593 g_error ("Unknown intrinsic exception %s\n", name);
5599 mono_arch_emit_exceptions (MonoCompile *cfg)
5602 MonoJumpInfo *patch_info;
5605 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5606 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5607 int max_epilog_size = 50;
5609 /* count the number of exception infos */
5612 * make sure we have enough space for exceptions
5613 * 24 is the simulated call to throw_exception_by_name
5615 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5617 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5618 i = exception_id_by_name (patch_info->data.target);
5619 g_assert (i < MONO_EXC_INTRINS_NUM);
5620 if (!exc_throw_found [i]) {
5621 max_epilog_size += 12;
5622 exc_throw_found [i] = TRUE;
5628 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5629 cfg->code_size *= 2;
5630 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5631 cfg->stat_code_reallocs++;
5634 code = cfg->native_code + cfg->code_len;
5636 /* add code to raise exceptions */
5637 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5638 switch (patch_info->type) {
5639 case MONO_PATCH_INFO_EXC: {
5641 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5643 i = exception_id_by_name (patch_info->data.target);
5644 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5645 if (!exc_throw_pos [i]) {
5648 exc_throw_pos [i] = code;
5649 //g_print ("exc: writing stub at %p\n", code);
5650 mips_load_const (code, mips_a0, patch_info->data.target);
5651 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5652 mips_load_const (code, mips_t9, addr);
5653 mips_jr (code, mips_t9);
5656 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5658 /* Turn into a Relative patch, pointing at code stub */
5659 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5660 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5662 g_assert_not_reached();
5672 cfg->code_len = code - cfg->native_code;
5674 g_assert (cfg->code_len < cfg->code_size);
5679 * Thread local storage support
5682 setup_tls_access (void)
5685 //guint32 *ins, *code;
5687 if (tls_mode == TLS_MODE_FAILED)
5690 if (g_getenv ("MONO_NO_TLS")) {
5691 tls_mode = TLS_MODE_FAILED;
5695 if (tls_mode == TLS_MODE_DETECT) {
5697 tls_mode = TLS_MODE_FAILED;
5701 ins = (guint32*)pthread_getspecific;
5702 /* uncond branch to the real method */
5703 if ((*ins >> 26) == 18) {
5705 val = (*ins & ~3) << 6;
5709 ins = (guint32*)val;
5711 ins = (guint32*) ((char*)ins + val);
5714 code = &cmplwi_1023;
5715 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5717 ppc_li (code, ppc_r4, 0x48);
5720 if (*ins == cmplwi_1023) {
5721 int found_lwz_284 = 0;
5722 for (ptk = 0; ptk < 20; ++ptk) {
5724 if (!*ins || *ins == blr_ins)
5726 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5731 if (!found_lwz_284) {
5732 tls_mode = TLS_MODE_FAILED;
5735 tls_mode = TLS_MODE_LTHREADS;
5736 } else if (*ins == li_0x48) {
5738 /* uncond branch to the real method */
5739 if ((*ins >> 26) == 18) {
5741 val = (*ins & ~3) << 6;
5745 ins = (guint32*)val;
5747 ins = (guint32*) ((char*)ins + val);
5750 ppc_li (code, ppc_r0, 0x7FF2);
5751 if (ins [1] == val) {
5752 /* Darwin on G4, implement */
5753 tls_mode = TLS_MODE_FAILED;
5757 ppc_mfspr (code, ppc_r3, 104);
5758 if (ins [1] != val) {
5759 tls_mode = TLS_MODE_FAILED;
5762 tls_mode = TLS_MODE_DARWIN_G5;
5765 tls_mode = TLS_MODE_FAILED;
5769 tls_mode = TLS_MODE_FAILED;
5774 if (lmf_pthread_key == -1) {
5775 ptk = mono_jit_tls_id;
5777 /*g_print ("MonoLMF at: %d\n", ptk);*/
5778 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5779 init_tls_failed = 1;
5782 lmf_pthread_key = ptk;
5785 if (monothread_key == -1) {
5786 ptk = mono_thread_get_tls_key ();
5788 monothread_key = ptk;
5789 /*g_print ("thread inited: %d\n", ptk);*/
5791 /*g_print ("thread not inited yet %d\n", ptk);*/
5797 mono_arch_finish_init (void)
5799 setup_tls_access ();
5803 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5808 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5810 int this_dreg = mips_a0;
5813 this_dreg = mips_a1;
5815 /* add the this argument */
5816 if (this_reg != -1) {
5818 MONO_INST_NEW (cfg, this, OP_MOVE);
5819 this->type = this_type;
5820 this->sreg1 = this_reg;
5821 this->dreg = mono_alloc_ireg (cfg);
5822 mono_bblock_add_inst (cfg->cbb, this);
5823 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5828 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5829 vtarg->type = STACK_MP;
5830 vtarg->sreg1 = vt_reg;
5831 vtarg->dreg = mono_alloc_ireg (cfg);
5832 mono_bblock_add_inst (cfg->cbb, vtarg);
5833 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5838 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5840 MonoInst *ins = NULL;
5846 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5852 mono_arch_print_tree (MonoInst *tree, int arity)
5858 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5860 return ctx->sc_regs [reg];
5863 #define ENABLE_WRONG_METHOD_CHECK 0
5865 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5866 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5868 #define LOADSTORE_SIZE 4
5869 #define JUMP_IMM_SIZE 16
5870 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5871 #define LOAD_CONST_SIZE 8
5872 #define JUMP_JR_SIZE 8
5875 * LOCKING: called with the domain lock held
5878 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5879 gpointer fail_tramp)
5883 guint8 *code, *start, *patch;
5885 for (i = 0; i < count; ++i) {
5886 MonoIMTCheckItem *item = imt_entries [i];
5888 if (item->is_equals) {
5889 if (item->check_target_idx) {
5890 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5891 if (item->has_target_code)
5892 item->chunk_size += LOAD_CONST_SIZE;
5894 item->chunk_size += LOADSTORE_SIZE;
5897 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5898 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5899 if (!item->has_target_code)
5900 item->chunk_size += LOADSTORE_SIZE;
5902 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5903 #if ENABLE_WRONG_METHOD_CHECK
5904 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5909 item->chunk_size += CMP_SIZE + BR_SIZE;
5910 imt_entries [item->check_target_idx]->compare_done = TRUE;
5912 size += item->chunk_size;
5914 /* the initial load of the vtable address */
5915 size += MIPS_LOAD_SEQUENCE_LENGTH;
5917 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5919 code = mono_domain_code_reserve (domain, size);
5923 /* t7 points to the vtable */
5924 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5926 for (i = 0; i < count; ++i) {
5927 MonoIMTCheckItem *item = imt_entries [i];
5929 item->code_target = code;
5930 if (item->is_equals) {
5931 if (item->check_target_idx) {
5932 mips_load_const (code, mips_temp, (gsize)item->key);
5933 item->jmp_code = code;
5934 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5936 if (item->has_target_code) {
5937 mips_load_const (code, mips_t9,
5938 item->value.target_code);
5941 mips_lw (code, mips_t9, mips_t7,
5942 (sizeof (gpointer) * item->value.vtable_slot));
5944 mips_jr (code, mips_t9);
5948 mips_load_const (code, mips_temp, (gsize)item->key);
5950 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5952 if (item->has_target_code) {
5953 mips_load_const (code, mips_t9,
5954 item->value.target_code);
5957 mips_load_const (code, mips_at,
5958 & (vtable->vtable [item->value.vtable_slot]));
5959 mips_lw (code, mips_t9, mips_at, 0);
5961 mips_jr (code, mips_t9);
5963 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5964 mips_load_const (code, mips_t9, fail_tramp);
5965 mips_jr (code, mips_t9);
5968 /* enable the commented code to assert on wrong method */
5969 #if ENABLE_WRONG_METHOD_CHECK
5970 ppc_load (code, ppc_r0, (guint32)item->key);
5971 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5973 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5975 mips_lw (code, mips_t9, mips_t7,
5976 (sizeof (gpointer) * item->value.vtable_slot));
5977 mips_jr (code, mips_t9);
5980 #if ENABLE_WRONG_METHOD_CHECK
5981 ppc_patch (patch, code);
5987 mips_load_const (code, mips_temp, (gulong)item->key);
5988 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5990 item->jmp_code = code;
5991 mips_beq (code, mips_temp, mips_zero, 0);
5995 /* patch the branches to get to the target items */
5996 for (i = 0; i < count; ++i) {
5997 MonoIMTCheckItem *item = imt_entries [i];
5998 if (item->jmp_code && item->check_target_idx) {
5999 mips_patch ((guint32 *)item->jmp_code,
6000 (guint32)imt_entries [item->check_target_idx]->code_target);
6005 mono_stats.imt_thunks_size += code - start;
6006 g_assert (code - start <= size);
6007 mono_arch_flush_icache (start, size);
6012 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6014 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6018 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6020 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6023 /* Soft Debug support */
6024 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6027 * mono_arch_set_breakpoint:
6029 * See mini-amd64.c for docs.
6032 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6035 guint32 addr = (guint32)bp_trigger_page;
6037 mips_load_const (code, mips_t9, addr);
6038 mips_lw (code, mips_t9, mips_t9, 0);
6040 mono_arch_flush_icache (ip, code - ip);
6044 * mono_arch_clear_breakpoint:
6046 * See mini-amd64.c for docs.
6049 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6057 mono_arch_flush_icache (ip, code - ip);
6061 * mono_arch_start_single_stepping:
6063 * See mini-amd64.c for docs.
6066 mono_arch_start_single_stepping (void)
6068 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6072 * mono_arch_stop_single_stepping:
6074 * See mini-amd64.c for docs.
6077 mono_arch_stop_single_stepping (void)
6079 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6083 * mono_arch_is_single_step_event:
6085 * See mini-amd64.c for docs.
6088 mono_arch_is_single_step_event (void *info, void *sigctx)
6090 siginfo_t* sinfo = (siginfo_t*) info;
6091 /* Sometimes the address is off by 4 */
6092 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6099 * mono_arch_is_breakpoint_event:
6101 * See mini-amd64.c for docs.
6104 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6106 siginfo_t* sinfo = (siginfo_t*) info;
6107 /* Sometimes the address is off by 4 */
6108 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6115 * mono_arch_skip_breakpoint:
6117 * See mini-amd64.c for docs.
6120 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6122 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6126 * mono_arch_skip_single_step:
6128 * See mini-amd64.c for docs.
6131 mono_arch_skip_single_step (MonoContext *ctx)
6133 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6137 * mono_arch_get_seq_point_info:
6139 * See mini-amd64.c for docs.
6142 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6149 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6151 ext->lmf.previous_lmf = prev_lmf;
6152 /* Mark that this is a MonoLMFExt */
6153 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6154 ext->lmf.iregs [mips_sp] = (gssize)ext;
6157 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
6160 mono_arch_opcode_supported (int opcode)