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_os_mutex_lock (&mini_arch_mutex)
61 #define mono_mini_arch_unlock() mono_os_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_load_from_name (mono_defaults.corlib, "System", name);
226 mips_load_const (code, mips_a0, exc_class->type_token);
227 addr = mono_get_throw_corlib_exception ();
228 mips_call (code, mips_t9, addr);
234 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
236 if (mips_is_imm16 (v))
237 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
239 #if SIZEOF_REGISTER == 8
241 /* v is not a sign-extended 32-bit value */
242 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
243 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
244 mips_dsll (code, dreg, dreg, 16);
245 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
246 mips_dsll (code, dreg, dreg, 16);
247 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
251 if (((guint32)v) & (1 << 15)) {
252 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
255 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
257 if (((guint32)v) & 0xffff)
258 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
264 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
267 if (cfg->arch.long_branch) {
270 /* Invert test and emit branch around jump */
273 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
277 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
281 mips_bltz (code, ins->sreg1, br_offset);
285 mips_blez (code, ins->sreg1, br_offset);
289 mips_bgtz (code, ins->sreg1, br_offset);
293 mips_bgez (code, ins->sreg1, br_offset);
297 g_assert_not_reached ();
299 mono_add_patch_info (cfg, code - cfg->native_code,
300 MONO_PATCH_INFO_BB, ins->inst_true_bb);
301 mips_lui (code, mips_at, mips_zero, 0);
302 mips_addiu (code, mips_at, mips_at, 0);
303 mips_jr (code, mips_at);
307 mono_add_patch_info (cfg, code - cfg->native_code,
308 MONO_PATCH_INFO_BB, ins->inst_true_bb);
311 mips_beq (code, ins->sreg1, ins->sreg2, 0);
315 mips_bne (code, ins->sreg1, ins->sreg2, 0);
319 mips_bgez (code, ins->sreg1, 0);
323 mips_bgtz (code, ins->sreg1, 0);
327 mips_blez (code, ins->sreg1, 0);
331 mips_bltz (code, ins->sreg1, 0);
335 g_assert_not_reached ();
341 /* XXX - big-endian dependent? */
343 patch_lui_addiu(guint32 *ip, guint32 val)
345 guint16 *__lui_addiu = (guint16*)(void *)(ip);
348 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
349 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
352 if (((guint32)(val)) & (1 << 15))
353 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
355 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
356 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
357 mono_arch_flush_icache ((guint8 *)ip, 8);
362 mips_patch (guint32 *code, guint32 target)
365 guint32 op = ins >> 26;
366 guint32 diff, offset;
368 g_assert (trap_target != target);
369 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
371 case 0x00: /* jr ra */
372 if (ins == 0x3e00008)
374 g_assert_not_reached ();
378 g_assert (!(target & 0x03));
379 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
380 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
382 mono_arch_flush_icache ((guint8 *)code, 4);
384 case 0x01: /* BLTZ */
387 case 0x06: /* BLEZ */
388 case 0x07: /* BGTZ */
389 case 0x11: /* bc1t */
390 diff = target - (guint32)(code + 1);
391 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
392 g_assert (!(diff & 0x03));
393 offset = ((gint32)diff) >> 2;
394 if (((int)offset) != ((int)(short)offset))
395 g_assert (((int)offset) == ((int)(short)offset));
396 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
398 mono_arch_flush_icache ((guint8 *)code, 4);
400 case 0x0f: /* LUI / ADDIU pair */
401 g_assert ((code[1] >> 26) == 0x9);
402 patch_lui_addiu (code, target);
403 mono_arch_flush_icache ((guint8 *)code, 8);
407 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
408 g_assert_not_reached ();
414 offsets_from_pthread_key (guint32 key, int *offset2)
418 *offset2 = idx2 * sizeof (gpointer);
419 return 284 + idx1 * sizeof (gpointer);
423 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
426 mono_arch_regname (int reg) {
427 #if _MIPS_SIM == _ABIO32
428 static const char * rnames[] = {
429 "zero", "at", "v0", "v1",
430 "a0", "a1", "a2", "a3",
431 "t0", "t1", "t2", "t3",
432 "t4", "t5", "t6", "t7",
433 "s0", "s1", "s2", "s3",
434 "s4", "s5", "s6", "s7",
435 "t8", "t9", "k0", "k1",
436 "gp", "sp", "fp", "ra"
438 #elif _MIPS_SIM == _ABIN32
439 static const char * rnames[] = {
440 "zero", "at", "v0", "v1",
441 "a0", "a1", "a2", "a3",
442 "a4", "a5", "a6", "a7",
443 "t0", "t1", "t2", "t3",
444 "s0", "s1", "s2", "s3",
445 "s4", "s5", "s6", "s7",
446 "t8", "t9", "k0", "k1",
447 "gp", "sp", "fp", "ra"
450 if (reg >= 0 && reg < 32)
456 mono_arch_fregname (int reg) {
457 static const char * rnames[] = {
458 "f0", "f1", "f2", "f3",
459 "f4", "f5", "f6", "f7",
460 "f8", "f9", "f10", "f11",
461 "f12", "f13", "f14", "f15",
462 "f16", "f17", "f18", "f19",
463 "f20", "f21", "f22", "f23",
464 "f24", "f25", "f26", "f27",
465 "f28", "f29", "f30", "f31"
467 if (reg >= 0 && reg < 32)
472 /* this function overwrites at */
474 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
476 /* XXX write a loop, not an unrolled loop */
478 mips_lw (code, mips_at, sreg, soffset);
479 mips_sw (code, mips_at, dreg, doffset);
488 * mono_arch_get_argument_info:
489 * @csig: a method signature
490 * @param_count: the number of parameters to consider
491 * @arg_info: an array to store the result infos
493 * Gathers information on parameters such as size, alignment and
494 * padding. arg_info should be large enought to hold param_count + 1 entries.
496 * Returns the size of the activation frame.
499 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
501 int k, frame_size = 0;
502 guint32 size, align, pad;
505 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
506 frame_size += sizeof (gpointer);
510 arg_info [0].offset = offset;
513 frame_size += sizeof (gpointer);
517 arg_info [0].size = frame_size;
519 for (k = 0; k < param_count; k++) {
520 size = mini_type_stack_size_full (csig->params [k], &align, csig->pinvoke);
522 /* ignore alignment for now */
525 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
526 arg_info [k].pad = pad;
528 arg_info [k + 1].pad = 0;
529 arg_info [k + 1].size = size;
531 arg_info [k + 1].offset = offset;
535 align = MONO_ARCH_FRAME_ALIGNMENT;
536 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
537 arg_info [k].pad = pad;
542 /* The delegate object plus 3 params */
543 #define MAX_ARCH_DELEGATE_PARAMS (4 - 1)
546 get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean param_count)
548 guint8 *code, *start;
551 start = code = mono_global_codeman_reserve (16);
553 /* Replace the this argument with the target */
554 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
555 mips_lw (code, mips_a0, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, target));
556 mips_jr (code, mips_temp);
559 g_assert ((code - start) <= 16);
561 mono_arch_flush_icache (start, 16);
565 size = 16 + param_count * 4;
566 start = code = mono_global_codeman_reserve (size);
568 mips_lw (code, mips_temp, mips_a0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
569 /* slide down the arguments */
570 for (i = 0; i < param_count; ++i) {
571 mips_move (code, mips_a0 + i, mips_a0 + i + 1);
573 mips_jr (code, mips_temp);
576 g_assert ((code - start) <= size);
578 mono_arch_flush_icache (start, size);
582 *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL);
584 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count);
585 *info = mono_tramp_info_create (name, start, code - start, NULL, NULL);
593 * mono_arch_get_delegate_invoke_impls:
595 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
599 mono_arch_get_delegate_invoke_impls (void)
605 get_delegate_invoke_impl (&info, TRUE, 0);
606 res = g_slist_prepend (res, info);
608 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
609 get_delegate_invoke_impl (&info, FALSE, i);
610 res = g_slist_prepend (res, info);
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");
637 start = get_delegate_invoke_impl (&info, TRUE, 0);
638 mono_tramp_info_register (info, NULL);
641 mono_mini_arch_unlock ();
644 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
647 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
649 for (i = 0; i < sig->param_count; ++i)
650 if (!mono_is_regsize_var (sig->params [i]))
653 mono_mini_arch_lock ();
654 code = cache [sig->param_count];
656 mono_mini_arch_unlock ();
661 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
662 start = mono_aot_get_trampoline (name);
666 start = get_delegate_invoke_impl (&info, FALSE, sig->param_count);
667 mono_tramp_info_register (info, NULL);
669 cache [sig->param_count] = start;
670 mono_mini_arch_unlock ();
678 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
684 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
687 return (gpointer)regs [mips_a0];
691 * Initialize the cpu to execute managed code.
694 mono_arch_cpu_init (void)
696 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
705 ls_word_offset = ls_word_idx * 4;
706 ms_word_offset = ms_word_idx * 4;
710 * Initialize architecture specific code.
713 mono_arch_init (void)
715 mono_os_mutex_init_recursive (&mini_arch_mutex);
717 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
718 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
719 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
723 * Cleanup architecture specific code.
726 mono_arch_cleanup (void)
728 mono_os_mutex_destroy (&mini_arch_mutex);
732 * This function returns the optimizations supported on this cpu.
735 mono_arch_cpu_optimizations (guint32 *exclude_mask)
739 /* no mips-specific optimizations yet */
745 * This function test for all SIMD functions supported.
747 * Returns a bitmask corresponding to all supported versions.
751 mono_arch_cpu_enumerate_simd_versions (void)
753 /* SIMD is currently unimplemented */
758 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
763 for (i = 0; i < cfg->num_varinfo; i++) {
764 MonoInst *ins = cfg->varinfo [i];
765 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
768 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
771 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
774 /* we can only allocate 32 bit values */
775 if (mono_is_regsize_var (ins->inst_vtype)) {
776 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
777 g_assert (i == vmv->idx);
778 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
786 mono_arch_get_global_int_regs (MonoCompile *cfg)
790 regs = g_list_prepend (regs, (gpointer)mips_s0);
791 regs = g_list_prepend (regs, (gpointer)mips_s1);
792 regs = g_list_prepend (regs, (gpointer)mips_s2);
793 regs = g_list_prepend (regs, (gpointer)mips_s3);
794 regs = g_list_prepend (regs, (gpointer)mips_s4);
795 //regs = g_list_prepend (regs, (gpointer)mips_s5);
796 regs = g_list_prepend (regs, (gpointer)mips_s6);
797 regs = g_list_prepend (regs, (gpointer)mips_s7);
803 * mono_arch_regalloc_cost:
805 * Return the cost, in number of memory references, of the action of
806 * allocating the variable VMV into a register during global register
810 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
817 args_onto_stack (CallInfo *info)
819 g_assert (!info->on_stack);
820 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
821 info->on_stack = TRUE;
822 info->stack_size = MIPS_STACK_PARAM_OFFSET;
825 #if _MIPS_SIM == _ABIO32
827 * O32 calling convention version
831 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
832 /* First, see if we need to drop onto the stack */
833 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
834 args_onto_stack (info);
836 /* Now, place the argument */
837 if (info->on_stack) {
838 ainfo->storage = ArgOnStack;
839 ainfo->reg = mips_sp; /* in the caller */
840 ainfo->offset = info->stack_size;
843 ainfo->storage = ArgInIReg;
844 ainfo->reg = info->gr;
846 info->gr_passed = TRUE;
848 info->stack_size += 4;
852 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
853 /* First, see if we need to drop onto the stack */
854 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
855 args_onto_stack (info);
857 /* Now, place the argument */
858 if (info->on_stack) {
859 g_assert (info->stack_size % 4 == 0);
860 info->stack_size += (info->stack_size % 8);
862 ainfo->storage = ArgOnStack;
863 ainfo->reg = mips_sp; /* in the caller */
864 ainfo->offset = info->stack_size;
867 // info->gr must be a0 or a2
868 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
869 g_assert(info->gr <= MIPS_LAST_ARG_REG);
871 ainfo->storage = ArgInIReg;
872 ainfo->reg = info->gr;
874 info->gr_passed = TRUE;
876 info->stack_size += 8;
880 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
881 /* First, see if we need to drop onto the stack */
882 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
883 args_onto_stack (info);
885 /* Now, place the argument */
886 if (info->on_stack) {
887 ainfo->storage = ArgOnStack;
888 ainfo->reg = mips_sp; /* in the caller */
889 ainfo->offset = info->stack_size;
892 /* Only use FP regs for args if no int args passed yet */
893 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
894 ainfo->storage = ArgInFReg;
895 ainfo->reg = info->fr;
896 /* Even though it's a single-precision float, it takes up two FP regs */
898 /* FP and GP slots do not overlap */
902 /* Passing single-precision float arg in a GP register
903 * such as: func (0, 1.0, 2, 3);
904 * In this case, only one 'gr' register is consumed.
906 ainfo->storage = ArgInIReg;
907 ainfo->reg = info->gr;
910 info->gr_passed = TRUE;
913 info->stack_size += 4;
917 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
918 /* First, see if we need to drop onto the stack */
919 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
920 args_onto_stack (info);
922 /* Now, place the argument */
923 if (info->on_stack) {
924 g_assert(info->stack_size % 4 == 0);
925 info->stack_size += (info->stack_size % 8);
927 ainfo->storage = ArgOnStack;
928 ainfo->reg = mips_sp; /* in the caller */
929 ainfo->offset = info->stack_size;
932 /* Only use FP regs for args if no int args passed yet */
933 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
934 ainfo->storage = ArgInFReg;
935 ainfo->reg = info->fr;
937 /* FP and GP slots do not overlap */
941 // info->gr must be a0 or a2
942 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
943 g_assert(info->gr <= MIPS_LAST_ARG_REG);
945 ainfo->storage = ArgInIReg;
946 ainfo->reg = info->gr;
948 info->gr_passed = TRUE;
951 info->stack_size += 8;
953 #elif _MIPS_SIM == _ABIN32
955 * N32 calling convention version
959 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
960 /* First, see if we need to drop onto the stack */
961 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
962 args_onto_stack (info);
964 /* Now, place the argument */
965 if (info->on_stack) {
966 ainfo->storage = ArgOnStack;
967 ainfo->reg = mips_sp; /* in the caller */
968 ainfo->offset = info->stack_size;
969 info->stack_size += SIZEOF_REGISTER;
972 ainfo->storage = ArgInIReg;
973 ainfo->reg = info->gr;
975 info->gr_passed = TRUE;
980 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
981 /* First, see if we need to drop onto the stack */
982 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
983 args_onto_stack (info);
985 /* Now, place the argument */
986 if (info->on_stack) {
987 g_assert (info->stack_size % 4 == 0);
988 info->stack_size += (info->stack_size % 8);
990 ainfo->storage = ArgOnStack;
991 ainfo->reg = mips_sp; /* in the caller */
992 ainfo->offset = info->stack_size;
993 info->stack_size += SIZEOF_REGISTER;
996 g_assert (info->gr <= MIPS_LAST_ARG_REG);
998 ainfo->storage = ArgInIReg;
999 ainfo->reg = info->gr;
1001 info->gr_passed = TRUE;
1006 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
1007 /* First, see if we need to drop onto the stack */
1008 if (!info->on_stack) {
1009 if (info->gr > MIPS_LAST_ARG_REG)
1010 args_onto_stack (info);
1011 else if (info->fr > MIPS_LAST_FPARG_REG)
1012 args_onto_stack (info);
1015 /* Now, place the argument */
1016 if (info->on_stack) {
1017 ainfo->storage = ArgOnStack;
1018 ainfo->reg = mips_sp; /* in the caller */
1019 ainfo->offset = info->stack_size;
1020 info->stack_size += FREG_SIZE;
1023 ainfo->storage = ArgInFReg;
1024 ainfo->reg = info->fr;
1026 /* FP and GP slots do not overlap */
1032 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1033 /* First, see if we need to drop onto the stack */
1034 if (!info->on_stack) {
1035 if (info->gr > MIPS_LAST_ARG_REG)
1036 args_onto_stack (info);
1037 else if (info->fr > MIPS_LAST_FPARG_REG)
1038 args_onto_stack (info);
1041 /* Now, place the argument */
1042 if (info->on_stack) {
1043 g_assert(info->stack_size % 4 == 0);
1044 info->stack_size += (info->stack_size % 8);
1046 ainfo->storage = ArgOnStack;
1047 ainfo->reg = mips_sp; /* in the caller */
1048 ainfo->offset = info->stack_size;
1049 info->stack_size += FREG_SIZE;
1052 ainfo->storage = ArgInFReg;
1053 ainfo->reg = info->fr;
1055 /* FP and GP slots do not overlap */
1062 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1065 int n = sig->hasthis + sig->param_count;
1067 MonoType* simpletype;
1069 gboolean is_pinvoke = sig->pinvoke;
1072 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1074 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1076 cinfo->fr = MIPS_FIRST_FPARG_REG;
1077 cinfo->gr = MIPS_FIRST_ARG_REG;
1078 cinfo->stack_size = 0;
1080 DEBUG(printf("calculate_sizes\n"));
1082 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1086 /* handle returning a struct */
1087 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1088 cinfo->struct_ret = cinfo->gr;
1089 add_int32_arg (cinfo, &cinfo->ret);
1093 add_int32_arg (cinfo, cinfo->args + n);
1098 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1099 * the first argument, allowing 'this' to be always passed in the first arg reg.
1100 * Also do this if the first argument is a reference type, since virtual calls
1101 * are sometimes made using calli without sig->hasthis set, like in the delegate
1104 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_get_underlying_type (sig->params [0]))))) {
1106 add_int32_arg (cinfo, cinfo->args + n);
1109 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1113 add_int32_arg (cinfo, &cinfo->ret);
1114 cinfo->struct_ret = cinfo->ret.reg;
1118 add_int32_arg (cinfo, cinfo->args + n);
1122 if (cinfo->vtype_retaddr) {
1123 add_int32_arg (cinfo, &cinfo->ret);
1124 cinfo->struct_ret = cinfo->ret.reg;
1129 DEBUG(printf("params: %d\n", sig->param_count));
1130 for (i = pstart; i < sig->param_count; ++i) {
1131 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1132 /* Prevent implicit arguments and sig_cookie from
1133 being passed in registers */
1134 args_onto_stack (cinfo);
1135 /* Emit the signature cookie just before the implicit arguments */
1136 add_int32_arg (cinfo, &cinfo->sig_cookie);
1138 DEBUG(printf("param %d: ", i));
1139 simpletype = mini_get_underlying_type (sig->params [i]);
1140 switch (simpletype->type) {
1141 case MONO_TYPE_BOOLEAN:
1144 DEBUG(printf("1 byte\n"));
1145 cinfo->args [n].size = 1;
1146 add_int32_arg (cinfo, &cinfo->args[n]);
1149 case MONO_TYPE_CHAR:
1152 DEBUG(printf("2 bytes\n"));
1153 cinfo->args [n].size = 2;
1154 add_int32_arg (cinfo, &cinfo->args[n]);
1159 DEBUG(printf("4 bytes\n"));
1160 cinfo->args [n].size = 4;
1161 add_int32_arg (cinfo, &cinfo->args[n]);
1167 case MONO_TYPE_FNPTR:
1168 case MONO_TYPE_CLASS:
1169 case MONO_TYPE_OBJECT:
1170 case MONO_TYPE_STRING:
1171 case MONO_TYPE_SZARRAY:
1172 case MONO_TYPE_ARRAY:
1173 cinfo->args [n].size = sizeof (gpointer);
1174 add_int32_arg (cinfo, &cinfo->args[n]);
1177 case MONO_TYPE_GENERICINST:
1178 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1179 cinfo->args [n].size = sizeof (gpointer);
1180 add_int32_arg (cinfo, &cinfo->args[n]);
1185 case MONO_TYPE_TYPEDBYREF:
1186 case MONO_TYPE_VALUETYPE: {
1189 int has_offset = FALSE;
1191 gint size, alignment;
1194 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1195 size = sizeof (MonoTypedRef);
1196 alignment = sizeof (gpointer);
1198 klass = mono_class_from_mono_type (sig->params [i]);
1200 size = mono_class_native_size (klass, NULL);
1202 size = mono_class_value_size (klass, NULL);
1203 alignment = mono_class_min_align (klass);
1205 #if MIPS_PASS_STRUCTS_BY_VALUE
1206 /* Need to do alignment if struct contains long or double */
1207 if (alignment > 4) {
1208 /* Drop onto stack *before* looking at
1209 stack_size, if required. */
1210 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1211 args_onto_stack (cinfo);
1212 if (cinfo->stack_size & (alignment - 1)) {
1213 add_int32_arg (cinfo, &dummy_arg);
1215 g_assert (!(cinfo->stack_size & (alignment - 1)));
1219 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1220 mono_class_native_size (sig->params [i]->data.klass, NULL),
1221 cinfo->stack_size, alignment);
1223 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1224 g_assert (cinfo->args [n].size == 0);
1225 g_assert (cinfo->args [n].vtsize == 0);
1226 for (j = 0; j < nwords; ++j) {
1228 add_int32_arg (cinfo, &cinfo->args [n]);
1229 if (cinfo->on_stack)
1232 add_int32_arg (cinfo, &dummy_arg);
1233 if (!has_offset && cinfo->on_stack) {
1234 cinfo->args [n].offset = dummy_arg.offset;
1238 if (cinfo->on_stack)
1239 cinfo->args [n].vtsize += 1;
1241 cinfo->args [n].size += 1;
1243 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1244 cinfo->args [n].storage = ArgStructByVal;
1246 add_int32_arg (cinfo, &cinfo->args[n]);
1247 cinfo->args [n].storage = ArgStructByAddr;
1254 DEBUG(printf("8 bytes\n"));
1255 cinfo->args [n].size = 8;
1256 add_int64_arg (cinfo, &cinfo->args[n]);
1260 DEBUG(printf("R4\n"));
1261 cinfo->args [n].size = 4;
1262 add_float32_arg (cinfo, &cinfo->args[n]);
1266 DEBUG(printf("R8\n"));
1267 cinfo->args [n].size = 8;
1268 add_float64_arg (cinfo, &cinfo->args[n]);
1272 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1276 /* Handle the case where there are no implicit arguments */
1277 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1278 /* Prevent implicit arguments and sig_cookie from
1279 being passed in registers */
1280 args_onto_stack (cinfo);
1281 /* Emit the signature cookie just before the implicit arguments */
1282 add_int32_arg (cinfo, &cinfo->sig_cookie);
1286 simpletype = mini_get_underlying_type (sig->ret);
1287 switch (simpletype->type) {
1288 case MONO_TYPE_BOOLEAN:
1293 case MONO_TYPE_CHAR:
1299 case MONO_TYPE_FNPTR:
1300 case MONO_TYPE_CLASS:
1301 case MONO_TYPE_OBJECT:
1302 case MONO_TYPE_SZARRAY:
1303 case MONO_TYPE_ARRAY:
1304 case MONO_TYPE_STRING:
1305 cinfo->ret.reg = mips_v0;
1309 cinfo->ret.reg = mips_v0;
1313 cinfo->ret.reg = mips_f0;
1314 cinfo->ret.storage = ArgInFReg;
1316 case MONO_TYPE_GENERICINST:
1317 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1318 cinfo->ret.reg = mips_v0;
1322 case MONO_TYPE_VALUETYPE:
1323 case MONO_TYPE_TYPEDBYREF:
1325 case MONO_TYPE_VOID:
1328 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1332 /* align stack size to 16 */
1333 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1335 cinfo->stack_usage = cinfo->stack_size;
1340 debug_omit_fp (void)
1343 return mono_debug_count ();
1350 * mono_arch_compute_omit_fp:
1352 * Determine whenever the frame pointer can be eliminated.
1355 mono_arch_compute_omit_fp (MonoCompile *cfg)
1357 MonoMethodSignature *sig;
1358 MonoMethodHeader *header;
1362 if (cfg->arch.omit_fp_computed)
1365 header = cfg->header;
1367 sig = mono_method_signature (cfg->method);
1369 if (!cfg->arch.cinfo)
1370 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1371 cinfo = cfg->arch.cinfo;
1374 * FIXME: Remove some of the restrictions.
1376 cfg->arch.omit_fp = TRUE;
1377 cfg->arch.omit_fp_computed = TRUE;
1379 if (cfg->disable_omit_fp)
1380 cfg->arch.omit_fp = FALSE;
1381 if (!debug_omit_fp ())
1382 cfg->arch.omit_fp = FALSE;
1383 if (cfg->method->save_lmf)
1384 cfg->arch.omit_fp = FALSE;
1385 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1386 cfg->arch.omit_fp = FALSE;
1387 if (header->num_clauses)
1388 cfg->arch.omit_fp = FALSE;
1389 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1390 cfg->arch.omit_fp = FALSE;
1391 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1392 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1393 cfg->arch.omit_fp = FALSE;
1395 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1396 * there are stack arguments.
1399 if (cinfo->stack_usage)
1400 cfg->arch.omit_fp = FALSE;
1404 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1405 MonoInst *ins = cfg->varinfo [i];
1408 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1411 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1415 * Set var information according to the calling convention. mips version.
1416 * The locals var stuff should most likely be split in another method.
1419 mono_arch_allocate_vars (MonoCompile *cfg)
1421 MonoMethodSignature *sig;
1422 MonoMethodHeader *header;
1424 int i, offset, size, align, curinst;
1425 int frame_reg = mips_sp;
1426 guint32 iregs_to_save = 0;
1428 guint32 fregs_to_restore;
1432 sig = mono_method_signature (cfg->method);
1434 if (!cfg->arch.cinfo)
1435 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1436 cinfo = cfg->arch.cinfo;
1438 mono_arch_compute_omit_fp (cfg);
1440 /* spill down, we'll fix it in a separate pass */
1441 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1443 /* allow room for the vararg method args: void* and long/double */
1444 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1445 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1447 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1448 * call convs needs to be handled this way.
1450 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1451 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1453 /* gtk-sharp and other broken code will dllimport vararg functions even with
1454 * non-varargs signatures. Since there is little hope people will get this right
1455 * we assume they won't.
1457 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1458 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1460 /* a0-a3 always present */
1461 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1463 header = cfg->header;
1465 if (cfg->arch.omit_fp)
1466 frame_reg = mips_sp;
1468 frame_reg = mips_fp;
1469 cfg->frame_reg = frame_reg;
1470 if (frame_reg != mips_sp) {
1471 cfg->used_int_regs |= 1 << frame_reg;
1476 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1477 /* FIXME: handle long and FP values */
1478 switch (mini_get_underlying_type (sig->ret)->type) {
1479 case MONO_TYPE_VOID:
1483 cfg->ret->opcode = OP_REGVAR;
1484 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1487 cfg->ret->opcode = OP_REGVAR;
1488 cfg->ret->inst_c0 = mips_v0;
1492 /* Space for outgoing parameters, including a0-a3 */
1493 offset += cfg->param_area;
1495 /* allow room to save the return value (if it's a struct) */
1496 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1499 /* Now handle the local variables */
1501 curinst = cfg->locals_start;
1502 for (i = curinst; i < cfg->num_varinfo; ++i) {
1503 inst = cfg->varinfo [i];
1504 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1507 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1508 * pinvoke wrappers when they call functions returning structure
1510 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1511 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1513 size = mono_type_size (inst->inst_vtype, &align);
1515 offset += align - 1;
1516 offset &= ~(align - 1);
1517 inst->inst_offset = offset;
1518 inst->opcode = OP_REGOFFSET;
1519 inst->inst_basereg = frame_reg;
1521 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1524 /* Space for LMF (if needed) */
1525 if (cfg->method->save_lmf) {
1526 /* align the offset to 16 bytes */
1527 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1528 cfg->arch.lmf_offset = offset;
1529 offset += sizeof (MonoLMF);
1532 if (sig->call_convention == MONO_CALL_VARARG) {
1536 /* Allocate a local slot to hold the sig cookie address */
1537 offset += align - 1;
1538 offset &= ~(align - 1);
1539 cfg->sig_cookie = offset;
1543 offset += SIZEOF_REGISTER - 1;
1544 offset &= ~(SIZEOF_REGISTER - 1);
1546 /* Space for saved registers */
1547 cfg->arch.iregs_offset = offset;
1548 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1549 if (iregs_to_save) {
1550 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1551 if (iregs_to_save & (1 << i)) {
1552 offset += SIZEOF_REGISTER;
1557 /* saved float registers */
1559 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1560 if (fregs_to_restore) {
1561 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1562 if (fregs_to_restore & (1 << i)) {
1563 offset += sizeof(double);
1569 #if _MIPS_SIM == _ABIO32
1570 /* Now add space for saving the ra */
1571 offset += SIZEOF_VOID_P;
1574 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1575 cfg->stack_offset = offset;
1576 cfg->arch.local_alloc_offset = cfg->stack_offset;
1580 * Now allocate stack slots for the int arg regs (a0 - a3)
1581 * On MIPS o32, these are just above the incoming stack pointer
1582 * Even if the arg has been assigned to a regvar, it gets a stack slot
1585 /* Return struct-by-value results in a hidden first argument */
1586 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1587 cfg->vret_addr->opcode = OP_REGOFFSET;
1588 cfg->vret_addr->inst_c0 = mips_a0;
1589 cfg->vret_addr->inst_offset = offset;
1590 cfg->vret_addr->inst_basereg = frame_reg;
1591 offset += SIZEOF_REGISTER;
1594 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1595 inst = cfg->args [i];
1596 if (inst->opcode != OP_REGVAR) {
1599 if (sig->hasthis && (i == 0))
1600 arg_type = &mono_defaults.object_class->byval_arg;
1602 arg_type = sig->params [i - sig->hasthis];
1604 inst->opcode = OP_REGOFFSET;
1605 size = mono_type_size (arg_type, &align);
1607 if (size < SIZEOF_REGISTER) {
1608 size = SIZEOF_REGISTER;
1609 align = SIZEOF_REGISTER;
1611 inst->inst_basereg = frame_reg;
1612 offset = (offset + align - 1) & ~(align - 1);
1613 inst->inst_offset = offset;
1615 if (cfg->verbose_level > 1)
1616 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1619 #if _MIPS_SIM == _ABIO32
1620 /* o32: Even a0-a3 get stack slots */
1621 size = SIZEOF_REGISTER;
1622 align = SIZEOF_REGISTER;
1623 inst->inst_basereg = frame_reg;
1624 offset = (offset + align - 1) & ~(align - 1);
1625 inst->inst_offset = offset;
1627 if (cfg->verbose_level > 1)
1628 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1632 #if _MIPS_SIM == _ABIN32
1633 /* Now add space for saving the ra */
1634 offset += SIZEOF_VOID_P;
1637 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1638 cfg->stack_offset = offset;
1639 cfg->arch.local_alloc_offset = cfg->stack_offset;
1644 mono_arch_create_vars (MonoCompile *cfg)
1646 MonoMethodSignature *sig;
1648 sig = mono_method_signature (cfg->method);
1650 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1651 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1652 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1653 printf ("vret_addr = ");
1654 mono_print_ins (cfg->vret_addr);
1659 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1660 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1664 * take the arguments and generate the arch-specific
1665 * instructions to properly call the function in call.
1666 * This includes pushing, moving arguments to the right register
1668 * Issue: who does the spilling if needed, and when?
1671 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1673 MonoMethodSignature *tmp_sig;
1676 if (call->tail_call)
1679 /* FIXME: Add support for signature tokens to AOT */
1680 cfg->disable_aot = TRUE;
1683 * mono_ArgIterator_Setup assumes the signature cookie is
1684 * passed first and all the arguments which were before it are
1685 * passed on the stack after the signature. So compensate by
1686 * passing a different signature.
1688 tmp_sig = mono_metadata_signature_dup (call->signature);
1689 tmp_sig->param_count -= call->signature->sentinelpos;
1690 tmp_sig->sentinelpos = 0;
1691 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1693 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1694 sig_arg->dreg = mono_alloc_ireg (cfg);
1695 sig_arg->inst_p0 = tmp_sig;
1696 MONO_ADD_INS (cfg->cbb, sig_arg);
1698 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1702 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1705 MonoMethodSignature *sig;
1710 sig = call->signature;
1711 n = sig->param_count + sig->hasthis;
1713 cinfo = get_call_info (cfg->mempool, sig);
1714 if (cinfo->struct_ret)
1715 call->used_iregs |= 1 << cinfo->struct_ret;
1717 for (i = 0; i < n; ++i) {
1718 ArgInfo *ainfo = cinfo->args + i;
1721 if (i >= sig->hasthis)
1722 t = sig->params [i - sig->hasthis];
1724 t = &mono_defaults.int_class->byval_arg;
1725 t = mini_get_underlying_type (t);
1727 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1728 /* Emit the signature cookie just before the implicit arguments */
1729 emit_sig_cookie (cfg, call, cinfo);
1732 if (is_virtual && i == 0) {
1733 /* the argument will be attached to the call instrucion */
1734 in = call->args [i];
1735 call->used_iregs |= 1 << ainfo->reg;
1738 in = call->args [i];
1739 if (ainfo->storage == ArgInIReg) {
1740 #if SIZEOF_REGISTER == 4
1741 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1742 MONO_INST_NEW (cfg, ins, OP_MOVE);
1743 ins->dreg = mono_alloc_ireg (cfg);
1744 ins->sreg1 = MONO_LVREG_LS (in->dreg);
1745 MONO_ADD_INS (cfg->cbb, ins);
1746 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1748 MONO_INST_NEW (cfg, ins, OP_MOVE);
1749 ins->dreg = mono_alloc_ireg (cfg);
1750 ins->sreg1 = MONO_LVREG_MS (in->dreg);
1751 MONO_ADD_INS (cfg->cbb, ins);
1752 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1755 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1758 #if PROMOTE_R4_TO_R8
1759 /* ??? - convert to single first? */
1760 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1761 ins->dreg = mono_alloc_freg (cfg);
1762 ins->sreg1 = in->dreg;
1763 MONO_ADD_INS (cfg->cbb, ins);
1768 /* trying to load float value into int registers */
1769 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1770 ins->dreg = mono_alloc_ireg (cfg);
1772 MONO_ADD_INS (cfg->cbb, ins);
1773 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1774 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1775 /* trying to load float value into int registers */
1776 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1777 ins->dreg = mono_alloc_ireg (cfg);
1778 ins->sreg1 = in->dreg;
1779 MONO_ADD_INS (cfg->cbb, ins);
1780 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1782 MONO_INST_NEW (cfg, ins, OP_MOVE);
1783 ins->dreg = mono_alloc_ireg (cfg);
1784 ins->sreg1 = in->dreg;
1785 MONO_ADD_INS (cfg->cbb, ins);
1786 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1788 } else if (ainfo->storage == ArgStructByAddr) {
1789 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1790 ins->opcode = OP_OUTARG_VT;
1791 ins->sreg1 = in->dreg;
1792 ins->klass = in->klass;
1793 ins->inst_p0 = call;
1794 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1795 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1796 MONO_ADD_INS (cfg->cbb, ins);
1797 } else if (ainfo->storage == ArgStructByVal) {
1798 /* this is further handled in mono_arch_emit_outarg_vt () */
1799 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1800 ins->opcode = OP_OUTARG_VT;
1801 ins->sreg1 = in->dreg;
1802 ins->klass = in->klass;
1803 ins->inst_p0 = call;
1804 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1805 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1806 MONO_ADD_INS (cfg->cbb, ins);
1807 } else if (ainfo->storage == ArgOnStack) {
1808 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1809 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1810 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1811 if (t->type == MONO_TYPE_R8)
1812 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1814 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1816 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1818 } else if (ainfo->storage == ArgInFReg) {
1819 if (t->type == MONO_TYPE_VALUETYPE) {
1820 /* this is further handled in mono_arch_emit_outarg_vt () */
1821 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1822 ins->opcode = OP_OUTARG_VT;
1823 ins->sreg1 = in->dreg;
1824 ins->klass = in->klass;
1825 ins->inst_p0 = call;
1826 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1827 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1828 MONO_ADD_INS (cfg->cbb, ins);
1830 cfg->flags |= MONO_CFG_HAS_FPOUT;
1832 int dreg = mono_alloc_freg (cfg);
1834 if (ainfo->size == 4) {
1835 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1837 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1839 ins->sreg1 = in->dreg;
1840 MONO_ADD_INS (cfg->cbb, ins);
1843 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1844 cfg->flags |= MONO_CFG_HAS_FPOUT;
1847 g_assert_not_reached ();
1851 /* Handle the case where there are no implicit arguments */
1852 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1853 emit_sig_cookie (cfg, call, cinfo);
1855 if (cinfo->struct_ret) {
1858 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1859 vtarg->sreg1 = call->vret_var->dreg;
1860 vtarg->dreg = mono_alloc_preg (cfg);
1861 MONO_ADD_INS (cfg->cbb, vtarg);
1863 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1867 * Reverse the call->out_args list.
1870 MonoInst *prev = NULL, *list = call->out_args, *next;
1877 call->out_args = prev;
1880 call->stack_usage = cinfo->stack_usage;
1881 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1882 #if _MIPS_SIM == _ABIO32
1883 /* a0-a3 always present */
1884 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1886 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1887 cfg->flags |= MONO_CFG_HAS_CALLS;
1889 * should set more info in call, such as the stack space
1890 * used by the args that needs to be added back to esp
1895 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1897 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1898 ArgInfo *ainfo = ins->inst_p1;
1899 int ovf_size = ainfo->vtsize;
1900 int doffset = ainfo->offset;
1901 int i, soffset, dreg;
1903 if (ainfo->storage == ArgStructByVal) {
1905 if (cfg->verbose_level > 0) {
1906 char* nm = mono_method_full_name (cfg->method, TRUE);
1907 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1908 nm, doffset, ainfo->size, ovf_size);
1914 for (i = 0; i < ainfo->size; ++i) {
1915 dreg = mono_alloc_ireg (cfg);
1916 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1917 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1918 soffset += SIZEOF_REGISTER;
1920 if (ovf_size != 0) {
1921 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1923 } else if (ainfo->storage == ArgInFReg) {
1924 int tmpr = mono_alloc_freg (cfg);
1926 if (ainfo->size == 4)
1927 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1929 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1930 dreg = mono_alloc_freg (cfg);
1931 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1932 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1934 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1938 /* FIXME: alignment? */
1939 if (call->signature->pinvoke) {
1940 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1941 vtcopy->backend.is_pinvoke = 1;
1943 size = mini_type_stack_size (&src->klass->byval_arg, NULL);
1946 g_assert (ovf_size > 0);
1948 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1949 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1952 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1954 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1959 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1961 MonoType *ret = mini_get_underlying_type (mono_method_signature (method)->ret);
1964 #if (SIZEOF_REGISTER == 4)
1965 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1968 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1969 ins->sreg1 = MONO_LVREG_LS (val->dreg);
1970 ins->sreg2 = MONO_LVREG_MS (val->dreg);
1971 MONO_ADD_INS (cfg->cbb, ins);
1975 if (ret->type == MONO_TYPE_R8) {
1976 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1979 if (ret->type == MONO_TYPE_R4) {
1980 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1984 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1988 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1990 MonoInst *ins, *n, *last_ins = NULL;
1992 if (cfg->verbose_level > 2)
1993 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1996 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1997 if (cfg->verbose_level > 2)
1998 mono_print_ins_index (0, ins);
2000 switch (ins->opcode) {
2002 case OP_LOAD_MEMBASE:
2003 case OP_LOADI4_MEMBASE:
2005 * OP_IADD reg2, reg1, const1
2006 * OP_LOAD_MEMBASE const2(reg2), reg3
2008 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
2010 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)){
2011 int const1 = last_ins->inst_imm;
2012 int const2 = ins->inst_offset;
2014 if (mips_is_imm16 (const1 + const2)) {
2015 ins->inst_basereg = last_ins->sreg1;
2016 ins->inst_offset = const1 + const2;
2026 bb->last_ins = last_ins;
2030 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2032 MonoInst *ins, *n, *last_ins = NULL;
2035 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2036 MonoInst *last_ins = ins->prev;
2038 switch (ins->opcode) {
2040 /* remove unnecessary multiplication with 1 */
2041 if (ins->inst_imm == 1) {
2042 if (ins->dreg != ins->sreg1) {
2043 ins->opcode = OP_MOVE;
2045 MONO_DELETE_INS (bb, ins);
2049 int power2 = mono_is_power_of_two (ins->inst_imm);
2051 ins->opcode = OP_SHL_IMM;
2052 ins->inst_imm = power2;
2056 case OP_LOAD_MEMBASE:
2057 case OP_LOADI4_MEMBASE:
2059 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2060 * OP_LOAD_MEMBASE offset(basereg), reg
2062 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2063 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2064 ins->inst_basereg == last_ins->inst_destbasereg &&
2065 ins->inst_offset == last_ins->inst_offset) {
2066 if (ins->dreg == last_ins->sreg1) {
2067 MONO_DELETE_INS (bb, ins);
2070 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2071 ins->opcode = OP_MOVE;
2072 ins->sreg1 = last_ins->sreg1;
2077 * Note: reg1 must be different from the basereg in the second load
2078 * OP_LOAD_MEMBASE offset(basereg), reg1
2079 * OP_LOAD_MEMBASE offset(basereg), reg2
2081 * OP_LOAD_MEMBASE offset(basereg), reg1
2082 * OP_MOVE reg1, reg2
2084 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2085 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2086 ins->inst_basereg != last_ins->dreg &&
2087 ins->inst_basereg == last_ins->inst_basereg &&
2088 ins->inst_offset == last_ins->inst_offset) {
2090 if (ins->dreg == last_ins->dreg) {
2091 MONO_DELETE_INS (bb, ins);
2094 ins->opcode = OP_MOVE;
2095 ins->sreg1 = last_ins->dreg;
2098 //g_assert_not_reached ();
2103 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2104 * OP_LOAD_MEMBASE offset(basereg), reg
2106 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2107 * OP_ICONST reg, imm
2109 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2110 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2111 ins->inst_basereg == last_ins->inst_destbasereg &&
2112 ins->inst_offset == last_ins->inst_offset) {
2113 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2114 ins->opcode = OP_ICONST;
2115 ins->inst_c0 = last_ins->inst_imm;
2116 g_assert_not_reached (); // check this rule
2121 case OP_LOADU1_MEMBASE:
2122 case OP_LOADI1_MEMBASE:
2123 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2124 ins->inst_basereg == last_ins->inst_destbasereg &&
2125 ins->inst_offset == last_ins->inst_offset) {
2126 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2127 ins->sreg1 = last_ins->sreg1;
2130 case OP_LOADU2_MEMBASE:
2131 case OP_LOADI2_MEMBASE:
2132 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2133 ins->inst_basereg == last_ins->inst_destbasereg &&
2134 ins->inst_offset == last_ins->inst_offset) {
2135 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2136 ins->sreg1 = last_ins->sreg1;
2139 case OP_ICONV_TO_I4:
2140 case OP_ICONV_TO_U4:
2142 ins->opcode = OP_MOVE;
2146 if (ins->dreg == ins->sreg1) {
2147 MONO_DELETE_INS (bb, ins);
2151 * OP_MOVE sreg, dreg
2152 * OP_MOVE dreg, sreg
2154 if (last_ins && last_ins->opcode == OP_MOVE &&
2155 ins->sreg1 == last_ins->dreg &&
2156 ins->dreg == last_ins->sreg1) {
2157 MONO_DELETE_INS (bb, ins);
2165 bb->last_ins = last_ins;
2169 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2177 switch (ins->opcode) {
2180 case OP_LCOMPARE_IMM:
2181 mono_print_ins (ins);
2182 g_assert_not_reached ();
2185 tmp1 = mono_alloc_ireg (cfg);
2186 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2187 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2188 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2189 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2194 tmp1 = mono_alloc_ireg (cfg);
2195 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2196 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2197 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2198 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2203 tmp1 = mono_alloc_ireg (cfg);
2204 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2205 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2206 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2207 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2212 tmp1 = mono_alloc_ireg (cfg);
2213 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2214 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2215 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2216 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2228 mono_print_ins (ins);
2229 g_assert_not_reached ();
2232 tmp1 = mono_alloc_ireg (cfg);
2233 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2234 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2235 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2236 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2244 case OP_LCONV_TO_I1:
2245 case OP_LCONV_TO_I2:
2246 case OP_LCONV_TO_I4:
2247 case OP_LCONV_TO_I8:
2248 case OP_LCONV_TO_R4:
2249 case OP_LCONV_TO_R8:
2250 case OP_LCONV_TO_U4:
2251 case OP_LCONV_TO_U8:
2252 case OP_LCONV_TO_U2:
2253 case OP_LCONV_TO_U1:
2255 case OP_LCONV_TO_OVF_I:
2256 case OP_LCONV_TO_OVF_U:
2258 mono_print_ins (ins);
2259 g_assert_not_reached ();
2262 tmp1 = mono_alloc_ireg (cfg);
2263 tmp2 = mono_alloc_ireg (cfg);
2264 tmp3 = mono_alloc_ireg (cfg);
2265 tmp4 = mono_alloc_ireg (cfg);
2266 tmp5 = mono_alloc_ireg (cfg);
2268 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2270 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2271 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2273 /* add the high 32-bits, and add in the carry from the low 32-bits */
2274 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2275 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2277 /* Overflow happens if
2278 * neg + neg = pos or
2280 * XOR of the high bits returns 0 if the signs match
2281 * XOR of that with the high bit of the result return 1 if overflow.
2284 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2285 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2287 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2288 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2289 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2291 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2292 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2293 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2295 /* Now, if (tmp4 == 0) then overflow */
2296 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2300 case OP_LADD_OVF_UN:
2301 tmp1 = mono_alloc_ireg (cfg);
2302 tmp2 = mono_alloc_ireg (cfg);
2304 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2305 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2306 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2307 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2308 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2309 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2314 case OP_LMUL_OVF_UN:
2315 mono_print_ins (ins);
2316 g_assert_not_reached ();
2319 tmp1 = mono_alloc_ireg (cfg);
2320 tmp2 = mono_alloc_ireg (cfg);
2321 tmp3 = mono_alloc_ireg (cfg);
2322 tmp4 = mono_alloc_ireg (cfg);
2323 tmp5 = mono_alloc_ireg (cfg);
2325 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2327 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2328 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2329 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2331 /* Overflow happens if
2332 * neg - pos = pos or
2334 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2336 * tmp1 = (lhs ^ rhs)
2337 * tmp2 = (lhs ^ result)
2338 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2341 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2342 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2343 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2344 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2346 /* Now, if (tmp4 == 1) then overflow */
2347 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2351 case OP_LSUB_OVF_UN:
2352 tmp1 = mono_alloc_ireg (cfg);
2353 tmp2 = mono_alloc_ireg (cfg);
2355 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2356 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2357 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2358 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2360 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2361 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2365 case OP_LCONV_TO_OVF_I1_UN:
2366 case OP_LCONV_TO_OVF_I2_UN:
2367 case OP_LCONV_TO_OVF_I4_UN:
2368 case OP_LCONV_TO_OVF_I8_UN:
2369 case OP_LCONV_TO_OVF_U1_UN:
2370 case OP_LCONV_TO_OVF_U2_UN:
2371 case OP_LCONV_TO_OVF_U4_UN:
2372 case OP_LCONV_TO_OVF_U8_UN:
2373 case OP_LCONV_TO_OVF_I_UN:
2374 case OP_LCONV_TO_OVF_U_UN:
2375 case OP_LCONV_TO_OVF_I1:
2376 case OP_LCONV_TO_OVF_U1:
2377 case OP_LCONV_TO_OVF_I2:
2378 case OP_LCONV_TO_OVF_U2:
2379 case OP_LCONV_TO_OVF_I4:
2380 case OP_LCONV_TO_OVF_U4:
2381 case OP_LCONV_TO_OVF_I8:
2382 case OP_LCONV_TO_OVF_U8:
2390 case OP_LCONV_TO_R_UN:
2396 case OP_LSHR_UN_IMM:
2398 case OP_LDIV_UN_IMM:
2400 case OP_LREM_UN_IMM:
2411 mono_print_ins (ins);
2412 g_assert_not_reached ();
2414 case OP_LCONV_TO_R8_2:
2415 case OP_LCONV_TO_R4_2:
2416 case OP_LCONV_TO_R_UN_2:
2418 case OP_LCONV_TO_OVF_I4_2:
2419 tmp1 = mono_alloc_ireg (cfg);
2421 /* Overflows if reg2 != sign extension of reg1 */
2422 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2423 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2424 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2432 mono_print_ins (ins);
2433 g_assert_not_reached ();
2441 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2449 switch (ins->opcode) {
2451 tmp1 = mono_alloc_ireg (cfg);
2452 tmp2 = mono_alloc_ireg (cfg);
2453 tmp3 = mono_alloc_ireg (cfg);
2454 tmp4 = mono_alloc_ireg (cfg);
2455 tmp5 = mono_alloc_ireg (cfg);
2457 /* add the operands */
2459 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2461 /* Overflow happens if
2462 * neg + neg = pos or
2465 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2466 * XOR of the high bit returns 0 if the signs match
2467 * XOR of that with the high bit of the result return 1 if overflow.
2470 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2471 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2473 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2474 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2475 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2477 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2478 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2480 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2482 /* Now, if (tmp5 == 0) then overflow */
2483 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2484 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2485 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2489 case OP_IADD_OVF_UN:
2490 tmp1 = mono_alloc_ireg (cfg);
2492 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2493 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2494 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2495 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2496 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2501 tmp1 = mono_alloc_ireg (cfg);
2502 tmp2 = mono_alloc_ireg (cfg);
2503 tmp3 = mono_alloc_ireg (cfg);
2504 tmp4 = mono_alloc_ireg (cfg);
2505 tmp5 = mono_alloc_ireg (cfg);
2507 /* add the operands */
2509 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2511 /* Overflow happens if
2512 * neg - pos = pos or
2514 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2516 * tmp1 = (lhs ^ rhs)
2517 * tmp2 = (lhs ^ result)
2518 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2521 /* tmp3 = 1 if the signs of the two inputs differ */
2522 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2523 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2524 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2525 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2526 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2528 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2529 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2530 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2534 case OP_ISUB_OVF_UN:
2535 tmp1 = mono_alloc_ireg (cfg);
2537 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2538 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2539 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2540 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2541 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2548 map_to_reg_reg_op (int op)
2557 case OP_COMPARE_IMM:
2559 case OP_ICOMPARE_IMM:
2561 case OP_LCOMPARE_IMM:
2577 case OP_LOAD_MEMBASE:
2578 return OP_LOAD_MEMINDEX;
2579 case OP_LOADI4_MEMBASE:
2580 return OP_LOADI4_MEMINDEX;
2581 case OP_LOADU4_MEMBASE:
2582 return OP_LOADU4_MEMINDEX;
2583 case OP_LOADU1_MEMBASE:
2584 return OP_LOADU1_MEMINDEX;
2585 case OP_LOADI2_MEMBASE:
2586 return OP_LOADI2_MEMINDEX;
2587 case OP_LOADU2_MEMBASE:
2588 return OP_LOADU2_MEMINDEX;
2589 case OP_LOADI1_MEMBASE:
2590 return OP_LOADI1_MEMINDEX;
2591 case OP_LOADR4_MEMBASE:
2592 return OP_LOADR4_MEMINDEX;
2593 case OP_LOADR8_MEMBASE:
2594 return OP_LOADR8_MEMINDEX;
2595 case OP_STOREI1_MEMBASE_REG:
2596 return OP_STOREI1_MEMINDEX;
2597 case OP_STOREI2_MEMBASE_REG:
2598 return OP_STOREI2_MEMINDEX;
2599 case OP_STOREI4_MEMBASE_REG:
2600 return OP_STOREI4_MEMINDEX;
2601 case OP_STORE_MEMBASE_REG:
2602 return OP_STORE_MEMINDEX;
2603 case OP_STORER4_MEMBASE_REG:
2604 return OP_STORER4_MEMINDEX;
2605 case OP_STORER8_MEMBASE_REG:
2606 return OP_STORER8_MEMINDEX;
2607 case OP_STORE_MEMBASE_IMM:
2608 return OP_STORE_MEMBASE_REG;
2609 case OP_STOREI1_MEMBASE_IMM:
2610 return OP_STOREI1_MEMBASE_REG;
2611 case OP_STOREI2_MEMBASE_IMM:
2612 return OP_STOREI2_MEMBASE_REG;
2613 case OP_STOREI4_MEMBASE_IMM:
2614 return OP_STOREI4_MEMBASE_REG;
2615 case OP_STOREI8_MEMBASE_IMM:
2616 return OP_STOREI8_MEMBASE_REG;
2618 if (mono_op_imm_to_op (op) == -1)
2619 g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (op));
2620 return mono_op_imm_to_op (op);
2624 map_to_mips_op (int op)
2628 return OP_MIPS_FBEQ;
2630 return OP_MIPS_FBGE;
2632 return OP_MIPS_FBGT;
2634 return OP_MIPS_FBLE;
2636 return OP_MIPS_FBLT;
2638 return OP_MIPS_FBNE;
2640 return OP_MIPS_FBGE_UN;
2642 return OP_MIPS_FBGT_UN;
2644 return OP_MIPS_FBLE_UN;
2646 return OP_MIPS_FBLT_UN;
2654 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2655 g_assert_not_reached ();
2659 #define NEW_INS(cfg,after,dest,op) do { \
2660 MONO_INST_NEW((cfg), (dest), (op)); \
2661 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2664 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2666 MONO_INST_NEW(cfg, temp, (op)); \
2667 mono_bblock_insert_after_ins (bb, (pos), temp); \
2668 temp->dreg = (_dreg); \
2669 temp->sreg1 = (_sreg1); \
2670 temp->sreg2 = (_sreg2); \
2674 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2676 MONO_INST_NEW(cfg, temp, (op)); \
2677 mono_bblock_insert_after_ins (bb, (pos), temp); \
2678 temp->dreg = (_dreg); \
2679 temp->sreg1 = (_sreg1); \
2680 temp->inst_c0 = (_imm); \
2685 * Remove from the instruction list the instructions that can't be
2686 * represented with very simple instructions with no register
2690 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2692 MonoInst *ins, *next, *temp, *last_ins = NULL;
2696 if (cfg->verbose_level > 2) {
2699 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2700 MONO_BB_FOR_EACH_INS (bb, ins) {
2701 mono_print_ins_index (idx++, ins);
2707 MONO_BB_FOR_EACH_INS (bb, ins) {
2709 switch (ins->opcode) {
2714 /* Branch opts can eliminate the branch */
2715 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2721 case OP_COMPARE_IMM:
2722 case OP_ICOMPARE_IMM:
2723 case OP_LCOMPARE_IMM:
2725 /* Branch opts can eliminate the branch */
2726 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2730 if (ins->inst_imm) {
2731 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2732 temp->inst_c0 = ins->inst_imm;
2733 temp->dreg = mono_alloc_ireg (cfg);
2734 ins->sreg2 = temp->dreg;
2738 ins->sreg2 = mips_zero;
2740 if (ins->opcode == OP_COMPARE_IMM)
2741 ins->opcode = OP_COMPARE;
2742 else if (ins->opcode == OP_ICOMPARE_IMM)
2743 ins->opcode = OP_ICOMPARE;
2744 else if (ins->opcode == OP_LCOMPARE_IMM)
2745 ins->opcode = OP_LCOMPARE;
2748 case OP_IDIV_UN_IMM:
2751 case OP_IREM_UN_IMM:
2752 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2753 temp->inst_c0 = ins->inst_imm;
2754 temp->dreg = mono_alloc_ireg (cfg);
2755 ins->sreg2 = temp->dreg;
2756 if (ins->opcode == OP_IDIV_IMM)
2757 ins->opcode = OP_IDIV;
2758 else if (ins->opcode == OP_IREM_IMM)
2759 ins->opcode = OP_IREM;
2760 else if (ins->opcode == OP_IDIV_UN_IMM)
2761 ins->opcode = OP_IDIV_UN;
2762 else if (ins->opcode == OP_IREM_UN_IMM)
2763 ins->opcode = OP_IREM_UN;
2765 /* handle rem separately */
2772 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2773 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2774 temp->inst_c0 = ins->inst_imm;
2775 temp->dreg = mono_alloc_ireg (cfg);
2776 ins->sreg2 = temp->dreg;
2777 ins->opcode = map_to_reg_reg_op (ins->opcode);
2787 /* unsigned 16 bit immediate */
2788 if (ins->inst_imm & 0xffff0000) {
2789 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2790 temp->inst_c0 = ins->inst_imm;
2791 temp->dreg = mono_alloc_ireg (cfg);
2792 ins->sreg2 = temp->dreg;
2793 ins->opcode = map_to_reg_reg_op (ins->opcode);
2800 /* signed 16 bit immediate */
2801 if (!mips_is_imm16 (ins->inst_imm)) {
2802 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2803 temp->inst_c0 = ins->inst_imm;
2804 temp->dreg = mono_alloc_ireg (cfg);
2805 ins->sreg2 = temp->dreg;
2806 ins->opcode = map_to_reg_reg_op (ins->opcode);
2812 if (!mips_is_imm16 (-ins->inst_imm)) {
2813 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2814 temp->inst_c0 = ins->inst_imm;
2815 temp->dreg = mono_alloc_ireg (cfg);
2816 ins->sreg2 = temp->dreg;
2817 ins->opcode = map_to_reg_reg_op (ins->opcode);
2823 if (ins->inst_imm == 1) {
2824 ins->opcode = OP_MOVE;
2827 if (ins->inst_imm == 0) {
2828 ins->opcode = OP_ICONST;
2832 imm = mono_is_power_of_two (ins->inst_imm);
2834 ins->opcode = OP_SHL_IMM;
2835 ins->inst_imm = imm;
2838 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2839 temp->inst_c0 = ins->inst_imm;
2840 temp->dreg = mono_alloc_ireg (cfg);
2841 ins->sreg2 = temp->dreg;
2842 ins->opcode = map_to_reg_reg_op (ins->opcode);
2845 case OP_LOCALLOC_IMM:
2846 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2847 temp->inst_c0 = ins->inst_imm;
2848 temp->dreg = mono_alloc_ireg (cfg);
2849 ins->sreg1 = temp->dreg;
2850 ins->opcode = OP_LOCALLOC;
2853 case OP_LOADR4_MEMBASE:
2854 case OP_STORER4_MEMBASE_REG:
2855 /* we can do two things: load the immed in a register
2856 * and use an indexed load, or see if the immed can be
2857 * represented as an ad_imm + a load with a smaller offset
2858 * that fits. We just do the first for now, optimize later.
2860 if (mips_is_imm16 (ins->inst_offset))
2862 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2863 temp->inst_c0 = ins->inst_offset;
2864 temp->dreg = mono_alloc_ireg (cfg);
2865 ins->sreg2 = temp->dreg;
2866 ins->opcode = map_to_reg_reg_op (ins->opcode);
2869 case OP_STORE_MEMBASE_IMM:
2870 case OP_STOREI1_MEMBASE_IMM:
2871 case OP_STOREI2_MEMBASE_IMM:
2872 case OP_STOREI4_MEMBASE_IMM:
2873 case OP_STOREI8_MEMBASE_IMM:
2874 if (!ins->inst_imm) {
2875 ins->sreg1 = mips_zero;
2876 ins->opcode = map_to_reg_reg_op (ins->opcode);
2879 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2880 temp->inst_c0 = ins->inst_imm;
2881 temp->dreg = mono_alloc_ireg (cfg);
2882 ins->sreg1 = temp->dreg;
2883 ins->opcode = map_to_reg_reg_op (ins->opcode);
2885 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2891 /* Branch opts can eliminate the branch */
2892 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2899 * remap compare/branch and compare/set
2900 * to MIPS specific opcodes.
2902 next->opcode = map_to_mips_op (next->opcode);
2903 next->sreg1 = ins->sreg1;
2904 next->sreg2 = ins->sreg2;
2911 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2912 temp->inst_c0 = (guint32)ins->inst_p0;
2913 temp->dreg = mono_alloc_ireg (cfg);
2914 ins->inst_basereg = temp->dreg;
2915 ins->inst_offset = 0;
2916 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2918 /* make it handle the possibly big ins->inst_offset
2919 * later optimize to use lis + load_membase
2924 g_assert (ins_is_compare(last_ins));
2925 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2926 NULLIFY_INS(last_ins);
2930 g_assert (ins_is_compare(last_ins));
2931 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2932 NULLIFY_INS(last_ins);
2936 g_assert (ins_is_compare(last_ins));
2937 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2938 last_ins->dreg = mono_alloc_ireg (cfg);
2939 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2943 g_assert (ins_is_compare(last_ins));
2944 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2945 last_ins->dreg = mono_alloc_ireg (cfg);
2946 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2950 g_assert (ins_is_compare(last_ins));
2951 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2952 last_ins->dreg = mono_alloc_ireg (cfg);
2953 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2957 g_assert (ins_is_compare(last_ins));
2958 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2959 last_ins->dreg = mono_alloc_ireg (cfg);
2960 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2964 g_assert (ins_is_compare(last_ins));
2965 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2966 last_ins->dreg = mono_alloc_ireg (cfg);
2967 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2971 g_assert (ins_is_compare(last_ins));
2972 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2973 last_ins->dreg = mono_alloc_ireg (cfg);
2974 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2978 g_assert (ins_is_compare(last_ins));
2979 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2980 last_ins->dreg = mono_alloc_ireg (cfg);
2981 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2985 g_assert (ins_is_compare(last_ins));
2986 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2987 last_ins->dreg = mono_alloc_ireg (cfg);
2988 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2993 g_assert (ins_is_compare(last_ins));
2994 last_ins->opcode = OP_IXOR;
2995 last_ins->dreg = mono_alloc_ireg(cfg);
2996 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
3001 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
3002 NULLIFY_INS(last_ins);
3008 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
3009 NULLIFY_INS(last_ins);
3014 g_assert (ins_is_compare(last_ins));
3015 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
3016 MONO_DELETE_INS(bb, last_ins);
3021 g_assert (ins_is_compare(last_ins));
3022 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3023 MONO_DELETE_INS(bb, last_ins);
3026 case OP_COND_EXC_EQ:
3027 case OP_COND_EXC_IEQ:
3028 g_assert (ins_is_compare(last_ins));
3029 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3030 MONO_DELETE_INS(bb, last_ins);
3033 case OP_COND_EXC_GE:
3034 case OP_COND_EXC_IGE:
3035 g_assert (ins_is_compare(last_ins));
3036 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3037 MONO_DELETE_INS(bb, last_ins);
3040 case OP_COND_EXC_GT:
3041 case OP_COND_EXC_IGT:
3042 g_assert (ins_is_compare(last_ins));
3043 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3044 MONO_DELETE_INS(bb, last_ins);
3047 case OP_COND_EXC_LE:
3048 case OP_COND_EXC_ILE:
3049 g_assert (ins_is_compare(last_ins));
3050 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3051 MONO_DELETE_INS(bb, last_ins);
3054 case OP_COND_EXC_LT:
3055 case OP_COND_EXC_ILT:
3056 g_assert (ins_is_compare(last_ins));
3057 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3058 MONO_DELETE_INS(bb, last_ins);
3061 case OP_COND_EXC_NE_UN:
3062 case OP_COND_EXC_INE_UN:
3063 g_assert (ins_is_compare(last_ins));
3064 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3065 MONO_DELETE_INS(bb, last_ins);
3068 case OP_COND_EXC_GE_UN:
3069 case OP_COND_EXC_IGE_UN:
3070 g_assert (ins_is_compare(last_ins));
3071 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3072 MONO_DELETE_INS(bb, last_ins);
3075 case OP_COND_EXC_GT_UN:
3076 case OP_COND_EXC_IGT_UN:
3077 g_assert (ins_is_compare(last_ins));
3078 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3079 MONO_DELETE_INS(bb, last_ins);
3082 case OP_COND_EXC_LE_UN:
3083 case OP_COND_EXC_ILE_UN:
3084 g_assert (ins_is_compare(last_ins));
3085 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3086 MONO_DELETE_INS(bb, last_ins);
3089 case OP_COND_EXC_LT_UN:
3090 case OP_COND_EXC_ILT_UN:
3091 g_assert (ins_is_compare(last_ins));
3092 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3093 MONO_DELETE_INS(bb, last_ins);
3096 case OP_COND_EXC_OV:
3097 case OP_COND_EXC_IOV: {
3098 int tmp1, tmp2, tmp3, tmp4, tmp5;
3099 MonoInst *pos = last_ins;
3101 /* Overflow happens if
3102 * neg + neg = pos or
3105 * (bit31s of operands match) AND (bit31 of operand
3106 * != bit31 of result)
3107 * XOR of the high bit returns 0 if the signs match
3108 * XOR of that with the high bit of the result return 1
3111 g_assert (last_ins->opcode == OP_IADC);
3113 tmp1 = mono_alloc_ireg (cfg);
3114 tmp2 = mono_alloc_ireg (cfg);
3115 tmp3 = mono_alloc_ireg (cfg);
3116 tmp4 = mono_alloc_ireg (cfg);
3117 tmp5 = mono_alloc_ireg (cfg);
3119 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3120 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3122 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3123 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3124 INS (pos, OP_INOT, tmp3, tmp2, -1);
3126 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3127 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3128 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3130 /* Now, if (tmp5 == 0) then overflow */
3131 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3136 case OP_COND_EXC_NO:
3137 case OP_COND_EXC_INO:
3138 g_assert_not_reached ();
3142 case OP_COND_EXC_IC:
3143 g_assert_not_reached ();
3146 case OP_COND_EXC_NC:
3147 case OP_COND_EXC_INC:
3148 g_assert_not_reached ();
3154 bb->last_ins = last_ins;
3155 bb->max_vreg = cfg->next_vreg;
3158 if (cfg->verbose_level > 2) {
3161 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3162 MONO_BB_FOR_EACH_INS (bb, ins) {
3163 mono_print_ins_index (idx++, ins);
3172 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3174 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3176 mips_truncwd (code, mips_ftemp, sreg);
3178 mips_cvtwd (code, mips_ftemp, sreg);
3180 mips_mfc1 (code, dreg, mips_ftemp);
3183 mips_andi (code, dreg, dreg, 0xff);
3184 else if (size == 2) {
3185 mips_sll (code, dreg, dreg, 16);
3186 mips_srl (code, dreg, dreg, 16);
3190 mips_sll (code, dreg, dreg, 24);
3191 mips_sra (code, dreg, dreg, 24);
3193 else if (size == 2) {
3194 mips_sll (code, dreg, dreg, 16);
3195 mips_sra (code, dreg, dreg, 16);
3202 * emit_load_volatile_arguments:
3204 * Load volatile arguments from the stack to the original input registers.
3205 * Required before a tail call.
3208 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3210 MonoMethod *method = cfg->method;
3211 MonoMethodSignature *sig;
3216 sig = mono_method_signature (method);
3218 if (!cfg->arch.cinfo)
3219 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
3220 cinfo = cfg->arch.cinfo;
3222 if (cinfo->struct_ret) {
3223 ArgInfo *ainfo = &cinfo->ret;
3224 inst = cfg->vret_addr;
3225 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3228 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3229 ArgInfo *ainfo = cinfo->args + i;
3230 inst = cfg->args [i];
3231 if (inst->opcode == OP_REGVAR) {
3232 if (ainfo->storage == ArgInIReg)
3233 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3234 else if (ainfo->storage == ArgInFReg)
3235 g_assert_not_reached();
3236 else if (ainfo->storage == ArgOnStack) {
3239 g_assert_not_reached ();
3241 if (ainfo->storage == ArgInIReg) {
3242 g_assert (mips_is_imm16 (inst->inst_offset));
3243 switch (ainfo->size) {
3245 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3248 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3252 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3255 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3256 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3259 g_assert_not_reached ();
3262 } else if (ainfo->storage == ArgOnStack) {
3264 } else if (ainfo->storage == ArgInFReg) {
3265 g_assert (mips_is_imm16 (inst->inst_offset));
3266 if (ainfo->size == 8) {
3267 #if _MIPS_SIM == _ABIO32
3268 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3269 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3270 #elif _MIPS_SIM == _ABIN32
3271 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3274 else if (ainfo->size == 4)
3275 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3277 g_assert_not_reached ();
3278 } else if (ainfo->storage == ArgStructByVal) {
3280 int doffset = inst->inst_offset;
3282 g_assert (mips_is_imm16 (inst->inst_offset));
3283 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3284 for (i = 0; i < ainfo->size; ++i) {
3285 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3286 doffset += SIZEOF_REGISTER;
3288 } else if (ainfo->storage == ArgStructByAddr) {
3289 g_assert (mips_is_imm16 (inst->inst_offset));
3290 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3292 g_assert_not_reached ();
3300 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3302 int size = cfg->param_area;
3304 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3305 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3310 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3311 if (ppc_is_imm16 (-size)) {
3312 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3314 ppc_load (code, ppc_r12, -size);
3315 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3322 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3324 int size = cfg->param_area;
3326 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3327 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3332 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3333 if (ppc_is_imm16 (size)) {
3334 ppc_stwu (code, ppc_r0, size, ppc_sp);
3336 ppc_load (code, ppc_r12, size);
3337 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r12);
3344 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3349 guint8 *code = cfg->native_code + cfg->code_len;
3350 MonoInst *last_ins = NULL;
3351 guint last_offset = 0;
3355 /* we don't align basic blocks of loops on mips */
3357 if (cfg->verbose_level > 2)
3358 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3360 cpos = bb->max_offset;
3363 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3364 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3365 g_assert (!mono_compile_aot);
3368 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3369 /* this is not thread save, but good enough */
3370 /* fixme: howto handle overflows? */
3371 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3372 mips_lw (code, mips_temp, mips_at, 0);
3373 mips_addiu (code, mips_temp, mips_temp, 1);
3374 mips_sw (code, mips_temp, mips_at, 0);
3377 MONO_BB_FOR_EACH_INS (bb, ins) {
3378 offset = code - cfg->native_code;
3380 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3382 if (offset > (cfg->code_size - max_len - 16)) {
3383 cfg->code_size *= 2;
3384 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3385 code = cfg->native_code + offset;
3387 mono_debug_record_line_number (cfg, ins, offset);
3388 if (cfg->verbose_level > 2) {
3389 g_print (" @ 0x%x\t", offset);
3390 mono_print_ins_index (ins_cnt++, ins);
3392 /* Check for virtual regs that snuck by */
3393 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3395 switch (ins->opcode) {
3396 case OP_RELAXED_NOP:
3399 case OP_DUMMY_STORE:
3400 case OP_NOT_REACHED:
3403 case OP_IL_SEQ_POINT:
3404 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3406 case OP_SEQ_POINT: {
3407 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3408 guint32 addr = (guint32)ss_trigger_page;
3410 mips_load_const (code, mips_t9, addr);
3411 mips_lw (code, mips_t9, mips_t9, 0);
3414 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3417 * A placeholder for a possible breakpoint inserted by
3418 * mono_arch_set_breakpoint ().
3420 /* mips_load_const () + mips_lw */
3427 g_assert_not_reached();
3429 emit_tls_access (code, ins->dreg, ins->inst_offset);
3433 mips_mult (code, ins->sreg1, ins->sreg2);
3434 mips_mflo (code, ins->dreg);
3435 mips_mfhi (code, ins->dreg+1);
3438 mips_multu (code, ins->sreg1, ins->sreg2);
3439 mips_mflo (code, ins->dreg);
3440 mips_mfhi (code, ins->dreg+1);
3442 case OP_MEMORY_BARRIER:
3443 mips_sync (code, 0);
3445 case OP_STOREI1_MEMBASE_IMM:
3446 mips_load_const (code, mips_temp, ins->inst_imm);
3447 if (mips_is_imm16 (ins->inst_offset)) {
3448 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3450 mips_load_const (code, mips_at, ins->inst_offset);
3451 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3454 case OP_STOREI2_MEMBASE_IMM:
3455 mips_load_const (code, mips_temp, ins->inst_imm);
3456 if (mips_is_imm16 (ins->inst_offset)) {
3457 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3459 mips_load_const (code, mips_at, ins->inst_offset);
3460 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3463 case OP_STOREI8_MEMBASE_IMM:
3464 mips_load_const (code, mips_temp, ins->inst_imm);
3465 if (mips_is_imm16 (ins->inst_offset)) {
3466 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3468 mips_load_const (code, mips_at, ins->inst_offset);
3469 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3472 case OP_STORE_MEMBASE_IMM:
3473 case OP_STOREI4_MEMBASE_IMM:
3474 mips_load_const (code, mips_temp, ins->inst_imm);
3475 if (mips_is_imm16 (ins->inst_offset)) {
3476 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3478 mips_load_const (code, mips_at, ins->inst_offset);
3479 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3482 case OP_STOREI1_MEMBASE_REG:
3483 if (mips_is_imm16 (ins->inst_offset)) {
3484 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3486 mips_load_const (code, mips_at, ins->inst_offset);
3487 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3488 mips_sb (code, ins->sreg1, mips_at, 0);
3491 case OP_STOREI2_MEMBASE_REG:
3492 if (mips_is_imm16 (ins->inst_offset)) {
3493 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3495 mips_load_const (code, mips_at, ins->inst_offset);
3496 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3497 mips_sh (code, ins->sreg1, mips_at, 0);
3500 case OP_STORE_MEMBASE_REG:
3501 case OP_STOREI4_MEMBASE_REG:
3502 if (mips_is_imm16 (ins->inst_offset)) {
3503 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3505 mips_load_const (code, mips_at, ins->inst_offset);
3506 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3507 mips_sw (code, ins->sreg1, mips_at, 0);
3510 case OP_STOREI8_MEMBASE_REG:
3511 if (mips_is_imm16 (ins->inst_offset)) {
3512 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3514 mips_load_const (code, mips_at, ins->inst_offset);
3515 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3516 mips_sd (code, ins->sreg1, mips_at, 0);
3520 g_assert_not_reached ();
3521 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3522 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3524 case OP_LOADI8_MEMBASE:
3525 if (mips_is_imm16 (ins->inst_offset)) {
3526 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3528 mips_load_const (code, mips_at, ins->inst_offset);
3529 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3530 mips_ld (code, ins->dreg, mips_at, 0);
3533 case OP_LOAD_MEMBASE:
3534 case OP_LOADI4_MEMBASE:
3535 case OP_LOADU4_MEMBASE:
3536 g_assert (ins->dreg != -1);
3537 if (mips_is_imm16 (ins->inst_offset)) {
3538 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3540 mips_load_const (code, mips_at, ins->inst_offset);
3541 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3542 mips_lw (code, ins->dreg, mips_at, 0);
3545 case OP_LOADI1_MEMBASE:
3546 if (mips_is_imm16 (ins->inst_offset)) {
3547 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3549 mips_load_const (code, mips_at, ins->inst_offset);
3550 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3551 mips_lb (code, ins->dreg, mips_at, 0);
3554 case OP_LOADU1_MEMBASE:
3555 if (mips_is_imm16 (ins->inst_offset)) {
3556 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3558 mips_load_const (code, mips_at, ins->inst_offset);
3559 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3560 mips_lbu (code, ins->dreg, mips_at, 0);
3563 case OP_LOADI2_MEMBASE:
3564 if (mips_is_imm16 (ins->inst_offset)) {
3565 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3567 mips_load_const (code, mips_at, ins->inst_offset);
3568 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3569 mips_lh (code, ins->dreg, mips_at, 0);
3572 case OP_LOADU2_MEMBASE:
3573 if (mips_is_imm16 (ins->inst_offset)) {
3574 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3576 mips_load_const (code, mips_at, ins->inst_offset);
3577 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3578 mips_lhu (code, ins->dreg, mips_at, 0);
3581 case OP_ICONV_TO_I1:
3582 mips_sll (code, mips_at, ins->sreg1, 24);
3583 mips_sra (code, ins->dreg, mips_at, 24);
3585 case OP_ICONV_TO_I2:
3586 mips_sll (code, mips_at, ins->sreg1, 16);
3587 mips_sra (code, ins->dreg, mips_at, 16);
3589 case OP_ICONV_TO_U1:
3590 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3592 case OP_ICONV_TO_U2:
3593 mips_sll (code, mips_at, ins->sreg1, 16);
3594 mips_srl (code, ins->dreg, mips_at, 16);
3597 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3600 g_assert (mips_is_imm16 (ins->inst_imm));
3601 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3604 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3607 g_assert (mips_is_imm16 (ins->inst_imm));
3608 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3612 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3613 * So instead of emitting a trap, we emit a call a C function and place a
3616 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3617 (gpointer)"mono_break");
3618 mips_load (code, mips_t9, 0x1f1f1f1f);
3619 mips_jalr (code, mips_t9, mips_ra);
3623 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3626 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3631 g_assert (mips_is_imm16 (ins->inst_imm));
3632 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3635 g_assert (mips_is_imm16 (ins->inst_imm));
3636 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3640 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3643 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3648 // we add the negated value
3649 g_assert (mips_is_imm16 (-ins->inst_imm));
3650 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3654 // we add the negated value
3655 g_assert (mips_is_imm16 (-ins->inst_imm));
3656 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3661 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3667 g_assert (!(ins->inst_imm & 0xffff0000));
3668 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3673 guint32 *divisor_is_m1;
3674 guint32 *dividend_is_minvalue;
3675 guint32 *divisor_is_zero;
3677 mips_load_const (code, mips_at, -1);
3678 divisor_is_m1 = (guint32 *)(void *)code;
3679 mips_bne (code, ins->sreg2, mips_at, 0);
3680 mips_lui (code, mips_at, mips_zero, 0x8000);
3681 dividend_is_minvalue = (guint32 *)(void *)code;
3682 mips_bne (code, ins->sreg1, mips_at, 0);
3685 /* Divide Int32.MinValue by -1 -- throw exception */
3686 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3688 mips_patch (divisor_is_m1, (guint32)code);
3689 mips_patch (dividend_is_minvalue, (guint32)code);
3691 /* Put divide in branch delay slot (NOT YET) */
3692 divisor_is_zero = (guint32 *)(void *)code;
3693 mips_bne (code, ins->sreg2, mips_zero, 0);
3696 /* Divide by zero -- throw exception */
3697 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3699 mips_patch (divisor_is_zero, (guint32)code);
3700 mips_div (code, ins->sreg1, ins->sreg2);
3701 if (ins->opcode == OP_IDIV)
3702 mips_mflo (code, ins->dreg);
3704 mips_mfhi (code, ins->dreg);
3709 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3711 /* Put divide in branch delay slot (NOT YET) */
3712 mips_bne (code, ins->sreg2, mips_zero, 0);
3715 /* Divide by zero -- throw exception */
3716 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3718 mips_patch (divisor_is_zero, (guint32)code);
3719 mips_divu (code, ins->sreg1, ins->sreg2);
3720 if (ins->opcode == OP_IDIV_UN)
3721 mips_mflo (code, ins->dreg);
3723 mips_mfhi (code, ins->dreg);
3727 g_assert_not_reached ();
3729 ppc_load (code, ppc_r12, ins->inst_imm);
3730 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r12);
3731 ppc_mfspr (code, ppc_r0, ppc_xer);
3732 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3733 /* FIXME: use OverflowException for 0x80000000/-1 */
3734 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3736 g_assert_not_reached();
3739 g_assert_not_reached ();
3741 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3745 g_assert (!(ins->inst_imm & 0xffff0000));
3746 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3749 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3753 /* unsigned 16-bit immediate */
3754 g_assert (!(ins->inst_imm & 0xffff0000));
3755 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3758 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3762 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3765 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3768 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3772 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3775 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3778 case OP_ISHR_UN_IMM:
3779 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3781 case OP_LSHR_UN_IMM:
3782 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3785 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3788 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3792 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3795 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3798 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3802 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3804 mips_mult (code, ins->sreg1, ins->sreg2);
3805 mips_mflo (code, ins->dreg);
3810 #if SIZEOF_REGISTER == 8
3812 mips_dmult (code, ins->sreg1, ins->sreg2);
3813 mips_mflo (code, ins->dreg);
3818 mips_mult (code, ins->sreg1, ins->sreg2);
3819 mips_mflo (code, ins->dreg);
3820 mips_mfhi (code, mips_at);
3823 mips_sra (code, mips_temp, ins->dreg, 31);
3824 patch = (guint32 *)(void *)code;
3825 mips_beq (code, mips_temp, mips_at, 0);
3827 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3828 mips_patch (patch, (guint32)code);
3831 case OP_IMUL_OVF_UN: {
3833 mips_mult (code, ins->sreg1, ins->sreg2);
3834 mips_mflo (code, ins->dreg);
3835 mips_mfhi (code, mips_at);
3838 patch = (guint32 *)(void *)code;
3839 mips_beq (code, mips_at, mips_zero, 0);
3841 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3842 mips_patch (patch, (guint32)code);
3846 mips_load_const (code, ins->dreg, ins->inst_c0);
3848 #if SIZEOF_REGISTER == 8
3850 mips_load_const (code, ins->dreg, ins->inst_c0);
3854 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3855 mips_load (code, ins->dreg, 0);
3859 mips_mtc1 (code, ins->dreg, ins->sreg1);
3861 case OP_MIPS_MTC1S_2:
3862 mips_mtc1 (code, ins->dreg, ins->sreg1);
3863 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3866 mips_mfc1 (code, ins->dreg, ins->sreg1);
3869 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3873 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3875 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3876 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3880 case OP_ICONV_TO_I4:
3881 case OP_ICONV_TO_U4:
3883 if (ins->dreg != ins->sreg1)
3884 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3886 #if SIZEOF_REGISTER == 8
3888 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3889 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3892 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3893 mips_dsra (code, ins->dreg, ins->dreg, 32);
3897 int lsreg = mips_v0 + ls_word_idx;
3898 int msreg = mips_v0 + ms_word_idx;
3900 /* Get sreg1 into lsreg, sreg2 into msreg */
3902 if (ins->sreg1 == msreg) {
3903 if (ins->sreg1 != mips_at)
3904 MIPS_MOVE (code, mips_at, ins->sreg1);
3905 if (ins->sreg2 != msreg)
3906 MIPS_MOVE (code, msreg, ins->sreg2);
3907 MIPS_MOVE (code, lsreg, mips_at);
3910 if (ins->sreg2 != msreg)
3911 MIPS_MOVE (code, msreg, ins->sreg2);
3912 if (ins->sreg1 != lsreg)
3913 MIPS_MOVE (code, lsreg, ins->sreg1);
3918 if (ins->dreg != ins->sreg1) {
3919 mips_fmovd (code, ins->dreg, ins->sreg1);
3922 case OP_MOVE_F_TO_I4:
3923 mips_cvtsd (code, mips_ftemp, ins->sreg1);
3924 mips_mfc1 (code, ins->dreg, mips_ftemp);
3926 case OP_MOVE_I4_TO_F:
3927 mips_mtc1 (code, ins->dreg, ins->sreg1);
3928 mips_cvtds (code, ins->dreg, ins->dreg);
3931 /* Convert from double to float and leave it there */
3932 mips_cvtsd (code, ins->dreg, ins->sreg1);
3934 case OP_FCONV_TO_R4:
3936 mips_cvtsd (code, ins->dreg, ins->sreg1);
3938 /* Just a move, no precision change */
3939 if (ins->dreg != ins->sreg1) {
3940 mips_fmovd (code, ins->dreg, ins->sreg1);
3945 code = emit_load_volatile_arguments(cfg, code);
3948 * Pop our stack, then jump to specified method (tail-call)
3949 * Keep in sync with mono_arch_emit_epilog
3951 code = mono_arch_emit_epilog_sub (cfg, code);
3953 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3954 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3955 mips_load (code, mips_t9, 0);
3956 mips_jr (code, mips_t9);
3960 /* ensure ins->sreg1 is not NULL */
3961 mips_lw (code, mips_zero, ins->sreg1, 0);
3964 g_assert (mips_is_imm16 (cfg->sig_cookie));
3965 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3966 mips_sw (code, mips_at, ins->sreg1, 0);
3979 case OP_VOIDCALL_REG:
3981 case OP_FCALL_MEMBASE:
3982 case OP_LCALL_MEMBASE:
3983 case OP_VCALL_MEMBASE:
3984 case OP_VCALL2_MEMBASE:
3985 case OP_VOIDCALL_MEMBASE:
3986 case OP_CALL_MEMBASE:
3987 call = (MonoCallInst*)ins;
3988 switch (ins->opcode) {
3995 if (ins->flags & MONO_INST_HAS_METHOD) {
3996 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3997 mips_load (code, mips_t9, call->method);
4000 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4001 mips_load (code, mips_t9, call->fptr);
4003 mips_jalr (code, mips_t9, mips_ra);
4010 case OP_VOIDCALL_REG:
4012 MIPS_MOVE (code, mips_t9, ins->sreg1);
4013 mips_jalr (code, mips_t9, mips_ra);
4016 case OP_FCALL_MEMBASE:
4017 case OP_LCALL_MEMBASE:
4018 case OP_VCALL_MEMBASE:
4019 case OP_VCALL2_MEMBASE:
4020 case OP_VOIDCALL_MEMBASE:
4021 case OP_CALL_MEMBASE:
4022 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
4023 mips_jalr (code, mips_t9, mips_ra);
4027 #if PROMOTE_R4_TO_R8
4028 /* returned an FP R4 (single), promote to R8 (double) in place */
4029 switch (ins->opcode) {
4032 case OP_FCALL_MEMBASE:
4033 if (call->signature->ret->type == MONO_TYPE_R4)
4034 mips_cvtds (code, mips_f0, mips_f0);
4042 int area_offset = cfg->param_area;
4044 /* Round up ins->sreg1, mips_at ends up holding size */
4045 mips_addiu (code, mips_at, ins->sreg1, 31);
4046 mips_addiu (code, mips_temp, mips_zero, ~31);
4047 mips_and (code, mips_at, mips_at, mips_temp);
4049 mips_subu (code, mips_sp, mips_sp, mips_at);
4050 g_assert (mips_is_imm16 (area_offset));
4051 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4053 if (ins->flags & MONO_INST_INIT) {
4056 buf = (guint32*)(void*)code;
4057 mips_beq (code, mips_at, mips_zero, 0);
4060 mips_move (code, mips_temp, ins->dreg);
4061 mips_sb (code, mips_zero, mips_temp, 0);
4062 mips_addiu (code, mips_at, mips_at, -1);
4063 mips_bne (code, mips_at, mips_zero, -3);
4064 mips_addiu (code, mips_temp, mips_temp, 1);
4066 mips_patch (buf, (guint32)code);
4071 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4072 mips_move (code, mips_a0, ins->sreg1);
4073 mips_call (code, mips_t9, addr);
4074 mips_break (code, 0xfc);
4078 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4079 mips_move (code, mips_a0, ins->sreg1);
4080 mips_call (code, mips_t9, addr);
4081 mips_break (code, 0xfb);
4084 case OP_START_HANDLER: {
4086 * The START_HANDLER instruction marks the beginning of
4087 * a handler block. It is called using a call
4088 * instruction, so mips_ra contains the return address.
4089 * Since the handler executes in the same stack frame
4090 * as the method itself, we can't use save/restore to
4091 * save the return address. Instead, we save it into
4092 * a dedicated variable.
4094 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4095 g_assert (spvar->inst_basereg != mips_sp);
4096 code = emit_reserve_param_area (cfg, code);
4098 if (mips_is_imm16 (spvar->inst_offset)) {
4099 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4101 mips_load_const (code, mips_at, spvar->inst_offset);
4102 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4103 mips_sw (code, mips_ra, mips_at, 0);
4107 case OP_ENDFILTER: {
4108 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4109 g_assert (spvar->inst_basereg != mips_sp);
4110 code = emit_unreserve_param_area (cfg, code);
4112 if (ins->sreg1 != mips_v0)
4113 MIPS_MOVE (code, mips_v0, ins->sreg1);
4114 if (mips_is_imm16 (spvar->inst_offset)) {
4115 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4117 mips_load_const (code, mips_at, spvar->inst_offset);
4118 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4119 mips_lw (code, mips_ra, mips_at, 0);
4121 mips_jr (code, mips_ra);
4125 case OP_ENDFINALLY: {
4126 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4127 g_assert (spvar->inst_basereg != mips_sp);
4128 code = emit_unreserve_param_area (cfg, code);
4129 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4130 mips_jalr (code, mips_t9, mips_ra);
4134 case OP_CALL_HANDLER:
4135 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4136 mips_lui (code, mips_t9, mips_zero, 0);
4137 mips_addiu (code, mips_t9, mips_t9, 0);
4138 mips_jalr (code, mips_t9, mips_ra);
4140 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4141 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4144 ins->inst_c0 = code - cfg->native_code;
4147 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4148 if (cfg->arch.long_branch) {
4149 mips_lui (code, mips_at, mips_zero, 0);
4150 mips_addiu (code, mips_at, mips_at, 0);
4151 mips_jr (code, mips_at);
4155 mips_beq (code, mips_zero, mips_zero, 0);
4160 mips_jr (code, ins->sreg1);
4166 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4167 if (offset > (cfg->code_size - max_len - 16)) {
4168 cfg->code_size += max_len;
4169 cfg->code_size *= 2;
4170 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4171 code = cfg->native_code + offset;
4173 g_assert (ins->sreg1 != -1);
4174 mips_sll (code, mips_at, ins->sreg1, 2);
4175 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4176 MIPS_MOVE (code, mips_t8, mips_ra);
4177 mips_bgezal (code, mips_zero, 1); /* bal */
4179 mips_addu (code, mips_t9, mips_ra, mips_at);
4180 /* Table is 16 or 20 bytes from target of bal above */
4181 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4182 MIPS_MOVE (code, mips_ra, mips_t8);
4183 mips_lw (code, mips_t9, mips_t9, 20);
4186 mips_lw (code, mips_t9, mips_t9, 16);
4187 mips_jalr (code, mips_t9, mips_t8);
4189 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4190 mips_emit32 (code, 0xfefefefe);
4195 mips_addiu (code, ins->dreg, mips_zero, 1);
4196 mips_beq (code, mips_at, mips_zero, 2);
4198 MIPS_MOVE (code, ins->dreg, mips_zero);
4204 mips_addiu (code, ins->dreg, mips_zero, 1);
4205 mips_bltz (code, mips_at, 2);
4207 MIPS_MOVE (code, ins->dreg, mips_zero);
4213 mips_addiu (code, ins->dreg, mips_zero, 1);
4214 mips_bgtz (code, mips_at, 2);
4216 MIPS_MOVE (code, ins->dreg, mips_zero);
4219 case OP_MIPS_COND_EXC_EQ:
4220 case OP_MIPS_COND_EXC_GE:
4221 case OP_MIPS_COND_EXC_GT:
4222 case OP_MIPS_COND_EXC_LE:
4223 case OP_MIPS_COND_EXC_LT:
4224 case OP_MIPS_COND_EXC_NE_UN:
4225 case OP_MIPS_COND_EXC_GE_UN:
4226 case OP_MIPS_COND_EXC_GT_UN:
4227 case OP_MIPS_COND_EXC_LE_UN:
4228 case OP_MIPS_COND_EXC_LT_UN:
4230 case OP_MIPS_COND_EXC_OV:
4231 case OP_MIPS_COND_EXC_NO:
4232 case OP_MIPS_COND_EXC_C:
4233 case OP_MIPS_COND_EXC_NC:
4235 case OP_MIPS_COND_EXC_IEQ:
4236 case OP_MIPS_COND_EXC_IGE:
4237 case OP_MIPS_COND_EXC_IGT:
4238 case OP_MIPS_COND_EXC_ILE:
4239 case OP_MIPS_COND_EXC_ILT:
4240 case OP_MIPS_COND_EXC_INE_UN:
4241 case OP_MIPS_COND_EXC_IGE_UN:
4242 case OP_MIPS_COND_EXC_IGT_UN:
4243 case OP_MIPS_COND_EXC_ILE_UN:
4244 case OP_MIPS_COND_EXC_ILT_UN:
4246 case OP_MIPS_COND_EXC_IOV:
4247 case OP_MIPS_COND_EXC_INO:
4248 case OP_MIPS_COND_EXC_IC:
4249 case OP_MIPS_COND_EXC_INC: {
4253 /* If the condition is true, raise the exception */
4255 /* need to reverse test to skip around exception raising */
4257 /* For the moment, branch around a branch to avoid reversing
4260 /* Remember, an unpatched branch to 0 branches to the delay slot */
4261 switch (ins->opcode) {
4262 case OP_MIPS_COND_EXC_EQ:
4263 throw = (guint32 *)(void *)code;
4264 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4268 case OP_MIPS_COND_EXC_NE_UN:
4269 throw = (guint32 *)(void *)code;
4270 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4274 case OP_MIPS_COND_EXC_LE_UN:
4275 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4276 throw = (guint32 *)(void *)code;
4277 mips_beq (code, mips_at, mips_zero, 0);
4281 case OP_MIPS_COND_EXC_GT:
4282 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4283 throw = (guint32 *)(void *)code;
4284 mips_bne (code, mips_at, mips_zero, 0);
4288 case OP_MIPS_COND_EXC_GT_UN:
4289 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4290 throw = (guint32 *)(void *)code;
4291 mips_bne (code, mips_at, mips_zero, 0);
4295 case OP_MIPS_COND_EXC_LT:
4296 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4297 throw = (guint32 *)(void *)code;
4298 mips_bne (code, mips_at, mips_zero, 0);
4302 case OP_MIPS_COND_EXC_LT_UN:
4303 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4304 throw = (guint32 *)(void *)code;
4305 mips_bne (code, mips_at, mips_zero, 0);
4310 /* Not yet implemented */
4311 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4312 g_assert_not_reached ();
4314 skip = (guint32 *)(void *)code;
4315 mips_beq (code, mips_zero, mips_zero, 0);
4317 mips_patch (throw, (guint32)code);
4318 code = mips_emit_exc_by_name (code, ins->inst_p1);
4319 mips_patch (skip, (guint32)code);
4320 cfg->bb_exit->max_offset += 24;
4329 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4332 /* floating point opcodes */
4335 if (((guint32)ins->inst_p0) & (1 << 15))
4336 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4338 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4339 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4341 mips_load_const (code, mips_at, ins->inst_p0);
4342 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4343 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4347 if (((guint32)ins->inst_p0) & (1 << 15))
4348 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4350 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4351 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4352 #if PROMOTE_R4_TO_R8
4353 mips_cvtds (code, ins->dreg, ins->dreg);
4356 case OP_STORER8_MEMBASE_REG:
4357 if (mips_is_imm16 (ins->inst_offset)) {
4358 #if _MIPS_SIM == _ABIO32
4359 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4360 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4361 #elif _MIPS_SIM == _ABIN32
4362 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4365 mips_load_const (code, mips_at, ins->inst_offset);
4366 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4367 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4368 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4371 case OP_LOADR8_MEMBASE:
4372 if (mips_is_imm16 (ins->inst_offset)) {
4373 #if _MIPS_SIM == _ABIO32
4374 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4375 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4376 #elif _MIPS_SIM == _ABIN32
4377 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4380 mips_load_const (code, mips_at, ins->inst_offset);
4381 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4382 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4383 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4386 case OP_STORER4_MEMBASE_REG:
4387 g_assert (mips_is_imm16 (ins->inst_offset));
4388 #if PROMOTE_R4_TO_R8
4389 /* Need to convert ins->sreg1 to single-precision first */
4390 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4391 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4393 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4397 g_assert (mips_is_imm16 (ins->inst_offset));
4398 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4400 case OP_LOADR4_MEMBASE:
4401 g_assert (mips_is_imm16 (ins->inst_offset));
4402 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4403 #if PROMOTE_R4_TO_R8
4404 /* Convert to double precision in place */
4405 mips_cvtds (code, ins->dreg, ins->dreg);
4408 case OP_LOADR4_MEMINDEX:
4409 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4410 mips_lwc1 (code, ins->dreg, mips_at, 0);
4412 case OP_LOADR8_MEMINDEX:
4413 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4414 #if _MIPS_SIM == _ABIO32
4415 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4416 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4417 #elif _MIPS_SIM == _ABIN32
4418 mips_ldc1 (code, ins->dreg, mips_at, 0);
4421 case OP_STORER4_MEMINDEX:
4422 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4423 #if PROMOTE_R4_TO_R8
4424 /* Need to convert ins->sreg1 to single-precision first */
4425 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4426 mips_swc1 (code, mips_ftemp, mips_at, 0);
4428 mips_swc1 (code, ins->sreg1, mips_at, 0);
4431 case OP_STORER8_MEMINDEX:
4432 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4433 #if _MIPS_SIM == _ABIO32
4434 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4435 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4436 #elif _MIPS_SIM == _ABIN32
4437 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4440 case OP_ICONV_TO_R_UN: {
4441 static const guint64 adjust_val = 0x41F0000000000000ULL;
4443 /* convert unsigned int to double */
4444 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4445 mips_bgez (code, ins->sreg1, 5);
4446 mips_cvtdw (code, ins->dreg, mips_ftemp);
4448 mips_load (code, mips_at, (guint32) &adjust_val);
4449 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4450 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4451 /* target is here */
4454 case OP_ICONV_TO_R4:
4455 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4456 mips_cvtsw (code, ins->dreg, mips_ftemp);
4457 mips_cvtds (code, ins->dreg, ins->dreg);
4459 case OP_ICONV_TO_R8:
4460 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4461 mips_cvtdw (code, ins->dreg, mips_ftemp);
4463 case OP_FCONV_TO_I1:
4464 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4466 case OP_FCONV_TO_U1:
4467 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4469 case OP_FCONV_TO_I2:
4470 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4472 case OP_FCONV_TO_U2:
4473 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4475 case OP_FCONV_TO_I4:
4477 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4479 case OP_FCONV_TO_U4:
4481 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4484 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4487 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4490 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4493 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4496 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4499 mips_fnegd (code, ins->dreg, ins->sreg1);
4502 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4503 mips_addiu (code, ins->dreg, mips_zero, 1);
4504 mips_fbtrue (code, 2);
4506 MIPS_MOVE (code, ins->dreg, mips_zero);
4509 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4510 mips_addiu (code, ins->dreg, mips_zero, 1);
4511 mips_fbtrue (code, 2);
4513 MIPS_MOVE (code, ins->dreg, mips_zero);
4516 /* Less than, or Unordered */
4517 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4518 mips_addiu (code, ins->dreg, mips_zero, 1);
4519 mips_fbtrue (code, 2);
4521 MIPS_MOVE (code, ins->dreg, mips_zero);
4524 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4525 MIPS_MOVE (code, ins->dreg, mips_zero);
4526 mips_fbtrue (code, 2);
4528 mips_addiu (code, ins->dreg, mips_zero, 1);
4531 /* Greater than, or Unordered */
4532 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4533 MIPS_MOVE (code, ins->dreg, mips_zero);
4534 mips_fbtrue (code, 2);
4536 mips_addiu (code, ins->dreg, mips_zero, 1);
4541 case OP_MIPS_FBLT_UN:
4543 case OP_MIPS_FBGT_UN:
4545 case OP_MIPS_FBGE_UN:
4547 case OP_MIPS_FBLE_UN: {
4549 gboolean is_true = TRUE, is_ordered = FALSE;
4550 guint32 *buf = NULL;
4552 switch (ins->opcode) {
4566 case OP_MIPS_FBLT_UN:
4567 cond = MIPS_FPU_ULT;
4575 case OP_MIPS_FBGT_UN:
4576 cond = MIPS_FPU_OLE;
4584 case OP_MIPS_FBGE_UN:
4585 cond = MIPS_FPU_OLT;
4589 cond = MIPS_FPU_OLE;
4593 case OP_MIPS_FBLE_UN:
4594 cond = MIPS_FPU_ULE;
4598 g_assert_not_reached ();
4602 /* Skip the check if unordered */
4603 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4605 buf = (guint32*)code;
4606 mips_fbtrue (code, 0);
4610 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4612 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4614 mips_fbtrue (code, 0);
4616 mips_fbfalse (code, 0);
4620 mips_patch (buf, (guint32)code);
4624 guint32 *branch_patch;
4626 mips_mfc1 (code, mips_at, ins->sreg1+1);
4627 mips_srl (code, mips_at, mips_at, 16+4);
4628 mips_andi (code, mips_at, mips_at, 2047);
4629 mips_addiu (code, mips_at, mips_at, -2047);
4631 branch_patch = (guint32 *)(void *)code;
4632 mips_bne (code, mips_at, mips_zero, 0);
4635 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
4636 mips_patch (branch_patch, (guint32)code);
4637 mips_fmovd (code, ins->dreg, ins->sreg1);
4641 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4642 mips_load (code, ins->dreg, 0x0f0f0f0f);
4644 case OP_GC_SAFE_POINT:
4649 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4650 g_assert_not_reached ();
4653 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4654 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4655 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4656 g_assert_not_reached ();
4662 last_offset = offset;
4665 cfg->code_len = code - cfg->native_code;
4669 mono_arch_register_lowlevel_calls (void)
4674 mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4676 MonoJumpInfo *patch_info;
4679 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4680 unsigned char *ip = patch_info->ip.i + code;
4681 const unsigned char *target = NULL;
4683 switch (patch_info->type) {
4684 case MONO_PATCH_INFO_IP:
4685 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4687 case MONO_PATCH_INFO_SWITCH: {
4688 gpointer *table = (gpointer *)patch_info->data.table->table;
4691 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4693 for (i = 0; i < patch_info->data.table->table_size; i++) {
4694 table [i] = (int)patch_info->data.table->table [i] + code;
4698 case MONO_PATCH_INFO_METHODCONST:
4699 case MONO_PATCH_INFO_CLASS:
4700 case MONO_PATCH_INFO_IMAGE:
4701 case MONO_PATCH_INFO_FIELD:
4702 case MONO_PATCH_INFO_VTABLE:
4703 case MONO_PATCH_INFO_IID:
4704 case MONO_PATCH_INFO_SFLDA:
4705 case MONO_PATCH_INFO_LDSTR:
4706 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4707 case MONO_PATCH_INFO_LDTOKEN:
4708 case MONO_PATCH_INFO_R4:
4709 case MONO_PATCH_INFO_R8:
4710 /* from OP_AOTCONST : lui + addiu */
4711 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, &error);
4712 mono_error_raise_exception (&error); /* FIXME: don't raise here */
4713 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4716 case MONO_PATCH_INFO_EXC_NAME:
4717 g_assert_not_reached ();
4718 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4721 case MONO_PATCH_INFO_NONE:
4722 /* everything is dealt with at epilog output time */
4725 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors, &error);
4726 mono_error_raise_exception (&error); /* FIXME: don't raise here */
4727 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4734 * Allow tracing to work with this interface (with an optional argument)
4736 * This code is expected to be inserted just after the 'real' prolog code,
4737 * and before the first basic block. We need to allocate a 2nd, temporary
4738 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4742 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4745 int offset = cfg->arch.tracing_offset;
4751 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4752 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4753 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4754 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4755 #if _MIPS_SIM == _ABIN32
4757 /* FIXME: Need a separate region for these */
4758 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4759 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4760 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4761 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4765 mips_load_const (code, mips_a0, cfg->method);
4766 mips_addiu (code, mips_a1, mips_sp, offset);
4767 mips_call (code, mips_t9, func);
4770 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4771 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4772 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4773 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4774 #if _MIPS_SIM == _ABIN32
4777 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4778 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4779 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4780 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4791 mips_adjust_stackframe(MonoCompile *cfg)
4794 int delta, threshold, i;
4795 MonoMethodSignature *sig;
4798 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4801 /* adjust cfg->stack_offset for account for down-spilling */
4802 cfg->stack_offset += SIZEOF_REGISTER;
4804 /* re-align cfg->stack_offset if needed (due to var spilling) */
4805 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4806 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4807 if (cfg->verbose_level > 2) {
4808 g_print ("mips_adjust_stackframe:\n");
4809 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4811 threshold = cfg->arch.local_alloc_offset;
4812 ra_offset = cfg->stack_offset - sizeof(gpointer);
4813 if (cfg->verbose_level > 2) {
4814 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4817 sig = mono_method_signature (cfg->method);
4818 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4819 cfg->vret_addr->inst_offset += delta;
4821 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4822 MonoInst *inst = cfg->args [i];
4824 inst->inst_offset += delta;
4828 * loads and stores based off the frame reg that (used to) lie
4829 * above the spill var area need to be increased by 'delta'
4830 * to make room for the spill vars.
4832 /* Need to find loads and stores to adjust that
4833 * are above where the spillvars were inserted, but
4834 * which are not the spillvar references themselves.
4836 * Idea - since all offsets from fp are positive, make
4837 * spillvar offsets negative to begin with so we can spot
4842 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4846 if (cfg->verbose_level > 2) {
4847 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4849 MONO_BB_FOR_EACH_INS (bb, ins) {
4853 if (cfg->verbose_level > 2) {
4854 mono_print_ins_index (ins_cnt, ins);
4856 /* The == mips_sp tests catch FP spills */
4857 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4858 (ins->inst_basereg == mips_sp))) {
4859 switch (ins->opcode) {
4860 case OP_LOADI8_MEMBASE:
4861 case OP_LOADR8_MEMBASE:
4868 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4869 (ins->dreg == mips_sp))) {
4870 switch (ins->opcode) {
4871 case OP_STOREI8_MEMBASE_REG:
4872 case OP_STORER8_MEMBASE_REG:
4873 case OP_STOREI8_MEMBASE_IMM:
4881 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4884 if (ins->inst_c0 >= threshold) {
4885 ins->inst_c0 += delta;
4886 if (cfg->verbose_level > 2) {
4888 mono_print_ins_index (ins_cnt, ins);
4891 else if (ins->inst_c0 < 0) {
4892 /* Adj_c0 holds the size of the datatype. */
4893 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4894 if (cfg->verbose_level > 2) {
4896 mono_print_ins_index (ins_cnt, ins);
4899 g_assert (ins->inst_c0 != ra_offset);
4902 if (ins->inst_imm >= threshold) {
4903 ins->inst_imm += delta;
4904 if (cfg->verbose_level > 2) {
4906 mono_print_ins_index (ins_cnt, ins);
4909 g_assert (ins->inst_c0 != ra_offset);
4919 * Stack frame layout:
4921 * ------------------- sp + cfg->stack_usage + cfg->param_area
4922 * param area incoming
4923 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4925 * ------------------- sp + cfg->stack_usage
4927 * ------------------- sp + cfg->stack_usage-4
4929 * ------------------- sp +
4930 * MonoLMF structure optional
4931 * ------------------- sp + cfg->arch.lmf_offset
4932 * saved registers s0-s8
4933 * ------------------- sp + cfg->arch.iregs_offset
4935 * ------------------- sp + cfg->param_area
4936 * param area outgoing
4937 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4939 * ------------------- sp
4943 mono_arch_emit_prolog (MonoCompile *cfg)
4945 MonoMethod *method = cfg->method;
4946 MonoMethodSignature *sig;
4948 int alloc_size, pos, i, max_offset;
4949 int alloc2_size = 0;
4953 guint32 iregs_to_save = 0;
4955 guint32 fregs_to_save = 0;
4957 /* lmf_offset is the offset of the LMF from our stack pointer. */
4958 guint32 lmf_offset = cfg->arch.lmf_offset;
4962 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4966 cfg->flags |= MONO_CFG_HAS_CALLS;
4968 sig = mono_method_signature (method);
4969 cfg->code_size = 768 + sig->param_count * 20;
4970 code = cfg->native_code = g_malloc (cfg->code_size);
4973 * compute max_offset in order to use short forward jumps.
4976 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4977 MonoInst *ins = bb->code;
4978 bb->max_offset = max_offset;
4980 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4983 MONO_BB_FOR_EACH_INS (bb, ins)
4984 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4986 if (max_offset > 0xffff)
4987 cfg->arch.long_branch = TRUE;
4990 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4991 * This means that we have to adjust the offsets inside instructions which reference
4992 * arguments received on the stack, since the initial offset doesn't take into
4993 * account spill slots.
4995 mips_adjust_stackframe (cfg);
4997 /* Offset between current sp and the CFA */
4999 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
5001 /* stack_offset should not be changed here. */
5002 alloc_size = cfg->stack_offset;
5003 cfg->stack_usage = alloc_size;
5005 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5008 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5010 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
5011 fregs_to_save |= (fregs_to_save << 1);
5014 /* If the stack size is too big, save 1024 bytes to start with
5015 * so the prologue can use imm16(reg) addressing, then allocate
5016 * the rest of the frame.
5018 if (alloc_size > ((1 << 15) - 1024)) {
5019 alloc2_size = alloc_size - 1024;
5023 g_assert (mips_is_imm16 (-alloc_size));
5024 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
5025 cfa_offset = alloc_size;
5026 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5029 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5030 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5031 if (mips_is_imm16(offset))
5032 mips_sw (code, mips_ra, mips_sp, offset);
5034 g_assert_not_reached ();
5036 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5037 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5040 /* XXX - optimize this later to not save all regs if LMF constructed */
5041 pos = cfg->arch.iregs_offset - alloc2_size;
5043 if (iregs_to_save) {
5044 /* save used registers in own stack frame (at pos) */
5045 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5046 if (iregs_to_save & (1 << i)) {
5047 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5048 g_assert (mips_is_imm16(pos));
5049 MIPS_SW (code, i, mips_sp, pos);
5050 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5051 pos += SIZEOF_REGISTER;
5056 // FIXME: Don't save registers twice if there is an LMF
5057 // s8 has to be special cased since it is overwritten with the updated value
5059 if (method->save_lmf) {
5060 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5061 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5062 g_assert (mips_is_imm16(offset));
5063 if (MIPS_LMF_IREGMASK & (1 << i))
5064 MIPS_SW (code, i, mips_sp, offset);
5069 /* Save float registers */
5070 if (fregs_to_save) {
5071 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5072 if (fregs_to_save & (1 << i)) {
5073 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5074 g_assert (mips_is_imm16(pos));
5075 mips_swc1 (code, i, mips_sp, pos);
5076 pos += sizeof (gulong);
5081 if (method->save_lmf) {
5082 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5083 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5084 g_assert (mips_is_imm16(offset));
5085 mips_swc1 (code, i, mips_sp, offset);
5090 if (cfg->frame_reg != mips_sp) {
5091 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5092 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5094 if (method->save_lmf) {
5095 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5096 g_assert (mips_is_imm16(offset));
5097 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5101 /* store runtime generic context */
5102 if (cfg->rgctx_var) {
5103 MonoInst *ins = cfg->rgctx_var;
5105 g_assert (ins->opcode == OP_REGOFFSET);
5107 g_assert (mips_is_imm16 (ins->inst_offset));
5108 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5111 /* load arguments allocated to register from the stack */
5114 if (!cfg->arch.cinfo)
5115 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
5116 cinfo = cfg->arch.cinfo;
5118 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5119 ArgInfo *ainfo = &cinfo->ret;
5120 inst = cfg->vret_addr;
5121 if (inst->opcode == OP_REGVAR)
5122 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5123 else if (mips_is_imm16 (inst->inst_offset)) {
5124 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5126 mips_load_const (code, mips_at, inst->inst_offset);
5127 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5128 mips_sw (code, ainfo->reg, mips_at, 0);
5132 if (sig->call_convention == MONO_CALL_VARARG) {
5133 ArgInfo *cookie = &cinfo->sig_cookie;
5134 int offset = alloc_size + cookie->offset;
5136 /* Save the sig cookie address */
5137 g_assert (cookie->storage == ArgOnStack);
5139 g_assert (mips_is_imm16(offset));
5140 mips_addi (code, mips_at, cfg->frame_reg, offset);
5141 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5144 /* Keep this in sync with emit_load_volatile_arguments */
5145 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5146 ArgInfo *ainfo = cinfo->args + i;
5147 inst = cfg->args [pos];
5149 if (cfg->verbose_level > 2)
5150 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5151 if (inst->opcode == OP_REGVAR) {
5152 /* Argument ends up in a register */
5153 if (ainfo->storage == ArgInIReg)
5154 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5155 else if (ainfo->storage == ArgInFReg) {
5156 g_assert_not_reached();
5158 ppc_fmr (code, inst->dreg, ainfo->reg);
5161 else if (ainfo->storage == ArgOnStack) {
5162 int offset = cfg->stack_usage + ainfo->offset;
5163 g_assert (mips_is_imm16(offset));
5164 mips_lw (code, inst->dreg, mips_sp, offset);
5166 g_assert_not_reached ();
5168 if (cfg->verbose_level > 2)
5169 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5171 /* Argument ends up on the stack */
5172 if (ainfo->storage == ArgInIReg) {
5174 /* Incoming parameters should be above this frame */
5175 if (cfg->verbose_level > 2)
5176 g_print ("stack slot at %d of %d+%d\n",
5177 inst->inst_offset, alloc_size, alloc2_size);
5178 /* g_assert (inst->inst_offset >= alloc_size); */
5179 g_assert (inst->inst_basereg == cfg->frame_reg);
5180 basereg_offset = inst->inst_offset - alloc2_size;
5181 g_assert (mips_is_imm16 (basereg_offset));
5182 switch (ainfo->size) {
5184 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5187 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5191 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5194 #if (SIZEOF_REGISTER == 4)
5195 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5196 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5197 #elif (SIZEOF_REGISTER == 8)
5198 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5202 g_assert_not_reached ();
5205 } else if (ainfo->storage == ArgOnStack) {
5207 * Argument comes in on the stack, and ends up on the stack
5208 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5209 * 8 and 16 bit quantities. Shorten them in place.
5211 g_assert (mips_is_imm16 (inst->inst_offset));
5212 switch (ainfo->size) {
5214 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5215 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5218 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5219 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5226 g_assert_not_reached ();
5228 } else if (ainfo->storage == ArgInFReg) {
5229 g_assert (mips_is_imm16 (inst->inst_offset));
5230 g_assert (mips_is_imm16 (inst->inst_offset+4));
5231 if (ainfo->size == 8) {
5232 #if _MIPS_SIM == _ABIO32
5233 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5234 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5235 #elif _MIPS_SIM == _ABIN32
5236 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5239 else if (ainfo->size == 4)
5240 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5242 g_assert_not_reached ();
5243 } else if (ainfo->storage == ArgStructByVal) {
5245 int doffset = inst->inst_offset;
5247 g_assert (mips_is_imm16 (inst->inst_offset));
5248 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5249 /* Push the argument registers into their stack slots */
5250 for (i = 0; i < ainfo->size; ++i) {
5251 g_assert (mips_is_imm16(doffset));
5252 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5253 doffset += SIZEOF_REGISTER;
5255 } else if (ainfo->storage == ArgStructByAddr) {
5256 g_assert (mips_is_imm16 (inst->inst_offset));
5257 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5258 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5260 g_assert_not_reached ();
5265 if (method->save_lmf) {
5266 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5267 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5269 if (lmf_pthread_key != -1) {
5270 g_assert_not_reached();
5272 emit_tls_access (code, mips_temp, lmf_pthread_key);
5274 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5275 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5276 g_assert (mips_is_imm16(offset));
5277 mips_addiu (code, mips_a0, mips_temp, offset);
5280 /* This can/will clobber the a0-a3 registers */
5281 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5284 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5285 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5286 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5287 /* new_lmf->previous_lmf = *lmf_addr */
5288 mips_lw (code, mips_at, mips_v0, 0);
5289 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5290 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5291 /* *(lmf_addr) = sp + lmf_offset */
5292 g_assert (mips_is_imm16(lmf_offset));
5293 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5294 mips_sw (code, mips_at, mips_v0, 0);
5296 /* save method info */
5297 mips_load_const (code, mips_at, method);
5298 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5299 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5301 /* save the current IP */
5302 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5303 mips_load_const (code, mips_at, 0x01010101);
5304 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5308 if (mips_is_imm16 (-alloc2_size)) {
5309 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5312 mips_load_const (code, mips_at, -alloc2_size);
5313 mips_addu (code, mips_sp, mips_sp, mips_at);
5315 alloc_size += alloc2_size;
5316 cfa_offset += alloc2_size;
5317 if (cfg->frame_reg != mips_sp)
5318 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5320 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5324 #if _MIPS_SIM == _ABIO32
5325 cfg->arch.tracing_offset = cfg->stack_offset;
5326 #elif _MIPS_SIM == _ABIN32
5327 /* no stack slots by default for argument regs, reserve a special block */
5328 g_assert_not_reached ();
5330 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5333 cfg->code_len = code - cfg->native_code;
5334 g_assert (cfg->code_len < cfg->code_size);
5348 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5351 int save_mode = SAVE_NONE;
5353 MonoMethod *method = cfg->method;
5354 int rtype = mini_get_underlying_type (mono_method_signature (method)->ret)->type;
5355 int save_offset = MIPS_STACK_PARAM_OFFSET;
5357 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5359 offset = code - cfg->native_code;
5360 /* we need about 16 instructions */
5361 if (offset > (cfg->code_size - 16 * 4)) {
5362 cfg->code_size *= 2;
5363 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5364 code = cfg->native_code + offset;
5369 case MONO_TYPE_VOID:
5370 /* special case string .ctor icall */
5371 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5372 save_mode = SAVE_ONE;
5374 save_mode = SAVE_NONE;
5378 save_mode = SAVE_FP;
5380 case MONO_TYPE_VALUETYPE:
5381 save_mode = SAVE_STRUCT;
5385 #if SIZEOF_REGISTER == 4
5386 save_mode = SAVE_TWO;
5387 #elif SIZEOF_REGISTER == 8
5388 save_mode = SAVE_ONE;
5392 save_mode = SAVE_ONE;
5396 mips_addiu (code, mips_sp, mips_sp, -32);
5397 g_assert (mips_is_imm16(save_offset));
5398 switch (save_mode) {
5400 mips_sw (code, mips_v0, mips_sp, save_offset);
5401 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5402 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5403 if (enable_arguments) {
5404 MIPS_MOVE (code, mips_a1, mips_v0);
5405 MIPS_MOVE (code, mips_a2, mips_v1);
5409 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5410 if (enable_arguments) {
5411 MIPS_MOVE (code, mips_a1, mips_v0);
5415 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5416 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5417 mips_lw (code, mips_a0, mips_sp, save_offset);
5418 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5419 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5426 mips_load_const (code, mips_a0, cfg->method);
5427 mips_call (code, mips_t9, func);
5429 switch (save_mode) {
5431 mips_lw (code, mips_v0, mips_sp, save_offset);
5432 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5433 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5436 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5439 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5446 mips_addiu (code, mips_sp, mips_sp, 32);
5453 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5455 MonoMethod *method = cfg->method;
5457 int max_epilog_size = 16 + 20*4;
5458 int alloc2_size = 0;
5459 guint32 iregs_to_restore;
5461 guint32 fregs_to_restore;
5464 if (cfg->method->save_lmf)
5465 max_epilog_size += 128;
5467 if (mono_jit_trace_calls != NULL)
5468 max_epilog_size += 50;
5470 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5471 max_epilog_size += 50;
5474 pos = code - cfg->native_code;
5475 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5476 cfg->code_size *= 2;
5477 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5478 cfg->stat_code_reallocs++;
5482 * Keep in sync with OP_JMP
5485 code = cfg->native_code + pos;
5487 code = cfg->native_code + cfg->code_len;
5489 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5490 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5492 if (cfg->frame_reg != mips_sp) {
5493 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5495 /* If the stack frame is really large, deconstruct it in two steps */
5496 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5497 alloc2_size = cfg->stack_usage - 1024;
5498 /* partially deconstruct the stack */
5499 mips_load_const (code, mips_at, alloc2_size);
5500 mips_addu (code, mips_sp, mips_sp, mips_at);
5502 pos = cfg->arch.iregs_offset - alloc2_size;
5503 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5504 if (iregs_to_restore) {
5505 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5506 if (iregs_to_restore & (1 << i)) {
5507 g_assert (mips_is_imm16(pos));
5508 MIPS_LW (code, i, mips_sp, pos);
5509 pos += SIZEOF_REGISTER;
5516 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5518 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5519 fregs_to_restore |= (fregs_to_restore << 1);
5521 if (fregs_to_restore) {
5522 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5523 if (fregs_to_restore & (1 << i)) {
5524 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5525 g_assert (mips_is_imm16(pos));
5526 mips_lwc1 (code, i, mips_sp, pos);
5533 /* Unlink the LMF if necessary */
5534 if (method->save_lmf) {
5535 int lmf_offset = cfg->arch.lmf_offset;
5537 /* t0 = current_lmf->previous_lmf */
5538 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5539 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5541 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5542 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5543 /* (*lmf_addr) = previous_lmf */
5544 mips_sw (code, mips_temp, mips_t1, 0);
5548 /* Restore the fp */
5549 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5552 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5553 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5554 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5556 /* Restore the stack pointer */
5557 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5558 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5560 /* Caller will emit either return or tail-call sequence */
5562 cfg->code_len = code - cfg->native_code;
5564 g_assert (cfg->code_len < cfg->code_size);
5569 mono_arch_emit_epilog (MonoCompile *cfg)
5573 code = mono_arch_emit_epilog_sub (cfg, NULL);
5575 mips_jr (code, mips_ra);
5578 cfg->code_len = code - cfg->native_code;
5580 g_assert (cfg->code_len < cfg->code_size);
5583 /* remove once throw_exception_by_name is eliminated */
5586 exception_id_by_name (const char *name)
5588 if (strcmp (name, "IndexOutOfRangeException") == 0)
5589 return MONO_EXC_INDEX_OUT_OF_RANGE;
5590 if (strcmp (name, "OverflowException") == 0)
5591 return MONO_EXC_OVERFLOW;
5592 if (strcmp (name, "ArithmeticException") == 0)
5593 return MONO_EXC_ARITHMETIC;
5594 if (strcmp (name, "DivideByZeroException") == 0)
5595 return MONO_EXC_DIVIDE_BY_ZERO;
5596 if (strcmp (name, "InvalidCastException") == 0)
5597 return MONO_EXC_INVALID_CAST;
5598 if (strcmp (name, "NullReferenceException") == 0)
5599 return MONO_EXC_NULL_REF;
5600 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5601 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5602 if (strcmp (name, "ArgumentException") == 0)
5603 return MONO_EXC_ARGUMENT;
5604 g_error ("Unknown intrinsic exception %s\n", name);
5610 mono_arch_emit_exceptions (MonoCompile *cfg)
5613 MonoJumpInfo *patch_info;
5616 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5617 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5618 int max_epilog_size = 50;
5620 /* count the number of exception infos */
5623 * make sure we have enough space for exceptions
5624 * 24 is the simulated call to throw_exception_by_name
5626 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5628 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5629 i = exception_id_by_name (patch_info->data.target);
5630 g_assert (i < MONO_EXC_INTRINS_NUM);
5631 if (!exc_throw_found [i]) {
5632 max_epilog_size += 12;
5633 exc_throw_found [i] = TRUE;
5639 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5640 cfg->code_size *= 2;
5641 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5642 cfg->stat_code_reallocs++;
5645 code = cfg->native_code + cfg->code_len;
5647 /* add code to raise exceptions */
5648 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5649 switch (patch_info->type) {
5650 case MONO_PATCH_INFO_EXC: {
5652 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5654 i = exception_id_by_name (patch_info->data.target);
5655 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5656 if (!exc_throw_pos [i]) {
5659 exc_throw_pos [i] = code;
5660 //g_print ("exc: writing stub at %p\n", code);
5661 mips_load_const (code, mips_a0, patch_info->data.target);
5662 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5663 mips_load_const (code, mips_t9, addr);
5664 mips_jr (code, mips_t9);
5667 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5669 /* Turn into a Relative patch, pointing at code stub */
5670 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5671 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5673 g_assert_not_reached();
5683 cfg->code_len = code - cfg->native_code;
5685 g_assert (cfg->code_len < cfg->code_size);
5690 * Thread local storage support
5693 setup_tls_access (void)
5696 //guint32 *ins, *code;
5698 if (tls_mode == TLS_MODE_FAILED)
5701 if (g_getenv ("MONO_NO_TLS")) {
5702 tls_mode = TLS_MODE_FAILED;
5706 if (tls_mode == TLS_MODE_DETECT) {
5708 tls_mode = TLS_MODE_FAILED;
5712 ins = (guint32*)pthread_getspecific;
5713 /* uncond branch to the real method */
5714 if ((*ins >> 26) == 18) {
5716 val = (*ins & ~3) << 6;
5720 ins = (guint32*)val;
5722 ins = (guint32*) ((char*)ins + val);
5725 code = &cmplwi_1023;
5726 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5728 ppc_li (code, ppc_r4, 0x48);
5731 if (*ins == cmplwi_1023) {
5732 int found_lwz_284 = 0;
5733 for (ptk = 0; ptk < 20; ++ptk) {
5735 if (!*ins || *ins == blr_ins)
5737 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5742 if (!found_lwz_284) {
5743 tls_mode = TLS_MODE_FAILED;
5746 tls_mode = TLS_MODE_LTHREADS;
5747 } else if (*ins == li_0x48) {
5749 /* uncond branch to the real method */
5750 if ((*ins >> 26) == 18) {
5752 val = (*ins & ~3) << 6;
5756 ins = (guint32*)val;
5758 ins = (guint32*) ((char*)ins + val);
5761 ppc_li (code, ppc_r0, 0x7FF2);
5762 if (ins [1] == val) {
5763 /* Darwin on G4, implement */
5764 tls_mode = TLS_MODE_FAILED;
5768 ppc_mfspr (code, ppc_r3, 104);
5769 if (ins [1] != val) {
5770 tls_mode = TLS_MODE_FAILED;
5773 tls_mode = TLS_MODE_DARWIN_G5;
5776 tls_mode = TLS_MODE_FAILED;
5780 tls_mode = TLS_MODE_FAILED;
5785 if (lmf_pthread_key == -1) {
5786 ptk = mono_jit_tls_id;
5788 /*g_print ("MonoLMF at: %d\n", ptk);*/
5789 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5790 init_tls_failed = 1;
5793 lmf_pthread_key = ptk;
5796 if (monothread_key == -1) {
5797 ptk = mono_thread_get_tls_key ();
5799 monothread_key = ptk;
5800 /*g_print ("thread inited: %d\n", ptk);*/
5802 /*g_print ("thread not inited yet %d\n", ptk);*/
5808 mono_arch_finish_init (void)
5810 setup_tls_access ();
5814 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5819 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5821 int this_dreg = mips_a0;
5824 this_dreg = mips_a1;
5826 /* add the this argument */
5827 if (this_reg != -1) {
5829 MONO_INST_NEW (cfg, this_ins, OP_MOVE);
5830 this_ins->type = this_type;
5831 this_ins->sreg1 = this_reg;
5832 this_ins->dreg = mono_alloc_ireg (cfg);
5833 mono_bblock_add_inst (cfg->cbb, this_ins);
5834 mono_call_inst_add_outarg_reg (cfg, inst, this_ins->dreg, this_dreg, FALSE);
5839 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5840 vtarg->type = STACK_MP;
5841 vtarg->sreg1 = vt_reg;
5842 vtarg->dreg = mono_alloc_ireg (cfg);
5843 mono_bblock_add_inst (cfg->cbb, vtarg);
5844 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5849 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5851 MonoInst *ins = NULL;
5857 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5863 mono_arch_print_tree (MonoInst *tree, int arity)
5869 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5871 return ctx->sc_regs [reg];
5874 #define ENABLE_WRONG_METHOD_CHECK 0
5876 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5877 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5879 #define LOADSTORE_SIZE 4
5880 #define JUMP_IMM_SIZE 16
5881 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5882 #define LOAD_CONST_SIZE 8
5883 #define JUMP_JR_SIZE 8
5886 * LOCKING: called with the domain lock held
5889 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5890 gpointer fail_tramp)
5894 guint8 *code, *start, *patch;
5896 for (i = 0; i < count; ++i) {
5897 MonoIMTCheckItem *item = imt_entries [i];
5899 if (item->is_equals) {
5900 if (item->check_target_idx) {
5901 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5902 if (item->has_target_code)
5903 item->chunk_size += LOAD_CONST_SIZE;
5905 item->chunk_size += LOADSTORE_SIZE;
5908 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5909 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5910 if (!item->has_target_code)
5911 item->chunk_size += LOADSTORE_SIZE;
5913 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5914 #if ENABLE_WRONG_METHOD_CHECK
5915 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5920 item->chunk_size += CMP_SIZE + BR_SIZE;
5921 imt_entries [item->check_target_idx]->compare_done = TRUE;
5923 size += item->chunk_size;
5925 /* the initial load of the vtable address */
5926 size += MIPS_LOAD_SEQUENCE_LENGTH;
5928 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5930 code = mono_domain_code_reserve (domain, size);
5934 /* t7 points to the vtable */
5935 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5937 for (i = 0; i < count; ++i) {
5938 MonoIMTCheckItem *item = imt_entries [i];
5940 item->code_target = code;
5941 if (item->is_equals) {
5942 if (item->check_target_idx) {
5943 mips_load_const (code, mips_temp, (gsize)item->key);
5944 item->jmp_code = code;
5945 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5947 if (item->has_target_code) {
5948 mips_load_const (code, mips_t9,
5949 item->value.target_code);
5952 mips_lw (code, mips_t9, mips_t7,
5953 (sizeof (gpointer) * item->value.vtable_slot));
5955 mips_jr (code, mips_t9);
5959 mips_load_const (code, mips_temp, (gsize)item->key);
5961 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5963 if (item->has_target_code) {
5964 mips_load_const (code, mips_t9,
5965 item->value.target_code);
5968 mips_load_const (code, mips_at,
5969 & (vtable->vtable [item->value.vtable_slot]));
5970 mips_lw (code, mips_t9, mips_at, 0);
5972 mips_jr (code, mips_t9);
5974 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5975 mips_load_const (code, mips_t9, fail_tramp);
5976 mips_jr (code, mips_t9);
5979 /* enable the commented code to assert on wrong method */
5980 #if ENABLE_WRONG_METHOD_CHECK
5981 ppc_load (code, ppc_r0, (guint32)item->key);
5982 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5984 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5986 mips_lw (code, mips_t9, mips_t7,
5987 (sizeof (gpointer) * item->value.vtable_slot));
5988 mips_jr (code, mips_t9);
5991 #if ENABLE_WRONG_METHOD_CHECK
5992 ppc_patch (patch, code);
5998 mips_load_const (code, mips_temp, (gulong)item->key);
5999 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
6001 item->jmp_code = code;
6002 mips_beq (code, mips_temp, mips_zero, 0);
6006 /* patch the branches to get to the target items */
6007 for (i = 0; i < count; ++i) {
6008 MonoIMTCheckItem *item = imt_entries [i];
6009 if (item->jmp_code && item->check_target_idx) {
6010 mips_patch ((guint32 *)item->jmp_code,
6011 (guint32)imt_entries [item->check_target_idx]->code_target);
6016 mono_stats.imt_thunks_size += code - start;
6017 g_assert (code - start <= size);
6018 mono_arch_flush_icache (start, size);
6020 mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
6026 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6028 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6032 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6034 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6037 /* Soft Debug support */
6038 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6041 * mono_arch_set_breakpoint:
6043 * See mini-amd64.c for docs.
6046 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6049 guint32 addr = (guint32)bp_trigger_page;
6051 mips_load_const (code, mips_t9, addr);
6052 mips_lw (code, mips_t9, mips_t9, 0);
6054 mono_arch_flush_icache (ip, code - ip);
6058 * mono_arch_clear_breakpoint:
6060 * See mini-amd64.c for docs.
6063 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6071 mono_arch_flush_icache (ip, code - ip);
6075 * mono_arch_start_single_stepping:
6077 * See mini-amd64.c for docs.
6080 mono_arch_start_single_stepping (void)
6082 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6086 * mono_arch_stop_single_stepping:
6088 * See mini-amd64.c for docs.
6091 mono_arch_stop_single_stepping (void)
6093 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6097 * mono_arch_is_single_step_event:
6099 * See mini-amd64.c for docs.
6102 mono_arch_is_single_step_event (void *info, void *sigctx)
6104 siginfo_t* sinfo = (siginfo_t*) info;
6105 /* Sometimes the address is off by 4 */
6106 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6113 * mono_arch_is_breakpoint_event:
6115 * See mini-amd64.c for docs.
6118 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6120 siginfo_t* sinfo = (siginfo_t*) info;
6121 /* Sometimes the address is off by 4 */
6122 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6129 * mono_arch_skip_breakpoint:
6131 * See mini-amd64.c for docs.
6134 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6136 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6140 * mono_arch_skip_single_step:
6142 * See mini-amd64.c for docs.
6145 mono_arch_skip_single_step (MonoContext *ctx)
6147 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6151 * mono_arch_get_seq_point_info:
6153 * See mini-amd64.c for docs.
6156 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6163 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6165 ext->lmf.previous_lmf = prev_lmf;
6166 /* Mark that this is a MonoLMFExt */
6167 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6168 ext->lmf.iregs [mips_sp] = (gssize)ext;
6171 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
6174 mono_arch_opcode_supported (int opcode)