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>
22 #include <mono/arch/mips/mips-codegen.h>
24 #include "mini-mips.h"
29 #define SAVE_FP_REGS 0
30 #define SAVE_ALL_REGS 0
33 #define ALWAYS_USE_FP 1
34 #define ALWAYS_SAVE_RA 1 /* call-handler & switch currently clobber ra */
36 #define PROMOTE_R4_TO_R8 1 /* promote single values in registers to doubles */
37 #define USE_MUL 1 /* use mul instead of mult/mflo for multiply */
39 /* Emit a call sequence to 'v', using 'D' as a scratch register if necessary */
40 #define mips_call(c,D,v) do { \
41 guint32 _target = (guint32)(v); \
42 if (1 || ((v) == NULL) || ((_target & 0xfc000000) != (((guint32)(c)) & 0xfc000000))) { \
43 mips_load_const (c, D, _target); \
44 mips_jalr (c, D, mips_ra); \
47 mips_jumpl (c, _target >> 2); \
59 /* This mutex protects architecture specific caches */
60 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
61 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
62 static CRITICAL_SECTION mini_arch_mutex;
64 int mono_exc_esp_offset = 0;
65 static int tls_mode = TLS_MODE_DETECT;
66 static int lmf_pthread_key = -1;
67 static int monothread_key = -1;
68 static int monodomain_key = -1;
70 /* Whenever the host is little-endian */
71 static int little_endian;
72 /* Index of ms word/register */
73 static int ls_word_idx;
74 /* Index of ls word/register */
75 static int ms_word_idx;
76 /* Same for offsets */
77 static int ls_word_offset;
78 static int ms_word_offset;
81 * The code generated for sequence points reads from this location, which is
82 * made read-only when single stepping is enabled.
84 static gpointer ss_trigger_page;
86 /* Enabled breakpoints read from this trigger page */
87 static gpointer bp_trigger_page;
90 #define DEBUG(a) if (cfg->verbose_level > 1) a
96 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
98 code = mips_emit_exc_by_name (code, exc_name); \
99 cfg->bb_exit->max_offset += 16; \
103 #define emit_linuxthreads_tls(code,dreg,key) do {\
105 off1 = offsets_from_pthread_key ((key), &off2); \
106 g_assert_not_reached (); \
107 ppc_lwz ((code), (dreg), off1, ppc_r2); \
108 ppc_lwz ((code), (dreg), off2, (dreg)); \
112 #define emit_tls_access(code,dreg,key) do { \
113 switch (tls_mode) { \
114 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
115 default: g_assert_not_reached (); \
119 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
121 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
122 inst->type = STACK_R8; \
124 inst->inst_p0 = (void*)(addr); \
125 mono_bblock_add_inst (cfg->cbb, inst); \
128 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
129 || ((ins)->opcode == OP_ICOMPARE) \
130 || ((ins)->opcode == OP_LCOMPARE)))
131 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
132 || ((ins)->opcode == OP_ICOMPARE_IMM) \
133 || ((ins)->opcode == OP_LCOMPARE_IMM)))
135 #define INS_REWRITE(ins, op, _s1, _s2) do { \
138 ins->opcode = (op); \
143 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
145 ins->opcode = (op); \
147 ins->inst_imm = (_imm); \
151 typedef struct InstList InstList;
169 guint16 vtsize; /* in param area */
172 guint8 size : 4; /* 1, 2, 4, 8, or regs used by ArgStructByVal */
181 gboolean vtype_retaddr;
190 void patch_lui_addiu(guint32 *ip, guint32 val);
191 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
192 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
193 void mips_adjust_stackframe(MonoCompile *cfg);
194 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
195 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
198 /* Not defined in asm/cachectl.h */
199 int cacheflush(char *addr, int nbytes, int cache);
202 mono_arch_flush_icache (guint8 *code, gint size)
204 /* Linux/MIPS specific */
205 cacheflush ((char*)code, size, BCACHE);
209 mono_arch_flush_register_windows (void)
214 mono_arch_is_inst_imm (gint64 imm)
220 mips_emit_exc_by_name(guint8 *code, const char *name)
223 MonoClass *exc_class;
225 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
226 g_assert (exc_class);
228 mips_load_const (code, mips_a0, exc_class->type_token);
229 addr = mono_get_throw_corlib_exception ();
230 mips_call (code, mips_t9, addr);
236 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
238 if (mips_is_imm16 (v))
239 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
241 #if SIZEOF_REGISTER == 8
243 /* v is not a sign-extended 32-bit value */
244 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
245 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
246 mips_dsll (code, dreg, dreg, 16);
247 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
248 mips_dsll (code, dreg, dreg, 16);
249 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
253 if (((guint32)v) & (1 << 15)) {
254 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
257 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
259 if (((guint32)v) & 0xffff)
260 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
266 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
269 if (cfg->arch.long_branch) {
272 /* Invert test and emit branch around jump */
275 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
279 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
283 mips_bltz (code, ins->sreg1, br_offset);
287 mips_blez (code, ins->sreg1, br_offset);
291 mips_bgtz (code, ins->sreg1, br_offset);
295 mips_bgez (code, ins->sreg1, br_offset);
299 g_assert_not_reached ();
301 mono_add_patch_info (cfg, code - cfg->native_code,
302 MONO_PATCH_INFO_BB, ins->inst_true_bb);
303 mips_lui (code, mips_at, mips_zero, 0);
304 mips_addiu (code, mips_at, mips_at, 0);
305 mips_jr (code, mips_at);
309 mono_add_patch_info (cfg, code - cfg->native_code,
310 MONO_PATCH_INFO_BB, ins->inst_true_bb);
313 mips_beq (code, ins->sreg1, ins->sreg2, 0);
317 mips_bne (code, ins->sreg1, ins->sreg2, 0);
321 mips_bgez (code, ins->sreg1, 0);
325 mips_bgtz (code, ins->sreg1, 0);
329 mips_blez (code, ins->sreg1, 0);
333 mips_bltz (code, ins->sreg1, 0);
337 g_assert_not_reached ();
343 /* XXX - big-endian dependent? */
345 patch_lui_addiu(guint32 *ip, guint32 val)
347 guint16 *__lui_addiu = (guint16*)(void *)(ip);
350 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
351 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
354 if (((guint32)(val)) & (1 << 15))
355 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
357 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
358 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
359 mono_arch_flush_icache ((guint8 *)ip, 8);
364 mips_patch (guint32 *code, guint32 target)
367 guint32 op = ins >> 26;
368 guint32 diff, offset;
370 g_assert (trap_target != target);
371 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
373 case 0x00: /* jr ra */
374 if (ins == 0x3e00008)
376 g_assert_not_reached ();
380 g_assert (!(target & 0x03));
381 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
382 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
384 mono_arch_flush_icache ((guint8 *)code, 4);
386 case 0x01: /* BLTZ */
389 case 0x06: /* BLEZ */
390 case 0x07: /* BGTZ */
391 case 0x11: /* bc1t */
392 diff = target - (guint32)(code + 1);
393 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
394 g_assert (!(diff & 0x03));
395 offset = ((gint32)diff) >> 2;
396 g_assert (((int)offset) == ((int)(short)offset));
397 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
399 mono_arch_flush_icache ((guint8 *)code, 4);
401 case 0x0f: /* LUI / ADDIU pair */
402 g_assert ((code[1] >> 26) == 0x9);
403 patch_lui_addiu (code, target);
404 mono_arch_flush_icache ((guint8 *)code, 8);
408 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
409 g_assert_not_reached ();
415 offsets_from_pthread_key (guint32 key, int *offset2)
419 *offset2 = idx2 * sizeof (gpointer);
420 return 284 + idx1 * sizeof (gpointer);
425 mono_arch_regname (int reg) {
426 #if _MIPS_SIM == _ABIO32
427 static const char * rnames[] = {
428 "zero", "at", "v0", "v1",
429 "a0", "a1", "a2", "a3",
430 "t0", "t1", "t2", "t3",
431 "t4", "t5", "t6", "t7",
432 "s0", "s1", "s2", "s3",
433 "s4", "s5", "s6", "s7",
434 "t8", "t9", "k0", "k1",
435 "gp", "sp", "fp", "ra"
437 #elif _MIPS_SIM == _ABIN32
438 static const char * rnames[] = {
439 "zero", "at", "v0", "v1",
440 "a0", "a1", "a2", "a3",
441 "a4", "a5", "a6", "a7",
442 "t0", "t1", "t2", "t3",
443 "s0", "s1", "s2", "s3",
444 "s4", "s5", "s6", "s7",
445 "t8", "t9", "k0", "k1",
446 "gp", "sp", "fp", "ra"
449 if (reg >= 0 && reg < 32)
455 mono_arch_fregname (int reg) {
456 static const char * rnames[] = {
457 "f0", "f1", "f2", "f3",
458 "f4", "f5", "f6", "f7",
459 "f8", "f9", "f10", "f11",
460 "f12", "f13", "f14", "f15",
461 "f16", "f17", "f18", "f19",
462 "f20", "f21", "f22", "f23",
463 "f24", "f25", "f26", "f27",
464 "f28", "f29", "f30", "f31"
466 if (reg >= 0 && reg < 32)
471 /* this function overwrites at */
473 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
475 /* XXX write a loop, not an unrolled loop */
477 mips_lw (code, mips_at, sreg, soffset);
478 mips_sw (code, mips_at, dreg, doffset);
487 * mono_arch_get_argument_info:
488 * @csig: a method signature
489 * @param_count: the number of parameters to consider
490 * @arg_info: an array to store the result infos
492 * Gathers information on parameters such as size, alignment and
493 * padding. arg_info should be large enought to hold param_count + 1 entries.
495 * Returns the size of the activation frame.
498 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
500 int k, frame_size = 0;
501 guint32 size, align, pad;
504 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
505 frame_size += sizeof (gpointer);
509 arg_info [0].offset = offset;
512 frame_size += sizeof (gpointer);
516 arg_info [0].size = frame_size;
518 for (k = 0; k < param_count; k++) {
519 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
521 /* ignore alignment for now */
524 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
525 arg_info [k].pad = pad;
527 arg_info [k + 1].pad = 0;
528 arg_info [k + 1].size = size;
530 arg_info [k + 1].offset = offset;
534 align = MONO_ARCH_FRAME_ALIGNMENT;
535 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
536 arg_info [k].pad = pad;
543 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
546 return (gpointer)regs [mips_a0];
550 * Initialize the cpu to execute managed code.
553 mono_arch_cpu_init (void)
555 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
564 ls_word_offset = ls_word_idx * 4;
565 ms_word_offset = ms_word_idx * 4;
569 * Initialize architecture specific code.
572 mono_arch_init (void)
574 InitializeCriticalSection (&mini_arch_mutex);
576 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
577 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
578 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
582 * Cleanup architecture specific code.
585 mono_arch_cleanup (void)
587 DeleteCriticalSection (&mini_arch_mutex);
591 * This function returns the optimizations supported on this cpu.
594 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
598 /* no mips-specific optimizations yet */
604 is_regsize_var (MonoType *t) {
607 t = mono_type_get_underlying_type (t);
611 #if (SIZEOF_REGISTER == 8)
618 case MONO_TYPE_FNPTR:
620 case MONO_TYPE_OBJECT:
621 case MONO_TYPE_STRING:
622 case MONO_TYPE_CLASS:
623 case MONO_TYPE_SZARRAY:
624 case MONO_TYPE_ARRAY:
626 case MONO_TYPE_GENERICINST:
627 if (!mono_type_generic_inst_is_valuetype (t))
630 case MONO_TYPE_VALUETYPE:
637 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
642 for (i = 0; i < cfg->num_varinfo; i++) {
643 MonoInst *ins = cfg->varinfo [i];
644 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
647 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
650 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
653 /* we can only allocate 32 bit values */
654 if (is_regsize_var (ins->inst_vtype)) {
655 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
656 g_assert (i == vmv->idx);
657 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
665 mono_arch_get_global_int_regs (MonoCompile *cfg)
669 regs = g_list_prepend (regs, (gpointer)mips_s0);
670 regs = g_list_prepend (regs, (gpointer)mips_s1);
671 regs = g_list_prepend (regs, (gpointer)mips_s2);
672 regs = g_list_prepend (regs, (gpointer)mips_s3);
673 regs = g_list_prepend (regs, (gpointer)mips_s4);
674 //regs = g_list_prepend (regs, (gpointer)mips_s5);
675 regs = g_list_prepend (regs, (gpointer)mips_s6);
676 regs = g_list_prepend (regs, (gpointer)mips_s7);
682 * mono_arch_regalloc_cost:
684 * Return the cost, in number of memory references, of the action of
685 * allocating the variable VMV into a register during global register
689 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
696 args_onto_stack (CallInfo *info)
698 g_assert (!info->on_stack);
699 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
700 info->on_stack = TRUE;
701 info->stack_size = MIPS_STACK_PARAM_OFFSET;
704 #if _MIPS_SIM == _ABIO32
706 * O32 calling convention version
710 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
711 /* First, see if we need to drop onto the stack */
712 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
713 args_onto_stack (info);
715 /* Now, place the argument */
716 if (info->on_stack) {
717 ainfo->storage = ArgOnStack;
718 ainfo->reg = mips_sp; /* in the caller */
719 ainfo->offset = info->stack_size;
722 ainfo->storage = ArgInIReg;
723 ainfo->reg = info->gr;
725 info->gr_passed = TRUE;
727 info->stack_size += 4;
731 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
732 /* First, see if we need to drop onto the stack */
733 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
734 args_onto_stack (info);
736 /* Now, place the argument */
737 if (info->on_stack) {
738 g_assert (info->stack_size % 4 == 0);
739 info->stack_size += (info->stack_size % 8);
741 ainfo->storage = ArgOnStack;
742 ainfo->reg = mips_sp; /* in the caller */
743 ainfo->offset = info->stack_size;
746 // info->gr must be a0 or a2
747 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
748 g_assert(info->gr <= MIPS_LAST_ARG_REG);
750 ainfo->storage = ArgInIReg;
751 ainfo->reg = info->gr;
753 info->gr_passed = TRUE;
755 info->stack_size += 8;
759 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
760 /* First, see if we need to drop onto the stack */
761 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
762 args_onto_stack (info);
764 /* Now, place the argument */
765 if (info->on_stack) {
766 ainfo->storage = ArgOnStack;
767 ainfo->reg = mips_sp; /* in the caller */
768 ainfo->offset = info->stack_size;
771 /* Only use FP regs for args if no int args passed yet */
772 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
773 ainfo->storage = ArgInFReg;
774 ainfo->reg = info->fr;
775 /* Even though it's a single-precision float, it takes up two FP regs */
777 /* FP and GP slots do not overlap */
781 /* Passing single-precision float arg in a GP register
782 * such as: func (0, 1.0, 2, 3);
783 * In this case, only one 'gr' register is consumed.
785 ainfo->storage = ArgInIReg;
786 ainfo->reg = info->gr;
789 info->gr_passed = TRUE;
792 info->stack_size += 4;
796 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
797 /* First, see if we need to drop onto the stack */
798 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
799 args_onto_stack (info);
801 /* Now, place the argument */
802 if (info->on_stack) {
803 g_assert(info->stack_size % 4 == 0);
804 info->stack_size += (info->stack_size % 8);
806 ainfo->storage = ArgOnStack;
807 ainfo->reg = mips_sp; /* in the caller */
808 ainfo->offset = info->stack_size;
811 /* Only use FP regs for args if no int args passed yet */
812 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
813 ainfo->storage = ArgInFReg;
814 ainfo->reg = info->fr;
816 /* FP and GP slots do not overlap */
820 // info->gr must be a0 or a2
821 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
822 g_assert(info->gr <= MIPS_LAST_ARG_REG);
824 ainfo->storage = ArgInIReg;
825 ainfo->reg = info->gr;
827 info->gr_passed = TRUE;
830 info->stack_size += 8;
832 #elif _MIPS_SIM == _ABIN32
834 * N32 calling convention version
838 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
839 /* First, see if we need to drop onto the stack */
840 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
841 args_onto_stack (info);
843 /* Now, place the argument */
844 if (info->on_stack) {
845 ainfo->storage = ArgOnStack;
846 ainfo->reg = mips_sp; /* in the caller */
847 ainfo->offset = info->stack_size;
848 info->stack_size += SIZEOF_REGISTER;
851 ainfo->storage = ArgInIReg;
852 ainfo->reg = info->gr;
854 info->gr_passed = TRUE;
859 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
860 /* First, see if we need to drop onto the stack */
861 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
862 args_onto_stack (info);
864 /* Now, place the argument */
865 if (info->on_stack) {
866 g_assert (info->stack_size % 4 == 0);
867 info->stack_size += (info->stack_size % 8);
869 ainfo->storage = ArgOnStack;
870 ainfo->reg = mips_sp; /* in the caller */
871 ainfo->offset = info->stack_size;
872 info->stack_size += SIZEOF_REGISTER;
875 g_assert (info->gr <= MIPS_LAST_ARG_REG);
877 ainfo->storage = ArgInIReg;
878 ainfo->reg = info->gr;
880 info->gr_passed = TRUE;
885 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
886 /* First, see if we need to drop onto the stack */
887 if (!info->on_stack) {
888 if (info->gr > MIPS_LAST_ARG_REG)
889 args_onto_stack (info);
890 else if (info->fr > MIPS_LAST_FPARG_REG)
891 args_onto_stack (info);
894 /* Now, place the argument */
895 if (info->on_stack) {
896 ainfo->storage = ArgOnStack;
897 ainfo->reg = mips_sp; /* in the caller */
898 ainfo->offset = info->stack_size;
899 info->stack_size += FREG_SIZE;
902 ainfo->storage = ArgInFReg;
903 ainfo->reg = info->fr;
905 /* FP and GP slots do not overlap */
911 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
912 /* First, see if we need to drop onto the stack */
913 if (!info->on_stack) {
914 if (info->gr > MIPS_LAST_ARG_REG)
915 args_onto_stack (info);
916 else if (info->fr > MIPS_LAST_FPARG_REG)
917 args_onto_stack (info);
920 /* Now, place the argument */
921 if (info->on_stack) {
922 g_assert(info->stack_size % 4 == 0);
923 info->stack_size += (info->stack_size % 8);
925 ainfo->storage = ArgOnStack;
926 ainfo->reg = mips_sp; /* in the caller */
927 ainfo->offset = info->stack_size;
928 info->stack_size += FREG_SIZE;
931 ainfo->storage = ArgInFReg;
932 ainfo->reg = info->fr;
934 /* FP and GP slots do not overlap */
941 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
944 int n = sig->hasthis + sig->param_count;
946 MonoType* simpletype;
948 gboolean is_pinvoke = sig->pinvoke;
951 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
953 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
955 cinfo->fr = MIPS_FIRST_FPARG_REG;
956 cinfo->gr = MIPS_FIRST_ARG_REG;
957 cinfo->stack_size = 0;
959 DEBUG(printf("calculate_sizes\n"));
961 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
965 /* handle returning a struct */
966 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
967 cinfo->struct_ret = cinfo->gr;
968 add_int32_arg (cinfo, &cinfo->ret);
972 add_int32_arg (cinfo, cinfo->args + n);
977 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
978 * the first argument, allowing 'this' to be always passed in the first arg reg.
979 * Also do this if the first argument is a reference type, since virtual calls
980 * are sometimes made using calli without sig->hasthis set, like in the delegate
983 if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (NULL, sig->params [0]))))) {
985 add_int32_arg (cinfo, cinfo->args + n);
988 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
992 add_int32_arg (cinfo, &cinfo->ret);
993 cinfo->struct_ret = cinfo->ret.reg;
997 add_int32_arg (cinfo, cinfo->args + n);
1001 if (cinfo->vtype_retaddr) {
1002 add_int32_arg (cinfo, &cinfo->ret);
1003 cinfo->struct_ret = cinfo->ret.reg;
1008 DEBUG(printf("params: %d\n", sig->param_count));
1009 for (i = pstart; i < sig->param_count; ++i) {
1010 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1011 /* Prevent implicit arguments and sig_cookie from
1012 being passed in registers */
1013 args_onto_stack (cinfo);
1014 /* Emit the signature cookie just before the implicit arguments */
1015 add_int32_arg (cinfo, &cinfo->sig_cookie);
1017 DEBUG(printf("param %d: ", i));
1018 if (sig->params [i]->byref) {
1019 DEBUG(printf("byref\n"));
1020 add_int32_arg (cinfo, &cinfo->args[n]);
1024 simpletype = mono_type_get_underlying_type (sig->params [i]);
1025 switch (simpletype->type) {
1026 case MONO_TYPE_BOOLEAN:
1029 DEBUG(printf("1 byte\n"));
1030 cinfo->args [n].size = 1;
1031 add_int32_arg (cinfo, &cinfo->args[n]);
1034 case MONO_TYPE_CHAR:
1037 DEBUG(printf("2 bytes\n"));
1038 cinfo->args [n].size = 2;
1039 add_int32_arg (cinfo, &cinfo->args[n]);
1044 DEBUG(printf("4 bytes\n"));
1045 cinfo->args [n].size = 4;
1046 add_int32_arg (cinfo, &cinfo->args[n]);
1052 case MONO_TYPE_FNPTR:
1053 case MONO_TYPE_CLASS:
1054 case MONO_TYPE_OBJECT:
1055 case MONO_TYPE_STRING:
1056 case MONO_TYPE_SZARRAY:
1057 case MONO_TYPE_ARRAY:
1058 cinfo->args [n].size = sizeof (gpointer);
1059 add_int32_arg (cinfo, &cinfo->args[n]);
1062 case MONO_TYPE_GENERICINST:
1063 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1064 cinfo->args [n].size = sizeof (gpointer);
1065 add_int32_arg (cinfo, &cinfo->args[n]);
1070 case MONO_TYPE_VALUETYPE: {
1073 int has_offset = FALSE;
1075 gint size, alignment;
1078 klass = mono_class_from_mono_type (sig->params [i]);
1080 size = mono_class_native_size (klass, NULL);
1082 size = mono_class_value_size (klass, NULL);
1083 alignment = mono_class_min_align (klass);
1084 #if MIPS_PASS_STRUCTS_BY_VALUE
1085 /* Need to do alignment if struct contains long or double */
1086 if (alignment > 4) {
1087 /* Drop onto stack *before* looking at
1088 stack_size, if required. */
1089 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1090 args_onto_stack (cinfo);
1091 if (cinfo->stack_size & (alignment - 1)) {
1092 add_int32_arg (cinfo, &dummy_arg);
1094 g_assert (!(cinfo->stack_size & (alignment - 1)));
1098 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1099 mono_class_native_size (sig->params [i]->data.klass, NULL),
1100 cinfo->stack_size, alignment);
1102 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1103 g_assert (cinfo->args [n].size == 0);
1104 g_assert (cinfo->args [n].vtsize == 0);
1105 for (j = 0; j < nwords; ++j) {
1107 add_int32_arg (cinfo, &cinfo->args [n]);
1108 if (cinfo->on_stack)
1111 add_int32_arg (cinfo, &dummy_arg);
1112 if (!has_offset && cinfo->on_stack) {
1113 cinfo->args [n].offset = dummy_arg.offset;
1117 if (cinfo->on_stack)
1118 cinfo->args [n].vtsize += 1;
1120 cinfo->args [n].size += 1;
1122 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1123 cinfo->args [n].storage = ArgStructByVal;
1125 add_int32_arg (cinfo, &cinfo->args[n]);
1126 cinfo->args [n].storage = ArgStructByAddr;
1131 case MONO_TYPE_TYPEDBYREF: {
1132 /* keep in sync or merge with the valuetype case */
1133 #if MIPS_PASS_STRUCTS_BY_VALUE
1135 int size = sizeof (MonoTypedRef);
1136 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1137 cinfo->args [n].storage = ArgStructByVal;
1138 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
1139 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
1140 int n_in_regs = rest >= nwords? nwords: rest;
1141 cinfo->args [n].size = n_in_regs;
1142 cinfo->args [n].vtsize = nwords - n_in_regs;
1143 cinfo->args [n].reg = cinfo->gr;
1144 cinfo->gr += n_in_regs;
1145 cinfo->gr_passed = TRUE;
1147 cinfo->args [n].size = 0;
1148 cinfo->args [n].vtsize = nwords;
1150 if (cinfo->args [n].vtsize > 0) {
1151 if (!cinfo->on_stack)
1152 args_onto_stack (cinfo);
1153 g_assert(cinfo->on_stack);
1154 cinfo->args [n].offset = cinfo->stack_size;
1155 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
1156 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
1160 add_int32_arg (cinfo, &cinfo->args[n]);
1161 cinfo->args [n].storage = ArgStructByAddr;
1168 DEBUG(printf("8 bytes\n"));
1169 cinfo->args [n].size = 8;
1170 add_int64_arg (cinfo, &cinfo->args[n]);
1174 DEBUG(printf("R4\n"));
1175 cinfo->args [n].size = 4;
1176 add_float32_arg (cinfo, &cinfo->args[n]);
1180 DEBUG(printf("R8\n"));
1181 cinfo->args [n].size = 8;
1182 add_float64_arg (cinfo, &cinfo->args[n]);
1186 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1191 simpletype = mono_type_get_underlying_type (sig->ret);
1192 switch (simpletype->type) {
1193 case MONO_TYPE_BOOLEAN:
1198 case MONO_TYPE_CHAR:
1204 case MONO_TYPE_FNPTR:
1205 case MONO_TYPE_CLASS:
1206 case MONO_TYPE_OBJECT:
1207 case MONO_TYPE_SZARRAY:
1208 case MONO_TYPE_ARRAY:
1209 case MONO_TYPE_STRING:
1210 cinfo->ret.reg = mips_v0;
1214 cinfo->ret.reg = mips_v0;
1218 cinfo->ret.reg = mips_f0;
1219 cinfo->ret.storage = ArgInFReg;
1221 case MONO_TYPE_GENERICINST:
1222 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1223 cinfo->ret.reg = mips_v0;
1227 case MONO_TYPE_VALUETYPE:
1229 case MONO_TYPE_TYPEDBYREF:
1230 case MONO_TYPE_VOID:
1233 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1237 /* align stack size to 16 */
1238 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1240 cinfo->stack_usage = cinfo->stack_size;
1246 * Set var information according to the calling convention. mips version.
1247 * The locals var stuff should most likely be split in another method.
1250 mono_arch_allocate_vars (MonoCompile *cfg)
1252 MonoMethodSignature *sig;
1253 MonoMethodHeader *header;
1255 int i, offset, size, align, curinst;
1256 int frame_reg = mips_sp;
1257 guint32 iregs_to_save = 0;
1259 guint32 fregs_to_restore;
1263 sig = mono_method_signature (cfg->method);
1265 if (!cfg->arch.cinfo)
1266 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1267 cinfo = cfg->arch.cinfo;
1269 /* spill down, we'll fix it in a separate pass */
1270 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1272 /* allow room for the vararg method args: void* and long/double */
1273 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1274 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1276 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1277 * call convs needs to be handled this way.
1279 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1280 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1282 /* gtk-sharp and other broken code will dllimport vararg functions even with
1283 * non-varargs signatures. Since there is little hope people will get this right
1284 * we assume they won't.
1286 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1287 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1289 /* a0-a3 always present */
1290 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1292 header = cfg->header;
1295 * We use the frame register also for any method that has
1296 * exception clauses. This way, when the handlers are called,
1297 * the code will reference local variables using the frame reg instead of
1298 * the stack pointer: if we had to restore the stack pointer, we'd
1299 * corrupt the method frames that are already on the stack (since
1300 * filters get called before stack unwinding happens) when the filter
1301 * code would call any method (this also applies to finally etc.).
1304 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1305 frame_reg = mips_fp;
1306 cfg->frame_reg = frame_reg;
1307 if (frame_reg != mips_sp) {
1308 cfg->used_int_regs |= 1 << frame_reg;
1313 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1314 /* FIXME: handle long and FP values */
1315 switch (mono_type_get_underlying_type (sig->ret)->type) {
1316 case MONO_TYPE_VOID:
1320 cfg->ret->opcode = OP_REGVAR;
1321 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1324 cfg->ret->opcode = OP_REGVAR;
1325 cfg->ret->inst_c0 = mips_v0;
1329 /* Space for outgoing parameters, including a0-a3 */
1330 offset += cfg->param_area;
1332 /* allow room to save the return value (if it's a struct) */
1333 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1336 if (sig->call_convention == MONO_CALL_VARARG) {
1337 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1340 /* Now handle the local variables */
1342 curinst = cfg->locals_start;
1343 for (i = curinst; i < cfg->num_varinfo; ++i) {
1344 inst = cfg->varinfo [i];
1345 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1348 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1349 * pinvoke wrappers when they call functions returning structure
1351 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1352 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1354 size = mono_type_size (inst->inst_vtype, &align);
1356 offset += align - 1;
1357 offset &= ~(align - 1);
1358 inst->inst_offset = offset;
1359 inst->opcode = OP_REGOFFSET;
1360 inst->inst_basereg = frame_reg;
1362 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1365 /* Space for LMF (if needed) */
1367 if (cfg->method->save_lmf) {
1368 /* align the offset to 16 bytes */
1369 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1370 cfg->arch.lmf_offset = offset;
1371 offset += sizeof (MonoLMF);
1375 /* Space for saved registers */
1376 cfg->arch.iregs_offset = offset;
1378 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1380 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1382 if (iregs_to_save) {
1383 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1384 if (iregs_to_save & (1 << i)) {
1385 offset += SIZEOF_REGISTER;
1390 /* saved float registers */
1392 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1393 if (fregs_to_restore) {
1394 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1395 if (fregs_to_restore & (1 << i)) {
1396 offset += sizeof(double);
1402 #if _MIPS_SIM == _ABIO32
1403 /* Now add space for saving the ra */
1404 offset += SIZEOF_VOID_P;
1407 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1408 cfg->stack_offset = offset;
1409 cfg->arch.local_alloc_offset = cfg->stack_offset;
1413 * Now allocate stack slots for the int arg regs (a0 - a3)
1414 * On MIPS o32, these are just above the incoming stack pointer
1415 * Even if the arg has been assigned to a regvar, it gets a stack slot
1418 /* Return struct-by-value results in a hidden first argument */
1419 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1420 cfg->vret_addr->opcode = OP_REGOFFSET;
1421 cfg->vret_addr->inst_c0 = mips_a0;
1422 cfg->vret_addr->inst_offset = offset;
1423 cfg->vret_addr->inst_basereg = frame_reg;
1424 offset += SIZEOF_REGISTER;
1427 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1428 inst = cfg->args [i];
1429 if (inst->opcode != OP_REGVAR) {
1431 ArgInfo *ainfo = &cinfo->args [i];
1433 if (sig->hasthis && (i == 0))
1434 arg_type = &mono_defaults.object_class->byval_arg;
1436 arg_type = sig->params [i - sig->hasthis];
1438 inst->opcode = OP_REGOFFSET;
1439 size = mono_type_size (arg_type, &align);
1441 if (size < SIZEOF_REGISTER) {
1442 size = SIZEOF_REGISTER;
1443 align = SIZEOF_REGISTER;
1445 inst->inst_basereg = frame_reg;
1446 offset = (offset + align - 1) & ~(align - 1);
1447 inst->inst_offset = offset;
1449 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1450 cfg->sig_cookie += size;
1451 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1454 #if _MIPS_SIM == _ABIO32
1455 /* o32: Even a0-a3 get stack slots */
1456 size = SIZEOF_REGISTER;
1457 align = SIZEOF_REGISTER;
1458 inst->inst_basereg = frame_reg;
1459 offset = (offset + align - 1) & ~(align - 1);
1460 inst->inst_offset = offset;
1462 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1463 cfg->sig_cookie += size;
1464 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1468 #if _MIPS_SIM == _ABIN32
1469 /* Now add space for saving the ra */
1470 offset += SIZEOF_VOID_P;
1473 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1474 cfg->stack_offset = offset;
1475 cfg->arch.local_alloc_offset = cfg->stack_offset;
1480 mono_arch_create_vars (MonoCompile *cfg)
1482 MonoMethodSignature *sig;
1484 sig = mono_method_signature (cfg->method);
1486 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1487 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1488 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1489 printf ("vret_addr = ");
1490 mono_print_ins (cfg->vret_addr);
1495 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1496 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1500 * take the arguments and generate the arch-specific
1501 * instructions to properly call the function in call.
1502 * This includes pushing, moving arguments to the right register
1504 * Issue: who does the spilling if needed, and when?
1507 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1509 int sig_reg = mono_alloc_ireg (cfg);
1511 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1512 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1513 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1517 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1520 MonoMethodSignature *sig;
1525 sig = call->signature;
1526 n = sig->param_count + sig->hasthis;
1528 cinfo = get_call_info (NULL, cfg->mempool, sig);
1529 if (cinfo->struct_ret)
1530 call->used_iregs |= 1 << cinfo->struct_ret;
1532 for (i = 0; i < n; ++i) {
1533 ArgInfo *ainfo = cinfo->args + i;
1536 if (i >= sig->hasthis)
1537 t = sig->params [i - sig->hasthis];
1539 t = &mono_defaults.int_class->byval_arg;
1540 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1542 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1543 emit_sig_cookie (cfg, call, cinfo);
1544 if (is_virtual && i == 0) {
1545 /* the argument will be attached to the call instrucion */
1546 in = call->args [i];
1547 call->used_iregs |= 1 << ainfo->reg;
1550 in = call->args [i];
1551 if (ainfo->storage == ArgInIReg) {
1552 #if SIZEOF_REGISTER == 4
1553 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1554 MONO_INST_NEW (cfg, ins, OP_MOVE);
1555 ins->dreg = mono_alloc_ireg (cfg);
1556 ins->sreg1 = in->dreg + 1;
1557 MONO_ADD_INS (cfg->cbb, ins);
1558 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ls_word_idx, FALSE);
1560 MONO_INST_NEW (cfg, ins, OP_MOVE);
1561 ins->dreg = mono_alloc_ireg (cfg);
1562 ins->sreg1 = in->dreg + 2;
1563 MONO_ADD_INS (cfg->cbb, ins);
1564 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + ms_word_idx, FALSE);
1567 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1570 #if PROMOTE_R4_TO_R8
1571 /* ??? - convert to single first? */
1572 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1573 ins->dreg = mono_alloc_freg (cfg);
1574 ins->sreg1 = in->dreg;
1575 MONO_ADD_INS (cfg->cbb, ins);
1580 /* trying to load float value into int registers */
1581 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1582 ins->dreg = mono_alloc_ireg (cfg);
1584 MONO_ADD_INS (cfg->cbb, ins);
1585 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1586 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1587 /* trying to load float value into int registers */
1588 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1589 ins->dreg = mono_alloc_ireg (cfg);
1590 ins->sreg1 = in->dreg;
1591 MONO_ADD_INS (cfg->cbb, ins);
1592 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1594 MONO_INST_NEW (cfg, ins, OP_MOVE);
1595 ins->dreg = mono_alloc_ireg (cfg);
1596 ins->sreg1 = in->dreg;
1597 MONO_ADD_INS (cfg->cbb, ins);
1598 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1600 } else if (ainfo->storage == ArgStructByAddr) {
1601 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1602 ins->opcode = OP_OUTARG_VT;
1603 ins->sreg1 = in->dreg;
1604 ins->klass = in->klass;
1605 ins->inst_p0 = call;
1606 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1607 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1608 MONO_ADD_INS (cfg->cbb, ins);
1609 } else if (ainfo->storage == ArgStructByVal) {
1610 /* this is further handled in mono_arch_emit_outarg_vt () */
1611 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1612 ins->opcode = OP_OUTARG_VT;
1613 ins->sreg1 = in->dreg;
1614 ins->klass = in->klass;
1615 ins->inst_p0 = call;
1616 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1617 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1618 MONO_ADD_INS (cfg->cbb, ins);
1619 } else if (ainfo->storage == ArgOnStack) {
1620 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1621 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1622 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1623 if (t->type == MONO_TYPE_R8)
1624 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1626 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1628 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1630 } else if (ainfo->storage == ArgInFReg) {
1631 if (t->type == MONO_TYPE_VALUETYPE) {
1632 /* this is further handled in mono_arch_emit_outarg_vt () */
1633 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1634 ins->opcode = OP_OUTARG_VT;
1635 ins->sreg1 = in->dreg;
1636 ins->klass = in->klass;
1637 ins->inst_p0 = call;
1638 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1639 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1640 MONO_ADD_INS (cfg->cbb, ins);
1642 cfg->flags |= MONO_CFG_HAS_FPOUT;
1644 int dreg = mono_alloc_freg (cfg);
1646 if (ainfo->size == 4) {
1647 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1649 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1651 ins->sreg1 = in->dreg;
1652 MONO_ADD_INS (cfg->cbb, ins);
1655 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1656 cfg->flags |= MONO_CFG_HAS_FPOUT;
1659 g_assert_not_reached ();
1663 /* Emit the signature cookie in the case that there is no
1664 additional argument */
1665 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1666 emit_sig_cookie (cfg, call, cinfo);
1668 if (cinfo->struct_ret) {
1671 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1672 vtarg->sreg1 = call->vret_var->dreg;
1673 vtarg->dreg = mono_alloc_preg (cfg);
1674 MONO_ADD_INS (cfg->cbb, vtarg);
1676 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1680 * Reverse the call->out_args list.
1683 MonoInst *prev = NULL, *list = call->out_args, *next;
1690 call->out_args = prev;
1693 call->stack_usage = cinfo->stack_usage;
1694 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1695 #if _MIPS_SIM == _ABIO32
1696 /* a0-a3 always present */
1697 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1699 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1700 cfg->flags |= MONO_CFG_HAS_CALLS;
1702 * should set more info in call, such as the stack space
1703 * used by the args that needs to be added back to esp
1708 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1710 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1711 ArgInfo *ainfo = ins->inst_p1;
1712 int ovf_size = ainfo->vtsize;
1713 int doffset = ainfo->offset;
1714 int i, soffset, dreg;
1716 if (ainfo->storage == ArgStructByVal) {
1718 if (cfg->verbose_level > 0) {
1719 char* nm = mono_method_full_name (cfg->method, TRUE);
1720 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1721 nm, doffset, ainfo->size, ovf_size);
1727 for (i = 0; i < ainfo->size; ++i) {
1728 dreg = mono_alloc_ireg (cfg);
1729 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1730 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1731 soffset += SIZEOF_REGISTER;
1733 if (ovf_size != 0) {
1734 mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1736 } else if (ainfo->storage == ArgInFReg) {
1737 int tmpr = mono_alloc_freg (cfg);
1739 if (ainfo->size == 4)
1740 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1742 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1743 dreg = mono_alloc_freg (cfg);
1744 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1745 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1747 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1751 /* FIXME: alignment? */
1752 if (call->signature->pinvoke) {
1753 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1754 vtcopy->backend.is_pinvoke = 1;
1756 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1759 g_assert (ovf_size > 0);
1761 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1762 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1765 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1767 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1772 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1774 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1775 mono_method_signature (method)->ret);
1778 #if (SIZEOF_REGISTER == 4)
1779 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1782 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1783 ins->sreg1 = val->dreg + 1;
1784 ins->sreg2 = val->dreg + 2;
1785 MONO_ADD_INS (cfg->cbb, ins);
1789 if (ret->type == MONO_TYPE_R8) {
1790 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1793 if (ret->type == MONO_TYPE_R4) {
1794 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1798 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1802 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1804 MonoInst *ins, *n, *last_ins = NULL;
1806 if (cfg->verbose_level > 2)
1807 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1810 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1811 if (cfg->verbose_level > 2)
1812 mono_print_ins_index (0, ins);
1814 switch (ins->opcode) {
1816 case OP_LOAD_MEMBASE:
1817 case OP_LOADI4_MEMBASE:
1819 * OP_IADD reg2, reg1, const1
1820 * OP_LOAD_MEMBASE const2(reg2), reg3
1822 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1824 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)){
1825 int const1 = last_ins->inst_imm;
1826 int const2 = ins->inst_offset;
1828 if (mips_is_imm16 (const1 + const2)) {
1829 ins->inst_basereg = last_ins->sreg1;
1830 ins->inst_offset = const1 + const2;
1840 bb->last_ins = last_ins;
1844 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1846 MonoInst *ins, *n, *last_ins = NULL;
1849 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1850 MonoInst *last_ins = ins->prev;
1852 switch (ins->opcode) {
1854 /* remove unnecessary multiplication with 1 */
1855 if (ins->inst_imm == 1) {
1856 if (ins->dreg != ins->sreg1) {
1857 ins->opcode = OP_MOVE;
1859 MONO_DELETE_INS (bb, ins);
1863 int power2 = mono_is_power_of_two (ins->inst_imm);
1865 ins->opcode = OP_SHL_IMM;
1866 ins->inst_imm = power2;
1870 case OP_LOAD_MEMBASE:
1871 case OP_LOADI4_MEMBASE:
1873 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1874 * OP_LOAD_MEMBASE offset(basereg), reg
1876 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1877 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1878 ins->inst_basereg == last_ins->inst_destbasereg &&
1879 ins->inst_offset == last_ins->inst_offset) {
1880 if (ins->dreg == last_ins->sreg1) {
1881 MONO_DELETE_INS (bb, ins);
1884 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1885 ins->opcode = OP_MOVE;
1886 ins->sreg1 = last_ins->sreg1;
1891 * Note: reg1 must be different from the basereg in the second load
1892 * OP_LOAD_MEMBASE offset(basereg), reg1
1893 * OP_LOAD_MEMBASE offset(basereg), reg2
1895 * OP_LOAD_MEMBASE offset(basereg), reg1
1896 * OP_MOVE reg1, reg2
1898 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1899 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1900 ins->inst_basereg != last_ins->dreg &&
1901 ins->inst_basereg == last_ins->inst_basereg &&
1902 ins->inst_offset == last_ins->inst_offset) {
1904 if (ins->dreg == last_ins->dreg) {
1905 MONO_DELETE_INS (bb, ins);
1908 ins->opcode = OP_MOVE;
1909 ins->sreg1 = last_ins->dreg;
1912 //g_assert_not_reached ();
1917 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1918 * OP_LOAD_MEMBASE offset(basereg), reg
1920 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1921 * OP_ICONST reg, imm
1923 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1924 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1925 ins->inst_basereg == last_ins->inst_destbasereg &&
1926 ins->inst_offset == last_ins->inst_offset) {
1927 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1928 ins->opcode = OP_ICONST;
1929 ins->inst_c0 = last_ins->inst_imm;
1930 g_assert_not_reached (); // check this rule
1935 case OP_LOADU1_MEMBASE:
1936 case OP_LOADI1_MEMBASE:
1937 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1938 ins->inst_basereg == last_ins->inst_destbasereg &&
1939 ins->inst_offset == last_ins->inst_offset) {
1940 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1941 ins->sreg1 = last_ins->sreg1;
1944 case OP_LOADU2_MEMBASE:
1945 case OP_LOADI2_MEMBASE:
1946 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1947 ins->inst_basereg == last_ins->inst_destbasereg &&
1948 ins->inst_offset == last_ins->inst_offset) {
1949 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1950 ins->sreg1 = last_ins->sreg1;
1953 case OP_ICONV_TO_I4:
1954 case OP_ICONV_TO_U4:
1956 ins->opcode = OP_MOVE;
1960 if (ins->dreg == ins->sreg1) {
1961 MONO_DELETE_INS (bb, ins);
1965 * OP_MOVE sreg, dreg
1966 * OP_MOVE dreg, sreg
1968 if (last_ins && last_ins->opcode == OP_MOVE &&
1969 ins->sreg1 == last_ins->dreg &&
1970 ins->dreg == last_ins->sreg1) {
1971 MONO_DELETE_INS (bb, ins);
1979 bb->last_ins = last_ins;
1983 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
1991 switch (ins->opcode) {
1994 case OP_LCOMPARE_IMM:
1995 mono_print_ins (ins);
1996 g_assert_not_reached ();
1999 tmp1 = mono_alloc_ireg (cfg);
2000 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2001 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2002 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2003 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2008 tmp1 = mono_alloc_ireg (cfg);
2009 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2010 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2011 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2012 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
2017 tmp1 = mono_alloc_ireg (cfg);
2018 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2019 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2020 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2021 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2026 tmp1 = mono_alloc_ireg (cfg);
2027 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
2028 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2029 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
2030 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2042 mono_print_ins (ins);
2043 g_assert_not_reached ();
2046 tmp1 = mono_alloc_ireg (cfg);
2047 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2048 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2049 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2050 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2058 case OP_LCONV_TO_I1:
2059 case OP_LCONV_TO_I2:
2060 case OP_LCONV_TO_I4:
2061 case OP_LCONV_TO_I8:
2062 case OP_LCONV_TO_R4:
2063 case OP_LCONV_TO_R8:
2064 case OP_LCONV_TO_U4:
2065 case OP_LCONV_TO_U8:
2066 case OP_LCONV_TO_U2:
2067 case OP_LCONV_TO_U1:
2069 case OP_LCONV_TO_OVF_I:
2070 case OP_LCONV_TO_OVF_U:
2072 mono_print_ins (ins);
2073 g_assert_not_reached ();
2076 tmp1 = mono_alloc_ireg (cfg);
2077 tmp2 = mono_alloc_ireg (cfg);
2078 tmp3 = mono_alloc_ireg (cfg);
2079 tmp4 = mono_alloc_ireg (cfg);
2080 tmp5 = mono_alloc_ireg (cfg);
2082 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2084 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2085 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2087 /* add the high 32-bits, and add in the carry from the low 32-bits */
2088 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2089 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2091 /* Overflow happens if
2092 * neg + neg = pos or
2094 * XOR of the high bits returns 0 if the signs match
2095 * XOR of that with the high bit of the result return 1 if overflow.
2098 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2099 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2101 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2102 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2103 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2105 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2106 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2107 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2109 /* Now, if (tmp4 == 0) then overflow */
2110 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2114 case OP_LADD_OVF_UN:
2115 tmp1 = mono_alloc_ireg (cfg);
2116 tmp2 = mono_alloc_ireg (cfg);
2118 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2119 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2120 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2121 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2122 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2123 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2128 case OP_LMUL_OVF_UN:
2129 mono_print_ins (ins);
2130 g_assert_not_reached ();
2133 tmp1 = mono_alloc_ireg (cfg);
2134 tmp2 = mono_alloc_ireg (cfg);
2135 tmp3 = mono_alloc_ireg (cfg);
2136 tmp4 = mono_alloc_ireg (cfg);
2137 tmp5 = mono_alloc_ireg (cfg);
2139 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2141 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2142 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2143 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2145 /* Overflow happens if
2146 * neg - pos = pos or
2148 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2150 * tmp1 = (lhs ^ rhs)
2151 * tmp2 = (lhs ^ result)
2152 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2155 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2156 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2157 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2158 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2160 /* Now, if (tmp4 == 1) then overflow */
2161 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2165 case OP_LSUB_OVF_UN:
2166 tmp1 = mono_alloc_ireg (cfg);
2167 tmp2 = mono_alloc_ireg (cfg);
2169 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2170 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2171 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2172 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2174 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2175 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2179 case OP_LCONV_TO_OVF_I1_UN:
2180 case OP_LCONV_TO_OVF_I2_UN:
2181 case OP_LCONV_TO_OVF_I4_UN:
2182 case OP_LCONV_TO_OVF_I8_UN:
2183 case OP_LCONV_TO_OVF_U1_UN:
2184 case OP_LCONV_TO_OVF_U2_UN:
2185 case OP_LCONV_TO_OVF_U4_UN:
2186 case OP_LCONV_TO_OVF_U8_UN:
2187 case OP_LCONV_TO_OVF_I_UN:
2188 case OP_LCONV_TO_OVF_U_UN:
2189 case OP_LCONV_TO_OVF_I1:
2190 case OP_LCONV_TO_OVF_U1:
2191 case OP_LCONV_TO_OVF_I2:
2192 case OP_LCONV_TO_OVF_U2:
2193 case OP_LCONV_TO_OVF_I4:
2194 case OP_LCONV_TO_OVF_U4:
2195 case OP_LCONV_TO_OVF_I8:
2196 case OP_LCONV_TO_OVF_U8:
2204 case OP_LCONV_TO_R_UN:
2210 case OP_LSHR_UN_IMM:
2212 case OP_LDIV_UN_IMM:
2214 case OP_LREM_UN_IMM:
2225 mono_print_ins (ins);
2226 g_assert_not_reached ();
2228 case OP_LCONV_TO_R8_2:
2229 case OP_LCONV_TO_R4_2:
2230 case OP_LCONV_TO_R_UN_2:
2232 case OP_LCONV_TO_OVF_I4_2:
2233 tmp1 = mono_alloc_ireg (cfg);
2235 /* Overflows if reg2 != sign extension of reg1 */
2236 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2237 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2238 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2246 mono_print_ins (ins);
2247 g_assert_not_reached ();
2255 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2263 switch (ins->opcode) {
2265 tmp1 = mono_alloc_ireg (cfg);
2266 tmp2 = mono_alloc_ireg (cfg);
2267 tmp3 = mono_alloc_ireg (cfg);
2268 tmp4 = mono_alloc_ireg (cfg);
2269 tmp5 = mono_alloc_ireg (cfg);
2271 /* add the operands */
2273 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2275 /* Overflow happens if
2276 * neg + neg = pos or
2279 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2280 * XOR of the high bit returns 0 if the signs match
2281 * XOR of that with the high bit of the result return 1 if overflow.
2284 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2285 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2287 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2288 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2289 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2291 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2292 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2294 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2296 /* Now, if (tmp5 == 0) then overflow */
2297 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2298 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2299 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2303 case OP_IADD_OVF_UN:
2304 tmp1 = mono_alloc_ireg (cfg);
2306 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2307 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2308 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2309 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2310 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2315 tmp1 = mono_alloc_ireg (cfg);
2316 tmp2 = mono_alloc_ireg (cfg);
2317 tmp3 = mono_alloc_ireg (cfg);
2318 tmp4 = mono_alloc_ireg (cfg);
2319 tmp5 = mono_alloc_ireg (cfg);
2321 /* add the operands */
2323 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2325 /* Overflow happens if
2326 * neg - pos = pos or
2328 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2330 * tmp1 = (lhs ^ rhs)
2331 * tmp2 = (lhs ^ result)
2332 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2335 /* tmp3 = 1 if the signs of the two inputs differ */
2336 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2337 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2338 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2339 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2340 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2342 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2343 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2344 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2348 case OP_ISUB_OVF_UN:
2349 tmp1 = mono_alloc_ireg (cfg);
2351 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2352 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2353 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2354 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2355 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2362 map_to_reg_reg_op (int op)
2371 case OP_COMPARE_IMM:
2373 case OP_ICOMPARE_IMM:
2375 case OP_LCOMPARE_IMM:
2391 case OP_LOAD_MEMBASE:
2392 return OP_LOAD_MEMINDEX;
2393 case OP_LOADI4_MEMBASE:
2394 return OP_LOADI4_MEMINDEX;
2395 case OP_LOADU4_MEMBASE:
2396 return OP_LOADU4_MEMINDEX;
2397 case OP_LOADU1_MEMBASE:
2398 return OP_LOADU1_MEMINDEX;
2399 case OP_LOADI2_MEMBASE:
2400 return OP_LOADI2_MEMINDEX;
2401 case OP_LOADU2_MEMBASE:
2402 return OP_LOADU2_MEMINDEX;
2403 case OP_LOADI1_MEMBASE:
2404 return OP_LOADI1_MEMINDEX;
2405 case OP_LOADR4_MEMBASE:
2406 return OP_LOADR4_MEMINDEX;
2407 case OP_LOADR8_MEMBASE:
2408 return OP_LOADR8_MEMINDEX;
2409 case OP_STOREI1_MEMBASE_REG:
2410 return OP_STOREI1_MEMINDEX;
2411 case OP_STOREI2_MEMBASE_REG:
2412 return OP_STOREI2_MEMINDEX;
2413 case OP_STOREI4_MEMBASE_REG:
2414 return OP_STOREI4_MEMINDEX;
2415 case OP_STORE_MEMBASE_REG:
2416 return OP_STORE_MEMINDEX;
2417 case OP_STORER4_MEMBASE_REG:
2418 return OP_STORER4_MEMINDEX;
2419 case OP_STORER8_MEMBASE_REG:
2420 return OP_STORER8_MEMINDEX;
2421 case OP_STORE_MEMBASE_IMM:
2422 return OP_STORE_MEMBASE_REG;
2423 case OP_STOREI1_MEMBASE_IMM:
2424 return OP_STOREI1_MEMBASE_REG;
2425 case OP_STOREI2_MEMBASE_IMM:
2426 return OP_STOREI2_MEMBASE_REG;
2427 case OP_STOREI4_MEMBASE_IMM:
2428 return OP_STOREI4_MEMBASE_REG;
2429 case OP_STOREI8_MEMBASE_IMM:
2430 return OP_STOREI8_MEMBASE_REG;
2432 return mono_op_imm_to_op (op);
2436 map_to_mips_op (int op)
2440 return OP_MIPS_FBEQ;
2442 return OP_MIPS_FBGE;
2444 return OP_MIPS_FBGT;
2446 return OP_MIPS_FBLE;
2448 return OP_MIPS_FBLT;
2450 return OP_MIPS_FBNE;
2452 return OP_MIPS_FBGE_UN;
2454 return OP_MIPS_FBGT_UN;
2456 return OP_MIPS_FBLE_UN;
2458 return OP_MIPS_FBLT_UN;
2466 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2467 g_assert_not_reached ();
2471 #define NEW_INS(cfg,after,dest,op) do { \
2472 MONO_INST_NEW((cfg), (dest), (op)); \
2473 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2476 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2478 MONO_INST_NEW(cfg, temp, (op)); \
2479 mono_bblock_insert_after_ins (bb, (pos), temp); \
2480 temp->dreg = (_dreg); \
2481 temp->sreg1 = (_sreg1); \
2482 temp->sreg2 = (_sreg2); \
2486 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2488 MONO_INST_NEW(cfg, temp, (op)); \
2489 mono_bblock_insert_after_ins (bb, (pos), temp); \
2490 temp->dreg = (_dreg); \
2491 temp->sreg1 = (_sreg1); \
2492 temp->inst_c0 = (_imm); \
2497 * Remove from the instruction list the instructions that can't be
2498 * represented with very simple instructions with no register
2502 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2504 MonoInst *ins, *next, *temp, *last_ins = NULL;
2508 if (cfg->verbose_level > 2) {
2511 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2512 MONO_BB_FOR_EACH_INS (bb, ins) {
2513 mono_print_ins_index (idx++, ins);
2519 MONO_BB_FOR_EACH_INS (bb, ins) {
2521 switch (ins->opcode) {
2526 /* Branch opts can eliminate the branch */
2527 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2533 case OP_COMPARE_IMM:
2534 case OP_ICOMPARE_IMM:
2535 case OP_LCOMPARE_IMM:
2537 /* Branch opts can eliminate the branch */
2538 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2542 if (ins->inst_imm) {
2543 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2544 temp->inst_c0 = ins->inst_imm;
2545 temp->dreg = mono_alloc_ireg (cfg);
2546 ins->sreg2 = temp->dreg;
2550 ins->sreg2 = mips_zero;
2552 if (ins->opcode == OP_COMPARE_IMM)
2553 ins->opcode = OP_COMPARE;
2554 else if (ins->opcode == OP_ICOMPARE_IMM)
2555 ins->opcode = OP_ICOMPARE;
2556 else if (ins->opcode == OP_LCOMPARE_IMM)
2557 ins->opcode = OP_LCOMPARE;
2560 case OP_IDIV_UN_IMM:
2563 case OP_IREM_UN_IMM:
2564 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2565 temp->inst_c0 = ins->inst_imm;
2566 temp->dreg = mono_alloc_ireg (cfg);
2567 ins->sreg2 = temp->dreg;
2568 if (ins->opcode == OP_IDIV_IMM)
2569 ins->opcode = OP_IDIV;
2570 else if (ins->opcode == OP_IREM_IMM)
2571 ins->opcode = OP_IREM;
2572 else if (ins->opcode == OP_IDIV_UN_IMM)
2573 ins->opcode = OP_IDIV_UN;
2574 else if (ins->opcode == OP_IREM_UN_IMM)
2575 ins->opcode = OP_IREM_UN;
2577 /* handle rem separately */
2584 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2585 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2586 temp->inst_c0 = ins->inst_imm;
2587 temp->dreg = mono_alloc_ireg (cfg);
2588 ins->sreg2 = temp->dreg;
2589 ins->opcode = map_to_reg_reg_op (ins->opcode);
2599 /* unsigned 16 bit immediate */
2600 if (ins->inst_imm & 0xffff0000) {
2601 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2602 temp->inst_c0 = ins->inst_imm;
2603 temp->dreg = mono_alloc_ireg (cfg);
2604 ins->sreg2 = temp->dreg;
2605 ins->opcode = map_to_reg_reg_op (ins->opcode);
2612 /* signed 16 bit immediate */
2613 if (!mips_is_imm16 (ins->inst_imm)) {
2614 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2615 temp->inst_c0 = ins->inst_imm;
2616 temp->dreg = mono_alloc_ireg (cfg);
2617 ins->sreg2 = temp->dreg;
2618 ins->opcode = map_to_reg_reg_op (ins->opcode);
2624 if (!mips_is_imm16 (-ins->inst_imm)) {
2625 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2626 temp->inst_c0 = ins->inst_imm;
2627 temp->dreg = mono_alloc_ireg (cfg);
2628 ins->sreg2 = temp->dreg;
2629 ins->opcode = map_to_reg_reg_op (ins->opcode);
2635 if (ins->inst_imm == 1) {
2636 ins->opcode = OP_MOVE;
2639 if (ins->inst_imm == 0) {
2640 ins->opcode = OP_ICONST;
2644 imm = mono_is_power_of_two (ins->inst_imm);
2646 ins->opcode = OP_SHL_IMM;
2647 ins->inst_imm = imm;
2650 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2651 temp->inst_c0 = ins->inst_imm;
2652 temp->dreg = mono_alloc_ireg (cfg);
2653 ins->sreg2 = temp->dreg;
2654 ins->opcode = map_to_reg_reg_op (ins->opcode);
2657 case OP_LOCALLOC_IMM:
2658 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2659 temp->inst_c0 = ins->inst_imm;
2660 temp->dreg = mono_alloc_ireg (cfg);
2661 ins->sreg1 = temp->dreg;
2662 ins->opcode = OP_LOCALLOC;
2665 case OP_LOADR4_MEMBASE:
2666 case OP_STORER4_MEMBASE_REG:
2667 /* we can do two things: load the immed in a register
2668 * and use an indexed load, or see if the immed can be
2669 * represented as an ad_imm + a load with a smaller offset
2670 * that fits. We just do the first for now, optimize later.
2672 if (mips_is_imm16 (ins->inst_offset))
2674 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2675 temp->inst_c0 = ins->inst_offset;
2676 temp->dreg = mono_alloc_ireg (cfg);
2677 ins->sreg2 = temp->dreg;
2678 ins->opcode = map_to_reg_reg_op (ins->opcode);
2681 case OP_STORE_MEMBASE_IMM:
2682 case OP_STOREI1_MEMBASE_IMM:
2683 case OP_STOREI2_MEMBASE_IMM:
2684 case OP_STOREI4_MEMBASE_IMM:
2685 case OP_STOREI8_MEMBASE_IMM:
2686 if (!ins->inst_imm) {
2687 ins->sreg1 = mips_zero;
2688 ins->opcode = map_to_reg_reg_op (ins->opcode);
2691 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2692 temp->inst_c0 = ins->inst_imm;
2693 temp->dreg = mono_alloc_ireg (cfg);
2694 ins->sreg1 = temp->dreg;
2695 ins->opcode = map_to_reg_reg_op (ins->opcode);
2697 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2703 /* Branch opts can eliminate the branch */
2704 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2711 * remap compare/branch and compare/set
2712 * to MIPS specific opcodes.
2714 next->opcode = map_to_mips_op (next->opcode);
2715 next->sreg1 = ins->sreg1;
2716 next->sreg2 = ins->sreg2;
2723 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2724 temp->inst_c0 = (guint32)ins->inst_p0;
2725 temp->dreg = mono_alloc_ireg (cfg);
2726 ins->inst_basereg = temp->dreg;
2727 ins->inst_offset = 0;
2728 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2730 /* make it handle the possibly big ins->inst_offset
2731 * later optimize to use lis + load_membase
2736 g_assert (ins_is_compare(last_ins));
2737 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2738 NULLIFY_INS(last_ins);
2742 g_assert (ins_is_compare(last_ins));
2743 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2744 NULLIFY_INS(last_ins);
2748 g_assert (ins_is_compare(last_ins));
2749 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2750 last_ins->dreg = mono_alloc_ireg (cfg);
2751 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2755 g_assert (ins_is_compare(last_ins));
2756 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2757 last_ins->dreg = mono_alloc_ireg (cfg);
2758 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2762 g_assert (ins_is_compare(last_ins));
2763 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2764 last_ins->dreg = mono_alloc_ireg (cfg);
2765 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2769 g_assert (ins_is_compare(last_ins));
2770 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2771 last_ins->dreg = mono_alloc_ireg (cfg);
2772 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2776 g_assert (ins_is_compare(last_ins));
2777 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2778 last_ins->dreg = mono_alloc_ireg (cfg);
2779 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2783 g_assert (ins_is_compare(last_ins));
2784 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2785 last_ins->dreg = mono_alloc_ireg (cfg);
2786 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2790 g_assert (ins_is_compare(last_ins));
2791 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2792 last_ins->dreg = mono_alloc_ireg (cfg);
2793 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2797 g_assert (ins_is_compare(last_ins));
2798 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2799 last_ins->dreg = mono_alloc_ireg (cfg);
2800 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2805 g_assert (ins_is_compare(last_ins));
2806 last_ins->opcode = OP_IXOR;
2807 last_ins->dreg = mono_alloc_ireg(cfg);
2808 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2813 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2814 NULLIFY_INS(last_ins);
2820 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2821 NULLIFY_INS(last_ins);
2826 g_assert (ins_is_compare(last_ins));
2827 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2828 MONO_DELETE_INS(bb, last_ins);
2833 g_assert (ins_is_compare(last_ins));
2834 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2835 MONO_DELETE_INS(bb, last_ins);
2838 case OP_COND_EXC_EQ:
2839 case OP_COND_EXC_IEQ:
2840 g_assert (ins_is_compare(last_ins));
2841 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2842 MONO_DELETE_INS(bb, last_ins);
2845 case OP_COND_EXC_GE:
2846 case OP_COND_EXC_IGE:
2847 g_assert (ins_is_compare(last_ins));
2848 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2849 MONO_DELETE_INS(bb, last_ins);
2852 case OP_COND_EXC_GT:
2853 case OP_COND_EXC_IGT:
2854 g_assert (ins_is_compare(last_ins));
2855 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2856 MONO_DELETE_INS(bb, last_ins);
2859 case OP_COND_EXC_LE:
2860 case OP_COND_EXC_ILE:
2861 g_assert (ins_is_compare(last_ins));
2862 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2863 MONO_DELETE_INS(bb, last_ins);
2866 case OP_COND_EXC_LT:
2867 case OP_COND_EXC_ILT:
2868 g_assert (ins_is_compare(last_ins));
2869 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2870 MONO_DELETE_INS(bb, last_ins);
2873 case OP_COND_EXC_NE_UN:
2874 case OP_COND_EXC_INE_UN:
2875 g_assert (ins_is_compare(last_ins));
2876 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2877 MONO_DELETE_INS(bb, last_ins);
2880 case OP_COND_EXC_GE_UN:
2881 case OP_COND_EXC_IGE_UN:
2882 g_assert (ins_is_compare(last_ins));
2883 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2884 MONO_DELETE_INS(bb, last_ins);
2887 case OP_COND_EXC_GT_UN:
2888 case OP_COND_EXC_IGT_UN:
2889 g_assert (ins_is_compare(last_ins));
2890 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2891 MONO_DELETE_INS(bb, last_ins);
2894 case OP_COND_EXC_LE_UN:
2895 case OP_COND_EXC_ILE_UN:
2896 g_assert (ins_is_compare(last_ins));
2897 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2898 MONO_DELETE_INS(bb, last_ins);
2901 case OP_COND_EXC_LT_UN:
2902 case OP_COND_EXC_ILT_UN:
2903 g_assert (ins_is_compare(last_ins));
2904 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2905 MONO_DELETE_INS(bb, last_ins);
2908 case OP_COND_EXC_OV:
2909 case OP_COND_EXC_IOV: {
2910 int tmp1, tmp2, tmp3, tmp4, tmp5;
2911 MonoInst *pos = last_ins;
2913 /* Overflow happens if
2914 * neg + neg = pos or
2917 * (bit31s of operands match) AND (bit31 of operand
2918 * != bit31 of result)
2919 * XOR of the high bit returns 0 if the signs match
2920 * XOR of that with the high bit of the result return 1
2923 g_assert (last_ins->opcode == OP_IADC);
2925 tmp1 = mono_alloc_ireg (cfg);
2926 tmp2 = mono_alloc_ireg (cfg);
2927 tmp3 = mono_alloc_ireg (cfg);
2928 tmp4 = mono_alloc_ireg (cfg);
2929 tmp5 = mono_alloc_ireg (cfg);
2931 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2932 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2934 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2935 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2936 INS (pos, OP_INOT, tmp3, tmp2, -1);
2938 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2939 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2940 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2942 /* Now, if (tmp5 == 0) then overflow */
2943 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2948 case OP_COND_EXC_NO:
2949 case OP_COND_EXC_INO:
2950 g_assert_not_reached ();
2954 case OP_COND_EXC_IC:
2955 g_assert_not_reached ();
2958 case OP_COND_EXC_NC:
2959 case OP_COND_EXC_INC:
2960 g_assert_not_reached ();
2966 bb->last_ins = last_ins;
2967 bb->max_vreg = cfg->next_vreg;
2970 if (cfg->verbose_level > 2) {
2973 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
2974 MONO_BB_FOR_EACH_INS (bb, ins) {
2975 mono_print_ins_index (idx++, ins);
2984 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2986 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2988 mips_truncwd (code, mips_ftemp, sreg);
2990 mips_cvtwd (code, mips_ftemp, sreg);
2992 mips_mfc1 (code, dreg, mips_ftemp);
2995 mips_andi (code, dreg, dreg, 0xff);
2996 else if (size == 2) {
2997 mips_sll (code, dreg, dreg, 16);
2998 mips_srl (code, dreg, dreg, 16);
3002 mips_sll (code, dreg, dreg, 24);
3003 mips_sra (code, dreg, dreg, 24);
3005 else if (size == 2) {
3006 mips_sll (code, dreg, dreg, 16);
3007 mips_sra (code, dreg, dreg, 16);
3014 * emit_load_volatile_arguments:
3016 * Load volatile arguments from the stack to the original input registers.
3017 * Required before a tail call.
3020 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
3022 MonoMethod *method = cfg->method;
3023 MonoMethodSignature *sig;
3028 sig = mono_method_signature (method);
3030 if (!cfg->arch.cinfo)
3031 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
3032 cinfo = cfg->arch.cinfo;
3034 if (cinfo->struct_ret) {
3035 ArgInfo *ainfo = &cinfo->ret;
3036 inst = cfg->vret_addr;
3037 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3040 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3041 ArgInfo *ainfo = cinfo->args + i;
3042 inst = cfg->args [i];
3043 if (inst->opcode == OP_REGVAR) {
3044 if (ainfo->storage == ArgInIReg)
3045 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3046 else if (ainfo->storage == ArgInFReg)
3047 g_assert_not_reached();
3048 else if (ainfo->storage == ArgOnStack) {
3051 g_assert_not_reached ();
3053 if (ainfo->storage == ArgInIReg) {
3054 g_assert (mips_is_imm16 (inst->inst_offset));
3055 switch (ainfo->size) {
3057 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3060 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3064 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3067 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3068 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3071 g_assert_not_reached ();
3074 } else if (ainfo->storage == ArgOnStack) {
3076 } else if (ainfo->storage == ArgInFReg) {
3077 g_assert (mips_is_imm16 (inst->inst_offset));
3078 if (ainfo->size == 8) {
3079 #if _MIPS_SIM == _ABIO32
3080 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
3081 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
3082 #elif _MIPS_SIM == _ABIN32
3083 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3086 else if (ainfo->size == 4)
3087 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3089 g_assert_not_reached ();
3090 } else if (ainfo->storage == ArgStructByVal) {
3092 int doffset = inst->inst_offset;
3094 g_assert (mips_is_imm16 (inst->inst_offset));
3095 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3096 for (i = 0; i < ainfo->size; ++i) {
3097 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3098 doffset += SIZEOF_REGISTER;
3100 } else if (ainfo->storage == ArgStructByAddr) {
3101 g_assert (mips_is_imm16 (inst->inst_offset));
3102 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3104 g_assert_not_reached ();
3112 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3114 int size = cfg->param_area;
3116 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3117 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3122 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3123 if (ppc_is_imm16 (-size)) {
3124 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3126 ppc_load (code, ppc_r11, -size);
3127 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3134 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3136 int size = cfg->param_area;
3138 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3139 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3144 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3145 if (ppc_is_imm16 (size)) {
3146 ppc_stwu (code, ppc_r0, size, ppc_sp);
3148 ppc_load (code, ppc_r11, size);
3149 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3156 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3161 guint8 *code = cfg->native_code + cfg->code_len;
3162 MonoInst *last_ins = NULL;
3163 guint last_offset = 0;
3167 /* we don't align basic blocks of loops on mips */
3169 if (cfg->verbose_level > 2)
3170 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3172 cpos = bb->max_offset;
3175 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3176 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3177 g_assert (!mono_compile_aot);
3180 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3181 /* this is not thread save, but good enough */
3182 /* fixme: howto handle overflows? */
3183 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3184 mips_lw (code, mips_temp, mips_at, 0);
3185 mips_addiu (code, mips_temp, mips_temp, 1);
3186 mips_sw (code, mips_temp, mips_at, 0);
3189 MONO_BB_FOR_EACH_INS (bb, ins) {
3190 offset = code - cfg->native_code;
3192 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3194 if (offset > (cfg->code_size - max_len - 16)) {
3195 cfg->code_size *= 2;
3196 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3197 code = cfg->native_code + offset;
3199 mono_debug_record_line_number (cfg, ins, offset);
3200 if (cfg->verbose_level > 2) {
3201 g_print (" @ 0x%x\t", offset);
3202 mono_print_ins_index (ins_cnt++, ins);
3204 /* Check for virtual regs that snuck by */
3205 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3207 switch (ins->opcode) {
3208 case OP_RELAXED_NOP:
3211 case OP_DUMMY_STORE:
3212 case OP_NOT_REACHED:
3215 case OP_SEQ_POINT: {
3216 if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3217 guint32 addr = (guint32)ss_trigger_page;
3219 mips_load_const (code, mips_t9, addr);
3220 mips_lw (code, mips_t9, mips_t9, 0);
3223 mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3226 * A placeholder for a possible breakpoint inserted by
3227 * mono_arch_set_breakpoint ().
3229 /* mips_load_const () + mips_lw */
3236 g_assert_not_reached();
3238 emit_tls_access (code, ins->dreg, ins->inst_offset);
3242 mips_mult (code, ins->sreg1, ins->sreg2);
3243 mips_mflo (code, ins->dreg);
3244 mips_mfhi (code, ins->dreg+1);
3247 mips_multu (code, ins->sreg1, ins->sreg2);
3248 mips_mflo (code, ins->dreg);
3249 mips_mfhi (code, ins->dreg+1);
3251 case OP_MEMORY_BARRIER:
3256 case OP_STOREI1_MEMBASE_IMM:
3257 mips_load_const (code, mips_temp, ins->inst_imm);
3258 if (mips_is_imm16 (ins->inst_offset)) {
3259 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3261 mips_load_const (code, mips_at, ins->inst_offset);
3262 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3265 case OP_STOREI2_MEMBASE_IMM:
3266 mips_load_const (code, mips_temp, ins->inst_imm);
3267 if (mips_is_imm16 (ins->inst_offset)) {
3268 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3270 mips_load_const (code, mips_at, ins->inst_offset);
3271 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3274 case OP_STOREI8_MEMBASE_IMM:
3275 mips_load_const (code, mips_temp, ins->inst_imm);
3276 if (mips_is_imm16 (ins->inst_offset)) {
3277 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3279 mips_load_const (code, mips_at, ins->inst_offset);
3280 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3283 case OP_STORE_MEMBASE_IMM:
3284 case OP_STOREI4_MEMBASE_IMM:
3285 mips_load_const (code, mips_temp, ins->inst_imm);
3286 if (mips_is_imm16 (ins->inst_offset)) {
3287 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3289 mips_load_const (code, mips_at, ins->inst_offset);
3290 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3293 case OP_STOREI1_MEMBASE_REG:
3294 if (mips_is_imm16 (ins->inst_offset)) {
3295 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3297 mips_load_const (code, mips_at, ins->inst_offset);
3298 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3299 mips_sb (code, ins->sreg1, mips_at, 0);
3302 case OP_STOREI2_MEMBASE_REG:
3303 if (mips_is_imm16 (ins->inst_offset)) {
3304 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3306 mips_load_const (code, mips_at, ins->inst_offset);
3307 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3308 mips_sh (code, ins->sreg1, mips_at, 0);
3311 case OP_STORE_MEMBASE_REG:
3312 case OP_STOREI4_MEMBASE_REG:
3313 if (mips_is_imm16 (ins->inst_offset)) {
3314 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3316 mips_load_const (code, mips_at, ins->inst_offset);
3317 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3318 mips_sw (code, ins->sreg1, mips_at, 0);
3321 case OP_STOREI8_MEMBASE_REG:
3322 if (mips_is_imm16 (ins->inst_offset)) {
3323 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3325 mips_load_const (code, mips_at, ins->inst_offset);
3326 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3327 mips_sd (code, ins->sreg1, mips_at, 0);
3331 g_assert_not_reached ();
3332 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3333 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3335 case OP_LOADI8_MEMBASE:
3336 if (mips_is_imm16 (ins->inst_offset)) {
3337 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3339 mips_load_const (code, mips_at, ins->inst_offset);
3340 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3341 mips_ld (code, ins->dreg, mips_at, 0);
3344 case OP_LOAD_MEMBASE:
3345 case OP_LOADI4_MEMBASE:
3346 case OP_LOADU4_MEMBASE:
3347 g_assert (ins->dreg != -1);
3348 if (mips_is_imm16 (ins->inst_offset)) {
3349 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3351 mips_load_const (code, mips_at, ins->inst_offset);
3352 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3353 mips_lw (code, ins->dreg, mips_at, 0);
3356 case OP_LOADI1_MEMBASE:
3357 if (mips_is_imm16 (ins->inst_offset)) {
3358 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3360 mips_load_const (code, mips_at, ins->inst_offset);
3361 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3362 mips_lb (code, ins->dreg, mips_at, 0);
3365 case OP_LOADU1_MEMBASE:
3366 if (mips_is_imm16 (ins->inst_offset)) {
3367 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3369 mips_load_const (code, mips_at, ins->inst_offset);
3370 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3371 mips_lbu (code, ins->dreg, mips_at, 0);
3374 case OP_LOADI2_MEMBASE:
3375 if (mips_is_imm16 (ins->inst_offset)) {
3376 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3378 mips_load_const (code, mips_at, ins->inst_offset);
3379 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3380 mips_lh (code, ins->dreg, mips_at, 0);
3383 case OP_LOADU2_MEMBASE:
3384 if (mips_is_imm16 (ins->inst_offset)) {
3385 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3387 mips_load_const (code, mips_at, ins->inst_offset);
3388 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3389 mips_lhu (code, ins->dreg, mips_at, 0);
3392 case OP_ICONV_TO_I1:
3393 mips_sll (code, mips_at, ins->sreg1, 24);
3394 mips_sra (code, ins->dreg, mips_at, 24);
3396 case OP_ICONV_TO_I2:
3397 mips_sll (code, mips_at, ins->sreg1, 16);
3398 mips_sra (code, ins->dreg, mips_at, 16);
3400 case OP_ICONV_TO_U1:
3401 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3403 case OP_ICONV_TO_U2:
3404 mips_sll (code, mips_at, ins->sreg1, 16);
3405 mips_srl (code, ins->dreg, mips_at, 16);
3408 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3411 g_assert (mips_is_imm16 (ins->inst_imm));
3412 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3415 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3418 g_assert (mips_is_imm16 (ins->inst_imm));
3419 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3423 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3424 * So instead of emitting a trap, we emit a call a C function and place a
3427 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
3428 (gpointer)"mono_break");
3429 mips_load (code, mips_t9, 0x1f1f1f1f);
3430 mips_jalr (code, mips_t9, mips_ra);
3434 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3437 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3442 g_assert (mips_is_imm16 (ins->inst_imm));
3443 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3446 g_assert (mips_is_imm16 (ins->inst_imm));
3447 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3451 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3454 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3459 // we add the negated value
3460 g_assert (mips_is_imm16 (-ins->inst_imm));
3461 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3465 // we add the negated value
3466 g_assert (mips_is_imm16 (-ins->inst_imm));
3467 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3472 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3478 g_assert (!(ins->inst_imm & 0xffff0000));
3479 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3484 guint32 *divisor_is_m1;
3485 guint32 *dividend_is_minvalue;
3486 guint32 *divisor_is_zero;
3488 mips_load_const (code, mips_at, -1);
3489 divisor_is_m1 = (guint32 *)(void *)code;
3490 mips_bne (code, ins->sreg2, mips_at, 0);
3491 mips_lui (code, mips_at, mips_zero, 0x8000);
3492 dividend_is_minvalue = (guint32 *)(void *)code;
3493 mips_bne (code, ins->sreg1, mips_at, 0);
3496 /* Divide Int32.MinValue by -1 -- throw exception */
3497 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3499 mips_patch (divisor_is_m1, (guint32)code);
3500 mips_patch (dividend_is_minvalue, (guint32)code);
3502 /* Put divide in branch delay slot (NOT YET) */
3503 divisor_is_zero = (guint32 *)(void *)code;
3504 mips_bne (code, ins->sreg2, mips_zero, 0);
3507 /* Divide by zero -- throw exception */
3508 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3510 mips_patch (divisor_is_zero, (guint32)code);
3511 mips_div (code, ins->sreg1, ins->sreg2);
3512 if (ins->opcode == OP_IDIV)
3513 mips_mflo (code, ins->dreg);
3515 mips_mfhi (code, ins->dreg);
3520 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3522 /* Put divide in branch delay slot (NOT YET) */
3523 mips_bne (code, ins->sreg2, mips_zero, 0);
3526 /* Divide by zero -- throw exception */
3527 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3529 mips_patch (divisor_is_zero, (guint32)code);
3530 mips_divu (code, ins->sreg1, ins->sreg2);
3531 if (ins->opcode == OP_IDIV_UN)
3532 mips_mflo (code, ins->dreg);
3534 mips_mfhi (code, ins->dreg);
3538 g_assert_not_reached ();
3540 ppc_load (code, ppc_r11, ins->inst_imm);
3541 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3542 ppc_mfspr (code, ppc_r0, ppc_xer);
3543 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3544 /* FIXME: use OverflowException for 0x80000000/-1 */
3545 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3547 g_assert_not_reached();
3550 g_assert_not_reached ();
3552 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3556 g_assert (!(ins->inst_imm & 0xffff0000));
3557 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3560 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3564 /* unsigned 16-bit immediate */
3565 g_assert (!(ins->inst_imm & 0xffff0000));
3566 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3569 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3573 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3576 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3579 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3583 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3586 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3589 case OP_ISHR_UN_IMM:
3590 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3592 case OP_LSHR_UN_IMM:
3593 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3596 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3599 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3603 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3606 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3609 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3613 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3615 mips_mult (code, ins->sreg1, ins->sreg2);
3616 mips_mflo (code, ins->dreg);
3621 #if SIZEOF_REGISTER == 8
3623 mips_dmult (code, ins->sreg1, ins->sreg2);
3624 mips_mflo (code, ins->dreg);
3629 mips_mult (code, ins->sreg1, ins->sreg2);
3630 mips_mflo (code, ins->dreg);
3631 mips_mfhi (code, mips_at);
3634 mips_sra (code, mips_temp, ins->dreg, 31);
3635 patch = (guint32 *)(void *)code;
3636 mips_beq (code, mips_temp, mips_at, 0);
3638 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3639 mips_patch (patch, (guint32)code);
3642 case OP_IMUL_OVF_UN: {
3644 mips_mult (code, ins->sreg1, ins->sreg2);
3645 mips_mflo (code, ins->dreg);
3646 mips_mfhi (code, mips_at);
3649 patch = (guint32 *)(void *)code;
3650 mips_beq (code, mips_at, mips_zero, 0);
3652 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3653 mips_patch (patch, (guint32)code);
3657 mips_load_const (code, ins->dreg, ins->inst_c0);
3659 #if SIZEOF_REGISTER == 8
3661 mips_load_const (code, ins->dreg, ins->inst_c0);
3665 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3666 mips_load (code, ins->dreg, 0);
3670 mips_mtc1 (code, ins->dreg, ins->sreg1);
3672 case OP_MIPS_MTC1S_2:
3673 mips_mtc1 (code, ins->dreg, ins->sreg1);
3674 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3677 mips_mfc1 (code, ins->dreg, ins->sreg1);
3680 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3684 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3686 mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3687 mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3691 case OP_ICONV_TO_I4:
3692 case OP_ICONV_TO_U4:
3694 if (ins->dreg != ins->sreg1)
3695 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3697 #if SIZEOF_REGISTER == 8
3699 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3700 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3703 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3704 mips_dsra (code, ins->dreg, ins->dreg, 32);
3708 int lsreg = mips_v0 + ls_word_idx;
3709 int msreg = mips_v0 + ms_word_idx;
3711 /* Get sreg1 into lsreg, sreg2 into msreg */
3713 if (ins->sreg1 == msreg) {
3714 if (ins->sreg1 != mips_at)
3715 MIPS_MOVE (code, mips_at, ins->sreg1);
3716 if (ins->sreg2 != msreg)
3717 MIPS_MOVE (code, msreg, ins->sreg2);
3718 MIPS_MOVE (code, lsreg, mips_at);
3721 if (ins->sreg2 != msreg)
3722 MIPS_MOVE (code, msreg, ins->sreg2);
3723 if (ins->sreg1 != lsreg)
3724 MIPS_MOVE (code, lsreg, ins->sreg1);
3729 if (ins->dreg != ins->sreg1) {
3730 mips_fmovd (code, ins->dreg, ins->sreg1);
3734 /* Convert from double to float and leave it there */
3735 mips_cvtsd (code, ins->dreg, ins->sreg1);
3737 case OP_FCONV_TO_R4:
3739 mips_cvtsd (code, ins->dreg, ins->sreg1);
3741 /* Just a move, no precision change */
3742 if (ins->dreg != ins->sreg1) {
3743 mips_fmovd (code, ins->dreg, ins->sreg1);
3748 code = emit_load_volatile_arguments(cfg, code);
3751 * Pop our stack, then jump to specified method (tail-call)
3752 * Keep in sync with mono_arch_emit_epilog
3754 code = mono_arch_emit_epilog_sub (cfg, code);
3756 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3757 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3758 if (cfg->arch.long_branch) {
3759 mips_lui (code, mips_t9, mips_zero, 0);
3760 mips_addiu (code, mips_t9, mips_t9, 0);
3761 mips_jr (code, mips_t9);
3765 mips_beq (code, mips_zero, mips_zero, 0);
3770 /* ensure ins->sreg1 is not NULL */
3771 mips_lw (code, mips_zero, ins->sreg1, 0);
3774 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3775 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3777 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3778 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3780 mips_sw (code, mips_at, ins->sreg1, 0);
3793 case OP_VOIDCALL_REG:
3795 case OP_FCALL_MEMBASE:
3796 case OP_LCALL_MEMBASE:
3797 case OP_VCALL_MEMBASE:
3798 case OP_VCALL2_MEMBASE:
3799 case OP_VOIDCALL_MEMBASE:
3800 case OP_CALL_MEMBASE:
3801 call = (MonoCallInst*)ins;
3802 switch (ins->opcode) {
3809 if (ins->flags & MONO_INST_HAS_METHOD) {
3810 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3811 mips_load (code, mips_t9, call->method);
3814 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3815 mips_load (code, mips_t9, call->fptr);
3817 mips_jalr (code, mips_t9, mips_ra);
3824 case OP_VOIDCALL_REG:
3826 MIPS_MOVE (code, mips_t9, ins->sreg1);
3827 mips_jalr (code, mips_t9, mips_ra);
3830 case OP_FCALL_MEMBASE:
3831 case OP_LCALL_MEMBASE:
3832 case OP_VCALL_MEMBASE:
3833 case OP_VCALL2_MEMBASE:
3834 case OP_VOIDCALL_MEMBASE:
3835 case OP_CALL_MEMBASE:
3836 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3837 mips_jalr (code, mips_t9, mips_ra);
3841 #if PROMOTE_R4_TO_R8
3842 /* returned an FP R4 (single), promote to R8 (double) in place */
3843 if ((ins->opcode == OP_FCALL ||
3844 ins->opcode == OP_FCALL_REG) &&
3845 call->signature->ret->type == MONO_TYPE_R4) {
3846 mips_cvtds (code, mips_f0, mips_f0);
3851 int area_offset = cfg->param_area;
3853 /* Round up ins->sreg1, mips_at ends up holding size */
3854 mips_addiu (code, mips_at, ins->sreg1, 31);
3855 mips_addiu (code, mips_temp, mips_zero, ~31);
3856 mips_and (code, mips_at, mips_at, mips_temp);
3858 mips_subu (code, mips_sp, mips_sp, mips_at);
3859 g_assert (mips_is_imm16 (area_offset));
3860 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3862 if (ins->flags & MONO_INST_INIT) {
3863 mips_move (code, mips_temp, ins->dreg);
3864 mips_sb (code, mips_zero, mips_temp, 0);
3865 mips_addiu (code, mips_at, mips_at, -1);
3866 mips_bne (code, mips_at, mips_zero, -3);
3867 mips_addiu (code, mips_temp, mips_temp, 1);
3872 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3873 mips_move (code, mips_a0, ins->sreg1);
3874 mips_call (code, mips_t9, addr);
3875 mips_break (code, 0xfc);
3879 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3880 mips_move (code, mips_a0, ins->sreg1);
3881 mips_call (code, mips_t9, addr);
3882 mips_break (code, 0xfb);
3885 case OP_START_HANDLER: {
3887 * The START_HANDLER instruction marks the beginning of
3888 * a handler block. It is called using a call
3889 * instruction, so mips_ra contains the return address.
3890 * Since the handler executes in the same stack frame
3891 * as the method itself, we can't use save/restore to
3892 * save the return address. Instead, we save it into
3893 * a dedicated variable.
3895 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3896 g_assert (spvar->inst_basereg != mips_sp);
3897 code = emit_reserve_param_area (cfg, code);
3899 if (mips_is_imm16 (spvar->inst_offset)) {
3900 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3902 mips_load_const (code, mips_at, spvar->inst_offset);
3903 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3904 mips_sw (code, mips_ra, mips_at, 0);
3908 case OP_ENDFILTER: {
3909 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3910 g_assert (spvar->inst_basereg != mips_sp);
3911 code = emit_unreserve_param_area (cfg, code);
3913 if (ins->sreg1 != mips_v0)
3914 MIPS_MOVE (code, mips_v0, ins->sreg1);
3915 if (mips_is_imm16 (spvar->inst_offset)) {
3916 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3918 mips_load_const (code, mips_at, spvar->inst_offset);
3919 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3920 mips_lw (code, mips_ra, mips_at, 0);
3922 mips_jr (code, mips_ra);
3926 case OP_ENDFINALLY: {
3927 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3928 g_assert (spvar->inst_basereg != mips_sp);
3929 code = emit_unreserve_param_area (cfg, code);
3930 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3931 mips_jalr (code, mips_t9, mips_ra);
3935 case OP_CALL_HANDLER:
3936 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3937 mips_lui (code, mips_t9, mips_zero, 0);
3938 mips_addiu (code, mips_t9, mips_t9, 0);
3939 mips_jalr (code, mips_t9, mips_ra);
3941 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3942 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3945 ins->inst_c0 = code - cfg->native_code;
3948 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3949 if (cfg->arch.long_branch) {
3950 mips_lui (code, mips_at, mips_zero, 0);
3951 mips_addiu (code, mips_at, mips_at, 0);
3952 mips_jr (code, mips_at);
3956 mips_beq (code, mips_zero, mips_zero, 0);
3961 mips_jr (code, ins->sreg1);
3967 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3968 if (offset > (cfg->code_size - max_len - 16)) {
3969 cfg->code_size += max_len;
3970 cfg->code_size *= 2;
3971 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3972 code = cfg->native_code + offset;
3974 g_assert (ins->sreg1 != -1);
3975 mips_sll (code, mips_at, ins->sreg1, 2);
3976 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3977 MIPS_MOVE (code, mips_t8, mips_ra);
3978 mips_bgezal (code, mips_zero, 1); /* bal */
3980 mips_addu (code, mips_t9, mips_ra, mips_at);
3981 /* Table is 16 or 20 bytes from target of bal above */
3982 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3983 MIPS_MOVE (code, mips_ra, mips_t8);
3984 mips_lw (code, mips_t9, mips_t9, 20);
3987 mips_lw (code, mips_t9, mips_t9, 16);
3988 mips_jalr (code, mips_t9, mips_t8);
3990 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3991 mips_emit32 (code, 0xfefefefe);
3996 mips_addiu (code, ins->dreg, mips_zero, 1);
3997 mips_beq (code, mips_at, mips_zero, 2);
3999 MIPS_MOVE (code, ins->dreg, mips_zero);
4005 mips_addiu (code, ins->dreg, mips_zero, 1);
4006 mips_bltz (code, mips_at, 2);
4008 MIPS_MOVE (code, ins->dreg, mips_zero);
4014 mips_addiu (code, ins->dreg, mips_zero, 1);
4015 mips_bgtz (code, mips_at, 2);
4017 MIPS_MOVE (code, ins->dreg, mips_zero);
4020 case OP_MIPS_COND_EXC_EQ:
4021 case OP_MIPS_COND_EXC_GE:
4022 case OP_MIPS_COND_EXC_GT:
4023 case OP_MIPS_COND_EXC_LE:
4024 case OP_MIPS_COND_EXC_LT:
4025 case OP_MIPS_COND_EXC_NE_UN:
4026 case OP_MIPS_COND_EXC_GE_UN:
4027 case OP_MIPS_COND_EXC_GT_UN:
4028 case OP_MIPS_COND_EXC_LE_UN:
4029 case OP_MIPS_COND_EXC_LT_UN:
4031 case OP_MIPS_COND_EXC_OV:
4032 case OP_MIPS_COND_EXC_NO:
4033 case OP_MIPS_COND_EXC_C:
4034 case OP_MIPS_COND_EXC_NC:
4036 case OP_MIPS_COND_EXC_IEQ:
4037 case OP_MIPS_COND_EXC_IGE:
4038 case OP_MIPS_COND_EXC_IGT:
4039 case OP_MIPS_COND_EXC_ILE:
4040 case OP_MIPS_COND_EXC_ILT:
4041 case OP_MIPS_COND_EXC_INE_UN:
4042 case OP_MIPS_COND_EXC_IGE_UN:
4043 case OP_MIPS_COND_EXC_IGT_UN:
4044 case OP_MIPS_COND_EXC_ILE_UN:
4045 case OP_MIPS_COND_EXC_ILT_UN:
4047 case OP_MIPS_COND_EXC_IOV:
4048 case OP_MIPS_COND_EXC_INO:
4049 case OP_MIPS_COND_EXC_IC:
4050 case OP_MIPS_COND_EXC_INC: {
4054 /* If the condition is true, raise the exception */
4056 /* need to reverse test to skip around exception raising */
4058 /* For the moment, branch around a branch to avoid reversing
4061 /* Remember, an unpatched branch to 0 branches to the delay slot */
4062 switch (ins->opcode) {
4063 case OP_MIPS_COND_EXC_EQ:
4064 throw = (guint32 *)(void *)code;
4065 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4069 case OP_MIPS_COND_EXC_NE_UN:
4070 throw = (guint32 *)(void *)code;
4071 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4075 case OP_MIPS_COND_EXC_LE_UN:
4076 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4077 throw = (guint32 *)(void *)code;
4078 mips_beq (code, mips_at, mips_zero, 0);
4082 case OP_MIPS_COND_EXC_GT:
4083 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4084 throw = (guint32 *)(void *)code;
4085 mips_bne (code, mips_at, mips_zero, 0);
4089 case OP_MIPS_COND_EXC_GT_UN:
4090 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4091 throw = (guint32 *)(void *)code;
4092 mips_bne (code, mips_at, mips_zero, 0);
4096 case OP_MIPS_COND_EXC_LT:
4097 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4098 throw = (guint32 *)(void *)code;
4099 mips_bne (code, mips_at, mips_zero, 0);
4103 case OP_MIPS_COND_EXC_LT_UN:
4104 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4105 throw = (guint32 *)(void *)code;
4106 mips_bne (code, mips_at, mips_zero, 0);
4111 /* Not yet implemented */
4112 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4113 g_assert_not_reached ();
4115 skip = (guint32 *)(void *)code;
4116 mips_beq (code, mips_zero, mips_zero, 0);
4118 mips_patch (throw, (guint32)code);
4119 code = mips_emit_exc_by_name (code, ins->inst_p1);
4120 mips_patch (skip, (guint32)code);
4121 cfg->bb_exit->max_offset += 24;
4130 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4133 /* floating point opcodes */
4136 if (((guint32)ins->inst_p0) & (1 << 15))
4137 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4139 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4140 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4142 mips_load_const (code, mips_at, ins->inst_p0);
4143 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4144 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4148 if (((guint32)ins->inst_p0) & (1 << 15))
4149 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4151 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4152 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4153 #if PROMOTE_R4_TO_R8
4154 mips_cvtds (code, ins->dreg, ins->dreg);
4157 case OP_STORER8_MEMBASE_REG:
4158 if (mips_is_imm16 (ins->inst_offset)) {
4159 #if _MIPS_SIM == _ABIO32
4160 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset + ls_word_offset);
4161 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset + ms_word_offset);
4162 #elif _MIPS_SIM == _ABIN32
4163 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4166 mips_load_const (code, mips_at, ins->inst_offset);
4167 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4168 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4169 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4172 case OP_LOADR8_MEMBASE:
4173 if (mips_is_imm16 (ins->inst_offset)) {
4174 #if _MIPS_SIM == _ABIO32
4175 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset + ls_word_offset);
4176 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset + ms_word_offset);
4177 #elif _MIPS_SIM == _ABIN32
4178 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4181 mips_load_const (code, mips_at, ins->inst_offset);
4182 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4183 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4184 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4187 case OP_STORER4_MEMBASE_REG:
4188 g_assert (mips_is_imm16 (ins->inst_offset));
4189 #if PROMOTE_R4_TO_R8
4190 /* Need to convert ins->sreg1 to single-precision first */
4191 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4192 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4194 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4198 g_assert (mips_is_imm16 (ins->inst_offset));
4199 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4201 case OP_LOADR4_MEMBASE:
4202 g_assert (mips_is_imm16 (ins->inst_offset));
4203 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4204 #if PROMOTE_R4_TO_R8
4205 /* Convert to double precision in place */
4206 mips_cvtds (code, ins->dreg, ins->dreg);
4209 case OP_LOADR4_MEMINDEX:
4210 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4211 mips_lwc1 (code, ins->dreg, mips_at, 0);
4213 case OP_LOADR8_MEMINDEX:
4214 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4215 #if _MIPS_SIM == _ABIO32
4216 mips_lwc1 (code, ins->dreg, mips_at, ls_word_offset);
4217 mips_lwc1 (code, ins->dreg+1, mips_at, ms_word_offset);
4218 #elif _MIPS_SIM == _ABIN32
4219 mips_ldc1 (code, ins->dreg, mips_at, 0);
4222 case OP_STORER4_MEMINDEX:
4223 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4224 #if PROMOTE_R4_TO_R8
4225 /* Need to convert ins->sreg1 to single-precision first */
4226 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4227 mips_swc1 (code, mips_ftemp, mips_at, 0);
4229 mips_swc1 (code, ins->sreg1, mips_at, 0);
4232 case OP_STORER8_MEMINDEX:
4233 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4234 #if _MIPS_SIM == _ABIO32
4235 mips_swc1 (code, ins->sreg1, mips_at, ls_word_offset);
4236 mips_swc1 (code, ins->sreg1+1, mips_at, ms_word_offset);
4237 #elif _MIPS_SIM == _ABIN32
4238 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4241 case OP_ICONV_TO_R_UN: {
4242 static const guint64 adjust_val = 0x41F0000000000000ULL;
4244 /* convert unsigned int to double */
4245 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4246 mips_bgez (code, ins->sreg1, 5);
4247 mips_cvtdw (code, ins->dreg, mips_ftemp);
4249 mips_load (code, mips_at, (guint32) &adjust_val);
4250 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4251 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4252 /* target is here */
4255 case OP_ICONV_TO_R4:
4256 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4257 mips_cvtsw (code, ins->dreg, mips_ftemp);
4258 mips_cvtds (code, ins->dreg, ins->dreg);
4260 case OP_ICONV_TO_R8:
4261 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4262 mips_cvtdw (code, ins->dreg, mips_ftemp);
4264 case OP_FCONV_TO_I1:
4265 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4267 case OP_FCONV_TO_U1:
4268 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4270 case OP_FCONV_TO_I2:
4271 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4273 case OP_FCONV_TO_U2:
4274 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4276 case OP_FCONV_TO_I4:
4278 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4280 case OP_FCONV_TO_U4:
4282 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4285 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4288 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4291 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4294 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4297 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4300 mips_fnegd (code, ins->dreg, ins->sreg1);
4303 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4304 mips_addiu (code, ins->dreg, mips_zero, 1);
4305 mips_fbtrue (code, 2);
4307 MIPS_MOVE (code, ins->dreg, mips_zero);
4310 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4311 mips_addiu (code, ins->dreg, mips_zero, 1);
4312 mips_fbtrue (code, 2);
4314 MIPS_MOVE (code, ins->dreg, mips_zero);
4317 /* Less than, or Unordered */
4318 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4319 mips_addiu (code, ins->dreg, mips_zero, 1);
4320 mips_fbtrue (code, 2);
4322 MIPS_MOVE (code, ins->dreg, mips_zero);
4325 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4326 MIPS_MOVE (code, ins->dreg, mips_zero);
4327 mips_fbtrue (code, 2);
4329 mips_addiu (code, ins->dreg, mips_zero, 1);
4332 /* Greater than, or Unordered */
4333 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4334 MIPS_MOVE (code, ins->dreg, mips_zero);
4335 mips_fbtrue (code, 2);
4337 mips_addiu (code, ins->dreg, mips_zero, 1);
4342 case OP_MIPS_FBLT_UN:
4344 case OP_MIPS_FBGT_UN:
4346 case OP_MIPS_FBGE_UN:
4348 case OP_MIPS_FBLE_UN: {
4350 gboolean is_true = TRUE, is_ordered = FALSE;
4351 guint32 *buf = NULL;
4353 switch (ins->opcode) {
4367 case OP_MIPS_FBLT_UN:
4368 cond = MIPS_FPU_ULT;
4376 case OP_MIPS_FBGT_UN:
4377 cond = MIPS_FPU_OLE;
4385 case OP_MIPS_FBGE_UN:
4386 cond = MIPS_FPU_OLT;
4390 cond = MIPS_FPU_OLE;
4394 case OP_MIPS_FBLE_UN:
4395 cond = MIPS_FPU_ULE;
4399 g_assert_not_reached ();
4403 /* Skip the check if unordered */
4404 mips_fcmpd (code, MIPS_FPU_UN, ins->sreg1, ins->sreg2);
4406 buf = (guint32*)code;
4407 mips_fbtrue (code, 0);
4411 mips_fcmpd (code, cond, ins->sreg1, ins->sreg2);
4413 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4415 mips_fbtrue (code, 0);
4417 mips_fbfalse (code, 0);
4421 mips_patch (buf, (guint32)code);
4425 guint32 *branch_patch;
4427 mips_mfc1 (code, mips_at, ins->sreg1+1);
4428 mips_srl (code, mips_at, mips_at, 16+4);
4429 mips_andi (code, mips_at, mips_at, 2047);
4430 mips_addiu (code, mips_at, mips_at, -2047);
4432 branch_patch = (guint32 *)(void *)code;
4433 mips_bne (code, mips_at, mips_zero, 0);
4436 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4437 mips_patch (branch_patch, (guint32)code);
4438 mips_fmovd (code, ins->dreg, ins->sreg1);
4442 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4443 mips_load (code, ins->dreg, 0x0f0f0f0f);
4448 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4449 g_assert_not_reached ();
4452 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4453 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4454 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4455 g_assert_not_reached ();
4461 last_offset = offset;
4464 cfg->code_len = code - cfg->native_code;
4468 mono_arch_register_lowlevel_calls (void)
4473 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4475 MonoJumpInfo *patch_info;
4477 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4478 unsigned char *ip = patch_info->ip.i + code;
4479 const unsigned char *target = NULL;
4481 switch (patch_info->type) {
4482 case MONO_PATCH_INFO_IP:
4483 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4485 case MONO_PATCH_INFO_SWITCH: {
4486 gpointer *table = (gpointer *)patch_info->data.table->table;
4489 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4491 for (i = 0; i < patch_info->data.table->table_size; i++) {
4492 table [i] = (int)patch_info->data.table->table [i] + code;
4496 case MONO_PATCH_INFO_METHODCONST:
4497 case MONO_PATCH_INFO_CLASS:
4498 case MONO_PATCH_INFO_IMAGE:
4499 case MONO_PATCH_INFO_FIELD:
4500 case MONO_PATCH_INFO_VTABLE:
4501 case MONO_PATCH_INFO_IID:
4502 case MONO_PATCH_INFO_SFLDA:
4503 case MONO_PATCH_INFO_LDSTR:
4504 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4505 case MONO_PATCH_INFO_LDTOKEN:
4506 case MONO_PATCH_INFO_R4:
4507 case MONO_PATCH_INFO_R8:
4508 /* from OP_AOTCONST : lui + addiu */
4509 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4510 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4513 case MONO_PATCH_INFO_EXC_NAME:
4514 g_assert_not_reached ();
4515 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4518 case MONO_PATCH_INFO_NONE:
4519 /* everything is dealt with at epilog output time */
4522 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4523 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4532 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4538 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4544 * Allow tracing to work with this interface (with an optional argument)
4546 * This code is expected to be inserted just after the 'real' prolog code,
4547 * and before the first basic block. We need to allocate a 2nd, temporary
4548 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4552 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4555 int offset = cfg->arch.tracing_offset;
4561 /* For N32, need to know for each stack slot if it's an integer
4562 * or float argument, and save/restore the appropriate register
4564 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4565 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4566 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4567 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4568 #if _MIPS_SIM == _ABIN32
4569 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4570 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4571 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4572 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4575 mips_load_const (code, mips_a0, cfg->method);
4576 mips_addiu (code, mips_a1, mips_sp, offset);
4577 mips_call (code, mips_t9, func);
4579 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4580 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4581 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4582 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4583 #if _MIPS_SIM == _ABIN32
4584 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4585 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4586 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4587 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4597 mips_adjust_stackframe(MonoCompile *cfg)
4600 int delta, threshold, i;
4601 MonoMethodSignature *sig;
4604 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4607 /* adjust cfg->stack_offset for account for down-spilling */
4608 cfg->stack_offset += SIZEOF_REGISTER;
4610 /* re-align cfg->stack_offset if needed (due to var spilling) */
4611 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4612 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4613 if (cfg->verbose_level > 2) {
4614 g_print ("mips_adjust_stackframe:\n");
4615 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4617 threshold = cfg->arch.local_alloc_offset;
4618 ra_offset = cfg->stack_offset - sizeof(gpointer);
4619 if (cfg->verbose_level > 2) {
4620 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4623 sig = mono_method_signature (cfg->method);
4624 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4625 cfg->vret_addr->inst_offset += delta;
4627 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4628 MonoInst *inst = cfg->args [i];
4630 inst->inst_offset += delta;
4634 * loads and stores based off the frame reg that (used to) lie
4635 * above the spill var area need to be increased by 'delta'
4636 * to make room for the spill vars.
4638 /* Need to find loads and stores to adjust that
4639 * are above where the spillvars were inserted, but
4640 * which are not the spillvar references themselves.
4642 * Idea - since all offsets from fp are positive, make
4643 * spillvar offsets negative to begin with so we can spot
4648 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4652 if (cfg->verbose_level > 2) {
4653 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4655 MONO_BB_FOR_EACH_INS (bb, ins) {
4659 if (cfg->verbose_level > 2) {
4660 mono_print_ins_index (ins_cnt, ins);
4662 /* The == mips_sp tests catch FP spills */
4663 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4664 (ins->inst_basereg == mips_sp))) {
4665 switch (ins->opcode) {
4666 case OP_LOADI8_MEMBASE:
4667 case OP_LOADR8_MEMBASE:
4674 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4675 (ins->dreg == mips_sp))) {
4676 switch (ins->opcode) {
4677 case OP_STOREI8_MEMBASE_REG:
4678 case OP_STORER8_MEMBASE_REG:
4679 case OP_STOREI8_MEMBASE_IMM:
4687 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4690 if (ins->inst_c0 >= threshold) {
4691 ins->inst_c0 += delta;
4692 if (cfg->verbose_level > 2) {
4694 mono_print_ins_index (ins_cnt, ins);
4697 else if (ins->inst_c0 < 0) {
4698 /* Adj_c0 holds the size of the datatype. */
4699 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4700 if (cfg->verbose_level > 2) {
4702 mono_print_ins_index (ins_cnt, ins);
4705 g_assert (ins->inst_c0 != ra_offset);
4708 if (ins->inst_imm >= threshold) {
4709 ins->inst_imm += delta;
4710 if (cfg->verbose_level > 2) {
4712 mono_print_ins_index (ins_cnt, ins);
4715 g_assert (ins->inst_c0 != ra_offset);
4725 * Stack frame layout:
4727 * ------------------- sp + cfg->stack_usage + cfg->param_area
4728 * param area incoming
4729 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4731 * ------------------- sp + cfg->stack_usage
4733 * ------------------- sp + cfg->stack_usage-4
4735 * ------------------- sp +
4736 * MonoLMF structure optional
4737 * ------------------- sp + cfg->arch.lmf_offset
4738 * saved registers s0-s8
4739 * ------------------- sp + cfg->arch.iregs_offset
4741 * ------------------- sp + cfg->param_area
4742 * param area outgoing
4743 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4745 * ------------------- sp
4749 mono_arch_emit_prolog (MonoCompile *cfg)
4751 MonoMethod *method = cfg->method;
4752 MonoMethodSignature *sig;
4754 int alloc_size, pos, i;
4755 int alloc2_size = 0;
4759 guint32 iregs_to_save = 0;
4761 guint32 fregs_to_save = 0;
4764 /* lmf_offset is the offset of the LMF from our stack pointer. */
4765 guint32 lmf_offset = cfg->arch.lmf_offset;
4769 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4773 cfg->flags |= MONO_CFG_HAS_CALLS;
4775 sig = mono_method_signature (method);
4776 cfg->code_size = 768 + sig->param_count * 20;
4777 code = cfg->native_code = g_malloc (cfg->code_size);
4780 #if _MIPS_SIM == _ABIO32
4781 cfg->arch.tracing_offset = cfg->stack_offset;
4782 #elif _MIPS_SIM == _ABIN32
4783 /* no stack slots by default for argument regs, reserve a special block */
4784 cfg->arch.tracing_offset = cfg->stack_offset;
4785 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4789 /* adjust stackframe assignments for spillvars if needed */
4790 mips_adjust_stackframe (cfg);
4792 /* Offset between current sp and the CFA */
4794 mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
4796 /* stack_offset should not be changed here. */
4797 alloc_size = cfg->stack_offset;
4798 cfg->stack_usage = alloc_size;
4801 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4803 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4807 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4809 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4810 fregs_to_save |= (fregs_to_save << 1);
4813 /* If the stack size is too big, save 1024 bytes to start with
4814 * so the prologue can use imm16(reg) addressing, then allocate
4815 * the rest of the frame.
4817 if (alloc_size > ((1 << 15) - 1024)) {
4818 alloc2_size = alloc_size - 1024;
4822 g_assert (mips_is_imm16 (-alloc_size));
4823 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4824 cfa_offset = alloc_size;
4825 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4828 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4829 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4830 if (mips_is_imm16(offset))
4831 mips_sw (code, mips_ra, mips_sp, offset);
4833 g_assert_not_reached ();
4835 /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
4836 mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
4839 /* XXX - optimize this later to not save all regs if LMF constructed */
4840 pos = cfg->arch.iregs_offset - alloc2_size;
4842 if (iregs_to_save) {
4843 /* save used registers in own stack frame (at pos) */
4844 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4845 if (iregs_to_save & (1 << i)) {
4846 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4847 g_assert (mips_is_imm16(pos));
4848 MIPS_SW (code, i, mips_sp, pos);
4849 mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
4850 pos += SIZEOF_REGISTER;
4855 if (method->save_lmf) {
4856 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4857 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4858 g_assert (mips_is_imm16(offset));
4859 MIPS_SW (code, i, mips_sp, offset);
4865 /* Save float registers */
4866 if (fregs_to_save) {
4867 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4868 if (fregs_to_save & (1 << i)) {
4869 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4870 g_assert (mips_is_imm16(pos));
4871 mips_swc1 (code, i, mips_sp, pos);
4872 pos += sizeof (gulong);
4877 if (method->save_lmf) {
4878 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4879 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4880 g_assert (mips_is_imm16(offset));
4881 mips_swc1 (code, i, mips_sp, offset);
4886 if (cfg->frame_reg != mips_sp) {
4887 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4888 mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
4890 if (method->save_lmf) {
4891 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4892 g_assert (mips_is_imm16(offset));
4893 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4898 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4899 * to the t* registers, which would be clobbered by the instrumentation calls.
4902 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4906 /* load arguments allocated to register from the stack */
4909 if (!cfg->arch.cinfo)
4910 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
4911 cinfo = cfg->arch.cinfo;
4913 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4914 ArgInfo *ainfo = &cinfo->ret;
4915 inst = cfg->vret_addr;
4916 if (inst->opcode == OP_REGVAR)
4917 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4918 else if (mips_is_imm16 (inst->inst_offset)) {
4919 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4921 mips_load_const (code, mips_at, inst->inst_offset);
4922 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4923 mips_sw (code, ainfo->reg, mips_at, 0);
4926 /* Keep this in sync with emit_load_volatile_arguments */
4927 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4928 ArgInfo *ainfo = cinfo->args + i;
4929 inst = cfg->args [pos];
4931 if (cfg->verbose_level > 2)
4932 g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
4933 if (inst->opcode == OP_REGVAR) {
4934 /* Argument ends up in a register */
4935 if (ainfo->storage == ArgInIReg)
4936 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4937 else if (ainfo->storage == ArgInFReg) {
4938 g_assert_not_reached();
4940 ppc_fmr (code, inst->dreg, ainfo->reg);
4943 else if (ainfo->storage == ArgOnStack) {
4944 int offset = cfg->stack_usage + ainfo->offset;
4945 g_assert (mips_is_imm16(offset));
4946 mips_lw (code, inst->dreg, mips_sp, offset);
4948 g_assert_not_reached ();
4950 if (cfg->verbose_level > 2)
4951 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4953 /* Argument ends up on the stack */
4954 if (ainfo->storage == ArgInIReg) {
4956 /* Incoming parameters should be above this frame */
4957 if (cfg->verbose_level > 2)
4958 g_print ("stack slot at %d of %d+%d\n",
4959 inst->inst_offset, alloc_size, alloc2_size);
4960 /* g_assert (inst->inst_offset >= alloc_size); */
4961 g_assert (inst->inst_basereg == mips_fp);
4962 basereg_offset = inst->inst_offset - alloc2_size;
4963 g_assert (mips_is_imm16 (basereg_offset));
4964 switch (ainfo->size) {
4966 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4969 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4973 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4976 #if (SIZEOF_REGISTER == 4)
4977 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset + ls_word_offset);
4978 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + ms_word_offset);
4979 #elif (SIZEOF_REGISTER == 8)
4980 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4984 g_assert_not_reached ();
4987 } else if (ainfo->storage == ArgOnStack) {
4989 * Argument comes in on the stack, and ends up on the stack
4990 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4991 * 8 and 16 bit quantities. Shorten them in place.
4993 g_assert (mips_is_imm16 (inst->inst_offset));
4994 switch (ainfo->size) {
4996 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4997 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
5000 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
5001 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
5008 g_assert_not_reached ();
5010 } else if (ainfo->storage == ArgInFReg) {
5011 g_assert (mips_is_imm16 (inst->inst_offset));
5012 g_assert (mips_is_imm16 (inst->inst_offset+4));
5013 if (ainfo->size == 8) {
5014 #if _MIPS_SIM == _ABIO32
5015 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset + ls_word_offset);
5016 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset + ms_word_offset);
5017 #elif _MIPS_SIM == _ABIN32
5018 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5021 else if (ainfo->size == 4)
5022 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
5024 g_assert_not_reached ();
5025 } else if (ainfo->storage == ArgStructByVal) {
5027 int doffset = inst->inst_offset;
5029 g_assert (mips_is_imm16 (inst->inst_offset));
5030 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
5031 /* Push the argument registers into their stack slots */
5032 for (i = 0; i < ainfo->size; ++i) {
5033 g_assert (mips_is_imm16(doffset));
5034 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
5035 doffset += SIZEOF_REGISTER;
5037 } else if (ainfo->storage == ArgStructByAddr) {
5038 g_assert (mips_is_imm16 (inst->inst_offset));
5039 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
5040 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
5042 g_assert_not_reached ();
5047 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
5048 mips_load_const (code, mips_a0, cfg->domain);
5049 mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
5053 if (method->save_lmf) {
5054 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
5055 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
5057 if (lmf_pthread_key != -1) {
5058 g_assert_not_reached();
5060 emit_tls_access (code, mips_temp, lmf_pthread_key);
5062 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
5063 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
5064 g_assert (mips_is_imm16(offset));
5065 mips_addiu (code, mips_a0, mips_temp, offset);
5068 /* This can/will clobber the a0-a3 registers */
5069 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
5072 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
5073 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5074 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5075 /* new_lmf->previous_lmf = *lmf_addr */
5076 mips_lw (code, mips_at, mips_v0, 0);
5077 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5078 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5079 /* *(lmf_addr) = sp + lmf_offset */
5080 g_assert (mips_is_imm16(lmf_offset));
5081 mips_addiu (code, mips_at, mips_sp, lmf_offset);
5082 mips_sw (code, mips_at, mips_v0, 0);
5084 /* save method info */
5085 mips_load_const (code, mips_at, method);
5086 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
5087 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
5088 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
5089 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
5091 /* save the current IP */
5092 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5093 mips_load_const (code, mips_at, 0x01010101);
5094 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5098 /* The CFA is fp now, so this doesn't need unwind info */
5099 if (mips_is_imm16 (-alloc2_size)) {
5100 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5103 mips_load_const (code, mips_at, -alloc2_size);
5104 mips_addu (code, mips_sp, mips_sp, mips_at);
5106 if (cfg->frame_reg != mips_sp)
5107 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5108 alloc_size += alloc2_size;
5111 cfg->code_len = code - cfg->native_code;
5112 g_assert (cfg->code_len < cfg->code_size);
5126 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5129 int save_mode = SAVE_NONE;
5131 MonoMethod *method = cfg->method;
5132 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5133 int save_offset = MIPS_STACK_PARAM_OFFSET;
5135 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5137 offset = code - cfg->native_code;
5138 /* we need about 16 instructions */
5139 if (offset > (cfg->code_size - 16 * 4)) {
5140 cfg->code_size *= 2;
5141 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5142 code = cfg->native_code + offset;
5147 case MONO_TYPE_VOID:
5148 /* special case string .ctor icall */
5149 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5150 save_mode = SAVE_ONE;
5152 save_mode = SAVE_NONE;
5156 save_mode = SAVE_FP;
5158 case MONO_TYPE_VALUETYPE:
5159 save_mode = SAVE_STRUCT;
5163 #if SIZEOF_REGISTER == 4
5164 save_mode = SAVE_TWO;
5165 #elif SIZEOF_REGISTER == 8
5166 save_mode = SAVE_ONE;
5170 save_mode = SAVE_ONE;
5174 mips_addiu (code, mips_sp, mips_sp, -32);
5175 g_assert (mips_is_imm16(save_offset));
5176 switch (save_mode) {
5178 mips_sw (code, mips_v0, mips_sp, save_offset);
5179 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5180 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5181 if (enable_arguments) {
5182 MIPS_MOVE (code, mips_a1, mips_v0);
5183 MIPS_MOVE (code, mips_a2, mips_v1);
5187 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5188 if (enable_arguments) {
5189 MIPS_MOVE (code, mips_a1, mips_v0);
5193 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5194 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5195 mips_lw (code, mips_a0, mips_sp, save_offset);
5196 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5197 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5204 mips_load_const (code, mips_a0, cfg->method);
5205 mips_call (code, mips_t9, func);
5207 switch (save_mode) {
5209 mips_lw (code, mips_v0, mips_sp, save_offset);
5210 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5211 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5214 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5217 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5224 mips_addiu (code, mips_sp, mips_sp, 32);
5231 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5233 MonoMethod *method = cfg->method;
5235 int max_epilog_size = 16 + 20*4;
5236 int alloc2_size = 0;
5237 guint32 iregs_to_restore;
5239 guint32 fregs_to_restore;
5243 if (cfg->method->save_lmf)
5244 max_epilog_size += 128;
5247 if (mono_jit_trace_calls != NULL)
5248 max_epilog_size += 50;
5250 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5251 max_epilog_size += 50;
5254 pos = code - cfg->native_code;
5255 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5256 cfg->code_size *= 2;
5257 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5258 cfg->stat_code_reallocs++;
5262 * Keep in sync with OP_JMP
5265 code = cfg->native_code + pos;
5267 code = cfg->native_code + cfg->code_len;
5269 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5270 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5272 if (cfg->frame_reg != mips_sp) {
5273 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5275 /* If the stack frame is really large, deconstruct it in two steps */
5276 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5277 alloc2_size = cfg->stack_usage - 1024;
5278 /* partially deconstruct the stack */
5279 mips_load_const (code, mips_at, alloc2_size);
5280 mips_addu (code, mips_sp, mips_sp, mips_at);
5282 pos = cfg->arch.iregs_offset - alloc2_size;
5284 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5286 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5288 if (iregs_to_restore) {
5289 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5290 if (iregs_to_restore & (1 << i)) {
5291 g_assert (mips_is_imm16(pos));
5292 MIPS_LW (code, i, mips_sp, pos);
5293 pos += SIZEOF_REGISTER;
5300 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5302 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5303 fregs_to_restore |= (fregs_to_restore << 1);
5305 if (fregs_to_restore) {
5306 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5307 if (fregs_to_restore & (1 << i)) {
5308 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5309 g_assert (mips_is_imm16(pos));
5310 mips_lwc1 (code, i, mips_sp, pos);
5317 /* Unlink the LMF if necessary */
5318 if (method->save_lmf) {
5319 int lmf_offset = cfg->arch.lmf_offset;
5321 /* t0 = current_lmf->previous_lmf */
5322 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5323 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5325 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5326 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5327 /* (*lmf_addr) = previous_lmf */
5328 mips_sw (code, mips_temp, mips_t1, 0);
5332 /* Restore the fp */
5333 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5336 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5337 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5338 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5340 /* Restore the stack pointer */
5341 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5342 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5344 /* Caller will emit either return or tail-call sequence */
5346 cfg->code_len = code - cfg->native_code;
5348 g_assert (cfg->code_len < cfg->code_size);
5353 mono_arch_emit_epilog (MonoCompile *cfg)
5357 code = mono_arch_emit_epilog_sub (cfg, NULL);
5359 mips_jr (code, mips_ra);
5362 cfg->code_len = code - cfg->native_code;
5364 g_assert (cfg->code_len < cfg->code_size);
5367 /* remove once throw_exception_by_name is eliminated */
5370 exception_id_by_name (const char *name)
5372 if (strcmp (name, "IndexOutOfRangeException") == 0)
5373 return MONO_EXC_INDEX_OUT_OF_RANGE;
5374 if (strcmp (name, "OverflowException") == 0)
5375 return MONO_EXC_OVERFLOW;
5376 if (strcmp (name, "ArithmeticException") == 0)
5377 return MONO_EXC_ARITHMETIC;
5378 if (strcmp (name, "DivideByZeroException") == 0)
5379 return MONO_EXC_DIVIDE_BY_ZERO;
5380 if (strcmp (name, "InvalidCastException") == 0)
5381 return MONO_EXC_INVALID_CAST;
5382 if (strcmp (name, "NullReferenceException") == 0)
5383 return MONO_EXC_NULL_REF;
5384 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5385 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5386 if (strcmp (name, "ArgumentException") == 0)
5387 return MONO_EXC_ARGUMENT;
5388 g_error ("Unknown intrinsic exception %s\n", name);
5394 mono_arch_emit_exceptions (MonoCompile *cfg)
5397 MonoJumpInfo *patch_info;
5400 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5401 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5402 int max_epilog_size = 50;
5404 /* count the number of exception infos */
5407 * make sure we have enough space for exceptions
5408 * 24 is the simulated call to throw_exception_by_name
5410 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5412 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5413 i = exception_id_by_name (patch_info->data.target);
5414 g_assert (i < MONO_EXC_INTRINS_NUM);
5415 if (!exc_throw_found [i]) {
5416 max_epilog_size += 12;
5417 exc_throw_found [i] = TRUE;
5423 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5424 cfg->code_size *= 2;
5425 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5426 cfg->stat_code_reallocs++;
5429 code = cfg->native_code + cfg->code_len;
5431 /* add code to raise exceptions */
5432 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5433 switch (patch_info->type) {
5434 case MONO_PATCH_INFO_EXC: {
5436 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5438 i = exception_id_by_name (patch_info->data.target);
5439 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5440 if (!exc_throw_pos [i]) {
5443 exc_throw_pos [i] = code;
5444 //g_print ("exc: writing stub at %p\n", code);
5445 mips_load_const (code, mips_a0, patch_info->data.target);
5446 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5447 mips_load_const (code, mips_t9, addr);
5448 mips_jr (code, mips_t9);
5451 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5453 /* Turn into a Relative patch, pointing at code stub */
5454 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5455 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5457 g_assert_not_reached();
5467 cfg->code_len = code - cfg->native_code;
5469 g_assert (cfg->code_len < cfg->code_size);
5474 * Thread local storage support
5477 setup_tls_access (void)
5480 //guint32 *ins, *code;
5482 if (tls_mode == TLS_MODE_FAILED)
5485 if (g_getenv ("MONO_NO_TLS")) {
5486 tls_mode = TLS_MODE_FAILED;
5490 if (tls_mode == TLS_MODE_DETECT) {
5492 tls_mode = TLS_MODE_FAILED;
5496 ins = (guint32*)pthread_getspecific;
5497 /* uncond branch to the real method */
5498 if ((*ins >> 26) == 18) {
5500 val = (*ins & ~3) << 6;
5504 ins = (guint32*)val;
5506 ins = (guint32*) ((char*)ins + val);
5509 code = &cmplwi_1023;
5510 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5512 ppc_li (code, ppc_r4, 0x48);
5515 if (*ins == cmplwi_1023) {
5516 int found_lwz_284 = 0;
5517 for (ptk = 0; ptk < 20; ++ptk) {
5519 if (!*ins || *ins == blr_ins)
5521 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5526 if (!found_lwz_284) {
5527 tls_mode = TLS_MODE_FAILED;
5530 tls_mode = TLS_MODE_LTHREADS;
5531 } else if (*ins == li_0x48) {
5533 /* uncond branch to the real method */
5534 if ((*ins >> 26) == 18) {
5536 val = (*ins & ~3) << 6;
5540 ins = (guint32*)val;
5542 ins = (guint32*) ((char*)ins + val);
5545 ppc_li (code, ppc_r0, 0x7FF2);
5546 if (ins [1] == val) {
5547 /* Darwin on G4, implement */
5548 tls_mode = TLS_MODE_FAILED;
5552 ppc_mfspr (code, ppc_r3, 104);
5553 if (ins [1] != val) {
5554 tls_mode = TLS_MODE_FAILED;
5557 tls_mode = TLS_MODE_DARWIN_G5;
5560 tls_mode = TLS_MODE_FAILED;
5564 tls_mode = TLS_MODE_FAILED;
5569 if (monodomain_key == -1) {
5570 ptk = mono_domain_get_tls_key ();
5572 monodomain_key = ptk;
5574 if (lmf_pthread_key == -1) {
5575 ptk = mono_jit_tls_id;
5577 /*g_print ("MonoLMF at: %d\n", ptk);*/
5578 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5579 init_tls_failed = 1;
5582 lmf_pthread_key = ptk;
5585 if (monothread_key == -1) {
5586 ptk = mono_thread_get_tls_key ();
5588 monothread_key = ptk;
5589 /*g_print ("thread inited: %d\n", ptk);*/
5591 /*g_print ("thread not inited yet %d\n", ptk);*/
5597 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5599 setup_tls_access ();
5603 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5608 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5610 int this_dreg = mips_a0;
5613 this_dreg = mips_a1;
5615 /* add the this argument */
5616 if (this_reg != -1) {
5618 MONO_INST_NEW (cfg, this, OP_MOVE);
5619 this->type = this_type;
5620 this->sreg1 = this_reg;
5621 this->dreg = mono_alloc_ireg (cfg);
5622 mono_bblock_add_inst (cfg->cbb, this);
5623 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5628 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5629 vtarg->type = STACK_MP;
5630 vtarg->sreg1 = vt_reg;
5631 vtarg->dreg = mono_alloc_ireg (cfg);
5632 mono_bblock_add_inst (cfg->cbb, vtarg);
5633 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5638 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5640 MonoInst *ins = NULL;
5646 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5652 mono_arch_print_tree (MonoInst *tree, int arity)
5657 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5661 setup_tls_access ();
5662 if (monodomain_key == -1)
5665 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5666 ins->inst_offset = monodomain_key;
5671 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5673 return ctx->sc_regs [reg];
5676 #ifdef MONO_ARCH_HAVE_IMT
5678 #define ENABLE_WRONG_METHOD_CHECK 0
5680 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5681 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5683 #define LOADSTORE_SIZE 4
5684 #define JUMP_IMM_SIZE 16
5685 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5686 #define LOAD_CONST_SIZE 8
5687 #define JUMP_JR_SIZE 8
5690 * LOCKING: called with the domain lock held
5693 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5694 gpointer fail_tramp)
5698 guint8 *code, *start, *patch;
5700 for (i = 0; i < count; ++i) {
5701 MonoIMTCheckItem *item = imt_entries [i];
5703 if (item->is_equals) {
5704 if (item->check_target_idx) {
5705 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5706 if (item->has_target_code)
5707 item->chunk_size += LOAD_CONST_SIZE;
5709 item->chunk_size += LOADSTORE_SIZE;
5712 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5713 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5714 if (!item->has_target_code)
5715 item->chunk_size += LOADSTORE_SIZE;
5717 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5718 #if ENABLE_WRONG_METHOD_CHECK
5719 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5724 item->chunk_size += CMP_SIZE + BR_SIZE;
5725 imt_entries [item->check_target_idx]->compare_done = TRUE;
5727 size += item->chunk_size;
5729 /* the initial load of the vtable address */
5730 size += MIPS_LOAD_SEQUENCE_LENGTH;
5732 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5734 code = mono_domain_code_reserve (domain, size);
5740 * We need to save and restore r11 because it might be
5741 * used by the caller as the vtable register, so
5742 * clobbering it will trip up the magic trampoline.
5744 * FIXME: Get rid of this by making sure that r11 is
5745 * not used as the vtable register in interface calls.
5747 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5748 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5750 /* t7 points to the vtable */
5751 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5753 for (i = 0; i < count; ++i) {
5754 MonoIMTCheckItem *item = imt_entries [i];
5756 item->code_target = code;
5757 if (item->is_equals) {
5758 if (item->check_target_idx) {
5759 mips_load_const (code, mips_temp, (gsize)item->key);
5760 item->jmp_code = code;
5761 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5763 if (item->has_target_code) {
5764 mips_load_const (code, mips_t9,
5765 item->value.target_code);
5768 mips_lw (code, mips_t9, mips_t7,
5769 (sizeof (gpointer) * item->value.vtable_slot));
5771 mips_jr (code, mips_t9);
5775 mips_load_const (code, mips_temp, (gsize)item->key);
5777 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5779 if (item->has_target_code) {
5780 mips_load_const (code, mips_t9,
5781 item->value.target_code);
5784 mips_load_const (code, mips_at,
5785 & (vtable->vtable [item->value.vtable_slot]));
5786 mips_lw (code, mips_t9, mips_at, 0);
5788 mips_jr (code, mips_t9);
5790 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5791 mips_load_const (code, mips_at, fail_tramp);
5792 mips_lw (code, mips_t9, mips_at, 0);
5793 mips_jr (code, mips_t9);
5796 /* enable the commented code to assert on wrong method */
5797 #if ENABLE_WRONG_METHOD_CHECK
5798 ppc_load (code, ppc_r0, (guint32)item->key);
5799 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5801 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5803 mips_lw (code, mips_t9, mips_t7,
5804 (sizeof (gpointer) * item->value.vtable_slot));
5805 mips_jr (code, mips_t9);
5808 #if ENABLE_WRONG_METHOD_CHECK
5809 ppc_patch (patch, code);
5815 mips_load_const (code, mips_temp, (gulong)item->key);
5816 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5818 item->jmp_code = code;
5819 mips_beq (code, mips_temp, mips_zero, 0);
5823 /* patch the branches to get to the target items */
5824 for (i = 0; i < count; ++i) {
5825 MonoIMTCheckItem *item = imt_entries [i];
5826 if (item->jmp_code && item->check_target_idx) {
5827 mips_patch ((guint32 *)item->jmp_code,
5828 (guint32)imt_entries [item->check_target_idx]->code_target);
5833 mono_stats.imt_thunks_size += code - start;
5834 g_assert (code - start <= size);
5835 mono_arch_flush_icache (start, size);
5840 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5842 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5847 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5850 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5853 /* Soft Debug support */
5854 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5857 * mono_arch_set_breakpoint:
5859 * See mini-amd64.c for docs.
5862 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5865 guint32 addr = (guint32)bp_trigger_page;
5867 mips_load_const (code, mips_t9, addr);
5868 mips_lw (code, mips_t9, mips_t9, 0);
5870 mono_arch_flush_icache (ip, code - ip);
5874 * mono_arch_clear_breakpoint:
5876 * See mini-amd64.c for docs.
5879 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5887 mono_arch_flush_icache (ip, code - ip);
5891 * mono_arch_start_single_stepping:
5893 * See mini-amd64.c for docs.
5896 mono_arch_start_single_stepping (void)
5898 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5902 * mono_arch_stop_single_stepping:
5904 * See mini-amd64.c for docs.
5907 mono_arch_stop_single_stepping (void)
5909 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5913 * mono_arch_is_single_step_event:
5915 * See mini-amd64.c for docs.
5918 mono_arch_is_single_step_event (void *info, void *sigctx)
5920 siginfo_t* sinfo = (siginfo_t*) info;
5921 /* Sometimes the address is off by 4 */
5922 if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5929 * mono_arch_is_breakpoint_event:
5931 * See mini-amd64.c for docs.
5934 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5936 siginfo_t* sinfo = (siginfo_t*) info;
5937 /* Sometimes the address is off by 4 */
5938 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5945 * mono_arch_skip_breakpoint:
5947 * See mini-amd64.c for docs.
5950 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5952 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5956 * mono_arch_skip_single_step:
5958 * See mini-amd64.c for docs.
5961 mono_arch_skip_single_step (MonoContext *ctx)
5963 MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5967 * mono_arch_get_seq_point_info:
5969 * See mini-amd64.c for docs.
5972 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5978 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */