2 * mini-mips.c: MIPS backend for the Mono code generator
5 * Mark Mason (mason@broadcom.com)
7 * Based on mini-ppc.c by
8 * Paolo Molaro (lupus@ximian.com)
9 * Dietmar Maurer (dietmar@ximian.com)
12 * (C) 2003 Ximian, Inc.
16 #include <asm/cachectl.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/utils/mono-mmap.h>
21 #include <mono/utils/mono-hwcap-mips.h>
23 #include <mono/arch/mips/mips-codegen.h>
25 #include "mini-mips.h"
30 #define SAVE_FP_REGS 0
32 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
34 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
35 #define USE_MUL 0 /* use mul instead of mult/mflo for multiply
36 remember to update cpu-mips.md if you change this */
38 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
39 #define mips_call(c,D,v) do { \
40 guint32 _target = (guint32)(v); \
41 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
42 mips_load_const (c, D, _target); \
43 mips_jalr (c, D, mips_ra); \
46 mips_jumpl (c, _target >> 2); \
58 /* This mutex protects architecture specific caches */
59 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
60 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
61 static CRITICAL_SECTION mini_arch_mutex;
63 int mono_exc_esp_offset = 0;
64 static int tls_mode = TLS_MODE_DETECT;
65 static int lmf_pthread_key = -1;
66 static int monothread_key = -1;
68 /* Whenever the host is little-endian */
69 static int little_endian;
70 /* Index of ms word/register */
71 static int ls_word_idx;
72 /* Index of ls word/register */
73 static int ms_word_idx;
74 /* Same for offsets */
75 static int ls_word_offset;
76 static int ms_word_offset;
79 * The code generated for sequence points reads from this location, which is
80 * made read-only when single stepping is enabled.
82 static gpointer ss_trigger_page;
84 /* Enabled breakpoints read from this trigger page */
85 static gpointer bp_trigger_page;
88 #define DEBUG(a) if (cfg->verbose_level > 1) a
94 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
96 code = mips_emit_exc_by_name (code, exc_name); \
97 cfg->bb_exit->max_offset += 16; \
101 #define emit_linuxthreads_tls(code,dreg,key) do {\
103 off1 = offsets_from_pthread_key ((key), &off2); \
104 g_assert_not_reached (); \
105 ppc_lwz ((code), (dreg), off1, ppc_r2); \
106 ppc_lwz ((code), (dreg), off2, (dreg)); \
110 #define emit_tls_access(code,dreg,key) do { \
111 switch (tls_mode) { \
112 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
113 default: g_assert_not_reached (); \
117 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
119 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
120 inst->type = STACK_R8; \
122 inst->inst_p0 = (void*)(addr); \
123 mono_bblock_add_inst (cfg->cbb, inst); \
126 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
127 || ((ins)->opcode == OP_ICOMPARE) \
128 || ((ins)->opcode == OP_LCOMPARE)))
129 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
130 || ((ins)->opcode == OP_ICOMPARE_IMM) \
131 || ((ins)->opcode == OP_LCOMPARE_IMM)))
133 #define INS_REWRITE(ins, op, _s1, _s2) do { \
136 ins->opcode = (op); \
141 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
143 ins->opcode = (op); \
145 ins->inst_imm = (_imm); \
149 typedef struct InstList InstList;
167 guint16 vtsize; /* in param area */
170 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
179 gboolean vtype_retaddr;
188 void patch_lui_addiu(guint32 *ip, guint32 val);
189 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
190 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
191 void mips_adjust_stackframe(MonoCompile *cfg);
192 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
193 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
196 /* Not defined in asm/cachectl.h */
197 int cacheflush(char *addr, int nbytes, int cache);
200 mono_arch_flush_icache (guint8 *code, gint size)
202 /* Linux/MIPS specific */
203 cacheflush ((char*)code, size, BCACHE);
207 mono_arch_flush_register_windows (void)
212 mono_arch_is_inst_imm (gint64 imm)
218 mips_emit_exc_by_name(guint8 *code, const char *name)
221 MonoClass *exc_class;
223 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
224 g_assert (exc_class);
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 (MonoGenericSharingContext *gsctx, 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 (NULL, 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 (gboolean has_target, gboolean param_count, guint32 *code_size)
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, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
555 mips_lw (code, mips_a0, mips_a0, G_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, G_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 *code_size = code - start;
588 * mono_arch_get_delegate_invoke_impls:
590 * Return a list of MonoAotTrampInfo structures for the delegate invoke impl
594 mono_arch_get_delegate_invoke_impls (void)
602 code = get_delegate_invoke_impl (TRUE, 0, &code_len);
603 res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
605 for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
606 code = get_delegate_invoke_impl (FALSE, i, &code_len);
607 tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
608 res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
616 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
618 guint8 *code, *start;
620 /* FIXME: Support more cases */
621 if (MONO_TYPE_ISSTRUCT (sig->ret))
625 static guint8* cached = NULL;
626 mono_mini_arch_lock ();
628 mono_mini_arch_unlock ();
633 start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
635 start = get_delegate_invoke_impl (TRUE, 0, NULL);
637 mono_mini_arch_unlock ();
640 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
643 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
645 for (i = 0; i < sig->param_count; ++i)
646 if (!mono_is_regsize_var (sig->params [i]))
649 mono_mini_arch_lock ();
650 code = cache [sig->param_count];
652 mono_mini_arch_unlock ();
657 char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
658 start = mono_aot_get_trampoline (name);
661 start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
663 cache [sig->param_count] = start;
664 mono_mini_arch_unlock ();
672 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
675 return (gpointer)regs [mips_a0];
679 * Initialize the cpu to execute managed code.
682 mono_arch_cpu_init (void)
684 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
693 ls_word_offset = ls_word_idx * 4;
694 ms_word_offset = ms_word_idx * 4;
698 * Initialize architecture specific code.
701 mono_arch_init (void)
703 InitializeCriticalSection (&mini_arch_mutex);
705 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
706 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
707 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
711 * Cleanup architecture specific code.
714 mono_arch_cleanup (void)
716 DeleteCriticalSection (&mini_arch_mutex);
720 * This function returns the optimizations supported on this cpu.
723 mono_arch_cpu_optimizations (guint32 *exclude_mask)
727 /* no mips-specific optimizations yet */
733 * This function test for all SIMD functions supported.
735 * Returns a bitmask corresponding to all supported versions.
739 mono_arch_cpu_enumerate_simd_versions (void)
741 /* SIMD is currently unimplemented */
746 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
751 for (i = 0; i < cfg->num_varinfo; i++) {
752 MonoInst *ins = cfg->varinfo [i];
753 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
756 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
759 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
762 /* we can only allocate 32 bit values */
763 if (mono_is_regsize_var (ins->inst_vtype)) {
764 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
765 g_assert (i == vmv->idx);
766 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
774 mono_arch_get_global_int_regs (MonoCompile *cfg)
778 regs = g_list_prepend (regs, (gpointer)mips_s0);
779 regs = g_list_prepend (regs, (gpointer)mips_s1);
780 regs = g_list_prepend (regs, (gpointer)mips_s2);
781 regs = g_list_prepend (regs, (gpointer)mips_s3);
782 regs = g_list_prepend (regs, (gpointer)mips_s4);
783 //regs = g_list_prepend (regs, (gpointer)mips_s5);
784 regs = g_list_prepend (regs, (gpointer)mips_s6);
785 regs = g_list_prepend (regs, (gpointer)mips_s7);
791 * mono_arch_regalloc_cost:
793 * Return the cost, in number of memory references, of the action of
794 * allocating the variable VMV into a register during global register
798 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
805 args_onto_stack (CallInfo *info)
807 g_assert (!info->on_stack);
808 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
809 info->on_stack = TRUE;
810 info->stack_size = MIPS_STACK_PARAM_OFFSET;
813 #if _MIPS_SIM == _ABIO32
815 * O32 calling convention version
819 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
820 /* First, see if we need to drop onto the stack */
821 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
822 args_onto_stack (info);
824 /* Now, place the argument */
825 if (info->on_stack) {
826 ainfo->storage = ArgOnStack;
827 ainfo->reg = mips_sp; /* in the caller */
828 ainfo->offset = info->stack_size;
831 ainfo->storage = ArgInIReg;
832 ainfo->reg = info->gr;
834 info->gr_passed = TRUE;
836 info->stack_size += 4;
840 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
841 /* First, see if we need to drop onto the stack */
842 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
843 args_onto_stack (info);
845 /* Now, place the argument */
846 if (info->on_stack) {
847 g_assert (info->stack_size % 4 == 0);
848 info->stack_size += (info->stack_size % 8);
850 ainfo->storage = ArgOnStack;
851 ainfo->reg = mips_sp; /* in the caller */
852 ainfo->offset = info->stack_size;
855 // info->gr must be a0 or a2
856 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
857 g_assert(info->gr <= MIPS_LAST_ARG_REG);
859 ainfo->storage = ArgInIReg;
860 ainfo->reg = info->gr;
862 info->gr_passed = TRUE;
864 info->stack_size += 8;
868 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
869 /* First, see if we need to drop onto the stack */
870 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
871 args_onto_stack (info);
873 /* Now, place the argument */
874 if (info->on_stack) {
875 ainfo->storage = ArgOnStack;
876 ainfo->reg = mips_sp; /* in the caller */
877 ainfo->offset = info->stack_size;
880 /* Only use FP regs for args if no int args passed yet */
881 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
882 ainfo->storage = ArgInFReg;
883 ainfo->reg = info->fr;
884 /* Even though it's a single-precision float, it takes up two FP regs */
886 /* FP and GP slots do not overlap */
890 /* Passing single-precision float arg in a GP register
891 * such as: func (0, 1.0, 2, 3);
892 * In this case, only one 'gr' register is consumed.
894 ainfo->storage = ArgInIReg;
895 ainfo->reg = info->gr;
898 info->gr_passed = TRUE;
901 info->stack_size += 4;
905 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
906 /* First, see if we need to drop onto the stack */
907 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
908 args_onto_stack (info);
910 /* Now, place the argument */
911 if (info->on_stack) {
912 g_assert(info->stack_size % 4 == 0);
913 info->stack_size += (info->stack_size % 8);
915 ainfo->storage = ArgOnStack;
916 ainfo->reg = mips_sp; /* in the caller */
917 ainfo->offset = info->stack_size;
920 /* Only use FP regs for args if no int args passed yet */
921 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
922 ainfo->storage = ArgInFReg;
923 ainfo->reg = info->fr;
925 /* FP and GP slots do not overlap */
929 // info->gr must be a0 or a2
930 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
931 g_assert(info->gr <= MIPS_LAST_ARG_REG);
933 ainfo->storage = ArgInIReg;
934 ainfo->reg = info->gr;
936 info->gr_passed = TRUE;
939 info->stack_size += 8;
941 #elif _MIPS_SIM == _ABIN32
943 * N32 calling convention version
947 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
948 /* First, see if we need to drop onto the stack */
949 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
950 args_onto_stack (info);
952 /* Now, place the argument */
953 if (info->on_stack) {
954 ainfo->storage = ArgOnStack;
955 ainfo->reg = mips_sp; /* in the caller */
956 ainfo->offset = info->stack_size;
957 info->stack_size += SIZEOF_REGISTER;
960 ainfo->storage = ArgInIReg;
961 ainfo->reg = info->gr;
963 info->gr_passed = TRUE;
968 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
969 /* First, see if we need to drop onto the stack */
970 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
971 args_onto_stack (info);
973 /* Now, place the argument */
974 if (info->on_stack) {
975 g_assert (info->stack_size % 4 == 0);
976 info->stack_size += (info->stack_size % 8);
978 ainfo->storage = ArgOnStack;
979 ainfo->reg = mips_sp; /* in the caller */
980 ainfo->offset = info->stack_size;
981 info->stack_size += SIZEOF_REGISTER;
984 g_assert (info->gr <= MIPS_LAST_ARG_REG);
986 ainfo->storage = ArgInIReg;
987 ainfo->reg = info->gr;
989 info->gr_passed = TRUE;
994 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
995 /* First, see if we need to drop onto the stack */
996 if (!info->on_stack) {
997 if (info->gr > MIPS_LAST_ARG_REG)
998 args_onto_stack (info);
999 else if (info->fr > MIPS_LAST_FPARG_REG)
1000 args_onto_stack (info);
1003 /* Now, place the argument */
1004 if (info->on_stack) {
1005 ainfo->storage = ArgOnStack;
1006 ainfo->reg = mips_sp; /* in the caller */
1007 ainfo->offset = info->stack_size;
1008 info->stack_size += FREG_SIZE;
1011 ainfo->storage = ArgInFReg;
1012 ainfo->reg = info->fr;
1014 /* FP and GP slots do not overlap */
1020 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
1021 /* First, see if we need to drop onto the stack */
1022 if (!info->on_stack) {
1023 if (info->gr > MIPS_LAST_ARG_REG)
1024 args_onto_stack (info);
1025 else if (info->fr > MIPS_LAST_FPARG_REG)
1026 args_onto_stack (info);
1029 /* Now, place the argument */
1030 if (info->on_stack) {
1031 g_assert(info->stack_size % 4 == 0);
1032 info->stack_size += (info->stack_size % 8);
1034 ainfo->storage = ArgOnStack;
1035 ainfo->reg = mips_sp; /* in the caller */
1036 ainfo->offset = info->stack_size;
1037 info->stack_size += FREG_SIZE;
1040 ainfo->storage = ArgInFReg;
1041 ainfo->reg = info->fr;
1043 /* FP and GP slots do not overlap */
1050 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
1053 int n = sig->hasthis + sig->param_count;
1055 MonoType* simpletype;
1057 gboolean is_pinvoke = sig->pinvoke;
1060 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1062 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1064 cinfo->fr = MIPS_FIRST_FPARG_REG;
1065 cinfo->gr = MIPS_FIRST_ARG_REG;
1066 cinfo->stack_size = 0;
1068 DEBUG(printf("calculate_sizes\n"));
1070 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
1074 /* handle returning a struct */
1075 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1076 cinfo->struct_ret = cinfo->gr;
1077 add_int32_arg (cinfo, &cinfo->ret);
1081 add_int32_arg (cinfo, cinfo->args + n);
1086 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1087 * the first argument, allowing 'this' to be always passed in the first arg reg.
1088 * Also do this if the first argument is a reference type, since virtual calls
1089 * are sometimes made using calli without sig->hasthis set, like in the delegate
1092 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1094 add_int32_arg (cinfo, cinfo->args + n);
1097 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
1101 add_int32_arg (cinfo, &cinfo->ret);
1102 cinfo->struct_ret = cinfo->ret.reg;
1106 add_int32_arg (cinfo, cinfo->args + n);
1110 if (cinfo->vtype_retaddr) {
1111 add_int32_arg (cinfo, &cinfo->ret);
1112 cinfo->struct_ret = cinfo->ret.reg;
1117 DEBUG(printf("params: %d\n", sig->param_count));
1118 for (i = pstart; i < sig->param_count; ++i) {
1119 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1120 /* Prevent implicit arguments and sig_cookie from
1121 being passed in registers */
1122 args_onto_stack (cinfo);
1123 /* Emit the signature cookie just before the implicit arguments */
1124 add_int32_arg (cinfo, &cinfo->sig_cookie);
1126 DEBUG(printf("param %d: ", i));
1127 simpletype = mini_type_get_underlying_type (gsctx, sig->params [i]);
1128 switch (simpletype->type) {
1129 case MONO_TYPE_BOOLEAN:
1132 DEBUG(printf("1 byte\n"));
1133 cinfo->args [n].size = 1;
1134 add_int32_arg (cinfo, &cinfo->args[n]);
1137 case MONO_TYPE_CHAR:
1140 DEBUG(printf("2 bytes\n"));
1141 cinfo->args [n].size = 2;
1142 add_int32_arg (cinfo, &cinfo->args[n]);
1147 DEBUG(printf("4 bytes\n"));
1148 cinfo->args [n].size = 4;
1149 add_int32_arg (cinfo, &cinfo->args[n]);
1155 case MONO_TYPE_FNPTR:
1156 case MONO_TYPE_CLASS:
1157 case MONO_TYPE_OBJECT:
1158 case MONO_TYPE_STRING:
1159 case MONO_TYPE_SZARRAY:
1160 case MONO_TYPE_ARRAY:
1161 cinfo->args [n].size = sizeof (gpointer);
1162 add_int32_arg (cinfo, &cinfo->args[n]);
1165 case MONO_TYPE_GENERICINST:
1166 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1167 cinfo->args [n].size = sizeof (gpointer);
1168 add_int32_arg (cinfo, &cinfo->args[n]);
1173 case MONO_TYPE_TYPEDBYREF:
1174 case MONO_TYPE_VALUETYPE: {
1177 int has_offset = FALSE;
1179 gint size, alignment;
1182 if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
1183 size = sizeof (MonoTypedRef);
1184 alignment = sizeof (gpointer);
1186 klass = mono_class_from_mono_type (sig->params [i]);
1188 size = mono_class_native_size (klass, NULL);
1190 size = mono_class_value_size (klass, NULL);
1191 alignment = mono_class_min_align (klass);
1193 #if MIPS_PASS_STRUCTS_BY_VALUE
1194 /* Need to do alignment if struct contains long or double */
1195 if (alignment > 4) {
1196 /* Drop onto stack *before* looking at
1197 stack_size, if required. */
1198 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1199 args_onto_stack (cinfo);
1200 if (cinfo->stack_size & (alignment - 1)) {
1201 add_int32_arg (cinfo, &dummy_arg);
1203 g_assert (!(cinfo->stack_size & (alignment - 1)));
1207 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1208 mono_class_native_size (sig->params [i]->data.klass, NULL),
1209 cinfo->stack_size, alignment);
1211 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1212 g_assert (cinfo->args [n].size == 0);
1213 g_assert (cinfo->args [n].vtsize == 0);
1214 for (j = 0; j < nwords; ++j) {
1216 add_int32_arg (cinfo, &cinfo->args [n]);
1217 if (cinfo->on_stack)
1220 add_int32_arg (cinfo, &dummy_arg);
1221 if (!has_offset && cinfo->on_stack) {
1222 cinfo->args [n].offset = dummy_arg.offset;
1226 if (cinfo->on_stack)
1227 cinfo->args [n].vtsize += 1;
1229 cinfo->args [n].size += 1;
1231 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1232 cinfo->args [n].storage = ArgStructByVal;
1234 add_int32_arg (cinfo, &cinfo->args[n]);
1235 cinfo->args [n].storage = ArgStructByAddr;
1242 DEBUG(printf("8 bytes\n"));
1243 cinfo->args [n].size = 8;
1244 add_int64_arg (cinfo, &cinfo->args[n]);
1248 DEBUG(printf("R4\n"));
1249 cinfo->args [n].size = 4;
1250 add_float32_arg (cinfo, &cinfo->args[n]);
1254 DEBUG(printf("R8\n"));
1255 cinfo->args [n].size = 8;
1256 add_float64_arg (cinfo, &cinfo->args[n]);
1260 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1264 /* Handle the case where there are no implicit arguments */
1265 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1266 /* Prevent implicit arguments and sig_cookie from
1267 being passed in registers */
1268 args_onto_stack (cinfo);
1269 /* Emit the signature cookie just before the implicit arguments */
1270 add_int32_arg (cinfo, &cinfo->sig_cookie);
1274 simpletype = mini_type_get_underlying_type (gsctx, sig->ret);
1275 switch (simpletype->type) {
1276 case MONO_TYPE_BOOLEAN:
1281 case MONO_TYPE_CHAR:
1287 case MONO_TYPE_FNPTR:
1288 case MONO_TYPE_CLASS:
1289 case MONO_TYPE_OBJECT:
1290 case MONO_TYPE_SZARRAY:
1291 case MONO_TYPE_ARRAY:
1292 case MONO_TYPE_STRING:
1293 cinfo->ret.reg = mips_v0;
1297 cinfo->ret.reg = mips_v0;
1301 cinfo->ret.reg = mips_f0;
1302 cinfo->ret.storage = ArgInFReg;
1304 case MONO_TYPE_GENERICINST:
1305 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1306 cinfo->ret.reg = mips_v0;
1310 case MONO_TYPE_VALUETYPE:
1311 case MONO_TYPE_TYPEDBYREF:
1313 case MONO_TYPE_VOID:
1316 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1320 /* align stack size to 16 */
1321 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1323 cinfo->stack_usage = cinfo->stack_size;
1328 debug_omit_fp (void)
1331 return mono_debug_count ();
1338 * mono_arch_compute_omit_fp:
1340 * Determine whenever the frame pointer can be eliminated.
1343 mono_arch_compute_omit_fp (MonoCompile *cfg)
1345 MonoMethodSignature *sig;
1346 MonoMethodHeader *header;
1350 if (cfg->arch.omit_fp_computed)
1353 header = cfg->header;
1355 sig = mono_method_signature (cfg->method);
1357 if (!cfg->arch.cinfo)
1358 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1359 cinfo = cfg->arch.cinfo;
1362 * FIXME: Remove some of the restrictions.
1364 cfg->arch.omit_fp = TRUE;
1365 cfg->arch.omit_fp_computed = TRUE;
1367 if (cfg->disable_omit_fp)
1368 cfg->arch.omit_fp = FALSE;
1369 if (!debug_omit_fp ())
1370 cfg->arch.omit_fp = FALSE;
1371 if (cfg->method->save_lmf)
1372 cfg->arch.omit_fp = FALSE;
1373 if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1374 cfg->arch.omit_fp = FALSE;
1375 if (header->num_clauses)
1376 cfg->arch.omit_fp = FALSE;
1377 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1378 cfg->arch.omit_fp = FALSE;
1379 if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1380 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1381 cfg->arch.omit_fp = FALSE;
1383 * On MIPS, fp points to the bottom of the frame, so it can be eliminated even if
1384 * there are stack arguments.
1387 if (cinfo->stack_usage)
1388 cfg->arch.omit_fp = FALSE;
1392 for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1393 MonoInst *ins = cfg->varinfo [i];
1396 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1399 //printf ("D: %s %d\n", cfg->method->name, cfg->arch.omit_fp);
1403 * Set var information according to the calling convention. mips version.
1404 * The locals var stuff should most likely be split in another method.
1407 mono_arch_allocate_vars (MonoCompile *cfg)
1409 MonoMethodSignature *sig;
1410 MonoMethodHeader *header;
1412 int i, offset, size, align, curinst;
1413 int frame_reg = mips_sp;
1414 guint32 iregs_to_save = 0;
1416 guint32 fregs_to_restore;
1420 sig = mono_method_signature (cfg->method);
1422 if (!cfg->arch.cinfo)
1423 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1424 cinfo = cfg->arch.cinfo;
1426 mono_arch_compute_omit_fp (cfg);
1428 /* spill down, we'll fix it in a separate pass */
1429 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1431 /* allow room for the vararg method args: void* and long/double */
1432 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1433 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1435 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1436 * call convs needs to be handled this way.
1438 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1439 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1441 /* gtk-sharp and other broken code will dllimport vararg functions even with
1442 * non-varargs signatures. Since there is little hope people will get this right
1443 * we assume they won't.
1445 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1446 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1448 /* a0-a3 always present */
1449 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1451 header = cfg->header;
1453 if (cfg->arch.omit_fp)
1454 frame_reg = mips_sp;
1456 frame_reg = mips_fp;
1457 cfg->frame_reg = frame_reg;
1458 if (frame_reg != mips_sp) {
1459 cfg->used_int_regs |= 1 << frame_reg;
1464 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1465 /* FIXME: handle long and FP values */
1466 switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
1467 case MONO_TYPE_VOID:
1471 cfg->ret->opcode = OP_REGVAR;
1472 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1475 cfg->ret->opcode = OP_REGVAR;
1476 cfg->ret->inst_c0 = mips_v0;
1480 /* Space for outgoing parameters, including a0-a3 */
1481 offset += cfg->param_area;
1483 /* allow room to save the return value (if it's a struct) */
1484 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1487 /* Now handle the local variables */
1489 curinst = cfg->locals_start;
1490 for (i = curinst; i < cfg->num_varinfo; ++i) {
1491 inst = cfg->varinfo [i];
1492 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1495 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1496 * pinvoke wrappers when they call functions returning structure
1498 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1499 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1501 size = mono_type_size (inst->inst_vtype, &align);
1503 offset += align - 1;
1504 offset &= ~(align - 1);
1505 inst->inst_offset = offset;
1506 inst->opcode = OP_REGOFFSET;
1507 inst->inst_basereg = frame_reg;
1509 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1512 /* Space for LMF (if needed) */
1513 if (cfg->method->save_lmf) {
1514 /* align the offset to 16 bytes */
1515 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1516 cfg->arch.lmf_offset = offset;
1517 offset += sizeof (MonoLMF);
1520 if (sig->call_convention == MONO_CALL_VARARG) {
1524 /* Allocate a local slot to hold the sig cookie address */
1525 offset += align - 1;
1526 offset &= ~(align - 1);
1527 cfg->sig_cookie = offset;
1531 offset += SIZEOF_REGISTER - 1;
1532 offset &= ~(SIZEOF_REGISTER - 1);
1534 /* Space for saved registers */
1535 cfg->arch.iregs_offset = offset;
1536 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1537 if (iregs_to_save) {
1538 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1539 if (iregs_to_save & (1 << i)) {
1540 offset += SIZEOF_REGISTER;
1545 /* saved float registers */
1547 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1548 if (fregs_to_restore) {
1549 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1550 if (fregs_to_restore & (1 << i)) {
1551 offset += sizeof(double);
1557 #if _MIPS_SIM == _ABIO32
1558 /* Now add space for saving the ra */
1559 offset += SIZEOF_VOID_P;
1562 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1563 cfg->stack_offset = offset;
1564 cfg->arch.local_alloc_offset = cfg->stack_offset;
1568 * Now allocate stack slots for the int arg regs (a0 - a3)
1569 * On MIPS o32, these are just above the incoming stack pointer
1570 * Even if the arg has been assigned to a regvar, it gets a stack slot
1573 /* Return struct-by-value results in a hidden first argument */
1574 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1575 cfg->vret_addr->opcode = OP_REGOFFSET;
1576 cfg->vret_addr->inst_c0 = mips_a0;
1577 cfg->vret_addr->inst_offset = offset;
1578 cfg->vret_addr->inst_basereg = frame_reg;
1579 offset += SIZEOF_REGISTER;
1582 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1583 inst = cfg->args [i];
1584 if (inst->opcode != OP_REGVAR) {
1587 if (sig->hasthis && (i == 0))
1588 arg_type = &mono_defaults.object_class->byval_arg;
1590 arg_type = sig->params [i - sig->hasthis];
1592 inst->opcode = OP_REGOFFSET;
1593 size = mono_type_size (arg_type, &align);
1595 if (size < SIZEOF_REGISTER) {
1596 size = SIZEOF_REGISTER;
1597 align = SIZEOF_REGISTER;
1599 inst->inst_basereg = frame_reg;
1600 offset = (offset + align - 1) & ~(align - 1);
1601 inst->inst_offset = offset;
1603 if (cfg->verbose_level > 1)
1604 printf ("allocating param %d to fp[%d]\n", i, inst->inst_offset);
1607 #if _MIPS_SIM == _ABIO32
1608 /* o32: Even a0-a3 get stack slots */
1609 size = SIZEOF_REGISTER;
1610 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);
1620 #if _MIPS_SIM == _ABIN32
1621 /* Now add space for saving the ra */
1622 offset += SIZEOF_VOID_P;
1625 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1626 cfg->stack_offset = offset;
1627 cfg->arch.local_alloc_offset = cfg->stack_offset;
1632 mono_arch_create_vars (MonoCompile *cfg)
1634 MonoMethodSignature *sig;
1636 sig = mono_method_signature (cfg->method);
1638 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1639 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1640 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1641 printf ("vret_addr = ");
1642 mono_print_ins (cfg->vret_addr);
1647 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1648 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1652 * take the arguments and generate the arch-specific
1653 * instructions to properly call the function in call.
1654 * This includes pushing, moving arguments to the right register
1656 * Issue: who does the spilling if needed, and when?
1659 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1661 MonoMethodSignature *tmp_sig;
1664 if (call->tail_call)
1667 /* FIXME: Add support for signature tokens to AOT */
1668 cfg->disable_aot = TRUE;
1671 * mono_ArgIterator_Setup assumes the signature cookie is
1672 * passed first and all the arguments which were before it are
1673 * passed on the stack after the signature. So compensate by
1674 * passing a different signature.
1676 tmp_sig = mono_metadata_signature_dup (call->signature);
1677 tmp_sig->param_count -= call->signature->sentinelpos;
1678 tmp_sig->sentinelpos = 0;
1679 memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1681 MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1682 sig_arg->dreg = mono_alloc_ireg (cfg);
1683 sig_arg->inst_p0 = tmp_sig;
1684 MONO_ADD_INS (cfg->cbb, sig_arg);
1686 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, cinfo->sig_cookie.offset, sig_arg->dreg);
1690 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1693 MonoMethodSignature *sig;
1698 sig = call->signature;
1699 n = sig->param_count + sig->hasthis;
1701 cinfo = get_call_info (NULL, cfg->mempool, sig);
1702 if (cinfo->struct_ret)
1703 call->used_iregs |= 1 << cinfo->struct_ret;
1705 for (i = 0; i < n; ++i) {
1706 ArgInfo *ainfo = cinfo->args + i;
1709 if (i >= sig->hasthis)
1710 t = sig->params [i - sig->hasthis];
1712 t = &mono_defaults.int_class->byval_arg;
1713 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1715 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1716 /* Emit the signature cookie just before the implicit arguments */
1717 emit_sig_cookie (cfg, call, cinfo);
1720 if (is_virtual && i == 0) {
1721 /* the argument will be attached to the call instrucion */
1722 in = call->args [i];
1723 call->used_iregs |= 1 << ainfo->reg;
1726 in = call->args [i];
1727 if (ainfo->storage == ArgInIReg) {
1728 #if SIZEOF_REGISTER == 4
1729 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1730 MONO_INST_NEW (cfg, ins, OP_MOVE);
1731 ins->dreg = mono_alloc_ireg (cfg);
1732 ins->sreg1 = in->dreg + 1;
1733 MONO_ADD_INS (cfg->cbb, ins);
1734 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1736 MONO_INST_NEW (cfg, ins, OP_MOVE);
1737 ins->dreg = mono_alloc_ireg (cfg);
1738 ins->sreg1 = in->dreg + 2;
1739 MONO_ADD_INS (cfg->cbb, ins);
1740 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1743 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1746 #if PROMOTE_R4_TO_R8
1747 /* ??? - convert to single first? */
1748 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1749 ins->dreg = mono_alloc_freg (cfg);
1750 ins->sreg1 = in->dreg;
1751 MONO_ADD_INS (cfg->cbb, ins);
1756 /* trying to load float value into int registers */
1757 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1758 ins->dreg = mono_alloc_ireg (cfg);
1760 MONO_ADD_INS (cfg->cbb, ins);
1761 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1762 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1763 /* trying to load float value into int registers */
1764 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1765 ins->dreg = mono_alloc_ireg (cfg);
1766 ins->sreg1 = in->dreg;
1767 MONO_ADD_INS (cfg->cbb, ins);
1768 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1770 MONO_INST_NEW (cfg, ins, OP_MOVE);
1771 ins->dreg = mono_alloc_ireg (cfg);
1772 ins->sreg1 = in->dreg;
1773 MONO_ADD_INS (cfg->cbb, ins);
1774 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1776 } else if (ainfo->storage == ArgStructByAddr) {
1777 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1778 ins->opcode = OP_OUTARG_VT;
1779 ins->sreg1 = in->dreg;
1780 ins->klass = in->klass;
1781 ins->inst_p0 = call;
1782 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1783 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1784 MONO_ADD_INS (cfg->cbb, ins);
1785 } else if (ainfo->storage == ArgStructByVal) {
1786 /* this is further handled in mono_arch_emit_outarg_vt () */
1787 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1788 ins->opcode = OP_OUTARG_VT;
1789 ins->sreg1 = in->dreg;
1790 ins->klass = in->klass;
1791 ins->inst_p0 = call;
1792 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1793 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1794 MONO_ADD_INS (cfg->cbb, ins);
1795 } else if (ainfo->storage == ArgOnStack) {
1796 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1797 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1798 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1799 if (t->type == MONO_TYPE_R8)
1800 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1802 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1804 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1806 } else if (ainfo->storage == ArgInFReg) {
1807 if (t->type == MONO_TYPE_VALUETYPE) {
1808 /* this is further handled in mono_arch_emit_outarg_vt () */
1809 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1810 ins->opcode = OP_OUTARG_VT;
1811 ins->sreg1 = in->dreg;
1812 ins->klass = in->klass;
1813 ins->inst_p0 = call;
1814 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1815 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1816 MONO_ADD_INS (cfg->cbb, ins);
1818 cfg->flags |= MONO_CFG_HAS_FPOUT;
1820 int dreg = mono_alloc_freg (cfg);
1822 if (ainfo->size == 4) {
1823 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1825 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1827 ins->sreg1 = in->dreg;
1828 MONO_ADD_INS (cfg->cbb, ins);
1831 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1832 cfg->flags |= MONO_CFG_HAS_FPOUT;
1835 g_assert_not_reached ();
1839 /* Handle the case where there are no implicit arguments */
1840 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1841 emit_sig_cookie (cfg, call, cinfo);
1843 if (cinfo->struct_ret) {
1846 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1847 vtarg->sreg1 = call->vret_var->dreg;
1848 vtarg->dreg = mono_alloc_preg (cfg);
1849 MONO_ADD_INS (cfg->cbb, vtarg);
1851 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1855 * Reverse the call->out_args list.
1858 MonoInst *prev = NULL, *list = call->out_args, *next;
1865 call->out_args = prev;
1868 call->stack_usage = cinfo->stack_usage;
1869 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1870 #if _MIPS_SIM == _ABIO32
1871 /* a0-a3 always present */
1872 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1874 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1875 cfg->flags |= MONO_CFG_HAS_CALLS;
1877 * should set more info in call, such as the stack space
1878 * used by the args that needs to be added back to esp
1883 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1885 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1886 ArgInfo *ainfo = ins->inst_p1;
1887 int ovf_size = ainfo->vtsize;
1888 int doffset = ainfo->offset;
1889 int i, soffset, dreg;
1891 if (ainfo->storage == ArgStructByVal) {
1893 if (cfg->verbose_level > 0) {
1894 char* nm = mono_method_full_name (cfg->method, TRUE);
1895 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1896 nm, doffset, ainfo->size, ovf_size);
1902 for (i = 0; i < ainfo->size; ++i) {
1903 dreg = mono_alloc_ireg (cfg);
1904 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1905 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1906 soffset += SIZEOF_REGISTER;
1908 if (ovf_size != 0) {
1909 mini_emit_memcpy (cfg, mips_sp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1911 } else if (ainfo->storage == ArgInFReg) {
1912 int tmpr = mono_alloc_freg (cfg);
1914 if (ainfo->size == 4)
1915 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1917 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1918 dreg = mono_alloc_freg (cfg);
1919 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1920 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1922 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1926 /* FIXME: alignment? */
1927 if (call->signature->pinvoke) {
1928 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1929 vtcopy->backend.is_pinvoke = 1;
1931 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1934 g_assert (ovf_size > 0);
1936 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1937 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1940 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1942 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1947 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1949 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1950 mono_method_signature (method)->ret);
1953 #if (SIZEOF_REGISTER == 4)
1954 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1957 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1958 ins->sreg1 = val->dreg + 1;
1959 ins->sreg2 = val->dreg + 2;
1960 MONO_ADD_INS (cfg->cbb, ins);
1964 if (ret->type == MONO_TYPE_R8) {
1965 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1968 if (ret->type == MONO_TYPE_R4) {
1969 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1973 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1977 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1979 MonoInst *ins, *n, *last_ins = NULL;
1981 if (cfg->verbose_level > 2)
1982 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1985 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1986 if (cfg->verbose_level > 2)
1987 mono_print_ins_index (0, ins);
1989 switch (ins->opcode) {
1991 case OP_LOAD_MEMBASE:
1992 case OP_LOADI4_MEMBASE:
1994 * OP_IADD reg2, reg1, const1
1995 * OP_LOAD_MEMBASE const2(reg2), reg3
1997 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1999 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)){
2000 int const1 = last_ins->inst_imm;
2001 int const2 = ins->inst_offset;
2003 if (mips_is_imm16 (const1 + const2)) {
2004 ins->inst_basereg = last_ins->sreg1;
2005 ins->inst_offset = const1 + const2;
2015 bb->last_ins = last_ins;
2019 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2021 MonoInst *ins, *n, *last_ins = NULL;
2024 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2025 MonoInst *last_ins = ins->prev;
2027 switch (ins->opcode) {
2029 /* remove unnecessary multiplication with 1 */
2030 if (ins->inst_imm == 1) {
2031 if (ins->dreg != ins->sreg1) {
2032 ins->opcode = OP_MOVE;
2034 MONO_DELETE_INS (bb, ins);
2038 int power2 = mono_is_power_of_two (ins->inst_imm);
2040 ins->opcode = OP_SHL_IMM;
2041 ins->inst_imm = power2;
2045 case OP_LOAD_MEMBASE:
2046 case OP_LOADI4_MEMBASE:
2048 * OP_STORE_MEMBASE_REG reg, offset(basereg)
2049 * OP_LOAD_MEMBASE offset(basereg), reg
2051 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
2052 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2053 ins->inst_basereg == last_ins->inst_destbasereg &&
2054 ins->inst_offset == last_ins->inst_offset) {
2055 if (ins->dreg == last_ins->sreg1) {
2056 MONO_DELETE_INS (bb, ins);
2059 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2060 ins->opcode = OP_MOVE;
2061 ins->sreg1 = last_ins->sreg1;
2066 * Note: reg1 must be different from the basereg in the second load
2067 * OP_LOAD_MEMBASE offset(basereg), reg1
2068 * OP_LOAD_MEMBASE offset(basereg), reg2
2070 * OP_LOAD_MEMBASE offset(basereg), reg1
2071 * OP_MOVE reg1, reg2
2073 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2074 || last_ins->opcode == OP_LOAD_MEMBASE) &&
2075 ins->inst_basereg != last_ins->dreg &&
2076 ins->inst_basereg == last_ins->inst_basereg &&
2077 ins->inst_offset == last_ins->inst_offset) {
2079 if (ins->dreg == last_ins->dreg) {
2080 MONO_DELETE_INS (bb, ins);
2083 ins->opcode = OP_MOVE;
2084 ins->sreg1 = last_ins->dreg;
2087 //g_assert_not_reached ();
2092 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2093 * OP_LOAD_MEMBASE offset(basereg), reg
2095 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
2096 * OP_ICONST reg, imm
2098 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2099 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2100 ins->inst_basereg == last_ins->inst_destbasereg &&
2101 ins->inst_offset == last_ins->inst_offset) {
2102 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2103 ins->opcode = OP_ICONST;
2104 ins->inst_c0 = last_ins->inst_imm;
2105 g_assert_not_reached (); // check this rule
2110 case OP_LOADU1_MEMBASE:
2111 case OP_LOADI1_MEMBASE:
2112 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2113 ins->inst_basereg == last_ins->inst_destbasereg &&
2114 ins->inst_offset == last_ins->inst_offset) {
2115 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2116 ins->sreg1 = last_ins->sreg1;
2119 case OP_LOADU2_MEMBASE:
2120 case OP_LOADI2_MEMBASE:
2121 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2122 ins->inst_basereg == last_ins->inst_destbasereg &&
2123 ins->inst_offset == last_ins->inst_offset) {
2124 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2125 ins->sreg1 = last_ins->sreg1;
2128 case OP_ICONV_TO_I4:
2129 case OP_ICONV_TO_U4:
2131 ins->opcode = OP_MOVE;
2135 if (ins->dreg == ins->sreg1) {
2136 MONO_DELETE_INS (bb, ins);
2140 * OP_MOVE sreg, dreg
2141 * OP_MOVE dreg, sreg
2143 if (last_ins && last_ins->opcode == OP_MOVE &&
2144 ins->sreg1 == last_ins->dreg &&
2145 ins->dreg == last_ins->sreg1) {
2146 MONO_DELETE_INS (bb, ins);
2154 bb->last_ins = last_ins;
2158 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
2166 switch (ins->opcode) {
2169 case OP_LCOMPARE_IMM:
2170 mono_print_ins (ins);
2171 g_assert_not_reached ();
2174 tmp1 = mono_alloc_ireg (cfg);
2175 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2176 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2177 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2178 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2183 tmp1 = mono_alloc_ireg (cfg);
2184 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2185 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2186 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2187 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2192 tmp1 = mono_alloc_ireg (cfg);
2193 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2194 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2195 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2196 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2201 tmp1 = mono_alloc_ireg (cfg);
2202 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2203 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2204 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2205 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2217 mono_print_ins (ins);
2218 g_assert_not_reached ();
2221 tmp1 = mono_alloc_ireg (cfg);
2222 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2223 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2224 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2225 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2233 case OP_LCONV_TO_I1:
2234 case OP_LCONV_TO_I2:
2235 case OP_LCONV_TO_I4:
2236 case OP_LCONV_TO_I8:
2237 case OP_LCONV_TO_R4:
2238 case OP_LCONV_TO_R8:
2239 case OP_LCONV_TO_U4:
2240 case OP_LCONV_TO_U8:
2241 case OP_LCONV_TO_U2:
2242 case OP_LCONV_TO_U1:
2244 case OP_LCONV_TO_OVF_I:
2245 case OP_LCONV_TO_OVF_U:
2247 mono_print_ins (ins);
2248 g_assert_not_reached ();
2251 tmp1 = mono_alloc_ireg (cfg);
2252 tmp2 = mono_alloc_ireg (cfg);
2253 tmp3 = mono_alloc_ireg (cfg);
2254 tmp4 = mono_alloc_ireg (cfg);
2255 tmp5 = mono_alloc_ireg (cfg);
2257 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2259 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2260 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2262 /* add the high 32-bits, and add in the carry from the low 32-bits */
2263 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2264 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2266 /* Overflow happens if
2267 * neg + neg = pos or
2269 * XOR of the high bits returns 0 if the signs match
2270 * XOR of that with the high bit of the result return 1 if overflow.
2273 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2274 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2276 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2277 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2278 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2280 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2281 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2282 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2284 /* Now, if (tmp4 == 0) then overflow */
2285 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2289 case OP_LADD_OVF_UN:
2290 tmp1 = mono_alloc_ireg (cfg);
2291 tmp2 = mono_alloc_ireg (cfg);
2293 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2294 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2295 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2296 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2297 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2298 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2303 case OP_LMUL_OVF_UN:
2304 mono_print_ins (ins);
2305 g_assert_not_reached ();
2308 tmp1 = mono_alloc_ireg (cfg);
2309 tmp2 = mono_alloc_ireg (cfg);
2310 tmp3 = mono_alloc_ireg (cfg);
2311 tmp4 = mono_alloc_ireg (cfg);
2312 tmp5 = mono_alloc_ireg (cfg);
2314 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2316 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2317 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2318 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2320 /* Overflow happens if
2321 * neg - pos = pos or
2323 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2325 * tmp1 = (lhs ^ rhs)
2326 * tmp2 = (lhs ^ result)
2327 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2330 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2331 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2332 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2333 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2335 /* Now, if (tmp4 == 1) then overflow */
2336 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2340 case OP_LSUB_OVF_UN:
2341 tmp1 = mono_alloc_ireg (cfg);
2342 tmp2 = mono_alloc_ireg (cfg);
2344 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2345 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2346 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2347 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2349 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2350 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2354 case OP_LCONV_TO_OVF_I1_UN:
2355 case OP_LCONV_TO_OVF_I2_UN:
2356 case OP_LCONV_TO_OVF_I4_UN:
2357 case OP_LCONV_TO_OVF_I8_UN:
2358 case OP_LCONV_TO_OVF_U1_UN:
2359 case OP_LCONV_TO_OVF_U2_UN:
2360 case OP_LCONV_TO_OVF_U4_UN:
2361 case OP_LCONV_TO_OVF_U8_UN:
2362 case OP_LCONV_TO_OVF_I_UN:
2363 case OP_LCONV_TO_OVF_U_UN:
2364 case OP_LCONV_TO_OVF_I1:
2365 case OP_LCONV_TO_OVF_U1:
2366 case OP_LCONV_TO_OVF_I2:
2367 case OP_LCONV_TO_OVF_U2:
2368 case OP_LCONV_TO_OVF_I4:
2369 case OP_LCONV_TO_OVF_U4:
2370 case OP_LCONV_TO_OVF_I8:
2371 case OP_LCONV_TO_OVF_U8:
2379 case OP_LCONV_TO_R_UN:
2385 case OP_LSHR_UN_IMM:
2387 case OP_LDIV_UN_IMM:
2389 case OP_LREM_UN_IMM:
2400 mono_print_ins (ins);
2401 g_assert_not_reached ();
2403 case OP_LCONV_TO_R8_2:
2404 case OP_LCONV_TO_R4_2:
2405 case OP_LCONV_TO_R_UN_2:
2407 case OP_LCONV_TO_OVF_I4_2:
2408 tmp1 = mono_alloc_ireg (cfg);
2410 /* Overflows if reg2 != sign extension of reg1 */
2411 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2412 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2413 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2421 mono_print_ins (ins);
2422 g_assert_not_reached ();
2430 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2438 switch (ins->opcode) {
2440 tmp1 = mono_alloc_ireg (cfg);
2441 tmp2 = mono_alloc_ireg (cfg);
2442 tmp3 = mono_alloc_ireg (cfg);
2443 tmp4 = mono_alloc_ireg (cfg);
2444 tmp5 = mono_alloc_ireg (cfg);
2446 /* add the operands */
2448 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2450 /* Overflow happens if
2451 * neg + neg = pos or
2454 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2455 * XOR of the high bit returns 0 if the signs match
2456 * XOR of that with the high bit of the result return 1 if overflow.
2459 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2460 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2462 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2463 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2464 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2466 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2467 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2469 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2471 /* Now, if (tmp5 == 0) then overflow */
2472 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2473 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2474 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2478 case OP_IADD_OVF_UN:
2479 tmp1 = mono_alloc_ireg (cfg);
2481 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2482 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2483 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, 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);
2490 tmp1 = mono_alloc_ireg (cfg);
2491 tmp2 = mono_alloc_ireg (cfg);
2492 tmp3 = mono_alloc_ireg (cfg);
2493 tmp4 = mono_alloc_ireg (cfg);
2494 tmp5 = mono_alloc_ireg (cfg);
2496 /* add the operands */
2498 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2500 /* Overflow happens if
2501 * neg - pos = pos or
2503 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2505 * tmp1 = (lhs ^ rhs)
2506 * tmp2 = (lhs ^ result)
2507 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2510 /* tmp3 = 1 if the signs of the two inputs differ */
2511 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2512 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2513 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2514 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2515 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2517 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2518 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2519 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2523 case OP_ISUB_OVF_UN:
2524 tmp1 = mono_alloc_ireg (cfg);
2526 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2527 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2528 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, 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);
2537 map_to_reg_reg_op (int op)
2546 case OP_COMPARE_IMM:
2548 case OP_ICOMPARE_IMM:
2550 case OP_LCOMPARE_IMM:
2566 case OP_LOAD_MEMBASE:
2567 return OP_LOAD_MEMINDEX;
2568 case OP_LOADI4_MEMBASE:
2569 return OP_LOADI4_MEMINDEX;
2570 case OP_LOADU4_MEMBASE:
2571 return OP_LOADU4_MEMINDEX;
2572 case OP_LOADU1_MEMBASE:
2573 return OP_LOADU1_MEMINDEX;
2574 case OP_LOADI2_MEMBASE:
2575 return OP_LOADI2_MEMINDEX;
2576 case OP_LOADU2_MEMBASE:
2577 return OP_LOADU2_MEMINDEX;
2578 case OP_LOADI1_MEMBASE:
2579 return OP_LOADI1_MEMINDEX;
2580 case OP_LOADR4_MEMBASE:
2581 return OP_LOADR4_MEMINDEX;
2582 case OP_LOADR8_MEMBASE:
2583 return OP_LOADR8_MEMINDEX;
2584 case OP_STOREI1_MEMBASE_REG:
2585 return OP_STOREI1_MEMINDEX;
2586 case OP_STOREI2_MEMBASE_REG:
2587 return OP_STOREI2_MEMINDEX;
2588 case OP_STOREI4_MEMBASE_REG:
2589 return OP_STOREI4_MEMINDEX;
2590 case OP_STORE_MEMBASE_REG:
2591 return OP_STORE_MEMINDEX;
2592 case OP_STORER4_MEMBASE_REG:
2593 return OP_STORER4_MEMINDEX;
2594 case OP_STORER8_MEMBASE_REG:
2595 return OP_STORER8_MEMINDEX;
2596 case OP_STORE_MEMBASE_IMM:
2597 return OP_STORE_MEMBASE_REG;
2598 case OP_STOREI1_MEMBASE_IMM:
2599 return OP_STOREI1_MEMBASE_REG;
2600 case OP_STOREI2_MEMBASE_IMM:
2601 return OP_STOREI2_MEMBASE_REG;
2602 case OP_STOREI4_MEMBASE_IMM:
2603 return OP_STOREI4_MEMBASE_REG;
2604 case OP_STOREI8_MEMBASE_IMM:
2605 return OP_STOREI8_MEMBASE_REG;
2607 return mono_op_imm_to_op (op);
2611 map_to_mips_op (int op)
2615 return OP_MIPS_FBEQ;
2617 return OP_MIPS_FBGE;
2619 return OP_MIPS_FBGT;
2621 return OP_MIPS_FBLE;
2623 return OP_MIPS_FBLT;
2625 return OP_MIPS_FBNE;
2627 return OP_MIPS_FBGE_UN;
2629 return OP_MIPS_FBGT_UN;
2631 return OP_MIPS_FBLE_UN;
2633 return OP_MIPS_FBLT_UN;
2641 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2642 g_assert_not_reached ();
2646 #define NEW_INS(cfg,after,dest,op) do { \
2647 MONO_INST_NEW((cfg), (dest), (op)); \
2648 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2651 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2653 MONO_INST_NEW(cfg, temp, (op)); \
2654 mono_bblock_insert_after_ins (bb, (pos), temp); \
2655 temp->dreg = (_dreg); \
2656 temp->sreg1 = (_sreg1); \
2657 temp->sreg2 = (_sreg2); \
2661 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2663 MONO_INST_NEW(cfg, temp, (op)); \
2664 mono_bblock_insert_after_ins (bb, (pos), temp); \
2665 temp->dreg = (_dreg); \
2666 temp->sreg1 = (_sreg1); \
2667 temp->inst_c0 = (_imm); \
2672 * Remove from the instruction list the instructions that can't be
2673 * represented with very simple instructions with no register
2677 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2679 MonoInst *ins, *next, *temp, *last_ins = NULL;
2683 if (cfg->verbose_level > 2) {
2686 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2687 MONO_BB_FOR_EACH_INS (bb, ins) {
2688 mono_print_ins_index (idx++, ins);
2694 MONO_BB_FOR_EACH_INS (bb, ins) {
2696 switch (ins->opcode) {
2701 /* Branch opts can eliminate the branch */
2702 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2708 case OP_COMPARE_IMM:
2709 case OP_ICOMPARE_IMM:
2710 case OP_LCOMPARE_IMM:
2712 /* Branch opts can eliminate the branch */
2713 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2717 if (ins->inst_imm) {
2718 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2719 temp->inst_c0 = ins->inst_imm;
2720 temp->dreg = mono_alloc_ireg (cfg);
2721 ins->sreg2 = temp->dreg;
2725 ins->sreg2 = mips_zero;
2727 if (ins->opcode == OP_COMPARE_IMM)
2728 ins->opcode = OP_COMPARE;
2729 else if (ins->opcode == OP_ICOMPARE_IMM)
2730 ins->opcode = OP_ICOMPARE;
2731 else if (ins->opcode == OP_LCOMPARE_IMM)
2732 ins->opcode = OP_LCOMPARE;
2735 case OP_IDIV_UN_IMM:
2738 case OP_IREM_UN_IMM:
2739 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2740 temp->inst_c0 = ins->inst_imm;
2741 temp->dreg = mono_alloc_ireg (cfg);
2742 ins->sreg2 = temp->dreg;
2743 if (ins->opcode == OP_IDIV_IMM)
2744 ins->opcode = OP_IDIV;
2745 else if (ins->opcode == OP_IREM_IMM)
2746 ins->opcode = OP_IREM;
2747 else if (ins->opcode == OP_IDIV_UN_IMM)
2748 ins->opcode = OP_IDIV_UN;
2749 else if (ins->opcode == OP_IREM_UN_IMM)
2750 ins->opcode = OP_IREM_UN;
2752 /* handle rem separately */
2759 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2760 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2761 temp->inst_c0 = ins->inst_imm;
2762 temp->dreg = mono_alloc_ireg (cfg);
2763 ins->sreg2 = temp->dreg;
2764 ins->opcode = map_to_reg_reg_op (ins->opcode);
2774 /* unsigned 16 bit immediate */
2775 if (ins->inst_imm & 0xffff0000) {
2776 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2777 temp->inst_c0 = ins->inst_imm;
2778 temp->dreg = mono_alloc_ireg (cfg);
2779 ins->sreg2 = temp->dreg;
2780 ins->opcode = map_to_reg_reg_op (ins->opcode);
2787 /* signed 16 bit immediate */
2788 if (!mips_is_imm16 (ins->inst_imm)) {
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);
2799 if (!mips_is_imm16 (-ins->inst_imm)) {
2800 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2801 temp->inst_c0 = ins->inst_imm;
2802 temp->dreg = mono_alloc_ireg (cfg);
2803 ins->sreg2 = temp->dreg;
2804 ins->opcode = map_to_reg_reg_op (ins->opcode);
2810 if (ins->inst_imm == 1) {
2811 ins->opcode = OP_MOVE;
2814 if (ins->inst_imm == 0) {
2815 ins->opcode = OP_ICONST;
2819 imm = mono_is_power_of_two (ins->inst_imm);
2821 ins->opcode = OP_SHL_IMM;
2822 ins->inst_imm = imm;
2825 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2826 temp->inst_c0 = ins->inst_imm;
2827 temp->dreg = mono_alloc_ireg (cfg);
2828 ins->sreg2 = temp->dreg;
2829 ins->opcode = map_to_reg_reg_op (ins->opcode);
2832 case OP_LOCALLOC_IMM:
2833 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2834 temp->inst_c0 = ins->inst_imm;
2835 temp->dreg = mono_alloc_ireg (cfg);
2836 ins->sreg1 = temp->dreg;
2837 ins->opcode = OP_LOCALLOC;
2840 case OP_LOADR4_MEMBASE:
2841 case OP_STORER4_MEMBASE_REG:
2842 /* we can do two things: load the immed in a register
2843 * and use an indexed load, or see if the immed can be
2844 * represented as an ad_imm + a load with a smaller offset
2845 * that fits. We just do the first for now, optimize later.
2847 if (mips_is_imm16 (ins->inst_offset))
2849 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2850 temp->inst_c0 = ins->inst_offset;
2851 temp->dreg = mono_alloc_ireg (cfg);
2852 ins->sreg2 = temp->dreg;
2853 ins->opcode = map_to_reg_reg_op (ins->opcode);
2856 case OP_STORE_MEMBASE_IMM:
2857 case OP_STOREI1_MEMBASE_IMM:
2858 case OP_STOREI2_MEMBASE_IMM:
2859 case OP_STOREI4_MEMBASE_IMM:
2860 case OP_STOREI8_MEMBASE_IMM:
2861 if (!ins->inst_imm) {
2862 ins->sreg1 = mips_zero;
2863 ins->opcode = map_to_reg_reg_op (ins->opcode);
2866 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2867 temp->inst_c0 = ins->inst_imm;
2868 temp->dreg = mono_alloc_ireg (cfg);
2869 ins->sreg1 = temp->dreg;
2870 ins->opcode = map_to_reg_reg_op (ins->opcode);
2872 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2878 /* Branch opts can eliminate the branch */
2879 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2886 * remap compare/branch and compare/set
2887 * to MIPS specific opcodes.
2889 next->opcode = map_to_mips_op (next->opcode);
2890 next->sreg1 = ins->sreg1;
2891 next->sreg2 = ins->sreg2;
2898 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2899 temp->inst_c0 = (guint32)ins->inst_p0;
2900 temp->dreg = mono_alloc_ireg (cfg);
2901 ins->inst_basereg = temp->dreg;
2902 ins->inst_offset = 0;
2903 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2905 /* make it handle the possibly big ins->inst_offset
2906 * later optimize to use lis + load_membase
2911 g_assert (ins_is_compare(last_ins));
2912 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2913 NULLIFY_INS(last_ins);
2917 g_assert (ins_is_compare(last_ins));
2918 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2919 NULLIFY_INS(last_ins);
2923 g_assert (ins_is_compare(last_ins));
2924 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2925 last_ins->dreg = mono_alloc_ireg (cfg);
2926 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2930 g_assert (ins_is_compare(last_ins));
2931 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2932 last_ins->dreg = mono_alloc_ireg (cfg);
2933 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2937 g_assert (ins_is_compare(last_ins));
2938 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2939 last_ins->dreg = mono_alloc_ireg (cfg);
2940 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2944 g_assert (ins_is_compare(last_ins));
2945 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2946 last_ins->dreg = mono_alloc_ireg (cfg);
2947 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2951 g_assert (ins_is_compare(last_ins));
2952 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2953 last_ins->dreg = mono_alloc_ireg (cfg);
2954 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2958 g_assert (ins_is_compare(last_ins));
2959 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2960 last_ins->dreg = mono_alloc_ireg (cfg);
2961 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2965 g_assert (ins_is_compare(last_ins));
2966 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2967 last_ins->dreg = mono_alloc_ireg (cfg);
2968 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2972 g_assert (ins_is_compare(last_ins));
2973 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2974 last_ins->dreg = mono_alloc_ireg (cfg);
2975 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2980 g_assert (ins_is_compare(last_ins));
2981 last_ins->opcode = OP_IXOR;
2982 last_ins->dreg = mono_alloc_ireg(cfg);
2983 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2988 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2989 NULLIFY_INS(last_ins);
2995 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2996 NULLIFY_INS(last_ins);
3001 g_assert (ins_is_compare(last_ins));
3002 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
3003 MONO_DELETE_INS(bb, last_ins);
3008 g_assert (ins_is_compare(last_ins));
3009 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
3010 MONO_DELETE_INS(bb, last_ins);
3013 case OP_COND_EXC_EQ:
3014 case OP_COND_EXC_IEQ:
3015 g_assert (ins_is_compare(last_ins));
3016 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
3017 MONO_DELETE_INS(bb, last_ins);
3020 case OP_COND_EXC_GE:
3021 case OP_COND_EXC_IGE:
3022 g_assert (ins_is_compare(last_ins));
3023 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
3024 MONO_DELETE_INS(bb, last_ins);
3027 case OP_COND_EXC_GT:
3028 case OP_COND_EXC_IGT:
3029 g_assert (ins_is_compare(last_ins));
3030 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
3031 MONO_DELETE_INS(bb, last_ins);
3034 case OP_COND_EXC_LE:
3035 case OP_COND_EXC_ILE:
3036 g_assert (ins_is_compare(last_ins));
3037 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
3038 MONO_DELETE_INS(bb, last_ins);
3041 case OP_COND_EXC_LT:
3042 case OP_COND_EXC_ILT:
3043 g_assert (ins_is_compare(last_ins));
3044 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
3045 MONO_DELETE_INS(bb, last_ins);
3048 case OP_COND_EXC_NE_UN:
3049 case OP_COND_EXC_INE_UN:
3050 g_assert (ins_is_compare(last_ins));
3051 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
3052 MONO_DELETE_INS(bb, last_ins);
3055 case OP_COND_EXC_GE_UN:
3056 case OP_COND_EXC_IGE_UN:
3057 g_assert (ins_is_compare(last_ins));
3058 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
3059 MONO_DELETE_INS(bb, last_ins);
3062 case OP_COND_EXC_GT_UN:
3063 case OP_COND_EXC_IGT_UN:
3064 g_assert (ins_is_compare(last_ins));
3065 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
3066 MONO_DELETE_INS(bb, last_ins);
3069 case OP_COND_EXC_LE_UN:
3070 case OP_COND_EXC_ILE_UN:
3071 g_assert (ins_is_compare(last_ins));
3072 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
3073 MONO_DELETE_INS(bb, last_ins);
3076 case OP_COND_EXC_LT_UN:
3077 case OP_COND_EXC_ILT_UN:
3078 g_assert (ins_is_compare(last_ins));
3079 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
3080 MONO_DELETE_INS(bb, last_ins);
3083 case OP_COND_EXC_OV:
3084 case OP_COND_EXC_IOV: {
3085 int tmp1, tmp2, tmp3, tmp4, tmp5;
3086 MonoInst *pos = last_ins;
3088 /* Overflow happens if
3089 * neg + neg = pos or
3092 * (bit31s of operands match) AND (bit31 of operand
3093 * != bit31 of result)
3094 * XOR of the high bit returns 0 if the signs match
3095 * XOR of that with the high bit of the result return 1
3098 g_assert (last_ins->opcode == OP_IADC);
3100 tmp1 = mono_alloc_ireg (cfg);
3101 tmp2 = mono_alloc_ireg (cfg);
3102 tmp3 = mono_alloc_ireg (cfg);
3103 tmp4 = mono_alloc_ireg (cfg);
3104 tmp5 = mono_alloc_ireg (cfg);
3106 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
3107 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
3109 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
3110 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
3111 INS (pos, OP_INOT, tmp3, tmp2, -1);
3113 /* OR(tmp1, tmp2) = 0 if both conditions are true */
3114 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
3115 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
3117 /* Now, if (tmp5 == 0) then overflow */
3118 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
3123 case OP_COND_EXC_NO:
3124 case OP_COND_EXC_INO:
3125 g_assert_not_reached ();
3129 case OP_COND_EXC_IC:
3130 g_assert_not_reached ();
3133 case OP_COND_EXC_NC:
3134 case OP_COND_EXC_INC:
3135 g_assert_not_reached ();
3141 bb->last_ins = last_ins;
3142 bb->max_vreg = cfg->next_vreg;
3145 if (cfg->verbose_level > 2) {
3148 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
3149 MONO_BB_FOR_EACH_INS (bb, ins) {
3150 mono_print_ins_index (idx++, ins);
3159 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3161 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
3163 mips_truncwd (code, mips_ftemp, sreg);
3165 mips_cvtwd (code, mips_ftemp, sreg);
3167 mips_mfc1 (code, dreg, mips_ftemp);
3170 mips_andi (code, dreg, dreg, 0xff);
3171 else if (size == 2) {
3172 mips_sll (code, dreg, dreg, 16);
3173 mips_srl (code, dreg, dreg, 16);
3177 mips_sll (code, dreg, dreg, 24);
3178 mips_sra (code, dreg, dreg, 24);
3180 else if (size == 2) {
3181 mips_sll (code, dreg, dreg, 16);
3182 mips_sra (code, dreg, dreg, 16);
3189 * emit_load_volatile_arguments:
3191 * Load volatile arguments from the stack to the original input registers.
3192 * Required before a tail call.
3195 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3197 MonoMethod *method = cfg->method;
3198 MonoMethodSignature *sig;
3203 sig = mono_method_signature (method);
3205 if (!cfg->arch.cinfo)
3206 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
3207 cinfo = cfg->arch.cinfo;
3209 if (cinfo->struct_ret) {
3210 ArgInfo *ainfo = &cinfo->ret;
3211 inst = cfg->vret_addr;
3212 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3215 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3216 ArgInfo *ainfo = cinfo->args + i;
3217 inst = cfg->args [i];
3218 if (inst->opcode == OP_REGVAR) {
3219 if (ainfo->storage == ArgInIReg)
3220 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3221 else if (ainfo->storage == ArgInFReg)
3222 g_assert_not_reached();
3223 else if (ainfo->storage == ArgOnStack) {
3226 g_assert_not_reached ();
3228 if (ainfo->storage == ArgInIReg) {
3229 g_assert (mips_is_imm16 (inst->inst_offset));
3230 switch (ainfo->size) {
3232 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3235 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3239 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3242 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3243 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3246 g_assert_not_reached ();
3249 } else if (ainfo->storage == ArgOnStack) {
3251 } else if (ainfo->storage == ArgInFReg) {
3252 g_assert (mips_is_imm16 (inst->inst_offset));
3253 if (ainfo->size == 8) {
3254 #if _MIPS_SIM == _ABIO32
3255 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3256 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3257 #elif _MIPS_SIM == _ABIN32
3258 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3261 else if (ainfo->size == 4)
3262 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3264 g_assert_not_reached ();
3265 } else if (ainfo->storage == ArgStructByVal) {
3267 int doffset = inst->inst_offset;
3269 g_assert (mips_is_imm16 (inst->inst_offset));
3270 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3271 for (i = 0; i < ainfo->size; ++i) {
3272 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3273 doffset += SIZEOF_REGISTER;
3275 } else if (ainfo->storage == ArgStructByAddr) {
3276 g_assert (mips_is_imm16 (inst->inst_offset));
3277 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3279 g_assert_not_reached ();
3287 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3289 int size = cfg->param_area;
3291 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3292 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3297 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3298 if (ppc_is_imm16 (-size)) {
3299 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3301 ppc_load (code, ppc_r11, -size);
3302 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3309 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3311 int size = cfg->param_area;
3313 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3314 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3319 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3320 if (ppc_is_imm16 (size)) {
3321 ppc_stwu (code, ppc_r0, size, ppc_sp);
3323 ppc_load (code, ppc_r11, size);
3324 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3331 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3336 guint8 *code = cfg->native_code + cfg->code_len;
3337 MonoInst *last_ins = NULL;
3338 guint last_offset = 0;
3342 /* we don't align basic blocks of loops on mips */
3344 if (cfg->verbose_level > 2)
3345 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3347 cpos = bb->max_offset;
3350 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3351 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3352 g_assert (!mono_compile_aot);
3355 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3356 /* this is not thread save, but good enough */
3357 /* fixme: howto handle overflows? */
3358 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3359 mips_lw (code, mips_temp, mips_at, 0);
3360 mips_addiu (code, mips_temp, mips_temp, 1);
3361 mips_sw (code, mips_temp, mips_at, 0);
3364 MONO_BB_FOR_EACH_INS (bb, ins) {
3365 offset = code - cfg->native_code;
3367 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3369 if (offset > (cfg->code_size - max_len - 16)) {
3370 cfg->code_size *= 2;
3371 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3372 code = cfg->native_code + offset;
3374 mono_debug_record_line_number (cfg, ins, offset);
3375 if (cfg->verbose_level > 2) {
3376 g_print (" @ 0x%x\t", offset);
3377 mono_print_ins_index (ins_cnt++, ins);
3379 /* Check for virtual regs that snuck by */
3380 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3382 switch (ins->opcode) {
3383 case OP_RELAXED_NOP:
3386 case OP_DUMMY_STORE:
3387 case OP_NOT_REACHED:
3390 case OP_SEQ_POINT: {
3391 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3392 guint32 addr = (guint32)ss_trigger_page;
3394 mips_load_const (code, mips_t9, addr);
3395 mips_lw (code, mips_t9, mips_t9, 0);
3398 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3401 * A placeholder for a possible breakpoint inserted by
3402 * mono_arch_set_breakpoint ().
3404 /* mips_load_const () + mips_lw */
3411 g_assert_not_reached();
3413 emit_tls_access (code, ins->dreg, ins->inst_offset);
3417 mips_mult (code, ins->sreg1, ins->sreg2);
3418 mips_mflo (code, ins->dreg);
3419 mips_mfhi (code, ins->dreg+1);
3422 mips_multu (code, ins->sreg1, ins->sreg2);
3423 mips_mflo (code, ins->dreg);
3424 mips_mfhi (code, ins->dreg+1);
3426 case OP_MEMORY_BARRIER:
3431 case OP_STOREI1_MEMBASE_IMM:
3432 mips_load_const (code, mips_temp, ins->inst_imm);
3433 if (mips_is_imm16 (ins->inst_offset)) {
3434 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3436 mips_load_const (code, mips_at, ins->inst_offset);
3437 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3440 case OP_STOREI2_MEMBASE_IMM:
3441 mips_load_const (code, mips_temp, ins->inst_imm);
3442 if (mips_is_imm16 (ins->inst_offset)) {
3443 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3445 mips_load_const (code, mips_at, ins->inst_offset);
3446 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3449 case OP_STOREI8_MEMBASE_IMM:
3450 mips_load_const (code, mips_temp, ins->inst_imm);
3451 if (mips_is_imm16 (ins->inst_offset)) {
3452 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3454 mips_load_const (code, mips_at, ins->inst_offset);
3455 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3458 case OP_STORE_MEMBASE_IMM:
3459 case OP_STOREI4_MEMBASE_IMM:
3460 mips_load_const (code, mips_temp, ins->inst_imm);
3461 if (mips_is_imm16 (ins->inst_offset)) {
3462 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3464 mips_load_const (code, mips_at, ins->inst_offset);
3465 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3468 case OP_STOREI1_MEMBASE_REG:
3469 if (mips_is_imm16 (ins->inst_offset)) {
3470 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3472 mips_load_const (code, mips_at, ins->inst_offset);
3473 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3474 mips_sb (code, ins->sreg1, mips_at, 0);
3477 case OP_STOREI2_MEMBASE_REG:
3478 if (mips_is_imm16 (ins->inst_offset)) {
3479 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3481 mips_load_const (code, mips_at, ins->inst_offset);
3482 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3483 mips_sh (code, ins->sreg1, mips_at, 0);
3486 case OP_STORE_MEMBASE_REG:
3487 case OP_STOREI4_MEMBASE_REG:
3488 if (mips_is_imm16 (ins->inst_offset)) {
3489 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3491 mips_load_const (code, mips_at, ins->inst_offset);
3492 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3493 mips_sw (code, ins->sreg1, mips_at, 0);
3496 case OP_STOREI8_MEMBASE_REG:
3497 if (mips_is_imm16 (ins->inst_offset)) {
3498 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3500 mips_load_const (code, mips_at, ins->inst_offset);
3501 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3502 mips_sd (code, ins->sreg1, mips_at, 0);
3506 g_assert_not_reached ();
3507 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3508 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3510 case OP_LOADI8_MEMBASE:
3511 if (mips_is_imm16 (ins->inst_offset)) {
3512 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3514 mips_load_const (code, mips_at, ins->inst_offset);
3515 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3516 mips_ld (code, ins->dreg, mips_at, 0);
3519 case OP_LOAD_MEMBASE:
3520 case OP_LOADI4_MEMBASE:
3521 case OP_LOADU4_MEMBASE:
3522 g_assert (ins->dreg != -1);
3523 if (mips_is_imm16 (ins->inst_offset)) {
3524 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3526 mips_load_const (code, mips_at, ins->inst_offset);
3527 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3528 mips_lw (code, ins->dreg, mips_at, 0);
3531 case OP_LOADI1_MEMBASE:
3532 if (mips_is_imm16 (ins->inst_offset)) {
3533 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3535 mips_load_const (code, mips_at, ins->inst_offset);
3536 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3537 mips_lb (code, ins->dreg, mips_at, 0);
3540 case OP_LOADU1_MEMBASE:
3541 if (mips_is_imm16 (ins->inst_offset)) {
3542 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3544 mips_load_const (code, mips_at, ins->inst_offset);
3545 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3546 mips_lbu (code, ins->dreg, mips_at, 0);
3549 case OP_LOADI2_MEMBASE:
3550 if (mips_is_imm16 (ins->inst_offset)) {
3551 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3553 mips_load_const (code, mips_at, ins->inst_offset);
3554 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3555 mips_lh (code, ins->dreg, mips_at, 0);
3558 case OP_LOADU2_MEMBASE:
3559 if (mips_is_imm16 (ins->inst_offset)) {
3560 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3562 mips_load_const (code, mips_at, ins->inst_offset);
3563 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3564 mips_lhu (code, ins->dreg, mips_at, 0);
3567 case OP_ICONV_TO_I1:
3568 mips_sll (code, mips_at, ins->sreg1, 24);
3569 mips_sra (code, ins->dreg, mips_at, 24);
3571 case OP_ICONV_TO_I2:
3572 mips_sll (code, mips_at, ins->sreg1, 16);
3573 mips_sra (code, ins->dreg, mips_at, 16);
3575 case OP_ICONV_TO_U1:
3576 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3578 case OP_ICONV_TO_U2:
3579 mips_sll (code, mips_at, ins->sreg1, 16);
3580 mips_srl (code, ins->dreg, mips_at, 16);
3583 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3586 g_assert (mips_is_imm16 (ins->inst_imm));
3587 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3590 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3593 g_assert (mips_is_imm16 (ins->inst_imm));
3594 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3598 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3599 * So instead of emitting a trap, we emit a call a C function and place a
3602 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3603 (gpointer)"mono_break");
3604 mips_load (code, mips_t9, 0x1f1f1f1f);
3605 mips_jalr (code, mips_t9, mips_ra);
3609 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3612 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3617 g_assert (mips_is_imm16 (ins->inst_imm));
3618 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3621 g_assert (mips_is_imm16 (ins->inst_imm));
3622 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3626 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3629 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3634 // we add the negated value
3635 g_assert (mips_is_imm16 (-ins->inst_imm));
3636 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3640 // we add the negated value
3641 g_assert (mips_is_imm16 (-ins->inst_imm));
3642 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3647 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3653 g_assert (!(ins->inst_imm & 0xffff0000));
3654 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3659 guint32 *divisor_is_m1;
3660 guint32 *dividend_is_minvalue;
3661 guint32 *divisor_is_zero;
3663 mips_load_const (code, mips_at, -1);
3664 divisor_is_m1 = (guint32 *)(void *)code;
3665 mips_bne (code, ins->sreg2, mips_at, 0);
3666 mips_lui (code, mips_at, mips_zero, 0x8000);
3667 dividend_is_minvalue = (guint32 *)(void *)code;
3668 mips_bne (code, ins->sreg1, mips_at, 0);
3671 /* Divide Int32.MinValue by -1 -- throw exception */
3672 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3674 mips_patch (divisor_is_m1, (guint32)code);
3675 mips_patch (dividend_is_minvalue, (guint32)code);
3677 /* Put divide in branch delay slot (NOT YET) */
3678 divisor_is_zero = (guint32 *)(void *)code;
3679 mips_bne (code, ins->sreg2, mips_zero, 0);
3682 /* Divide by zero -- throw exception */
3683 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3685 mips_patch (divisor_is_zero, (guint32)code);
3686 mips_div (code, ins->sreg1, ins->sreg2);
3687 if (ins->opcode == OP_IDIV)
3688 mips_mflo (code, ins->dreg);
3690 mips_mfhi (code, ins->dreg);
3695 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3697 /* Put divide in branch delay slot (NOT YET) */
3698 mips_bne (code, ins->sreg2, mips_zero, 0);
3701 /* Divide by zero -- throw exception */
3702 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3704 mips_patch (divisor_is_zero, (guint32)code);
3705 mips_divu (code, ins->sreg1, ins->sreg2);
3706 if (ins->opcode == OP_IDIV_UN)
3707 mips_mflo (code, ins->dreg);
3709 mips_mfhi (code, ins->dreg);
3713 g_assert_not_reached ();
3715 ppc_load (code, ppc_r11, ins->inst_imm);
3716 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3717 ppc_mfspr (code, ppc_r0, ppc_xer);
3718 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3719 /* FIXME: use OverflowException for 0x80000000/-1 */
3720 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3722 g_assert_not_reached();
3725 g_assert_not_reached ();
3727 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3731 g_assert (!(ins->inst_imm & 0xffff0000));
3732 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3735 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3739 /* unsigned 16-bit immediate */
3740 g_assert (!(ins->inst_imm & 0xffff0000));
3741 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3744 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3748 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3751 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3754 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3758 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3761 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3764 case OP_ISHR_UN_IMM:
3765 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3767 case OP_LSHR_UN_IMM:
3768 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3771 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3774 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3778 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3781 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3784 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3788 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3790 mips_mult (code, ins->sreg1, ins->sreg2);
3791 mips_mflo (code, ins->dreg);
3796 #if SIZEOF_REGISTER == 8
3798 mips_dmult (code, ins->sreg1, ins->sreg2);
3799 mips_mflo (code, ins->dreg);
3804 mips_mult (code, ins->sreg1, ins->sreg2);
3805 mips_mflo (code, ins->dreg);
3806 mips_mfhi (code, mips_at);
3809 mips_sra (code, mips_temp, ins->dreg, 31);
3810 patch = (guint32 *)(void *)code;
3811 mips_beq (code, mips_temp, mips_at, 0);
3813 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3814 mips_patch (patch, (guint32)code);
3817 case OP_IMUL_OVF_UN: {
3819 mips_mult (code, ins->sreg1, ins->sreg2);
3820 mips_mflo (code, ins->dreg);
3821 mips_mfhi (code, mips_at);
3824 patch = (guint32 *)(void *)code;
3825 mips_beq (code, mips_at, mips_zero, 0);
3827 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3828 mips_patch (patch, (guint32)code);
3832 mips_load_const (code, ins->dreg, ins->inst_c0);
3834 #if SIZEOF_REGISTER == 8
3836 mips_load_const (code, ins->dreg, ins->inst_c0);
3840 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3841 mips_load (code, ins->dreg, 0);
3845 mips_mtc1 (code, ins->dreg, ins->sreg1);
3847 case OP_MIPS_MTC1S_2:
3848 mips_mtc1 (code, ins->dreg, ins->sreg1);
3849 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3852 mips_mfc1 (code, ins->dreg, ins->sreg1);
3855 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3859 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3861 mips_mfc1 (code, ins->dreg, ins->sreg1 + ls_word_idx);
3862 mips_mfc1 (code, ins->dreg+1, ins->sreg1 + ms_word_idx);
3866 case OP_ICONV_TO_I4:
3867 case OP_ICONV_TO_U4:
3869 if (ins->dreg != ins->sreg1)
3870 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3872 #if SIZEOF_REGISTER == 8
3874 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3875 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3878 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3879 mips_dsra (code, ins->dreg, ins->dreg, 32);
3883 int lsreg = mips_v0 + ls_word_idx;
3884 int msreg = mips_v0 + ms_word_idx;
3886 /* Get sreg1 into lsreg, sreg2 into msreg */
3888 if (ins->sreg1 == msreg) {
3889 if (ins->sreg1 != mips_at)
3890 MIPS_MOVE (code, mips_at, ins->sreg1);
3891 if (ins->sreg2 != msreg)
3892 MIPS_MOVE (code, msreg, ins->sreg2);
3893 MIPS_MOVE (code, lsreg, mips_at);
3896 if (ins->sreg2 != msreg)
3897 MIPS_MOVE (code, msreg, ins->sreg2);
3898 if (ins->sreg1 != lsreg)
3899 MIPS_MOVE (code, lsreg, ins->sreg1);
3904 if (ins->dreg != ins->sreg1) {
3905 mips_fmovd (code, ins->dreg, ins->sreg1);
3909 /* Convert from double to float and leave it there */
3910 mips_cvtsd (code, ins->dreg, ins->sreg1);
3912 case OP_FCONV_TO_R4:
3914 mips_cvtsd (code, ins->dreg, ins->sreg1);
3916 /* Just a move, no precision change */
3917 if (ins->dreg != ins->sreg1) {
3918 mips_fmovd (code, ins->dreg, ins->sreg1);
3923 code = emit_load_volatile_arguments(cfg, code);
3926 * Pop our stack, then jump to specified method (tail-call)
3927 * Keep in sync with mono_arch_emit_epilog
3929 code = mono_arch_emit_epilog_sub (cfg, code);
3931 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3932 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3933 mips_load (code, mips_t9, 0);
3934 mips_jr (code, mips_t9);
3938 /* ensure ins->sreg1 is not NULL */
3939 mips_lw (code, mips_zero, ins->sreg1, 0);
3942 g_assert (mips_is_imm16 (cfg->sig_cookie));
3943 mips_lw (code, mips_at, cfg->frame_reg, cfg->sig_cookie);
3944 mips_sw (code, mips_at, ins->sreg1, 0);
3957 case OP_VOIDCALL_REG:
3959 case OP_FCALL_MEMBASE:
3960 case OP_LCALL_MEMBASE:
3961 case OP_VCALL_MEMBASE:
3962 case OP_VCALL2_MEMBASE:
3963 case OP_VOIDCALL_MEMBASE:
3964 case OP_CALL_MEMBASE:
3965 call = (MonoCallInst*)ins;
3966 switch (ins->opcode) {
3973 if (ins->flags & MONO_INST_HAS_METHOD) {
3974 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3975 mips_load (code, mips_t9, call->method);
3978 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3979 mips_load (code, mips_t9, call->fptr);
3981 mips_jalr (code, mips_t9, mips_ra);
3988 case OP_VOIDCALL_REG:
3990 MIPS_MOVE (code, mips_t9, ins->sreg1);
3991 mips_jalr (code, mips_t9, mips_ra);
3994 case OP_FCALL_MEMBASE:
3995 case OP_LCALL_MEMBASE:
3996 case OP_VCALL_MEMBASE:
3997 case OP_VCALL2_MEMBASE:
3998 case OP_VOIDCALL_MEMBASE:
3999 case OP_CALL_MEMBASE:
4000 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
4001 mips_jalr (code, mips_t9, mips_ra);
4005 #if PROMOTE_R4_TO_R8
4006 /* returned an FP R4 (single), promote to R8 (double) in place */
4007 switch (ins->opcode) {
4010 case OP_FCALL_MEMBASE:
4011 if (call->signature->ret->type == MONO_TYPE_R4)
4012 mips_cvtds (code, mips_f0, mips_f0);
4020 int area_offset = cfg->param_area;
4022 /* Round up ins->sreg1, mips_at ends up holding size */
4023 mips_addiu (code, mips_at, ins->sreg1, 31);
4024 mips_addiu (code, mips_temp, mips_zero, ~31);
4025 mips_and (code, mips_at, mips_at, mips_temp);
4027 mips_subu (code, mips_sp, mips_sp, mips_at);
4028 g_assert (mips_is_imm16 (area_offset));
4029 mips_addiu (code, ins->dreg, mips_sp, area_offset);
4031 if (ins->flags & MONO_INST_INIT) {
4034 buf = (guint32*)(void*)code;
4035 mips_beq (code, mips_at, mips_zero, 0);
4038 mips_move (code, mips_temp, ins->dreg);
4039 mips_sb (code, mips_zero, mips_temp, 0);
4040 mips_addiu (code, mips_at, mips_at, -1);
4041 mips_bne (code, mips_at, mips_zero, -3);
4042 mips_addiu (code, mips_temp, mips_temp, 1);
4044 mips_patch (buf, (guint32)code);
4049 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
4050 mips_move (code, mips_a0, ins->sreg1);
4051 mips_call (code, mips_t9, addr);
4052 mips_break (code, 0xfc);
4056 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
4057 mips_move (code, mips_a0, ins->sreg1);
4058 mips_call (code, mips_t9, addr);
4059 mips_break (code, 0xfb);
4062 case OP_START_HANDLER: {
4064 * The START_HANDLER instruction marks the beginning of
4065 * a handler block. It is called using a call
4066 * instruction, so mips_ra contains the return address.
4067 * Since the handler executes in the same stack frame
4068 * as the method itself, we can't use save/restore to
4069 * save the return address. Instead, we save it into
4070 * a dedicated variable.
4072 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4073 g_assert (spvar->inst_basereg != mips_sp);
4074 code = emit_reserve_param_area (cfg, code);
4076 if (mips_is_imm16 (spvar->inst_offset)) {
4077 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4079 mips_load_const (code, mips_at, spvar->inst_offset);
4080 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4081 mips_sw (code, mips_ra, mips_at, 0);
4085 case OP_ENDFILTER: {
4086 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4087 g_assert (spvar->inst_basereg != mips_sp);
4088 code = emit_unreserve_param_area (cfg, code);
4090 if (ins->sreg1 != mips_v0)
4091 MIPS_MOVE (code, mips_v0, ins->sreg1);
4092 if (mips_is_imm16 (spvar->inst_offset)) {
4093 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
4095 mips_load_const (code, mips_at, spvar->inst_offset);
4096 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
4097 mips_lw (code, mips_ra, mips_at, 0);
4099 mips_jr (code, mips_ra);
4103 case OP_ENDFINALLY: {
4104 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4105 g_assert (spvar->inst_basereg != mips_sp);
4106 code = emit_unreserve_param_area (cfg, code);
4107 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
4108 mips_jalr (code, mips_t9, mips_ra);
4112 case OP_CALL_HANDLER:
4113 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4114 mips_lui (code, mips_t9, mips_zero, 0);
4115 mips_addiu (code, mips_t9, mips_t9, 0);
4116 mips_jalr (code, mips_t9, mips_ra);
4118 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
4119 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
4122 ins->inst_c0 = code - cfg->native_code;
4125 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
4126 if (cfg->arch.long_branch) {
4127 mips_lui (code, mips_at, mips_zero, 0);
4128 mips_addiu (code, mips_at, mips_at, 0);
4129 mips_jr (code, mips_at);
4133 mips_beq (code, mips_zero, mips_zero, 0);
4138 mips_jr (code, ins->sreg1);
4144 max_len += 4 * GPOINTER_TO_INT (ins->klass);
4145 if (offset > (cfg->code_size - max_len - 16)) {
4146 cfg->code_size += max_len;
4147 cfg->code_size *= 2;
4148 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4149 code = cfg->native_code + offset;
4151 g_assert (ins->sreg1 != -1);
4152 mips_sll (code, mips_at, ins->sreg1, 2);
4153 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
4154 MIPS_MOVE (code, mips_t8, mips_ra);
4155 mips_bgezal (code, mips_zero, 1); /* bal */
4157 mips_addu (code, mips_t9, mips_ra, mips_at);
4158 /* Table is 16 or 20 bytes from target of bal above */
4159 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
4160 MIPS_MOVE (code, mips_ra, mips_t8);
4161 mips_lw (code, mips_t9, mips_t9, 20);
4164 mips_lw (code, mips_t9, mips_t9, 16);
4165 mips_jalr (code, mips_t9, mips_t8);
4167 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
4168 mips_emit32 (code, 0xfefefefe);
4173 mips_addiu (code, ins->dreg, mips_zero, 1);
4174 mips_beq (code, mips_at, mips_zero, 2);
4176 MIPS_MOVE (code, ins->dreg, mips_zero);
4182 mips_addiu (code, ins->dreg, mips_zero, 1);
4183 mips_bltz (code, mips_at, 2);
4185 MIPS_MOVE (code, ins->dreg, mips_zero);
4191 mips_addiu (code, ins->dreg, mips_zero, 1);
4192 mips_bgtz (code, mips_at, 2);
4194 MIPS_MOVE (code, ins->dreg, mips_zero);
4197 case OP_MIPS_COND_EXC_EQ:
4198 case OP_MIPS_COND_EXC_GE:
4199 case OP_MIPS_COND_EXC_GT:
4200 case OP_MIPS_COND_EXC_LE:
4201 case OP_MIPS_COND_EXC_LT:
4202 case OP_MIPS_COND_EXC_NE_UN:
4203 case OP_MIPS_COND_EXC_GE_UN:
4204 case OP_MIPS_COND_EXC_GT_UN:
4205 case OP_MIPS_COND_EXC_LE_UN:
4206 case OP_MIPS_COND_EXC_LT_UN:
4208 case OP_MIPS_COND_EXC_OV:
4209 case OP_MIPS_COND_EXC_NO:
4210 case OP_MIPS_COND_EXC_C:
4211 case OP_MIPS_COND_EXC_NC:
4213 case OP_MIPS_COND_EXC_IEQ:
4214 case OP_MIPS_COND_EXC_IGE:
4215 case OP_MIPS_COND_EXC_IGT:
4216 case OP_MIPS_COND_EXC_ILE:
4217 case OP_MIPS_COND_EXC_ILT:
4218 case OP_MIPS_COND_EXC_INE_UN:
4219 case OP_MIPS_COND_EXC_IGE_UN:
4220 case OP_MIPS_COND_EXC_IGT_UN:
4221 case OP_MIPS_COND_EXC_ILE_UN:
4222 case OP_MIPS_COND_EXC_ILT_UN:
4224 case OP_MIPS_COND_EXC_IOV:
4225 case OP_MIPS_COND_EXC_INO:
4226 case OP_MIPS_COND_EXC_IC:
4227 case OP_MIPS_COND_EXC_INC: {
4231 /* If the condition is true, raise the exception */
4233 /* need to reverse test to skip around exception raising */
4235 /* For the moment, branch around a branch to avoid reversing
4238 /* Remember, an unpatched branch to 0 branches to the delay slot */
4239 switch (ins->opcode) {
4240 case OP_MIPS_COND_EXC_EQ:
4241 throw = (guint32 *)(void *)code;
4242 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4246 case OP_MIPS_COND_EXC_NE_UN:
4247 throw = (guint32 *)(void *)code;
4248 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4252 case OP_MIPS_COND_EXC_LE_UN:
4253 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4254 throw = (guint32 *)(void *)code;
4255 mips_beq (code, mips_at, mips_zero, 0);
4259 case OP_MIPS_COND_EXC_GT:
4260 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4261 throw = (guint32 *)(void *)code;
4262 mips_bne (code, mips_at, mips_zero, 0);
4266 case OP_MIPS_COND_EXC_GT_UN:
4267 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4268 throw = (guint32 *)(void *)code;
4269 mips_bne (code, mips_at, mips_zero, 0);
4273 case OP_MIPS_COND_EXC_LT:
4274 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4275 throw = (guint32 *)(void *)code;
4276 mips_bne (code, mips_at, mips_zero, 0);
4280 case OP_MIPS_COND_EXC_LT_UN:
4281 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4282 throw = (guint32 *)(void *)code;
4283 mips_bne (code, mips_at, mips_zero, 0);
4288 /* Not yet implemented */
4289 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4290 g_assert_not_reached ();
4292 skip = (guint32 *)(void *)code;
4293 mips_beq (code, mips_zero, mips_zero, 0);
4295 mips_patch (throw, (guint32)code);
4296 code = mips_emit_exc_by_name (code, ins->inst_p1);
4297 mips_patch (skip, (guint32)code);
4298 cfg->bb_exit->max_offset += 24;
4307 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4310 /* floating point opcodes */
4313 if (((guint32)ins->inst_p0) & (1 << 15))
4314 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4316 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4317 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4319 mips_load_const (code, mips_at, ins->inst_p0);
4320 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4321 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4325 if (((guint32)ins->inst_p0) & (1 << 15))
4326 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4328 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4329 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4330 #if PROMOTE_R4_TO_R8
4331 mips_cvtds (code, ins->dreg, ins->dreg);
4334 case OP_STORER8_MEMBASE_REG:
4335 if (mips_is_imm16 (ins->inst_offset)) {
4336 #if _MIPS_SIM == _ABIO32
4337 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4338 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4339 #elif _MIPS_SIM == _ABIN32
4340 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4343 mips_load_const (code, mips_at, ins->inst_offset);
4344 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4345 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4346 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4349 case OP_LOADR8_MEMBASE:
4350 if (mips_is_imm16 (ins->inst_offset)) {
4351 #if _MIPS_SIM == _ABIO32
4352 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4353 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4354 #elif _MIPS_SIM == _ABIN32
4355 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4358 mips_load_const (code, mips_at, ins->inst_offset);
4359 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4360 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4361 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4364 case OP_STORER4_MEMBASE_REG:
4365 g_assert (mips_is_imm16 (ins->inst_offset));
4366 #if PROMOTE_R4_TO_R8
4367 /* Need to convert ins->sreg1 to single-precision first */
4368 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4369 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4371 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4375 g_assert (mips_is_imm16 (ins->inst_offset));
4376 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4378 case OP_LOADR4_MEMBASE:
4379 g_assert (mips_is_imm16 (ins->inst_offset));
4380 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4381 #if PROMOTE_R4_TO_R8
4382 /* Convert to double precision in place */
4383 mips_cvtds (code, ins->dreg, ins->dreg);
4386 case OP_LOADR4_MEMINDEX:
4387 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4388 mips_lwc1 (code, ins->dreg, mips_at, 0);
4390 case OP_LOADR8_MEMINDEX:
4391 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4392 #if _MIPS_SIM == _ABIO32
4393 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4394 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4395 #elif _MIPS_SIM == _ABIN32
4396 mips_ldc1 (code, ins->dreg, mips_at, 0);
4399 case OP_STORER4_MEMINDEX:
4400 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4401 #if PROMOTE_R4_TO_R8
4402 /* Need to convert ins->sreg1 to single-precision first */
4403 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4404 mips_swc1 (code, mips_ftemp, mips_at, 0);
4406 mips_swc1 (code, ins->sreg1, mips_at, 0);
4409 case OP_STORER8_MEMINDEX:
4410 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4411 #if _MIPS_SIM == _ABIO32
4412 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4413 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4414 #elif _MIPS_SIM == _ABIN32
4415 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4418 case OP_ICONV_TO_R_UN: {
4419 static const guint64 adjust_val = 0x41F0000000000000ULL;
4421 /* convert unsigned int to double */
4422 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4423 mips_bgez (code, ins->sreg1, 5);
4424 mips_cvtdw (code, ins->dreg, mips_ftemp);
4426 mips_load (code, mips_at, (guint32) &adjust_val);
4427 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4428 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4429 /* target is here */
4432 case OP_ICONV_TO_R4:
4433 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4434 mips_cvtsw (code, ins->dreg, mips_ftemp);
4435 mips_cvtds (code, ins->dreg, ins->dreg);
4437 case OP_ICONV_TO_R8:
4438 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4439 mips_cvtdw (code, ins->dreg, mips_ftemp);
4441 case OP_FCONV_TO_I1:
4442 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4444 case OP_FCONV_TO_U1:
4445 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4447 case OP_FCONV_TO_I2:
4448 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4450 case OP_FCONV_TO_U2:
4451 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4453 case OP_FCONV_TO_I4:
4455 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4457 case OP_FCONV_TO_U4:
4459 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4462 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4465 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4468 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4471 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4474 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4477 mips_fnegd (code, ins->dreg, ins->sreg1);
4480 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4481 mips_addiu (code, ins->dreg, mips_zero, 1);
4482 mips_fbtrue (code, 2);
4484 MIPS_MOVE (code, ins->dreg, mips_zero);
4487 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4488 mips_addiu (code, ins->dreg, mips_zero, 1);
4489 mips_fbtrue (code, 2);
4491 MIPS_MOVE (code, ins->dreg, mips_zero);
4494 /* Less than, or Unordered */
4495 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4496 mips_addiu (code, ins->dreg, mips_zero, 1);
4497 mips_fbtrue (code, 2);
4499 MIPS_MOVE (code, ins->dreg, mips_zero);
4502 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4503 MIPS_MOVE (code, ins->dreg, mips_zero);
4504 mips_fbtrue (code, 2);
4506 mips_addiu (code, ins->dreg, mips_zero, 1);
4509 /* Greater than, or Unordered */
4510 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4511 MIPS_MOVE (code, ins->dreg, mips_zero);
4512 mips_fbtrue (code, 2);
4514 mips_addiu (code, ins->dreg, mips_zero, 1);
4519 case OP_MIPS_FBLT_UN:
4521 case OP_MIPS_FBGT_UN:
4523 case OP_MIPS_FBGE_UN:
4525 case OP_MIPS_FBLE_UN: {
4527 gboolean is_true = TRUE, is_ordered = FALSE;
4528 guint32 *buf = NULL;
4530 switch (ins->opcode) {
4544 case OP_MIPS_FBLT_UN:
4545 cond = MIPS_FPU_ULT;
4553 case OP_MIPS_FBGT_UN:
4554 cond = MIPS_FPU_OLE;
4562 case OP_MIPS_FBGE_UN:
4563 cond = MIPS_FPU_OLT;
4567 cond = MIPS_FPU_OLE;
4571 case OP_MIPS_FBLE_UN:
4572 cond = MIPS_FPU_ULE;
4576 g_assert_not_reached ();
4580 /* Skip the check if unordered */
4581 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4583 buf = (guint32*)code;
4584 mips_fbtrue (code, 0);
4588 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4590 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4592 mips_fbtrue (code, 0);
4594 mips_fbfalse (code, 0);
4598 mips_patch (buf, (guint32)code);
4602 guint32 *branch_patch;
4604 mips_mfc1 (code, mips_at, ins->sreg1+1);
4605 mips_srl (code, mips_at, mips_at, 16+4);
4606 mips_andi (code, mips_at, mips_at, 2047);
4607 mips_addiu (code, mips_at, mips_at, -2047);
4609 branch_patch = (guint32 *)(void *)code;
4610 mips_bne (code, mips_at, mips_zero, 0);
4613 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4614 mips_patch (branch_patch, (guint32)code);
4615 mips_fmovd (code, ins->dreg, ins->sreg1);
4619 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4620 mips_load (code, ins->dreg, 0x0f0f0f0f);
4625 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4626 g_assert_not_reached ();
4629 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4630 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4631 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4632 g_assert_not_reached ();
4638 last_offset = offset;
4641 cfg->code_len = code - cfg->native_code;
4645 mono_arch_register_lowlevel_calls (void)
4650 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4652 MonoJumpInfo *patch_info;
4654 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4655 unsigned char *ip = patch_info->ip.i + code;
4656 const unsigned char *target = NULL;
4658 switch (patch_info->type) {
4659 case MONO_PATCH_INFO_IP:
4660 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4662 case MONO_PATCH_INFO_SWITCH: {
4663 gpointer *table = (gpointer *)patch_info->data.table->table;
4666 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4668 for (i = 0; i < patch_info->data.table->table_size; i++) {
4669 table [i] = (int)patch_info->data.table->table [i] + code;
4673 case MONO_PATCH_INFO_METHODCONST:
4674 case MONO_PATCH_INFO_CLASS:
4675 case MONO_PATCH_INFO_IMAGE:
4676 case MONO_PATCH_INFO_FIELD:
4677 case MONO_PATCH_INFO_VTABLE:
4678 case MONO_PATCH_INFO_IID:
4679 case MONO_PATCH_INFO_SFLDA:
4680 case MONO_PATCH_INFO_LDSTR:
4681 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4682 case MONO_PATCH_INFO_LDTOKEN:
4683 case MONO_PATCH_INFO_R4:
4684 case MONO_PATCH_INFO_R8:
4685 /* from OP_AOTCONST : lui + addiu */
4686 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4687 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4690 case MONO_PATCH_INFO_EXC_NAME:
4691 g_assert_not_reached ();
4692 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4695 case MONO_PATCH_INFO_NONE:
4696 /* everything is dealt with at epilog output time */
4699 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4700 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4707 * Allow tracing to work with this interface (with an optional argument)
4709 * This code is expected to be inserted just after the 'real' prolog code,
4710 * and before the first basic block. We need to allocate a 2nd, temporary
4711 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4715 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4718 int offset = cfg->arch.tracing_offset;
4724 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4725 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4726 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4727 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4728 #if _MIPS_SIM == _ABIN32
4730 /* FIXME: Need a separate region for these */
4731 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4732 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4733 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4734 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4738 mips_load_const (code, mips_a0, cfg->method);
4739 mips_addiu (code, mips_a1, mips_sp, offset);
4740 mips_call (code, mips_t9, func);
4743 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4744 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4745 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4746 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4747 #if _MIPS_SIM == _ABIN32
4750 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4751 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4752 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4753 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4764 mips_adjust_stackframe(MonoCompile *cfg)
4767 int delta, threshold, i;
4768 MonoMethodSignature *sig;
4771 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4774 /* adjust cfg->stack_offset for account for down-spilling */
4775 cfg->stack_offset += SIZEOF_REGISTER;
4777 /* re-align cfg->stack_offset if needed (due to var spilling) */
4778 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4779 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4780 if (cfg->verbose_level > 2) {
4781 g_print ("mips_adjust_stackframe:\n");
4782 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4784 threshold = cfg->arch.local_alloc_offset;
4785 ra_offset = cfg->stack_offset - sizeof(gpointer);
4786 if (cfg->verbose_level > 2) {
4787 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4790 sig = mono_method_signature (cfg->method);
4791 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4792 cfg->vret_addr->inst_offset += delta;
4794 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4795 MonoInst *inst = cfg->args [i];
4797 inst->inst_offset += delta;
4801 * loads and stores based off the frame reg that (used to) lie
4802 * above the spill var area need to be increased by 'delta'
4803 * to make room for the spill vars.
4805 /* Need to find loads and stores to adjust that
4806 * are above where the spillvars were inserted, but
4807 * which are not the spillvar references themselves.
4809 * Idea - since all offsets from fp are positive, make
4810 * spillvar offsets negative to begin with so we can spot
4815 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4819 if (cfg->verbose_level > 2) {
4820 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4822 MONO_BB_FOR_EACH_INS (bb, ins) {
4826 if (cfg->verbose_level > 2) {
4827 mono_print_ins_index (ins_cnt, ins);
4829 /* The == mips_sp tests catch FP spills */
4830 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4831 (ins->inst_basereg == mips_sp))) {
4832 switch (ins->opcode) {
4833 case OP_LOADI8_MEMBASE:
4834 case OP_LOADR8_MEMBASE:
4841 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4842 (ins->dreg == mips_sp))) {
4843 switch (ins->opcode) {
4844 case OP_STOREI8_MEMBASE_REG:
4845 case OP_STORER8_MEMBASE_REG:
4846 case OP_STOREI8_MEMBASE_IMM:
4854 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == cfg->frame_reg))
4857 if (ins->inst_c0 >= threshold) {
4858 ins->inst_c0 += delta;
4859 if (cfg->verbose_level > 2) {
4861 mono_print_ins_index (ins_cnt, ins);
4864 else if (ins->inst_c0 < 0) {
4865 /* Adj_c0 holds the size of the datatype. */
4866 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4867 if (cfg->verbose_level > 2) {
4869 mono_print_ins_index (ins_cnt, ins);
4872 g_assert (ins->inst_c0 != ra_offset);
4875 if (ins->inst_imm >= threshold) {
4876 ins->inst_imm += delta;
4877 if (cfg->verbose_level > 2) {
4879 mono_print_ins_index (ins_cnt, ins);
4882 g_assert (ins->inst_c0 != ra_offset);
4892 * Stack frame layout:
4894 * ------------------- sp + cfg->stack_usage + cfg->param_area
4895 * param area incoming
4896 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4898 * ------------------- sp + cfg->stack_usage
4900 * ------------------- sp + cfg->stack_usage-4
4902 * ------------------- sp +
4903 * MonoLMF structure optional
4904 * ------------------- sp + cfg->arch.lmf_offset
4905 * saved registers s0-s8
4906 * ------------------- sp + cfg->arch.iregs_offset
4908 * ------------------- sp + cfg->param_area
4909 * param area outgoing
4910 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4912 * ------------------- sp
4916 mono_arch_emit_prolog (MonoCompile *cfg)
4918 MonoMethod *method = cfg->method;
4919 MonoMethodSignature *sig;
4921 int alloc_size, pos, i, max_offset;
4922 int alloc2_size = 0;
4926 guint32 iregs_to_save = 0;
4928 guint32 fregs_to_save = 0;
4930 /* lmf_offset is the offset of the LMF from our stack pointer. */
4931 guint32 lmf_offset = cfg->arch.lmf_offset;
4935 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4939 cfg->flags |= MONO_CFG_HAS_CALLS;
4941 sig = mono_method_signature (method);
4942 cfg->code_size = 768 + sig->param_count * 20;
4943 code = cfg->native_code = g_malloc (cfg->code_size);
4946 * compute max_offset in order to use short forward jumps.
4949 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4950 MonoInst *ins = bb->code;
4951 bb->max_offset = max_offset;
4953 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4956 MONO_BB_FOR_EACH_INS (bb, ins)
4957 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4959 if (max_offset > 0xffff)
4960 cfg->arch.long_branch = TRUE;
4963 * Currently, fp points to the bottom of the frame on MIPS, unlike other platforms.
4964 * This means that we have to adjust the offsets inside instructions which reference
4965 * arguments received on the stack, since the initial offset doesn't take into
4966 * account spill slots.
4968 mips_adjust_stackframe (cfg);
4970 /* Offset between current sp and the CFA */
4972 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4974 /* stack_offset should not be changed here. */
4975 alloc_size = cfg->stack_offset;
4976 cfg->stack_usage = alloc_size;
4978 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4981 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4983 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4984 fregs_to_save |= (fregs_to_save << 1);
4987 /* If the stack size is too big, save 1024 bytes to start with
4988 * so the prologue can use imm16(reg) addressing, then allocate
4989 * the rest of the frame.
4991 if (alloc_size > ((1 << 15) - 1024)) {
4992 alloc2_size = alloc_size - 1024;
4996 g_assert (mips_is_imm16 (-alloc_size));
4997 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4998 cfa_offset = alloc_size;
4999 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5002 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5003 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
5004 if (mips_is_imm16(offset))
5005 mips_sw (code, mips_ra, mips_sp, offset);
5007 g_assert_not_reached ();
5009 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
5010 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
5013 /* XXX - optimize this later to not save all regs if LMF constructed */
5014 pos = cfg->arch.iregs_offset - alloc2_size;
5016 if (iregs_to_save) {
5017 /* save used registers in own stack frame (at pos) */
5018 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5019 if (iregs_to_save & (1 << i)) {
5020 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
5021 g_assert (mips_is_imm16(pos));
5022 MIPS_SW (code, i, mips_sp, pos);
5023 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
5024 pos += SIZEOF_REGISTER;
5029 // FIXME: Don't save registers twice if there is an LMF
5030 // s8 has to be special cased since it is overwritten with the updated value
5032 if (method->save_lmf) {
5033 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5034 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
5035 g_assert (mips_is_imm16(offset));
5036 if (MIPS_LMF_IREGMASK & (1 << i))
5037 MIPS_SW (code, i, mips_sp, offset);
5042 /* Save float registers */
5043 if (fregs_to_save) {
5044 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5045 if (fregs_to_save & (1 << i)) {
5046 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5047 g_assert (mips_is_imm16(pos));
5048 mips_swc1 (code, i, mips_sp, pos);
5049 pos += sizeof (gulong);
5054 if (method->save_lmf) {
5055 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5056 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
5057 g_assert (mips_is_imm16(offset));
5058 mips_swc1 (code, i, mips_sp, offset);
5063 if (cfg->frame_reg != mips_sp) {
5064 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5065 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
5067 if (method->save_lmf) {
5068 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
5069 g_assert (mips_is_imm16(offset));
5070 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
5074 /* store runtime generic context */
5075 if (cfg->rgctx_var) {
5076 MonoInst *ins = cfg->rgctx_var;
5078 g_assert (ins->opcode == OP_REGOFFSET);
5080 g_assert (mips_is_imm16 (ins->inst_offset));
5081 mips_sw (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
5084 /* load arguments allocated to register from the stack */
5087 if (!cfg->arch.cinfo)
5088 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
5089 cinfo = cfg->arch.cinfo;
5091 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
5092 ArgInfo *ainfo = &cinfo->ret;
5093 inst = cfg->vret_addr;
5094 if (inst->opcode == OP_REGVAR)
5095 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5096 else if (mips_is_imm16 (inst->inst_offset)) {
5097 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5099 mips_load_const (code, mips_at, inst->inst_offset);
5100 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
5101 mips_sw (code, ainfo->reg, mips_at, 0);
5105 if (sig->call_convention == MONO_CALL_VARARG) {
5106 ArgInfo *cookie = &cinfo->sig_cookie;
5107 int offset = alloc_size + cookie->offset;
5109 /* Save the sig cookie address */
5110 g_assert (cookie->storage == ArgOnStack);
5112 g_assert (mips_is_imm16(offset));
5113 mips_addi (code, mips_at, cfg->frame_reg, offset);
5114 mips_sw (code, mips_at, cfg->frame_reg, cfg->sig_cookie - alloc2_size);
5117 /* Keep this in sync with emit_load_volatile_arguments */
5118 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5119 ArgInfo *ainfo = cinfo->args + i;
5120 inst = cfg->args [pos];
5122 if (cfg->verbose_level > 2)
5123 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
5124 if (inst->opcode == OP_REGVAR) {
5125 /* Argument ends up in a register */
5126 if (ainfo->storage == ArgInIReg)
5127 MIPS_MOVE (code, inst->dreg, ainfo->reg);
5128 else if (ainfo->storage == ArgInFReg) {
5129 g_assert_not_reached();
5131 ppc_fmr (code, inst->dreg, ainfo->reg);
5134 else if (ainfo->storage == ArgOnStack) {
5135 int offset = cfg->stack_usage + ainfo->offset;
5136 g_assert (mips_is_imm16(offset));
5137 mips_lw (code, inst->dreg, mips_sp, offset);
5139 g_assert_not_reached ();
5141 if (cfg->verbose_level > 2)
5142 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5144 /* Argument ends up on the stack */
5145 if (ainfo->storage == ArgInIReg) {
5147 /* Incoming parameters should be above this frame */
5148 if (cfg->verbose_level > 2)
5149 g_print ("stack slot at %d of %d+%d\n",
5150 inst->inst_offset, alloc_size, alloc2_size);
5151 /* g_assert (inst->inst_offset >= alloc_size); */
5152 g_assert (inst->inst_basereg == cfg->frame_reg);
5153 basereg_offset = inst->inst_offset - alloc2_size;
5154 g_assert (mips_is_imm16 (basereg_offset));
5155 switch (ainfo->size) {
5157 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5160 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5164 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5167 #if (SIZEOF_REGISTER == 4)
5168 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
5169 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
5170 #elif (SIZEOF_REGISTER == 8)
5171 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
5175 g_assert_not_reached ();
5178 } else if (ainfo->storage == ArgOnStack) {
5180 * Argument comes in on the stack, and ends up on the stack
5181 * 1 and 2 byte args are passed as 32-bit quantities, but used as
5182 * 8 and 16 bit quantities. Shorten them in place.
5184 g_assert (mips_is_imm16 (inst->inst_offset));
5185 switch (ainfo->size) {
5187 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5188 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5191 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5192 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5199 g_assert_not_reached ();
5201 } else if (ainfo->storage == ArgInFReg) {
5202 g_assert (mips_is_imm16 (inst->inst_offset));
5203 g_assert (mips_is_imm16 (inst->inst_offset+4));
5204 if (ainfo->size == 8) {
5205 #if _MIPS_SIM == _ABIO32
5206 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5207 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5208 #elif _MIPS_SIM == _ABIN32
5209 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5212 else if (ainfo->size == 4)
5213 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5215 g_assert_not_reached ();
5216 } else if (ainfo->storage == ArgStructByVal) {
5218 int doffset = inst->inst_offset;
5220 g_assert (mips_is_imm16 (inst->inst_offset));
5221 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5222 /* Push the argument registers into their stack slots */
5223 for (i = 0; i < ainfo->size; ++i) {
5224 g_assert (mips_is_imm16(doffset));
5225 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5226 doffset += SIZEOF_REGISTER;
5228 } else if (ainfo->storage == ArgStructByAddr) {
5229 g_assert (mips_is_imm16 (inst->inst_offset));
5230 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5231 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5233 g_assert_not_reached ();
5238 if (method->save_lmf) {
5239 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5240 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5242 if (lmf_pthread_key != -1) {
5243 g_assert_not_reached();
5245 emit_tls_access (code, mips_temp, lmf_pthread_key);
5247 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5248 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5249 g_assert (mips_is_imm16(offset));
5250 mips_addiu (code, mips_a0, mips_temp, offset);
5253 /* This can/will clobber the a0-a3 registers */
5254 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5257 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5258 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5259 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5260 /* new_lmf->previous_lmf = *lmf_addr */
5261 mips_lw (code, mips_at, mips_v0, 0);
5262 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5263 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5264 /* *(lmf_addr) = sp + lmf_offset */
5265 g_assert (mips_is_imm16(lmf_offset));
5266 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5267 mips_sw (code, mips_at, mips_v0, 0);
5269 /* save method info */
5270 mips_load_const (code, mips_at, method);
5271 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5272 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5274 /* save the current IP */
5275 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5276 mips_load_const (code, mips_at, 0x01010101);
5277 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5281 if (mips_is_imm16 (-alloc2_size)) {
5282 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5285 mips_load_const (code, mips_at, -alloc2_size);
5286 mips_addu (code, mips_sp, mips_sp, mips_at);
5288 alloc_size += alloc2_size;
5289 cfa_offset += alloc2_size;
5290 if (cfg->frame_reg != mips_sp)
5291 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5293 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5297 #if _MIPS_SIM == _ABIO32
5298 cfg->arch.tracing_offset = cfg->stack_offset;
5299 #elif _MIPS_SIM == _ABIN32
5300 /* no stack slots by default for argument regs, reserve a special block */
5301 g_assert_not_reached ();
5303 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5306 cfg->code_len = code - cfg->native_code;
5307 g_assert (cfg->code_len < cfg->code_size);
5321 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5324 int save_mode = SAVE_NONE;
5326 MonoMethod *method = cfg->method;
5327 int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type;
5328 int save_offset = MIPS_STACK_PARAM_OFFSET;
5330 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5332 offset = code - cfg->native_code;
5333 /* we need about 16 instructions */
5334 if (offset > (cfg->code_size - 16 * 4)) {
5335 cfg->code_size *= 2;
5336 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5337 code = cfg->native_code + offset;
5342 case MONO_TYPE_VOID:
5343 /* special case string .ctor icall */
5344 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5345 save_mode = SAVE_ONE;
5347 save_mode = SAVE_NONE;
5351 save_mode = SAVE_FP;
5353 case MONO_TYPE_VALUETYPE:
5354 save_mode = SAVE_STRUCT;
5358 #if SIZEOF_REGISTER == 4
5359 save_mode = SAVE_TWO;
5360 #elif SIZEOF_REGISTER == 8
5361 save_mode = SAVE_ONE;
5365 save_mode = SAVE_ONE;
5369 mips_addiu (code, mips_sp, mips_sp, -32);
5370 g_assert (mips_is_imm16(save_offset));
5371 switch (save_mode) {
5373 mips_sw (code, mips_v0, mips_sp, save_offset);
5374 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5375 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5376 if (enable_arguments) {
5377 MIPS_MOVE (code, mips_a1, mips_v0);
5378 MIPS_MOVE (code, mips_a2, mips_v1);
5382 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5383 if (enable_arguments) {
5384 MIPS_MOVE (code, mips_a1, mips_v0);
5388 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5389 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5390 mips_lw (code, mips_a0, mips_sp, save_offset);
5391 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5392 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5399 mips_load_const (code, mips_a0, cfg->method);
5400 mips_call (code, mips_t9, func);
5402 switch (save_mode) {
5404 mips_lw (code, mips_v0, mips_sp, save_offset);
5405 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5406 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5409 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5412 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5419 mips_addiu (code, mips_sp, mips_sp, 32);
5426 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5428 MonoMethod *method = cfg->method;
5430 int max_epilog_size = 16 + 20*4;
5431 int alloc2_size = 0;
5432 guint32 iregs_to_restore;
5434 guint32 fregs_to_restore;
5437 if (cfg->method->save_lmf)
5438 max_epilog_size += 128;
5440 if (mono_jit_trace_calls != NULL)
5441 max_epilog_size += 50;
5443 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5444 max_epilog_size += 50;
5447 pos = code - cfg->native_code;
5448 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5449 cfg->code_size *= 2;
5450 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5451 cfg->stat_code_reallocs++;
5455 * Keep in sync with OP_JMP
5458 code = cfg->native_code + pos;
5460 code = cfg->native_code + cfg->code_len;
5462 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5463 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5465 if (cfg->frame_reg != mips_sp) {
5466 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5468 /* If the stack frame is really large, deconstruct it in two steps */
5469 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5470 alloc2_size = cfg->stack_usage - 1024;
5471 /* partially deconstruct the stack */
5472 mips_load_const (code, mips_at, alloc2_size);
5473 mips_addu (code, mips_sp, mips_sp, mips_at);
5475 pos = cfg->arch.iregs_offset - alloc2_size;
5476 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5477 if (iregs_to_restore) {
5478 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5479 if (iregs_to_restore & (1 << i)) {
5480 g_assert (mips_is_imm16(pos));
5481 MIPS_LW (code, i, mips_sp, pos);
5482 pos += SIZEOF_REGISTER;
5489 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5491 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5492 fregs_to_restore |= (fregs_to_restore << 1);
5494 if (fregs_to_restore) {
5495 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5496 if (fregs_to_restore & (1 << i)) {
5497 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5498 g_assert (mips_is_imm16(pos));
5499 mips_lwc1 (code, i, mips_sp, pos);
5506 /* Unlink the LMF if necessary */
5507 if (method->save_lmf) {
5508 int lmf_offset = cfg->arch.lmf_offset;
5510 /* t0 = current_lmf->previous_lmf */
5511 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5512 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5514 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5515 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5516 /* (*lmf_addr) = previous_lmf */
5517 mips_sw (code, mips_temp, mips_t1, 0);
5521 /* Restore the fp */
5522 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5525 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5526 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5527 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5529 /* Restore the stack pointer */
5530 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5531 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5533 /* Caller will emit either return or tail-call sequence */
5535 cfg->code_len = code - cfg->native_code;
5537 g_assert (cfg->code_len < cfg->code_size);
5542 mono_arch_emit_epilog (MonoCompile *cfg)
5546 code = mono_arch_emit_epilog_sub (cfg, NULL);
5548 mips_jr (code, mips_ra);
5551 cfg->code_len = code - cfg->native_code;
5553 g_assert (cfg->code_len < cfg->code_size);
5556 /* remove once throw_exception_by_name is eliminated */
5559 exception_id_by_name (const char *name)
5561 if (strcmp (name, "IndexOutOfRangeException") == 0)
5562 return MONO_EXC_INDEX_OUT_OF_RANGE;
5563 if (strcmp (name, "OverflowException") == 0)
5564 return MONO_EXC_OVERFLOW;
5565 if (strcmp (name, "ArithmeticException") == 0)
5566 return MONO_EXC_ARITHMETIC;
5567 if (strcmp (name, "DivideByZeroException") == 0)
5568 return MONO_EXC_DIVIDE_BY_ZERO;
5569 if (strcmp (name, "InvalidCastException") == 0)
5570 return MONO_EXC_INVALID_CAST;
5571 if (strcmp (name, "NullReferenceException") == 0)
5572 return MONO_EXC_NULL_REF;
5573 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5574 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5575 if (strcmp (name, "ArgumentException") == 0)
5576 return MONO_EXC_ARGUMENT;
5577 g_error ("Unknown intrinsic exception %s\n", name);
5583 mono_arch_emit_exceptions (MonoCompile *cfg)
5586 MonoJumpInfo *patch_info;
5589 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5590 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5591 int max_epilog_size = 50;
5593 /* count the number of exception infos */
5596 * make sure we have enough space for exceptions
5597 * 24 is the simulated call to throw_exception_by_name
5599 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5601 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5602 i = exception_id_by_name (patch_info->data.target);
5603 g_assert (i < MONO_EXC_INTRINS_NUM);
5604 if (!exc_throw_found [i]) {
5605 max_epilog_size += 12;
5606 exc_throw_found [i] = TRUE;
5612 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5613 cfg->code_size *= 2;
5614 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5615 cfg->stat_code_reallocs++;
5618 code = cfg->native_code + cfg->code_len;
5620 /* add code to raise exceptions */
5621 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5622 switch (patch_info->type) {
5623 case MONO_PATCH_INFO_EXC: {
5625 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5627 i = exception_id_by_name (patch_info->data.target);
5628 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5629 if (!exc_throw_pos [i]) {
5632 exc_throw_pos [i] = code;
5633 //g_print ("exc: writing stub at %p\n", code);
5634 mips_load_const (code, mips_a0, patch_info->data.target);
5635 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5636 mips_load_const (code, mips_t9, addr);
5637 mips_jr (code, mips_t9);
5640 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5642 /* Turn into a Relative patch, pointing at code stub */
5643 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5644 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5646 g_assert_not_reached();
5656 cfg->code_len = code - cfg->native_code;
5658 g_assert (cfg->code_len < cfg->code_size);
5663 * Thread local storage support
5666 setup_tls_access (void)
5669 //guint32 *ins, *code;
5671 if (tls_mode == TLS_MODE_FAILED)
5674 if (g_getenv ("MONO_NO_TLS")) {
5675 tls_mode = TLS_MODE_FAILED;
5679 if (tls_mode == TLS_MODE_DETECT) {
5681 tls_mode = TLS_MODE_FAILED;
5685 ins = (guint32*)pthread_getspecific;
5686 /* uncond branch to the real method */
5687 if ((*ins >> 26) == 18) {
5689 val = (*ins & ~3) << 6;
5693 ins = (guint32*)val;
5695 ins = (guint32*) ((char*)ins + val);
5698 code = &cmplwi_1023;
5699 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5701 ppc_li (code, ppc_r4, 0x48);
5704 if (*ins == cmplwi_1023) {
5705 int found_lwz_284 = 0;
5706 for (ptk = 0; ptk < 20; ++ptk) {
5708 if (!*ins || *ins == blr_ins)
5710 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5715 if (!found_lwz_284) {
5716 tls_mode = TLS_MODE_FAILED;
5719 tls_mode = TLS_MODE_LTHREADS;
5720 } else if (*ins == li_0x48) {
5722 /* uncond branch to the real method */
5723 if ((*ins >> 26) == 18) {
5725 val = (*ins & ~3) << 6;
5729 ins = (guint32*)val;
5731 ins = (guint32*) ((char*)ins + val);
5734 ppc_li (code, ppc_r0, 0x7FF2);
5735 if (ins [1] == val) {
5736 /* Darwin on G4, implement */
5737 tls_mode = TLS_MODE_FAILED;
5741 ppc_mfspr (code, ppc_r3, 104);
5742 if (ins [1] != val) {
5743 tls_mode = TLS_MODE_FAILED;
5746 tls_mode = TLS_MODE_DARWIN_G5;
5749 tls_mode = TLS_MODE_FAILED;
5753 tls_mode = TLS_MODE_FAILED;
5758 if (lmf_pthread_key == -1) {
5759 ptk = mono_jit_tls_id;
5761 /*g_print ("MonoLMF at: %d\n", ptk);*/
5762 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5763 init_tls_failed = 1;
5766 lmf_pthread_key = ptk;
5769 if (monothread_key == -1) {
5770 ptk = mono_thread_get_tls_key ();
5772 monothread_key = ptk;
5773 /*g_print ("thread inited: %d\n", ptk);*/
5775 /*g_print ("thread not inited yet %d\n", ptk);*/
5781 mono_arch_finish_init (void)
5783 setup_tls_access ();
5787 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5792 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5794 int this_dreg = mips_a0;
5797 this_dreg = mips_a1;
5799 /* add the this argument */
5800 if (this_reg != -1) {
5802 MONO_INST_NEW (cfg, this, OP_MOVE);
5803 this->type = this_type;
5804 this->sreg1 = this_reg;
5805 this->dreg = mono_alloc_ireg (cfg);
5806 mono_bblock_add_inst (cfg->cbb, this);
5807 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5812 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5813 vtarg->type = STACK_MP;
5814 vtarg->sreg1 = vt_reg;
5815 vtarg->dreg = mono_alloc_ireg (cfg);
5816 mono_bblock_add_inst (cfg->cbb, vtarg);
5817 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5822 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5824 MonoInst *ins = NULL;
5830 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5836 mono_arch_print_tree (MonoInst *tree, int arity)
5842 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5844 return ctx->sc_regs [reg];
5847 #ifdef MONO_ARCH_HAVE_IMT
5849 #define ENABLE_WRONG_METHOD_CHECK 0
5851 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5852 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5854 #define LOADSTORE_SIZE 4
5855 #define JUMP_IMM_SIZE 16
5856 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5857 #define LOAD_CONST_SIZE 8
5858 #define JUMP_JR_SIZE 8
5861 * LOCKING: called with the domain lock held
5864 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5865 gpointer fail_tramp)
5869 guint8 *code, *start, *patch;
5871 for (i = 0; i < count; ++i) {
5872 MonoIMTCheckItem *item = imt_entries [i];
5874 if (item->is_equals) {
5875 if (item->check_target_idx) {
5876 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5877 if (item->has_target_code)
5878 item->chunk_size += LOAD_CONST_SIZE;
5880 item->chunk_size += LOADSTORE_SIZE;
5883 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5884 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5885 if (!item->has_target_code)
5886 item->chunk_size += LOADSTORE_SIZE;
5888 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5889 #if ENABLE_WRONG_METHOD_CHECK
5890 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5895 item->chunk_size += CMP_SIZE + BR_SIZE;
5896 imt_entries [item->check_target_idx]->compare_done = TRUE;
5898 size += item->chunk_size;
5900 /* the initial load of the vtable address */
5901 size += MIPS_LOAD_SEQUENCE_LENGTH;
5903 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5905 code = mono_domain_code_reserve (domain, size);
5909 /* t7 points to the vtable */
5910 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5912 for (i = 0; i < count; ++i) {
5913 MonoIMTCheckItem *item = imt_entries [i];
5915 item->code_target = code;
5916 if (item->is_equals) {
5917 if (item->check_target_idx) {
5918 mips_load_const (code, mips_temp, (gsize)item->key);
5919 item->jmp_code = code;
5920 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5922 if (item->has_target_code) {
5923 mips_load_const (code, mips_t9,
5924 item->value.target_code);
5927 mips_lw (code, mips_t9, mips_t7,
5928 (sizeof (gpointer) * item->value.vtable_slot));
5930 mips_jr (code, mips_t9);
5934 mips_load_const (code, mips_temp, (gsize)item->key);
5936 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5938 if (item->has_target_code) {
5939 mips_load_const (code, mips_t9,
5940 item->value.target_code);
5943 mips_load_const (code, mips_at,
5944 & (vtable->vtable [item->value.vtable_slot]));
5945 mips_lw (code, mips_t9, mips_at, 0);
5947 mips_jr (code, mips_t9);
5949 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5950 mips_load_const (code, mips_t9, fail_tramp);
5951 mips_jr (code, mips_t9);
5954 /* enable the commented code to assert on wrong method */
5955 #if ENABLE_WRONG_METHOD_CHECK
5956 ppc_load (code, ppc_r0, (guint32)item->key);
5957 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5959 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5961 mips_lw (code, mips_t9, mips_t7,
5962 (sizeof (gpointer) * item->value.vtable_slot));
5963 mips_jr (code, mips_t9);
5966 #if ENABLE_WRONG_METHOD_CHECK
5967 ppc_patch (patch, code);
5973 mips_load_const (code, mips_temp, (gulong)item->key);
5974 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5976 item->jmp_code = code;
5977 mips_beq (code, mips_temp, mips_zero, 0);
5981 /* patch the branches to get to the target items */
5982 for (i = 0; i < count; ++i) {
5983 MonoIMTCheckItem *item = imt_entries [i];
5984 if (item->jmp_code && item->check_target_idx) {
5985 mips_patch ((guint32 *)item->jmp_code,
5986 (guint32)imt_entries [item->check_target_idx]->code_target);
5991 mono_stats.imt_thunks_size += code - start;
5992 g_assert (code - start <= size);
5993 mono_arch_flush_icache (start, size);
5998 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6000 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
6005 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6007 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6010 /* Soft Debug support */
6011 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6014 * mono_arch_set_breakpoint:
6016 * See mini-amd64.c for docs.
6019 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6022 guint32 addr = (guint32)bp_trigger_page;
6024 mips_load_const (code, mips_t9, addr);
6025 mips_lw (code, mips_t9, mips_t9, 0);
6027 mono_arch_flush_icache (ip, code - ip);
6031 * mono_arch_clear_breakpoint:
6033 * See mini-amd64.c for docs.
6036 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6044 mono_arch_flush_icache (ip, code - ip);
6048 * mono_arch_start_single_stepping:
6050 * See mini-amd64.c for docs.
6053 mono_arch_start_single_stepping (void)
6055 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6059 * mono_arch_stop_single_stepping:
6061 * See mini-amd64.c for docs.
6064 mono_arch_stop_single_stepping (void)
6066 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6070 * mono_arch_is_single_step_event:
6072 * See mini-amd64.c for docs.
6075 mono_arch_is_single_step_event (void *info, void *sigctx)
6077 siginfo_t* sinfo = (siginfo_t*) info;
6078 /* Sometimes the address is off by 4 */
6079 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
6086 * mono_arch_is_breakpoint_event:
6088 * See mini-amd64.c for docs.
6091 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6093 siginfo_t* sinfo = (siginfo_t*) info;
6094 /* Sometimes the address is off by 4 */
6095 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
6102 * mono_arch_skip_breakpoint:
6104 * See mini-amd64.c for docs.
6107 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6109 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6113 * mono_arch_skip_single_step:
6115 * See mini-amd64.c for docs.
6118 mono_arch_skip_single_step (MonoContext *ctx)
6120 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
6124 * mono_arch_get_seq_point_info:
6126 * See mini-amd64.c for docs.
6129 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6136 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
6138 ext->lmf.previous_lmf = prev_lmf;
6139 /* Mark that this is a MonoLMFExt */
6140 ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
6141 ext->lmf.iregs [mips_sp] = (gssize)ext;
6144 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */