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>
21 #include <mono/arch/mips/mips-codegen.h>
23 #include "mini-mips.h"
28 #define SAVE_FP_REGS 0
29 #define SAVE_ALL_REGS 0
30 #define EXTRA_STACK_SPACE 0 /* suppresses some s-reg corruption issues */
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) || ((_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;
71 #define DEBUG(a) if (cfg->verbose_level > 1) a
77 #define EMIT_SYSTEM_EXCEPTION_NAME(exc_name) \
79 code = mips_emit_exc_by_name (code, exc_name); \
80 cfg->bb_exit->max_offset += 16; \
84 #define emit_linuxthreads_tls(code,dreg,key) do {\
86 off1 = offsets_from_pthread_key ((key), &off2); \
87 g_assert_not_reached (); \
88 ppc_lwz ((code), (dreg), off1, ppc_r2); \
89 ppc_lwz ((code), (dreg), off2, (dreg)); \
93 #define emit_tls_access(code,dreg,key) do { \
95 case TLS_MODE_LTHREADS: emit_linuxthreads_tls(code,dreg,key); break; \
96 default: g_assert_not_reached (); \
100 #define MONO_EMIT_NEW_LOAD_R8(cfg,dr,addr) do { \
102 MONO_INST_NEW ((cfg), (inst), OP_R8CONST); \
103 inst->type = STACK_R8; \
105 inst->inst_p0 = (void*)(addr); \
106 mono_bblock_add_inst (cfg->cbb, inst); \
109 #define ins_is_compare(ins) ((ins) && (((ins)->opcode == OP_COMPARE) \
110 || ((ins)->opcode == OP_ICOMPARE) \
111 || ((ins)->opcode == OP_LCOMPARE)))
112 #define ins_is_compare_imm(ins) ((ins) && (((ins)->opcode == OP_COMPARE_IMM) \
113 || ((ins)->opcode == OP_ICOMPARE_IMM) \
114 || ((ins)->opcode == OP_LCOMPARE_IMM)))
116 #define INS_REWRITE(ins, op, _s1, _s2) do { \
119 ins->opcode = (op); \
124 #define INS_REWRITE_IMM(ins, op, _s1, _imm) do { \
126 ins->opcode = (op); \
128 ins->inst_imm = (_imm); \
132 typedef struct InstList InstList;
150 guint16 vtsize; /* in param area */
152 guint8 regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
153 guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
162 gboolean vtype_retaddr;
171 void patch_lui_addiu(guint32 *ip, guint32 val);
172 guint8 *mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code);
173 guint8 *mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins);
174 void mips_adjust_stackframe(MonoCompile *cfg);
175 void mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg);
176 MonoInst *mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
180 mono_arch_flush_icache (guint8 *code, gint size)
182 /* Linux/MIPS specific */
183 cacheflush (code, size, BCACHE);
187 mono_arch_flush_register_windows (void)
192 mono_arch_is_inst_imm (gint64 imm)
198 mips_emit_exc_by_name(guint8 *code, const char *name)
201 MonoClass *exc_class;
203 exc_class = mono_class_from_name (mono_defaults.corlib, "System", name);
204 g_assert (exc_class);
206 mips_load_const (code, mips_a0, exc_class->type_token);
207 addr = (guint32) mono_get_throw_corlib_exception ();
208 mips_call (code, mips_t9, addr);
214 mips_emit_load_const(guint8 *code, int dreg, mgreg_t v)
216 if (mips_is_imm16 (v))
217 mips_addiu (code, dreg, mips_zero, ((guint32)v) & 0xffff);
219 #if SIZEOF_REGISTER == 8
221 /* v is not a sign-extended 32-bit value */
222 mips_lui (code, dreg, mips_zero, (guint32)((v >> (32+16)) & 0xffff));
223 mips_ori (code, dreg, dreg, (guint32)((v >> (32)) & 0xffff));
224 mips_dsll (code, dreg, dreg, 16);
225 mips_ori (code, dreg, dreg, (guint32)((v >> (16)) & 0xffff));
226 mips_dsll (code, dreg, dreg, 16);
227 mips_ori (code, dreg, dreg, (guint32)(v & 0xffff));
231 if (((guint32)v) & (1 << 15)) {
232 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16)+1);
235 mips_lui (code, dreg, mips_zero, (((guint32)v)>>16));
237 if (((guint32)v) & 0xffff)
238 mips_addiu (code, dreg, dreg, ((guint32)v) & 0xffff);
244 mips_emit_cond_branch (MonoCompile *cfg, guint8 *code, int op, MonoInst *ins)
247 if (cfg->arch.long_branch) {
250 /* Invert test and emit branch around jump */
253 mips_bne (code, ins->sreg1, ins->sreg2, br_offset);
257 mips_beq (code, ins->sreg1, ins->sreg2, br_offset);
261 mips_bltz (code, ins->sreg1, br_offset);
265 mips_blez (code, ins->sreg1, br_offset);
269 mips_bgtz (code, ins->sreg1, br_offset);
273 mips_bgez (code, ins->sreg1, br_offset);
277 g_assert_not_reached ();
279 mono_add_patch_info (cfg, code - cfg->native_code,
280 MONO_PATCH_INFO_BB, ins->inst_true_bb);
281 mips_lui (code, mips_at, mips_zero, 0);
282 mips_addiu (code, mips_at, mips_at, 0);
283 mips_jr (code, mips_at);
287 mono_add_patch_info (cfg, code - cfg->native_code,
288 MONO_PATCH_INFO_BB, ins->inst_true_bb);
291 mips_beq (code, ins->sreg1, ins->sreg2, 0);
295 mips_bne (code, ins->sreg1, ins->sreg2, 0);
299 mips_bgez (code, ins->sreg1, 0);
303 mips_bgtz (code, ins->sreg1, 0);
307 mips_blez (code, ins->sreg1, 0);
311 mips_bltz (code, ins->sreg1, 0);
315 g_assert_not_reached ();
321 /* XXX - big-endian dependent? */
323 patch_lui_addiu(guint32 *ip, guint32 val)
325 guint16 *__lui_addiu = (guint16*)(void *)(ip);
328 printf ("patch_lui_addiu ip=0x%08x (0x%08x, 0x%08x) to point to 0x%08x\n",
329 ip, ((guint32 *)ip)[0], ((guint32 *)ip)[1], val);
332 if (((guint32)(val)) & (1 << 15))
333 __lui_addiu [MINI_LS_WORD_IDX] = ((((guint32)(val)) >> 16) & 0xffff) + 1;
335 __lui_addiu [MINI_LS_WORD_IDX] = (((guint32)(val)) >> 16) & 0xffff;
336 __lui_addiu [MINI_LS_WORD_IDX + 2] = ((guint32)(val)) & 0xffff;
337 mono_arch_flush_icache ((guint8 *)ip, 8);
342 mips_patch (guint32 *code, guint32 target)
345 guint32 op = ins >> 26;
346 guint32 diff, offset;
348 g_assert (trap_target != target);
349 //printf ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
351 case 0x00: /* jr ra */
352 if (ins == 0x3e00008)
354 g_assert_not_reached ();
358 g_assert (!(target & 0x03));
359 g_assert ((target & 0xfc000000) == (((guint32)code) & 0xfc000000));
360 ins = (ins & 0xfc000000) | (((target) >> 2) & 0x03ffffff);
362 mono_arch_flush_icache ((guint8 *)code, 4);
364 case 0x01: /* BLTZ */
367 case 0x06: /* BLEZ */
368 case 0x07: /* BGTZ */
369 case 0x11: /* bc1t */
370 diff = target - (guint32)(code + 1);
371 g_assert (((diff & 0x0003ffff) == diff) || ((diff | 0xfffc0000) == diff));
372 g_assert (!(diff & 0x03));
373 offset = ((gint32)diff) >> 2;
374 g_assert (((int)offset) == ((int)(short)offset));
375 ins = (ins & 0xffff0000) | (offset & 0x0000ffff);
377 mono_arch_flush_icache ((guint8 *)code, 4);
379 case 0x0f: /* LUI / ADDIU pair */
380 patch_lui_addiu (code, target);
381 mono_arch_flush_icache ((guint8 *)code, 8);
385 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
386 g_assert_not_reached ();
392 offsets_from_pthread_key (guint32 key, int *offset2)
396 *offset2 = idx2 * sizeof (gpointer);
397 return 284 + idx1 * sizeof (gpointer);
402 mono_arch_regname (int reg) {
403 #if _MIPS_SIM == _ABIO32
404 static const char * rnames[] = {
405 "zero", "at", "v0", "v1",
406 "a0", "a1", "a2", "a3",
407 "t0", "t1", "t2", "t3",
408 "t4", "t5", "t6", "t7",
409 "s0", "s1", "s2", "s3",
410 "s4", "s5", "s6", "s7",
411 "t8", "t9", "k0", "k1",
412 "gp", "sp", "fp", "ra"
414 #elif _MIPS_SIM == _ABIN32
415 static const char * rnames[] = {
416 "zero", "at", "v0", "v1",
417 "a0", "a1", "a2", "a3",
418 "a4", "a5", "a6", "a7",
419 "t0", "t1", "t2", "t3",
420 "s0", "s1", "s2", "s3",
421 "s4", "s5", "s6", "s7",
422 "t8", "t9", "k0", "k1",
423 "gp", "sp", "fp", "ra"
426 if (reg >= 0 && reg < 32)
432 mono_arch_fregname (int reg) {
433 static const char * rnames[] = {
434 "f0", "f1", "f2", "f3",
435 "f4", "f5", "f6", "f7",
436 "f8", "f9", "f10", "f11",
437 "f12", "f13", "f14", "f15",
438 "f16", "f17", "f18", "f19",
439 "f20", "f21", "f22", "f23",
440 "f24", "f25", "f26", "f27",
441 "f28", "f29", "f30", "f31"
443 if (reg >= 0 && reg < 32)
448 /* this function overwrites at */
450 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
452 /* XXX write a loop, not an unrolled loop */
454 mips_lw (code, mips_at, sreg, soffset);
455 mips_sw (code, mips_at, dreg, doffset);
464 * mono_arch_get_argument_info:
465 * @csig: a method signature
466 * @param_count: the number of parameters to consider
467 * @arg_info: an array to store the result infos
469 * Gathers information on parameters such as size, alignment and
470 * padding. arg_info should be large enought to hold param_count + 1 entries.
472 * Returns the size of the activation frame.
475 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
477 int k, frame_size = 0;
478 guint32 size, align, pad;
481 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
482 frame_size += sizeof (gpointer);
486 arg_info [0].offset = offset;
489 frame_size += sizeof (gpointer);
493 arg_info [0].size = frame_size;
495 for (k = 0; k < param_count; k++) {
496 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
498 /* ignore alignment for now */
501 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
502 arg_info [k].pad = pad;
504 arg_info [k + 1].pad = 0;
505 arg_info [k + 1].size = size;
507 arg_info [k + 1].offset = offset;
511 align = MONO_ARCH_FRAME_ALIGNMENT;
512 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
513 arg_info [k].pad = pad;
520 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
523 return (gpointer)regs [mips_a0];
527 * Initialize the cpu to execute managed code.
530 mono_arch_cpu_init (void)
535 * Initialize architecture specific code.
538 mono_arch_init (void)
540 InitializeCriticalSection (&mini_arch_mutex);
544 * Cleanup architecture specific code.
547 mono_arch_cleanup (void)
549 DeleteCriticalSection (&mini_arch_mutex);
553 * This function returns the optimizations supported on this cpu.
556 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
560 /* no mips-specific optimizations yet */
566 is_regsize_var (MonoType *t) {
569 t = mono_type_get_underlying_type (t);
573 #if (SIZEOF_REGISTER == 8)
580 case MONO_TYPE_FNPTR:
582 case MONO_TYPE_OBJECT:
583 case MONO_TYPE_STRING:
584 case MONO_TYPE_CLASS:
585 case MONO_TYPE_SZARRAY:
586 case MONO_TYPE_ARRAY:
588 case MONO_TYPE_GENERICINST:
589 if (!mono_type_generic_inst_is_valuetype (t))
592 case MONO_TYPE_VALUETYPE:
599 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
604 for (i = 0; i < cfg->num_varinfo; i++) {
605 MonoInst *ins = cfg->varinfo [i];
606 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
609 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
612 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
615 /* we can only allocate 32 bit values */
616 if (is_regsize_var (ins->inst_vtype)) {
617 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
618 g_assert (i == vmv->idx);
619 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
627 mono_arch_get_global_int_regs (MonoCompile *cfg)
631 regs = g_list_prepend (regs, (gpointer)mips_s0);
632 regs = g_list_prepend (regs, (gpointer)mips_s1);
633 regs = g_list_prepend (regs, (gpointer)mips_s2);
634 regs = g_list_prepend (regs, (gpointer)mips_s3);
635 regs = g_list_prepend (regs, (gpointer)mips_s4);
636 //regs = g_list_prepend (regs, (gpointer)mips_s5);
637 regs = g_list_prepend (regs, (gpointer)mips_s6);
638 regs = g_list_prepend (regs, (gpointer)mips_s7);
644 * mono_arch_regalloc_cost:
646 * Return the cost, in number of memory references, of the action of
647 * allocating the variable VMV into a register during global register
651 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
658 args_onto_stack (CallInfo *info)
660 g_assert (!info->on_stack);
661 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
662 info->on_stack = TRUE;
663 info->stack_size = MIPS_STACK_PARAM_OFFSET;
666 #if _MIPS_SIM == _ABIO32
668 * O32 calling convention version
672 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
673 /* First, see if we need to drop onto the stack */
674 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
675 args_onto_stack (info);
677 /* Now, place the argument */
678 if (info->on_stack) {
679 ainfo->regtype = RegTypeBase;
680 ainfo->reg = mips_sp; /* in the caller */
681 ainfo->offset = info->stack_size;
684 ainfo->regtype = RegTypeGeneral;
685 ainfo->reg = info->gr;
687 info->gr_passed = TRUE;
689 info->stack_size += 4;
693 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
694 /* First, see if we need to drop onto the stack */
695 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
696 args_onto_stack (info);
698 /* Now, place the argument */
699 if (info->on_stack) {
700 g_assert (info->stack_size % 4 == 0);
701 info->stack_size += (info->stack_size % 8);
703 ainfo->regtype = RegTypeBase;
704 ainfo->reg = mips_sp; /* in the caller */
705 ainfo->offset = info->stack_size;
708 // info->gr must be a0 or a2
709 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
710 g_assert(info->gr <= MIPS_LAST_ARG_REG);
712 ainfo->regtype = RegTypeGeneral;
713 ainfo->reg = info->gr;
715 info->gr_passed = TRUE;
717 info->stack_size += 8;
721 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
722 /* First, see if we need to drop onto the stack */
723 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
724 args_onto_stack (info);
726 /* Now, place the argument */
727 if (info->on_stack) {
728 ainfo->regtype = RegTypeBase;
729 ainfo->reg = mips_sp; /* in the caller */
730 ainfo->offset = info->stack_size;
733 /* Only use FP regs for args if no int args passed yet */
734 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
735 ainfo->regtype = RegTypeFP;
736 ainfo->reg = info->fr;
737 /* Even though it's a single-precision float, it takes up two FP regs */
739 /* FP and GP slots do not overlap */
743 /* Passing single-precision float arg in a GP register
744 * such as: func (0, 1.0, 2, 3);
745 * In this case, only one 'gr' register is consumed.
747 ainfo->regtype = RegTypeGeneral;
748 ainfo->reg = info->gr;
751 info->gr_passed = TRUE;
754 info->stack_size += 4;
758 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
759 /* First, see if we need to drop onto the stack */
760 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
761 args_onto_stack (info);
763 /* Now, place the argument */
764 if (info->on_stack) {
765 g_assert(info->stack_size % 4 == 0);
766 info->stack_size += (info->stack_size % 8);
768 ainfo->regtype = RegTypeBase;
769 ainfo->reg = mips_sp; /* in the caller */
770 ainfo->offset = info->stack_size;
773 /* Only use FP regs for args if no int args passed yet */
774 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
775 ainfo->regtype = RegTypeFP;
776 ainfo->reg = info->fr;
778 /* FP and GP slots do not overlap */
782 // info->gr must be a0 or a2
783 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
784 g_assert(info->gr <= MIPS_LAST_ARG_REG);
786 ainfo->regtype = RegTypeGeneral;
787 ainfo->reg = info->gr;
789 info->gr_passed = TRUE;
792 info->stack_size += 8;
794 #elif _MIPS_SIM == _ABIN32
796 * N32 calling convention version
800 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
801 /* First, see if we need to drop onto the stack */
802 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
803 args_onto_stack (info);
805 /* Now, place the argument */
806 if (info->on_stack) {
807 ainfo->regtype = RegTypeBase;
808 ainfo->reg = mips_sp; /* in the caller */
809 ainfo->offset = info->stack_size;
810 info->stack_size += SIZEOF_REGISTER;
813 ainfo->regtype = RegTypeGeneral;
814 ainfo->reg = info->gr;
816 info->gr_passed = TRUE;
821 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
822 /* First, see if we need to drop onto the stack */
823 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
824 args_onto_stack (info);
826 /* Now, place the argument */
827 if (info->on_stack) {
828 g_assert (info->stack_size % 4 == 0);
829 info->stack_size += (info->stack_size % 8);
831 ainfo->regtype = RegTypeBase;
832 ainfo->reg = mips_sp; /* in the caller */
833 ainfo->offset = info->stack_size;
834 info->stack_size += SIZEOF_REGISTER;
837 g_assert (info->gr <= MIPS_LAST_ARG_REG);
839 ainfo->regtype = RegTypeGeneral;
840 ainfo->reg = info->gr;
842 info->gr_passed = TRUE;
847 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
848 /* First, see if we need to drop onto the stack */
849 if (!info->on_stack) {
850 if (info->gr > MIPS_LAST_ARG_REG)
851 args_onto_stack (info);
852 else if (info->fr > MIPS_LAST_FPARG_REG)
853 args_onto_stack (info);
856 /* Now, place the argument */
857 if (info->on_stack) {
858 ainfo->regtype = RegTypeBase;
859 ainfo->reg = mips_sp; /* in the caller */
860 ainfo->offset = info->stack_size;
861 info->stack_size += FREG_SIZE;
864 ainfo->regtype = RegTypeFP;
865 ainfo->reg = info->fr;
867 /* FP and GP slots do not overlap */
873 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
874 /* First, see if we need to drop onto the stack */
875 if (!info->on_stack) {
876 if (info->gr > MIPS_LAST_ARG_REG)
877 args_onto_stack (info);
878 else if (info->fr > MIPS_LAST_FPARG_REG)
879 args_onto_stack (info);
882 /* Now, place the argument */
883 if (info->on_stack) {
884 g_assert(info->stack_size % 4 == 0);
885 info->stack_size += (info->stack_size % 8);
887 ainfo->regtype = RegTypeBase;
888 ainfo->reg = mips_sp; /* in the caller */
889 ainfo->offset = info->stack_size;
890 info->stack_size += FREG_SIZE;
893 ainfo->regtype = RegTypeFP;
894 ainfo->reg = info->fr;
896 /* FP and GP slots do not overlap */
903 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
906 int n = sig->hasthis + sig->param_count;
908 MonoType* simpletype;
909 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
911 cinfo->fr = MIPS_FIRST_FPARG_REG;
912 cinfo->gr = MIPS_FIRST_ARG_REG;
913 cinfo->stack_size = 0;
915 DEBUG(printf("calculate_sizes\n"));
917 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
921 /* handle returning a struct */
922 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
923 cinfo->struct_ret = cinfo->gr;
924 add_int32_arg (cinfo, &cinfo->ret);
928 add_int32_arg (cinfo, cinfo->args + n);
933 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
934 * the first argument, allowing 'this' to be always passed in the first arg reg.
935 * Also do this if the first argument is a reference type, since virtual calls
936 * are sometimes made using calli without sig->hasthis set, like in the delegate
939 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]))))) {
941 add_int32_arg (cinfo, cinfo->args + n);
944 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
948 add_int32_arg (cinfo, &cinfo->ret);
949 cinfo->struct_ret = cinfo->ret.reg;
953 add_int32_arg (cinfo, cinfo->args + n);
957 if (cinfo->vtype_retaddr) {
958 add_int32_arg (cinfo, &cinfo->ret);
959 cinfo->struct_ret = cinfo->ret.reg;
964 DEBUG(printf("params: %d\n", sig->param_count));
965 for (i = pstart; i < sig->param_count; ++i) {
966 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
967 /* Prevent implicit arguments and sig_cookie from
968 being passed in registers */
969 args_onto_stack (cinfo);
970 /* Emit the signature cookie just before the implicit arguments */
971 add_int32_arg (cinfo, &cinfo->sig_cookie);
973 DEBUG(printf("param %d: ", i));
974 if (sig->params [i]->byref) {
975 DEBUG(printf("byref\n"));
976 add_int32_arg (cinfo, &cinfo->args[n]);
980 simpletype = mono_type_get_underlying_type (sig->params [i]);
981 switch (simpletype->type) {
982 case MONO_TYPE_BOOLEAN:
985 DEBUG(printf("1 byte\n"));
986 cinfo->args [n].size = 1;
987 add_int32_arg (cinfo, &cinfo->args[n]);
993 DEBUG(printf("2 bytes\n"));
994 cinfo->args [n].size = 2;
995 add_int32_arg (cinfo, &cinfo->args[n]);
1000 DEBUG(printf("4 bytes\n"));
1001 cinfo->args [n].size = 4;
1002 add_int32_arg (cinfo, &cinfo->args[n]);
1008 case MONO_TYPE_FNPTR:
1009 case MONO_TYPE_CLASS:
1010 case MONO_TYPE_OBJECT:
1011 case MONO_TYPE_STRING:
1012 case MONO_TYPE_SZARRAY:
1013 case MONO_TYPE_ARRAY:
1014 cinfo->args [n].size = sizeof (gpointer);
1015 add_int32_arg (cinfo, &cinfo->args[n]);
1018 case MONO_TYPE_GENERICINST:
1019 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1020 cinfo->args [n].size = sizeof (gpointer);
1021 add_int32_arg (cinfo, &cinfo->args[n]);
1026 case MONO_TYPE_VALUETYPE: {
1029 int has_offset = FALSE;
1031 gint size, alignment;
1034 klass = mono_class_from_mono_type (sig->params [i]);
1036 size = mono_class_native_size (klass, NULL);
1038 size = mono_class_value_size (klass, NULL);
1039 alignment = mono_class_min_align (klass);
1040 #if MIPS_PASS_STRUCTS_BY_VALUE
1041 /* Need to do alignment if struct contains long or double */
1042 if (alignment > 4) {
1043 if (cinfo->stack_size & (alignment - 1)) {
1044 add_int32_arg (cinfo, &dummy_arg);
1046 g_assert (!(cinfo->stack_size & (alignment - 1)));
1050 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1051 mono_class_native_size (sig->params [i]->data.klass, NULL),
1052 cinfo->stack_size, alignment);
1054 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1055 g_assert (cinfo->args [n].size == 0);
1056 g_assert (cinfo->args [n].vtsize == 0);
1057 for (j = 0; j < nwords; ++j) {
1059 add_int32_arg (cinfo, &cinfo->args [n]);
1060 if (cinfo->on_stack)
1063 add_int32_arg (cinfo, &dummy_arg);
1064 if (!has_offset && cinfo->on_stack) {
1065 cinfo->args [n].offset = dummy_arg.offset;
1069 if (cinfo->on_stack)
1070 cinfo->args [n].vtsize += 1;
1072 cinfo->args [n].size += 1;
1074 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1075 cinfo->args [n].regtype = RegTypeStructByVal;
1077 add_int32_arg (cinfo, &cinfo->args[n]);
1078 cinfo->args [n].regtype = RegTypeStructByAddr;
1083 case MONO_TYPE_TYPEDBYREF: {
1084 /* keep in sync or merge with the valuetype case */
1085 #if MIPS_PASS_STRUCTS_BY_VALUE
1087 int size = sizeof (MonoTypedRef);
1088 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1089 cinfo->args [n].regtype = RegTypeStructByVal;
1090 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
1091 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
1092 int n_in_regs = rest >= nwords? nwords: rest;
1093 cinfo->args [n].size = n_in_regs;
1094 cinfo->args [n].vtsize = nwords - n_in_regs;
1095 cinfo->args [n].reg = cinfo->gr;
1096 cinfo->gr += n_in_regs;
1097 cinfo->gr_passed = TRUE;
1099 cinfo->args [n].size = 0;
1100 cinfo->args [n].vtsize = nwords;
1102 if (cinfo->args [n].vtsize > 0) {
1103 if (!cinfo->on_stack)
1104 args_onto_stack (cinfo);
1105 g_assert(cinfo->on_stack);
1106 cinfo->args [n].offset = cinfo->stack_size;
1107 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
1108 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
1112 add_int32_arg (cinfo, &cinfo->args[n]);
1113 cinfo->args [n].regtype = RegTypeStructByAddr;
1120 DEBUG(printf("8 bytes\n"));
1121 cinfo->args [n].size = 8;
1122 add_int64_arg (cinfo, &cinfo->args[n]);
1126 DEBUG(printf("R4\n"));
1127 cinfo->args [n].size = 4;
1128 add_float32_arg (cinfo, &cinfo->args[n]);
1132 DEBUG(printf("R8\n"));
1133 cinfo->args [n].size = 8;
1134 add_float64_arg (cinfo, &cinfo->args[n]);
1138 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1143 simpletype = mono_type_get_underlying_type (sig->ret);
1144 switch (simpletype->type) {
1145 case MONO_TYPE_BOOLEAN:
1150 case MONO_TYPE_CHAR:
1156 case MONO_TYPE_FNPTR:
1157 case MONO_TYPE_CLASS:
1158 case MONO_TYPE_OBJECT:
1159 case MONO_TYPE_SZARRAY:
1160 case MONO_TYPE_ARRAY:
1161 case MONO_TYPE_STRING:
1162 cinfo->ret.reg = mips_v0;
1166 cinfo->ret.reg = mips_v0;
1170 cinfo->ret.reg = mips_f0;
1171 cinfo->ret.regtype = RegTypeFP;
1173 case MONO_TYPE_GENERICINST:
1174 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1175 cinfo->ret.reg = mips_v0;
1179 case MONO_TYPE_VALUETYPE:
1181 case MONO_TYPE_TYPEDBYREF:
1182 case MONO_TYPE_VOID:
1185 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1189 /* align stack size to 16 */
1190 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1192 cinfo->stack_usage = cinfo->stack_size;
1198 * Set var information according to the calling convention. mips version.
1199 * The locals var stuff should most likely be split in another method.
1202 mono_arch_allocate_vars (MonoCompile *cfg)
1204 MonoMethodSignature *sig;
1205 MonoMethodHeader *header;
1207 int i, offset, size, align, curinst;
1208 int frame_reg = mips_sp;
1209 guint32 iregs_to_save = 0;
1211 guint32 fregs_to_restore;
1214 /* spill down, we'll fix it in a separate pass */
1215 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1217 /* allow room for the vararg method args: void* and long/double */
1218 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1219 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1221 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1222 * call convs needs to be handled this way.
1224 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1225 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1227 /* gtk-sharp and other broken code will dllimport vararg functions even with
1228 * non-varargs signatures. Since there is little hope people will get this right
1229 * we assume they won't.
1231 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1232 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1234 /* a0-a3 always present */
1235 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1237 header = cfg->header;
1239 sig = mono_method_signature (cfg->method);
1242 * We use the frame register also for any method that has
1243 * exception clauses. This way, when the handlers are called,
1244 * the code will reference local variables using the frame reg instead of
1245 * the stack pointer: if we had to restore the stack pointer, we'd
1246 * corrupt the method frames that are already on the stack (since
1247 * filters get called before stack unwinding happens) when the filter
1248 * code would call any method (this also applies to finally etc.).
1251 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1252 frame_reg = mips_fp;
1253 cfg->frame_reg = frame_reg;
1254 if (frame_reg != mips_sp) {
1255 cfg->used_int_regs |= 1 << frame_reg;
1260 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1261 /* FIXME: handle long and FP values */
1262 switch (mono_type_get_underlying_type (sig->ret)->type) {
1263 case MONO_TYPE_VOID:
1267 cfg->ret->opcode = OP_REGVAR;
1268 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1271 cfg->ret->opcode = OP_REGVAR;
1272 cfg->ret->inst_c0 = mips_v0;
1276 /* Space for outgoing parameters, including a0-a3 */
1277 offset += cfg->param_area;
1279 /* allow room to save the return value (if it's a struct) */
1280 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1283 if (sig->call_convention == MONO_CALL_VARARG) {
1284 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1287 /* Now handle the local variables */
1289 curinst = cfg->locals_start;
1290 for (i = curinst; i < cfg->num_varinfo; ++i) {
1291 inst = cfg->varinfo [i];
1292 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1295 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1296 * pinvoke wrappers when they call functions returning structure
1298 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1299 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1301 size = mono_type_size (inst->inst_vtype, &align);
1303 offset += align - 1;
1304 offset &= ~(align - 1);
1305 inst->inst_offset = offset;
1306 inst->opcode = OP_REGOFFSET;
1307 inst->inst_basereg = frame_reg;
1309 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1312 /* Space for LMF (if needed) */
1314 if (cfg->method->save_lmf) {
1315 /* align the offset to 16 bytes */
1316 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1317 cfg->arch.lmf_offset = offset;
1318 offset += sizeof (MonoLMF);
1322 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1323 * args or return vals. Extra stack space avoids this in a lot of cases.
1325 offset += EXTRA_STACK_SPACE;
1327 /* Space for saved registers */
1328 cfg->arch.iregs_offset = offset;
1330 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1332 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1334 if (iregs_to_save) {
1335 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1336 if (iregs_to_save & (1 << i)) {
1337 offset += SIZEOF_REGISTER;
1342 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1343 * args or return vals. Extra stack space avoids this in a lot of cases.
1345 offset += EXTRA_STACK_SPACE;
1347 /* saved float registers */
1349 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1350 if (fregs_to_restore) {
1351 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1352 if (fregs_to_restore & (1 << i)) {
1353 offset += sizeof(double);
1359 #if _MIPS_SIM == _ABIO32
1360 /* Now add space for saving the ra */
1361 offset += SIZEOF_VOID_P;
1364 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1365 cfg->stack_offset = offset;
1366 cfg->arch.local_alloc_offset = cfg->stack_offset;
1370 * Now allocate stack slots for the int arg regs (a0 - a3)
1371 * On MIPS o32, these are just above the incoming stack pointer
1372 * Even if the arg has been assigned to a regvar, it gets a stack slot
1375 /* Return struct-by-value results in a hidden first argument */
1376 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1377 cfg->vret_addr->opcode = OP_REGOFFSET;
1378 cfg->vret_addr->inst_c0 = mips_a0;
1379 cfg->vret_addr->inst_offset = offset;
1380 cfg->vret_addr->inst_basereg = frame_reg;
1381 offset += SIZEOF_REGISTER;
1384 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1385 inst = cfg->args [i];
1386 if (inst->opcode != OP_REGVAR) {
1389 if (sig->hasthis && (i == 0))
1390 arg_type = &mono_defaults.object_class->byval_arg;
1392 arg_type = sig->params [i - sig->hasthis];
1394 inst->opcode = OP_REGOFFSET;
1395 size = mono_type_size (arg_type, &align);
1397 if (size < SIZEOF_REGISTER) {
1398 size = SIZEOF_REGISTER;
1399 align = SIZEOF_REGISTER;
1401 inst->inst_basereg = frame_reg;
1402 offset = (offset + align - 1) & ~(align - 1);
1403 inst->inst_offset = offset;
1405 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1406 cfg->sig_cookie += size;
1407 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1410 #if _MIPS_SIM == _ABIO32
1411 /* o32: Even a0-a3 get stack slots */
1412 size = SIZEOF_REGISTER;
1413 align = SIZEOF_REGISTER;
1414 inst->inst_basereg = frame_reg;
1415 offset = (offset + align - 1) & ~(align - 1);
1416 inst->inst_offset = offset;
1418 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1419 cfg->sig_cookie += size;
1420 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1424 #if _MIPS_SIM == _ABIN32
1425 /* Now add space for saving the ra */
1426 offset += SIZEOF_VOID_P;
1429 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1430 cfg->stack_offset = offset;
1431 cfg->arch.local_alloc_offset = cfg->stack_offset;
1436 mono_arch_create_vars (MonoCompile *cfg)
1438 MonoMethodSignature *sig;
1440 sig = mono_method_signature (cfg->method);
1442 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1443 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1444 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1445 printf ("vret_addr = ");
1446 mono_print_ins (cfg->vret_addr);
1451 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1452 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1456 * take the arguments and generate the arch-specific
1457 * instructions to properly call the function in call.
1458 * This includes pushing, moving arguments to the right register
1460 * Issue: who does the spilling if needed, and when?
1463 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1465 int sig_reg = mono_alloc_ireg (cfg);
1467 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1468 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1469 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1473 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1476 MonoMethodSignature *sig;
1481 sig = call->signature;
1482 n = sig->param_count + sig->hasthis;
1484 cinfo = calculate_sizes (sig, sig->pinvoke);
1485 if (cinfo->struct_ret)
1486 call->used_iregs |= 1 << cinfo->struct_ret;
1488 for (i = 0; i < n; ++i) {
1489 ArgInfo *ainfo = cinfo->args + i;
1492 if (i >= sig->hasthis)
1493 t = sig->params [i - sig->hasthis];
1495 t = &mono_defaults.int_class->byval_arg;
1496 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1498 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1499 emit_sig_cookie (cfg, call, cinfo);
1500 if (is_virtual && i == 0) {
1501 /* the argument will be attached to the call instrucion */
1502 in = call->args [i];
1503 call->used_iregs |= 1 << ainfo->reg;
1506 in = call->args [i];
1507 if (ainfo->regtype == RegTypeGeneral) {
1508 #if SIZEOF_REGISTER == 4
1509 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1510 MONO_INST_NEW (cfg, ins, OP_MOVE);
1511 ins->dreg = mono_alloc_ireg (cfg);
1512 ins->sreg1 = in->dreg + 1;
1513 MONO_ADD_INS (cfg->cbb, ins);
1514 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1516 MONO_INST_NEW (cfg, ins, OP_MOVE);
1517 ins->dreg = mono_alloc_ireg (cfg);
1518 ins->sreg1 = in->dreg + 2;
1519 MONO_ADD_INS (cfg->cbb, ins);
1520 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1523 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1526 #if PROMOTE_R4_TO_R8
1527 /* ??? - convert to single first? */
1528 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1529 ins->dreg = mono_alloc_freg (cfg);
1530 ins->sreg1 = in->dreg;
1531 MONO_ADD_INS (cfg->cbb, ins);
1536 /* trying to load float value into int registers */
1537 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1538 ins->dreg = mono_alloc_ireg (cfg);
1540 MONO_ADD_INS (cfg->cbb, ins);
1541 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1542 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1543 /* trying to load float value into int registers */
1544 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1545 ins->dreg = mono_alloc_ireg (cfg);
1546 ins->sreg1 = in->dreg;
1547 MONO_ADD_INS (cfg->cbb, ins);
1548 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1550 MONO_INST_NEW (cfg, ins, OP_MOVE);
1551 ins->dreg = mono_alloc_ireg (cfg);
1552 ins->sreg1 = in->dreg;
1553 MONO_ADD_INS (cfg->cbb, ins);
1554 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1556 } else if (ainfo->regtype == RegTypeStructByAddr) {
1557 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1558 ins->opcode = OP_OUTARG_VT;
1559 ins->sreg1 = in->dreg;
1560 ins->klass = in->klass;
1561 ins->inst_p0 = call;
1562 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1563 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1564 MONO_ADD_INS (cfg->cbb, ins);
1565 } else if (ainfo->regtype == RegTypeStructByVal) {
1566 /* this is further handled in mono_arch_emit_outarg_vt () */
1567 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1568 ins->opcode = OP_OUTARG_VT;
1569 ins->sreg1 = in->dreg;
1570 ins->klass = in->klass;
1571 ins->inst_p0 = call;
1572 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1573 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1574 MONO_ADD_INS (cfg->cbb, ins);
1575 } else if (ainfo->regtype == RegTypeBase) {
1576 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1577 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1578 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1579 if (t->type == MONO_TYPE_R8)
1580 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1582 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1584 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1586 } else if (ainfo->regtype == RegTypeFP) {
1587 if (t->type == MONO_TYPE_VALUETYPE) {
1588 /* this is further handled in mono_arch_emit_outarg_vt () */
1589 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1590 ins->opcode = OP_OUTARG_VT;
1591 ins->sreg1 = in->dreg;
1592 ins->klass = in->klass;
1593 ins->inst_p0 = call;
1594 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1595 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1596 MONO_ADD_INS (cfg->cbb, ins);
1598 cfg->flags |= MONO_CFG_HAS_FPOUT;
1600 int dreg = mono_alloc_freg (cfg);
1602 if (ainfo->size == 4) {
1603 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1605 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1607 ins->sreg1 = in->dreg;
1608 MONO_ADD_INS (cfg->cbb, ins);
1611 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1612 cfg->flags |= MONO_CFG_HAS_FPOUT;
1615 g_assert_not_reached ();
1619 /* Emit the signature cookie in the case that there is no
1620 additional argument */
1621 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1622 emit_sig_cookie (cfg, call, cinfo);
1624 if (cinfo->struct_ret) {
1627 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1628 vtarg->sreg1 = call->vret_var->dreg;
1629 vtarg->dreg = mono_alloc_preg (cfg);
1630 MONO_ADD_INS (cfg->cbb, vtarg);
1632 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1636 * Reverse the call->out_args list.
1639 MonoInst *prev = NULL, *list = call->out_args, *next;
1646 call->out_args = prev;
1649 call->stack_usage = cinfo->stack_usage;
1650 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1651 #if _MIPS_SIM == _ABIO32
1652 /* a0-a3 always present */
1653 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1655 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1656 cfg->flags |= MONO_CFG_HAS_CALLS;
1658 * should set more info in call, such as the stack space
1659 * used by the args that needs to be added back to esp
1666 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1668 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1669 ArgInfo *ainfo = ins->inst_p1;
1670 int ovf_size = ainfo->vtsize;
1671 int doffset = ainfo->offset;
1672 int i, soffset, dreg;
1674 if (ainfo->regtype == RegTypeStructByVal) {
1676 if (cfg->verbose_level > 0) {
1677 char* nm = mono_method_full_name (cfg->method, TRUE);
1678 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1679 nm, doffset, ainfo->size, ovf_size);
1685 for (i = 0; i < ainfo->size; ++i) {
1686 dreg = mono_alloc_ireg (cfg);
1687 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1688 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1689 soffset += SIZEOF_REGISTER;
1691 if (ovf_size != 0) {
1692 mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1694 } else if (ainfo->regtype == RegTypeFP) {
1695 int tmpr = mono_alloc_freg (cfg);
1697 if (ainfo->size == 4)
1698 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1700 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1701 dreg = mono_alloc_freg (cfg);
1702 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1703 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1705 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1709 /* FIXME: alignment? */
1710 if (call->signature->pinvoke) {
1711 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1712 vtcopy->backend.is_pinvoke = 1;
1714 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1717 g_assert (ovf_size > 0);
1719 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1720 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1723 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1725 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1730 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1732 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1733 mono_method_signature (method)->ret);
1736 #if (SIZEOF_REGISTER == 4)
1737 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1740 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1741 ins->sreg1 = val->dreg + 1;
1742 ins->sreg2 = val->dreg + 2;
1743 MONO_ADD_INS (cfg->cbb, ins);
1747 if (ret->type == MONO_TYPE_R8) {
1748 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1751 if (ret->type == MONO_TYPE_R4) {
1752 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1756 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1760 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1762 MonoInst *ins, *n, *last_ins = NULL;
1764 if (cfg->verbose_level > 2)
1765 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1768 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1769 if (cfg->verbose_level > 2)
1770 mono_print_ins_index (0, ins);
1772 switch (ins->opcode) {
1774 case OP_LOAD_MEMBASE:
1775 case OP_LOADI4_MEMBASE:
1777 * OP_IADD reg2, reg1, const1
1778 * OP_LOAD_MEMBASE const2(reg2), reg3
1780 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1782 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)){
1783 int const1 = last_ins->inst_imm;
1784 int const2 = ins->inst_offset;
1786 if (mips_is_imm16 (const1 + const2)) {
1787 ins->inst_basereg = last_ins->sreg1;
1788 ins->inst_offset = const1 + const2;
1798 bb->last_ins = last_ins;
1802 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1804 MonoInst *ins, *n, *last_ins = NULL;
1807 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1808 MonoInst *last_ins = ins->prev;
1810 switch (ins->opcode) {
1812 /* remove unnecessary multiplication with 1 */
1813 if (ins->inst_imm == 1) {
1814 if (ins->dreg != ins->sreg1) {
1815 ins->opcode = OP_MOVE;
1817 MONO_DELETE_INS (bb, ins);
1821 int power2 = mono_is_power_of_two (ins->inst_imm);
1823 ins->opcode = OP_SHL_IMM;
1824 ins->inst_imm = power2;
1828 case OP_LOAD_MEMBASE:
1829 case OP_LOADI4_MEMBASE:
1831 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1832 * OP_LOAD_MEMBASE offset(basereg), reg
1834 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1835 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1836 ins->inst_basereg == last_ins->inst_destbasereg &&
1837 ins->inst_offset == last_ins->inst_offset) {
1838 if (ins->dreg == last_ins->sreg1) {
1839 MONO_DELETE_INS (bb, ins);
1842 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1843 ins->opcode = OP_MOVE;
1844 ins->sreg1 = last_ins->sreg1;
1849 * Note: reg1 must be different from the basereg in the second load
1850 * OP_LOAD_MEMBASE offset(basereg), reg1
1851 * OP_LOAD_MEMBASE offset(basereg), reg2
1853 * OP_LOAD_MEMBASE offset(basereg), reg1
1854 * OP_MOVE reg1, reg2
1856 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1857 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1858 ins->inst_basereg != last_ins->dreg &&
1859 ins->inst_basereg == last_ins->inst_basereg &&
1860 ins->inst_offset == last_ins->inst_offset) {
1862 if (ins->dreg == last_ins->dreg) {
1863 MONO_DELETE_INS (bb, ins);
1866 ins->opcode = OP_MOVE;
1867 ins->sreg1 = last_ins->dreg;
1870 //g_assert_not_reached ();
1875 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1876 * OP_LOAD_MEMBASE offset(basereg), reg
1878 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1879 * OP_ICONST reg, imm
1881 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1882 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1883 ins->inst_basereg == last_ins->inst_destbasereg &&
1884 ins->inst_offset == last_ins->inst_offset) {
1885 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1886 ins->opcode = OP_ICONST;
1887 ins->inst_c0 = last_ins->inst_imm;
1888 g_assert_not_reached (); // check this rule
1893 case OP_LOADU1_MEMBASE:
1894 case OP_LOADI1_MEMBASE:
1895 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1896 ins->inst_basereg == last_ins->inst_destbasereg &&
1897 ins->inst_offset == last_ins->inst_offset) {
1898 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1899 ins->sreg1 = last_ins->sreg1;
1902 case OP_LOADU2_MEMBASE:
1903 case OP_LOADI2_MEMBASE:
1904 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1905 ins->inst_basereg == last_ins->inst_destbasereg &&
1906 ins->inst_offset == last_ins->inst_offset) {
1907 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1908 ins->sreg1 = last_ins->sreg1;
1911 case OP_ICONV_TO_I4:
1912 case OP_ICONV_TO_U4:
1914 ins->opcode = OP_MOVE;
1918 if (ins->dreg == ins->sreg1) {
1919 MONO_DELETE_INS (bb, ins);
1923 * OP_MOVE sreg, dreg
1924 * OP_MOVE dreg, sreg
1926 if (last_ins && last_ins->opcode == OP_MOVE &&
1927 ins->sreg1 == last_ins->dreg &&
1928 ins->dreg == last_ins->sreg1) {
1929 MONO_DELETE_INS (bb, ins);
1937 bb->last_ins = last_ins;
1941 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
1949 switch (ins->opcode) {
1952 case OP_LCOMPARE_IMM:
1953 mono_print_ins (ins);
1954 g_assert_not_reached ();
1957 tmp1 = mono_alloc_ireg (cfg);
1958 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1959 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1960 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1961 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1966 tmp1 = mono_alloc_ireg (cfg);
1967 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1968 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1969 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1970 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1975 tmp1 = mono_alloc_ireg (cfg);
1976 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1977 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1978 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1979 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1984 tmp1 = mono_alloc_ireg (cfg);
1985 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1986 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1987 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1988 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2000 mono_print_ins (ins);
2001 g_assert_not_reached ();
2004 tmp1 = mono_alloc_ireg (cfg);
2005 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2006 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2007 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2008 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2016 case OP_LCONV_TO_I1:
2017 case OP_LCONV_TO_I2:
2018 case OP_LCONV_TO_I4:
2019 case OP_LCONV_TO_I8:
2020 case OP_LCONV_TO_R4:
2021 case OP_LCONV_TO_R8:
2022 case OP_LCONV_TO_U4:
2023 case OP_LCONV_TO_U8:
2024 case OP_LCONV_TO_U2:
2025 case OP_LCONV_TO_U1:
2027 case OP_LCONV_TO_OVF_I:
2028 case OP_LCONV_TO_OVF_U:
2030 mono_print_ins (ins);
2031 g_assert_not_reached ();
2034 tmp1 = mono_alloc_ireg (cfg);
2035 tmp2 = mono_alloc_ireg (cfg);
2036 tmp3 = mono_alloc_ireg (cfg);
2037 tmp4 = mono_alloc_ireg (cfg);
2038 tmp5 = mono_alloc_ireg (cfg);
2040 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2042 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2043 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2045 /* add the high 32-bits, and add in the carry from the low 32-bits */
2046 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2047 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2049 /* Overflow happens if
2050 * neg + neg = pos or
2052 * XOR of the high bits returns 0 if the signs match
2053 * XOR of that with the high bit of the result return 1 if overflow.
2056 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2057 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2059 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2060 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2061 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2063 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2064 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2065 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2067 /* Now, if (tmp4 == 0) then overflow */
2068 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2072 case OP_LADD_OVF_UN:
2073 tmp1 = mono_alloc_ireg (cfg);
2074 tmp2 = mono_alloc_ireg (cfg);
2076 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2077 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2078 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2079 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2080 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2081 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2086 case OP_LMUL_OVF_UN:
2087 mono_print_ins (ins);
2088 g_assert_not_reached ();
2091 tmp1 = mono_alloc_ireg (cfg);
2092 tmp2 = mono_alloc_ireg (cfg);
2093 tmp3 = mono_alloc_ireg (cfg);
2094 tmp4 = mono_alloc_ireg (cfg);
2095 tmp5 = mono_alloc_ireg (cfg);
2097 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2099 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2100 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2101 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2103 /* Overflow happens if
2104 * neg - pos = pos or
2106 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2108 * tmp1 = (lhs ^ rhs)
2109 * tmp2 = (lhs ^ result)
2110 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2113 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2114 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2115 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2116 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2118 /* Now, if (tmp4 == 1) then overflow */
2119 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2123 case OP_LSUB_OVF_UN:
2124 tmp1 = mono_alloc_ireg (cfg);
2125 tmp2 = mono_alloc_ireg (cfg);
2127 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2128 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2129 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2130 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2132 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2133 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2137 case OP_LCONV_TO_OVF_I1_UN:
2138 case OP_LCONV_TO_OVF_I2_UN:
2139 case OP_LCONV_TO_OVF_I4_UN:
2140 case OP_LCONV_TO_OVF_I8_UN:
2141 case OP_LCONV_TO_OVF_U1_UN:
2142 case OP_LCONV_TO_OVF_U2_UN:
2143 case OP_LCONV_TO_OVF_U4_UN:
2144 case OP_LCONV_TO_OVF_U8_UN:
2145 case OP_LCONV_TO_OVF_I_UN:
2146 case OP_LCONV_TO_OVF_U_UN:
2147 case OP_LCONV_TO_OVF_I1:
2148 case OP_LCONV_TO_OVF_U1:
2149 case OP_LCONV_TO_OVF_I2:
2150 case OP_LCONV_TO_OVF_U2:
2151 case OP_LCONV_TO_OVF_I4:
2152 case OP_LCONV_TO_OVF_U4:
2153 case OP_LCONV_TO_OVF_I8:
2154 case OP_LCONV_TO_OVF_U8:
2162 case OP_LCONV_TO_R_UN:
2168 case OP_LSHR_UN_IMM:
2170 case OP_LDIV_UN_IMM:
2172 case OP_LREM_UN_IMM:
2183 mono_print_ins (ins);
2184 g_assert_not_reached ();
2186 case OP_LCONV_TO_R8_2:
2187 case OP_LCONV_TO_R4_2:
2188 case OP_LCONV_TO_R_UN_2:
2190 case OP_LCONV_TO_OVF_I4_2:
2191 tmp1 = mono_alloc_ireg (cfg);
2193 /* Overflows if reg2 != sign extension of reg1 */
2194 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2195 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2196 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2204 mono_print_ins (ins);
2205 g_assert_not_reached ();
2213 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2221 switch (ins->opcode) {
2223 tmp1 = mono_alloc_ireg (cfg);
2224 tmp2 = mono_alloc_ireg (cfg);
2225 tmp3 = mono_alloc_ireg (cfg);
2226 tmp4 = mono_alloc_ireg (cfg);
2227 tmp5 = mono_alloc_ireg (cfg);
2229 /* add the operands */
2231 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2233 /* Overflow happens if
2234 * neg + neg = pos or
2237 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2238 * XOR of the high bit returns 0 if the signs match
2239 * XOR of that with the high bit of the result return 1 if overflow.
2242 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2243 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2245 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2246 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2247 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2249 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2250 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2252 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2254 /* Now, if (tmp5 == 0) then overflow */
2255 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2256 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2257 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2261 case OP_IADD_OVF_UN:
2262 tmp1 = mono_alloc_ireg (cfg);
2264 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2265 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2266 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2267 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2268 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2273 tmp1 = mono_alloc_ireg (cfg);
2274 tmp2 = mono_alloc_ireg (cfg);
2275 tmp3 = mono_alloc_ireg (cfg);
2276 tmp4 = mono_alloc_ireg (cfg);
2277 tmp5 = mono_alloc_ireg (cfg);
2279 /* add the operands */
2281 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2283 /* Overflow happens if
2284 * neg - pos = pos or
2286 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2288 * tmp1 = (lhs ^ rhs)
2289 * tmp2 = (lhs ^ result)
2290 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2293 /* tmp3 = 1 if the signs of the two inputs differ */
2294 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2295 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2296 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2297 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2298 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2300 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2301 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2302 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2306 case OP_ISUB_OVF_UN:
2307 tmp1 = mono_alloc_ireg (cfg);
2309 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2310 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2311 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2312 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2313 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2320 map_to_reg_reg_op (int op)
2329 case OP_COMPARE_IMM:
2331 case OP_ICOMPARE_IMM:
2333 case OP_LCOMPARE_IMM:
2349 case OP_LOAD_MEMBASE:
2350 return OP_LOAD_MEMINDEX;
2351 case OP_LOADI4_MEMBASE:
2352 return OP_LOADI4_MEMINDEX;
2353 case OP_LOADU4_MEMBASE:
2354 return OP_LOADU4_MEMINDEX;
2355 case OP_LOADU1_MEMBASE:
2356 return OP_LOADU1_MEMINDEX;
2357 case OP_LOADI2_MEMBASE:
2358 return OP_LOADI2_MEMINDEX;
2359 case OP_LOADU2_MEMBASE:
2360 return OP_LOADU2_MEMINDEX;
2361 case OP_LOADI1_MEMBASE:
2362 return OP_LOADI1_MEMINDEX;
2363 case OP_LOADR4_MEMBASE:
2364 return OP_LOADR4_MEMINDEX;
2365 case OP_LOADR8_MEMBASE:
2366 return OP_LOADR8_MEMINDEX;
2367 case OP_STOREI1_MEMBASE_REG:
2368 return OP_STOREI1_MEMINDEX;
2369 case OP_STOREI2_MEMBASE_REG:
2370 return OP_STOREI2_MEMINDEX;
2371 case OP_STOREI4_MEMBASE_REG:
2372 return OP_STOREI4_MEMINDEX;
2373 case OP_STORE_MEMBASE_REG:
2374 return OP_STORE_MEMINDEX;
2375 case OP_STORER4_MEMBASE_REG:
2376 return OP_STORER4_MEMINDEX;
2377 case OP_STORER8_MEMBASE_REG:
2378 return OP_STORER8_MEMINDEX;
2379 case OP_STORE_MEMBASE_IMM:
2380 return OP_STORE_MEMBASE_REG;
2381 case OP_STOREI1_MEMBASE_IMM:
2382 return OP_STOREI1_MEMBASE_REG;
2383 case OP_STOREI2_MEMBASE_IMM:
2384 return OP_STOREI2_MEMBASE_REG;
2385 case OP_STOREI4_MEMBASE_IMM:
2386 return OP_STOREI4_MEMBASE_REG;
2387 case OP_STOREI8_MEMBASE_IMM:
2388 return OP_STOREI8_MEMBASE_REG;
2390 return mono_op_imm_to_op (op);
2394 map_to_mips_op (int op)
2398 return OP_MIPS_FBEQ;
2400 return OP_MIPS_FBGE;
2402 return OP_MIPS_FBGT;
2404 return OP_MIPS_FBLE;
2406 return OP_MIPS_FBLT;
2408 return OP_MIPS_FBNE;
2410 return OP_MIPS_FBGE_UN;
2412 return OP_MIPS_FBGT_UN;
2414 return OP_MIPS_FBLE_UN;
2416 return OP_MIPS_FBLT_UN;
2424 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2425 g_assert_not_reached ();
2429 #define NEW_INS(cfg,after,dest,op) do { \
2430 MONO_INST_NEW((cfg), (dest), (op)); \
2431 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2434 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2436 MONO_INST_NEW(cfg, temp, (op)); \
2437 mono_bblock_insert_after_ins (bb, (pos), temp); \
2438 temp->dreg = (_dreg); \
2439 temp->sreg1 = (_sreg1); \
2440 temp->sreg2 = (_sreg2); \
2444 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2446 MONO_INST_NEW(cfg, temp, (op)); \
2447 mono_bblock_insert_after_ins (bb, (pos), temp); \
2448 temp->dreg = (_dreg); \
2449 temp->sreg1 = (_sreg1); \
2450 temp->inst_c0 = (_imm); \
2455 * Remove from the instruction list the instructions that can't be
2456 * represented with very simple instructions with no register
2460 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2462 MonoInst *ins, *next, *temp, *last_ins = NULL;
2466 if (cfg->verbose_level > 2) {
2469 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2470 MONO_BB_FOR_EACH_INS (bb, ins) {
2471 mono_print_ins_index (idx++, ins);
2477 MONO_BB_FOR_EACH_INS (bb, ins) {
2479 switch (ins->opcode) {
2484 /* Branch opts can eliminate the branch */
2485 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2491 case OP_COMPARE_IMM:
2492 case OP_ICOMPARE_IMM:
2493 case OP_LCOMPARE_IMM:
2495 /* Branch opts can eliminate the branch */
2496 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2500 if (ins->inst_imm) {
2501 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2502 temp->inst_c0 = ins->inst_imm;
2503 temp->dreg = mono_alloc_ireg (cfg);
2504 ins->sreg2 = temp->dreg;
2508 ins->sreg2 = mips_zero;
2510 if (ins->opcode == OP_COMPARE_IMM)
2511 ins->opcode = OP_COMPARE;
2512 else if (ins->opcode == OP_ICOMPARE_IMM)
2513 ins->opcode = OP_ICOMPARE;
2514 else if (ins->opcode == OP_LCOMPARE_IMM)
2515 ins->opcode = OP_LCOMPARE;
2518 case OP_IDIV_UN_IMM:
2521 case OP_IREM_UN_IMM:
2522 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2523 temp->inst_c0 = ins->inst_imm;
2524 temp->dreg = mono_alloc_ireg (cfg);
2525 ins->sreg2 = temp->dreg;
2526 if (ins->opcode == OP_IDIV_IMM)
2527 ins->opcode = OP_IDIV;
2528 else if (ins->opcode == OP_IREM_IMM)
2529 ins->opcode = OP_IREM;
2530 else if (ins->opcode == OP_IDIV_UN_IMM)
2531 ins->opcode = OP_IDIV_UN;
2532 else if (ins->opcode == OP_IREM_UN_IMM)
2533 ins->opcode = OP_IREM_UN;
2535 /* handle rem separately */
2542 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
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;
2547 ins->opcode = map_to_reg_reg_op (ins->opcode);
2557 /* unsigned 16 bit immediate */
2558 if (ins->inst_imm & 0xffff0000) {
2559 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2560 temp->inst_c0 = ins->inst_imm;
2561 temp->dreg = mono_alloc_ireg (cfg);
2562 ins->sreg2 = temp->dreg;
2563 ins->opcode = map_to_reg_reg_op (ins->opcode);
2570 /* signed 16 bit immediate */
2571 if (!mips_is_imm16 (ins->inst_imm)) {
2572 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2573 temp->inst_c0 = ins->inst_imm;
2574 temp->dreg = mono_alloc_ireg (cfg);
2575 ins->sreg2 = temp->dreg;
2576 ins->opcode = map_to_reg_reg_op (ins->opcode);
2582 if (!mips_is_imm16 (-ins->inst_imm)) {
2583 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2584 temp->inst_c0 = ins->inst_imm;
2585 temp->dreg = mono_alloc_ireg (cfg);
2586 ins->sreg2 = temp->dreg;
2587 ins->opcode = map_to_reg_reg_op (ins->opcode);
2593 if (ins->inst_imm == 1) {
2594 ins->opcode = OP_MOVE;
2597 if (ins->inst_imm == 0) {
2598 ins->opcode = OP_ICONST;
2602 imm = mono_is_power_of_two (ins->inst_imm);
2604 ins->opcode = OP_SHL_IMM;
2605 ins->inst_imm = imm;
2608 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2609 temp->inst_c0 = ins->inst_imm;
2610 temp->dreg = mono_alloc_ireg (cfg);
2611 ins->sreg2 = temp->dreg;
2612 ins->opcode = map_to_reg_reg_op (ins->opcode);
2615 case OP_LOCALLOC_IMM:
2616 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2617 temp->inst_c0 = ins->inst_imm;
2618 temp->dreg = mono_alloc_ireg (cfg);
2619 ins->sreg1 = temp->dreg;
2620 ins->opcode = OP_LOCALLOC;
2623 case OP_LOAD_MEMBASE:
2624 case OP_LOADI4_MEMBASE:
2625 case OP_LOADU4_MEMBASE:
2626 case OP_LOADI2_MEMBASE:
2627 case OP_LOADU2_MEMBASE:
2628 case OP_LOADI1_MEMBASE:
2629 case OP_LOADU1_MEMBASE:
2630 case OP_LOADR4_MEMBASE:
2631 case OP_LOADR8_MEMBASE:
2632 case OP_STORE_MEMBASE_REG:
2633 case OP_STOREI4_MEMBASE_REG:
2634 case OP_STOREI2_MEMBASE_REG:
2635 case OP_STOREI1_MEMBASE_REG:
2636 case OP_STORER4_MEMBASE_REG:
2637 case OP_STORER8_MEMBASE_REG:
2638 /* we can do two things: load the immed in a register
2639 * and use an indexed load, or see if the immed can be
2640 * represented as an ad_imm + a load with a smaller offset
2641 * that fits. We just do the first for now, optimize later.
2643 if (mips_is_imm16 (ins->inst_offset))
2645 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2646 temp->inst_c0 = ins->inst_offset;
2647 temp->dreg = mono_alloc_ireg (cfg);
2648 ins->sreg2 = temp->dreg;
2649 ins->opcode = map_to_reg_reg_op (ins->opcode);
2652 case OP_STORE_MEMBASE_IMM:
2653 case OP_STOREI1_MEMBASE_IMM:
2654 case OP_STOREI2_MEMBASE_IMM:
2655 case OP_STOREI4_MEMBASE_IMM:
2656 case OP_STOREI8_MEMBASE_IMM:
2657 if (!ins->inst_imm) {
2658 ins->sreg1 = mips_zero;
2659 ins->opcode = map_to_reg_reg_op (ins->opcode);
2662 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2663 temp->inst_c0 = ins->inst_imm;
2664 temp->dreg = mono_alloc_ireg (cfg);
2665 ins->sreg1 = temp->dreg;
2666 ins->opcode = map_to_reg_reg_op (ins->opcode);
2668 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2674 /* Branch opts can eliminate the branch */
2675 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2682 * remap compare/branch and compare/set
2683 * to MIPS specific opcodes.
2685 next->opcode = map_to_mips_op (next->opcode);
2686 next->sreg1 = ins->sreg1;
2687 next->sreg2 = ins->sreg2;
2694 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2695 temp->inst_c0 = (guint32)ins->inst_p0;
2696 temp->dreg = mono_alloc_ireg (cfg);
2697 ins->inst_basereg = temp->dreg;
2698 ins->inst_offset = 0;
2699 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2701 /* make it handle the possibly big ins->inst_offset
2702 * later optimize to use lis + load_membase
2707 g_assert (ins_is_compare(last_ins));
2708 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2709 NULLIFY_INS(last_ins);
2713 g_assert (ins_is_compare(last_ins));
2714 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2715 NULLIFY_INS(last_ins);
2719 g_assert (ins_is_compare(last_ins));
2720 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2721 last_ins->dreg = mono_alloc_ireg (cfg);
2722 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2726 g_assert (ins_is_compare(last_ins));
2727 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2728 last_ins->dreg = mono_alloc_ireg (cfg);
2729 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2733 g_assert (ins_is_compare(last_ins));
2734 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2735 last_ins->dreg = mono_alloc_ireg (cfg);
2736 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2740 g_assert (ins_is_compare(last_ins));
2741 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2742 last_ins->dreg = mono_alloc_ireg (cfg);
2743 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2747 g_assert (ins_is_compare(last_ins));
2748 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2749 last_ins->dreg = mono_alloc_ireg (cfg);
2750 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2754 g_assert (ins_is_compare(last_ins));
2755 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2756 last_ins->dreg = mono_alloc_ireg (cfg);
2757 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2761 g_assert (ins_is_compare(last_ins));
2762 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2763 last_ins->dreg = mono_alloc_ireg (cfg);
2764 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2768 g_assert (ins_is_compare(last_ins));
2769 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2770 last_ins->dreg = mono_alloc_ireg (cfg);
2771 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2776 g_assert (ins_is_compare(last_ins));
2777 last_ins->opcode = OP_IXOR;
2778 last_ins->dreg = mono_alloc_ireg(cfg);
2779 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2784 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2785 NULLIFY_INS(last_ins);
2791 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2792 NULLIFY_INS(last_ins);
2797 g_assert (ins_is_compare(last_ins));
2798 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2799 MONO_DELETE_INS(bb, last_ins);
2804 g_assert (ins_is_compare(last_ins));
2805 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2806 MONO_DELETE_INS(bb, last_ins);
2809 case OP_COND_EXC_EQ:
2810 case OP_COND_EXC_IEQ:
2811 g_assert (ins_is_compare(last_ins));
2812 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2813 MONO_DELETE_INS(bb, last_ins);
2816 case OP_COND_EXC_GE:
2817 case OP_COND_EXC_IGE:
2818 g_assert (ins_is_compare(last_ins));
2819 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2820 MONO_DELETE_INS(bb, last_ins);
2823 case OP_COND_EXC_GT:
2824 case OP_COND_EXC_IGT:
2825 g_assert (ins_is_compare(last_ins));
2826 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2827 MONO_DELETE_INS(bb, last_ins);
2830 case OP_COND_EXC_LE:
2831 case OP_COND_EXC_ILE:
2832 g_assert (ins_is_compare(last_ins));
2833 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2834 MONO_DELETE_INS(bb, last_ins);
2837 case OP_COND_EXC_LT:
2838 case OP_COND_EXC_ILT:
2839 g_assert (ins_is_compare(last_ins));
2840 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2841 MONO_DELETE_INS(bb, last_ins);
2844 case OP_COND_EXC_NE_UN:
2845 case OP_COND_EXC_INE_UN:
2846 g_assert (ins_is_compare(last_ins));
2847 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2848 MONO_DELETE_INS(bb, last_ins);
2851 case OP_COND_EXC_GE_UN:
2852 case OP_COND_EXC_IGE_UN:
2853 g_assert (ins_is_compare(last_ins));
2854 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2855 MONO_DELETE_INS(bb, last_ins);
2858 case OP_COND_EXC_GT_UN:
2859 case OP_COND_EXC_IGT_UN:
2860 g_assert (ins_is_compare(last_ins));
2861 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2862 MONO_DELETE_INS(bb, last_ins);
2865 case OP_COND_EXC_LE_UN:
2866 case OP_COND_EXC_ILE_UN:
2867 g_assert (ins_is_compare(last_ins));
2868 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2869 MONO_DELETE_INS(bb, last_ins);
2872 case OP_COND_EXC_LT_UN:
2873 case OP_COND_EXC_ILT_UN:
2874 g_assert (ins_is_compare(last_ins));
2875 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2876 MONO_DELETE_INS(bb, last_ins);
2879 case OP_COND_EXC_OV:
2880 case OP_COND_EXC_IOV: {
2881 int tmp1, tmp2, tmp3, tmp4, tmp5;
2882 MonoInst *pos = last_ins;
2884 /* Overflow happens if
2885 * neg + neg = pos or
2888 * (bit31s of operands match) AND (bit31 of operand
2889 * != bit31 of result)
2890 * XOR of the high bit returns 0 if the signs match
2891 * XOR of that with the high bit of the result return 1
2894 g_assert (last_ins->opcode == OP_IADC);
2896 tmp1 = mono_alloc_ireg (cfg);
2897 tmp2 = mono_alloc_ireg (cfg);
2898 tmp3 = mono_alloc_ireg (cfg);
2899 tmp4 = mono_alloc_ireg (cfg);
2900 tmp5 = mono_alloc_ireg (cfg);
2902 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2903 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2905 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2906 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2907 INS (pos, OP_INOT, tmp3, tmp2, -1);
2909 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2910 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2911 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2913 /* Now, if (tmp5 == 0) then overflow */
2914 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2919 case OP_COND_EXC_NO:
2920 case OP_COND_EXC_INO:
2921 g_assert_not_reached ();
2925 case OP_COND_EXC_IC:
2926 g_assert_not_reached ();
2929 case OP_COND_EXC_NC:
2930 case OP_COND_EXC_INC:
2931 g_assert_not_reached ();
2937 bb->last_ins = last_ins;
2938 bb->max_vreg = cfg->next_vreg;
2941 if (cfg->verbose_level > 2) {
2944 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
2945 MONO_BB_FOR_EACH_INS (bb, ins) {
2946 mono_print_ins_index (idx++, ins);
2955 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2957 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2959 mips_truncwd (code, mips_ftemp, sreg);
2961 mips_cvtwd (code, mips_ftemp, sreg);
2963 mips_mfc1 (code, dreg, mips_ftemp);
2966 mips_andi (code, dreg, dreg, 0xff);
2967 else if (size == 2) {
2968 mips_sll (code, dreg, dreg, 16);
2969 mips_srl (code, dreg, dreg, 16);
2973 mips_sll (code, dreg, dreg, 24);
2974 mips_sra (code, dreg, dreg, 24);
2976 else if (size == 2) {
2977 mips_sll (code, dreg, dreg, 16);
2978 mips_sra (code, dreg, dreg, 16);
2985 * emit_load_volatile_arguments:
2987 * Load volatile arguments from the stack to the original input registers.
2988 * Required before a tail call.
2991 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
2993 MonoMethod *method = cfg->method;
2994 MonoMethodSignature *sig;
2999 sig = mono_method_signature (method);
3000 cinfo = calculate_sizes (sig, sig->pinvoke);
3001 if (cinfo->struct_ret) {
3002 ArgInfo *ainfo = &cinfo->ret;
3003 inst = cfg->vret_addr;
3004 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3007 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3008 ArgInfo *ainfo = cinfo->args + i;
3009 inst = cfg->args [i];
3010 if (inst->opcode == OP_REGVAR) {
3011 if (ainfo->regtype == RegTypeGeneral)
3012 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3013 else if (ainfo->regtype == RegTypeFP)
3014 g_assert_not_reached();
3015 else if (ainfo->regtype == RegTypeBase) {
3018 g_assert_not_reached ();
3020 if (ainfo->regtype == RegTypeGeneral) {
3021 g_assert (mips_is_imm16 (inst->inst_offset));
3022 switch (ainfo->size) {
3024 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3027 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3031 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3034 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3035 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3038 g_assert_not_reached ();
3041 } else if (ainfo->regtype == RegTypeBase) {
3043 } else if (ainfo->regtype == RegTypeFP) {
3044 g_assert (mips_is_imm16 (inst->inst_offset));
3045 if (ainfo->size == 8) {
3046 #if _MIPS_SIM == _ABIO32
3047 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3048 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3049 #elif _MIPS_SIM == _ABIN32
3050 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3053 else if (ainfo->size == 4)
3054 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3056 g_assert_not_reached ();
3057 } else if (ainfo->regtype == RegTypeStructByVal) {
3059 int doffset = inst->inst_offset;
3061 g_assert (mips_is_imm16 (inst->inst_offset));
3062 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3063 for (i = 0; i < ainfo->size; ++i) {
3064 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3065 doffset += SIZEOF_REGISTER;
3067 } else if (ainfo->regtype == RegTypeStructByAddr) {
3068 g_assert (mips_is_imm16 (inst->inst_offset));
3069 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3071 g_assert_not_reached ();
3081 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3083 int size = cfg->param_area;
3085 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3086 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3091 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3092 if (ppc_is_imm16 (-size)) {
3093 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3095 ppc_load (code, ppc_r11, -size);
3096 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3103 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3105 int size = cfg->param_area;
3107 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3108 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3113 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3114 if (ppc_is_imm16 (size)) {
3115 ppc_stwu (code, ppc_r0, size, ppc_sp);
3117 ppc_load (code, ppc_r11, size);
3118 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3125 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3130 guint8 *code = cfg->native_code + cfg->code_len;
3131 MonoInst *last_ins = NULL;
3132 guint last_offset = 0;
3136 /* we don't align basic blocks of loops on mips */
3138 if (cfg->verbose_level > 2)
3139 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3141 cpos = bb->max_offset;
3144 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3145 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3146 g_assert (!mono_compile_aot);
3149 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3150 /* this is not thread save, but good enough */
3151 /* fixme: howto handle overflows? */
3152 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3153 mips_lw (code, mips_temp, mips_at, 0);
3154 mips_addiu (code, mips_temp, mips_temp, 1);
3155 mips_sw (code, mips_temp, mips_at, 0);
3158 MONO_BB_FOR_EACH_INS (bb, ins) {
3159 offset = code - cfg->native_code;
3161 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3163 if (offset > (cfg->code_size - max_len - 16)) {
3164 cfg->code_size *= 2;
3165 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3166 code = cfg->native_code + offset;
3168 mono_debug_record_line_number (cfg, ins, offset);
3169 if (cfg->verbose_level > 2) {
3170 g_print (" @ 0x%x\t", offset);
3171 mono_print_ins_index (ins_cnt++, ins);
3173 /* Check for virtual regs that snuck by */
3174 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3176 switch (ins->opcode) {
3177 case OP_RELAXED_NOP:
3180 case OP_DUMMY_STORE:
3181 case OP_NOT_REACHED:
3185 g_assert_not_reached();
3187 emit_tls_access (code, ins->dreg, ins->inst_offset);
3191 mips_mult (code, ins->sreg1, ins->sreg2);
3192 mips_mflo (code, ins->dreg);
3193 mips_mfhi (code, ins->dreg+1);
3196 mips_multu (code, ins->sreg1, ins->sreg2);
3197 mips_mflo (code, ins->dreg);
3198 mips_mfhi (code, ins->dreg+1);
3200 case OP_MEMORY_BARRIER:
3205 case OP_STOREI1_MEMBASE_IMM:
3206 mips_load_const (code, mips_temp, ins->inst_imm);
3207 if (mips_is_imm16 (ins->inst_offset)) {
3208 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3210 mips_load_const (code, mips_at, ins->inst_offset);
3211 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3214 case OP_STOREI2_MEMBASE_IMM:
3215 mips_load_const (code, mips_temp, ins->inst_imm);
3216 if (mips_is_imm16 (ins->inst_offset)) {
3217 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3219 mips_load_const (code, mips_at, ins->inst_offset);
3220 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3223 case OP_STOREI8_MEMBASE_IMM:
3224 mips_load_const (code, mips_temp, ins->inst_imm);
3225 if (mips_is_imm16 (ins->inst_offset)) {
3226 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3228 mips_load_const (code, mips_at, ins->inst_offset);
3229 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3232 case OP_STORE_MEMBASE_IMM:
3233 case OP_STOREI4_MEMBASE_IMM:
3234 mips_load_const (code, mips_temp, ins->inst_imm);
3235 if (mips_is_imm16 (ins->inst_offset)) {
3236 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3238 mips_load_const (code, mips_at, ins->inst_offset);
3239 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3242 case OP_STOREI1_MEMBASE_REG:
3243 if (mips_is_imm16 (ins->inst_offset)) {
3244 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3246 mips_load_const (code, mips_at, ins->inst_offset);
3247 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3248 mips_sb (code, ins->sreg1, mips_at, 0);
3251 case OP_STOREI2_MEMBASE_REG:
3252 if (mips_is_imm16 (ins->inst_offset)) {
3253 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3255 mips_load_const (code, mips_at, ins->inst_offset);
3256 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3257 mips_sh (code, ins->sreg1, mips_at, 0);
3260 case OP_STORE_MEMBASE_REG:
3261 case OP_STOREI4_MEMBASE_REG:
3262 if (mips_is_imm16 (ins->inst_offset)) {
3263 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3265 mips_load_const (code, mips_at, ins->inst_offset);
3266 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3267 mips_sw (code, ins->sreg1, mips_at, 0);
3270 case OP_STOREI8_MEMBASE_REG:
3271 if (mips_is_imm16 (ins->inst_offset)) {
3272 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3274 mips_load_const (code, mips_at, ins->inst_offset);
3275 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3276 mips_sd (code, ins->sreg1, mips_at, 0);
3280 g_assert_not_reached ();
3281 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3282 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3284 case OP_LOADI8_MEMBASE:
3285 if (mips_is_imm16 (ins->inst_offset)) {
3286 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3288 mips_load_const (code, mips_at, ins->inst_offset);
3289 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3290 mips_ld (code, ins->dreg, mips_at, 0);
3293 case OP_LOAD_MEMBASE:
3294 case OP_LOADI4_MEMBASE:
3295 case OP_LOADU4_MEMBASE:
3296 g_assert (ins->dreg != -1);
3297 if (mips_is_imm16 (ins->inst_offset)) {
3298 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3300 mips_load_const (code, mips_at, ins->inst_offset);
3301 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3302 mips_lw (code, ins->dreg, mips_at, 0);
3305 case OP_LOADI1_MEMBASE:
3306 if (mips_is_imm16 (ins->inst_offset)) {
3307 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3309 mips_load_const (code, mips_at, ins->inst_offset);
3310 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3311 mips_lb (code, ins->dreg, mips_at, 0);
3314 case OP_LOADU1_MEMBASE:
3315 if (mips_is_imm16 (ins->inst_offset)) {
3316 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3318 mips_load_const (code, mips_at, ins->inst_offset);
3319 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3320 mips_lbu (code, ins->dreg, mips_at, 0);
3323 case OP_LOADI2_MEMBASE:
3324 if (mips_is_imm16 (ins->inst_offset)) {
3325 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3327 mips_load_const (code, mips_at, ins->inst_offset);
3328 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3329 mips_lh (code, ins->dreg, mips_at, 0);
3332 case OP_LOADU2_MEMBASE:
3333 if (mips_is_imm16 (ins->inst_offset)) {
3334 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3336 mips_load_const (code, mips_at, ins->inst_offset);
3337 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3338 mips_lhu (code, ins->dreg, mips_at, 0);
3341 case OP_ICONV_TO_I1:
3342 mips_sll (code, mips_at, ins->sreg1, 24);
3343 mips_sra (code, ins->dreg, mips_at, 24);
3345 case OP_ICONV_TO_I2:
3346 mips_sll (code, mips_at, ins->sreg1, 16);
3347 mips_sra (code, ins->dreg, mips_at, 16);
3349 case OP_ICONV_TO_U1:
3350 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3352 case OP_ICONV_TO_U2:
3353 mips_sll (code, mips_at, ins->sreg1, 16);
3354 mips_srl (code, ins->dreg, mips_at, 16);
3357 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3360 g_assert (mips_is_imm16 (ins->inst_imm));
3361 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3364 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3367 g_assert (mips_is_imm16 (ins->inst_imm));
3368 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3371 mips_break (code, 0xfd);
3374 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3377 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3382 g_assert (mips_is_imm16 (ins->inst_imm));
3383 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3386 g_assert (mips_is_imm16 (ins->inst_imm));
3387 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3391 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3394 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3399 // we add the negated value
3400 g_assert (mips_is_imm16 (-ins->inst_imm));
3401 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3405 // we add the negated value
3406 g_assert (mips_is_imm16 (-ins->inst_imm));
3407 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3412 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3418 g_assert (!(ins->inst_imm & 0xffff0000));
3419 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3424 guint32 *divisor_is_m1;
3425 guint32 *dividend_is_minvalue;
3426 guint32 *divisor_is_zero;
3428 mips_load_const (code, mips_at, -1);
3429 divisor_is_m1 = (guint32 *)(void *)code;
3430 mips_bne (code, ins->sreg2, mips_at, 0);
3431 mips_lui (code, mips_at, mips_zero, 0x8000);
3432 dividend_is_minvalue = (guint32 *)(void *)code;
3433 mips_bne (code, ins->sreg1, mips_at, 0);
3436 /* Divide Int32.MinValue by -1 -- throw exception */
3437 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3439 mips_patch (divisor_is_m1, (guint32)code);
3440 mips_patch (dividend_is_minvalue, (guint32)code);
3442 /* Put divide in branch delay slot (NOT YET) */
3443 divisor_is_zero = (guint32 *)(void *)code;
3444 mips_bne (code, ins->sreg2, mips_zero, 0);
3447 /* Divide by zero -- throw exception */
3448 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3450 mips_patch (divisor_is_zero, (guint32)code);
3451 mips_div (code, ins->sreg1, ins->sreg2);
3452 if (ins->opcode == OP_IDIV)
3453 mips_mflo (code, ins->dreg);
3455 mips_mfhi (code, ins->dreg);
3460 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3462 /* Put divide in branch delay slot (NOT YET) */
3463 mips_bne (code, ins->sreg2, mips_zero, 0);
3466 /* Divide by zero -- throw exception */
3467 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3469 mips_patch (divisor_is_zero, (guint32)code);
3470 mips_divu (code, ins->sreg1, ins->sreg2);
3471 if (ins->opcode == OP_IDIV_UN)
3472 mips_mflo (code, ins->dreg);
3474 mips_mfhi (code, ins->dreg);
3478 g_assert_not_reached ();
3480 ppc_load (code, ppc_r11, ins->inst_imm);
3481 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3482 ppc_mfspr (code, ppc_r0, ppc_xer);
3483 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3484 /* FIXME: use OverflowException for 0x80000000/-1 */
3485 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3487 g_assert_not_reached();
3490 g_assert_not_reached ();
3492 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3496 g_assert (!(ins->inst_imm & 0xffff0000));
3497 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3500 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3504 /* unsigned 16-bit immediate */
3505 g_assert (!(ins->inst_imm & 0xffff0000));
3506 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3509 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3513 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3516 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3519 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3523 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3526 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3529 case OP_ISHR_UN_IMM:
3530 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3532 case OP_LSHR_UN_IMM:
3533 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3536 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3539 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3543 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3546 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3549 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3553 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3555 mips_mult (code, ins->sreg1, ins->sreg2);
3556 mips_mflo (code, ins->dreg);
3561 #if SIZEOF_REGISTER == 8
3563 mips_dmult (code, ins->sreg1, ins->sreg2);
3564 mips_mflo (code, ins->dreg);
3569 mips_mult (code, ins->sreg1, ins->sreg2);
3570 mips_mflo (code, ins->dreg);
3571 mips_mfhi (code, mips_at);
3574 mips_sra (code, mips_temp, ins->dreg, 31);
3575 patch = (guint32 *)(void *)code;
3576 mips_beq (code, mips_temp, mips_at, 0);
3578 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3579 mips_patch (patch, (guint32)code);
3582 case OP_IMUL_OVF_UN: {
3584 mips_mult (code, ins->sreg1, ins->sreg2);
3585 mips_mflo (code, ins->dreg);
3586 mips_mfhi (code, mips_at);
3589 patch = (guint32 *)(void *)code;
3590 mips_beq (code, mips_at, mips_zero, 0);
3592 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3593 mips_patch (patch, (guint32)code);
3597 mips_load_const (code, ins->dreg, ins->inst_c0);
3599 #if SIZEOF_REGISTER == 8
3601 mips_load_const (code, ins->dreg, ins->inst_c0);
3605 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3606 mips_load (code, ins->dreg, 0);
3610 mips_mtc1 (code, ins->dreg, ins->sreg1);
3612 case OP_MIPS_MTC1S_2:
3613 mips_mtc1 (code, ins->dreg, ins->sreg1);
3614 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3617 mips_mfc1 (code, ins->dreg, ins->sreg1);
3620 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3624 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3626 mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3627 mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3631 case OP_ICONV_TO_I4:
3632 case OP_ICONV_TO_U4:
3634 if (ins->dreg != ins->sreg1)
3635 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3637 #if SIZEOF_REGISTER == 8
3639 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3640 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3643 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3644 mips_dsra (code, ins->dreg, ins->dreg, 32);
3648 /* Get sreg1 into v1, sreg2 into v0 */
3650 if (ins->sreg1 == mips_v0) {
3651 if (ins->sreg1 != mips_at)
3652 MIPS_MOVE (code, mips_at, ins->sreg1);
3653 if (ins->sreg2 != mips_v0)
3654 MIPS_MOVE (code, mips_v0, ins->sreg2);
3655 MIPS_MOVE (code, mips_v1, mips_at);
3658 if (ins->sreg2 != mips_v0)
3659 MIPS_MOVE (code, mips_v0, ins->sreg2);
3660 if (ins->sreg1 != mips_v1)
3661 MIPS_MOVE (code, mips_v1, ins->sreg1);
3665 if (ins->dreg != ins->sreg1) {
3666 mips_fmovd (code, ins->dreg, ins->sreg1);
3670 /* Convert from double to float and leave it there */
3671 mips_cvtsd (code, ins->dreg, ins->sreg1);
3673 case OP_FCONV_TO_R4:
3675 mips_cvtsd (code, ins->dreg, ins->sreg1);
3677 /* Just a move, no precision change */
3678 if (ins->dreg != ins->sreg1) {
3679 mips_fmovd (code, ins->dreg, ins->sreg1);
3684 code = emit_load_volatile_arguments(cfg, code);
3687 * Pop our stack, then jump to specified method (tail-call)
3688 * Keep in sync with mono_arch_emit_epilog
3690 code = mono_arch_emit_epilog_sub (cfg, code);
3692 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3693 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3694 if (cfg->arch.long_branch) {
3695 mips_lui (code, mips_t9, mips_zero, 0);
3696 mips_addiu (code, mips_t9, mips_t9, 0);
3697 mips_jr (code, mips_t9);
3701 mips_beq (code, mips_zero, mips_zero, 0);
3706 /* ensure ins->sreg1 is not NULL */
3707 mips_lw (code, mips_zero, ins->sreg1, 0);
3710 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3711 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3713 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3714 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3716 mips_sw (code, mips_at, ins->sreg1, 0);
3729 case OP_VOIDCALL_REG:
3731 case OP_FCALL_MEMBASE:
3732 case OP_LCALL_MEMBASE:
3733 case OP_VCALL_MEMBASE:
3734 case OP_VCALL2_MEMBASE:
3735 case OP_VOIDCALL_MEMBASE:
3736 case OP_CALL_MEMBASE:
3737 call = (MonoCallInst*)ins;
3738 switch (ins->opcode) {
3745 if (ins->flags & MONO_INST_HAS_METHOD) {
3746 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3747 mips_call (code, mips_t9, call->method);
3750 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3751 mips_call (code, mips_t9, call->fptr);
3758 case OP_VOIDCALL_REG:
3760 MIPS_MOVE (code, mips_t9, ins->sreg1);
3761 mips_jalr (code, mips_t9, mips_ra);
3764 case OP_FCALL_MEMBASE:
3765 case OP_LCALL_MEMBASE:
3766 case OP_VCALL_MEMBASE:
3767 case OP_VCALL2_MEMBASE:
3768 case OP_VOIDCALL_MEMBASE:
3769 case OP_CALL_MEMBASE:
3770 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3771 mips_jalr (code, mips_t9, mips_ra);
3775 #if PROMOTE_R4_TO_R8
3776 /* returned an FP R4 (single), promote to R8 (double) in place */
3777 if ((ins->opcode == OP_FCALL ||
3778 ins->opcode == OP_FCALL_REG) &&
3779 call->signature->ret->type == MONO_TYPE_R4) {
3780 mips_cvtds (code, mips_f0, mips_f0);
3785 int area_offset = cfg->param_area;
3787 /* Round up ins->sreg1, mips_at ends up holding size */
3788 mips_addiu (code, mips_at, ins->sreg1, 31);
3789 mips_addiu (code, mips_temp, mips_zero, ~31);
3790 mips_and (code, mips_at, mips_at, mips_temp);
3792 mips_subu (code, mips_sp, mips_sp, mips_at);
3793 g_assert (mips_is_imm16 (area_offset));
3794 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3796 if (ins->flags & MONO_INST_INIT) {
3797 mips_move (code, mips_temp, ins->dreg);
3798 mips_sb (code, mips_zero, mips_temp, 0);
3799 mips_addiu (code, mips_at, mips_at, -1);
3800 mips_bne (code, mips_at, mips_zero, -3);
3801 mips_addiu (code, mips_temp, mips_temp, 1);
3806 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3807 mips_move (code, mips_a0, ins->sreg1);
3808 mips_call (code, mips_t9, addr);
3809 mips_break (code, 0xfc);
3813 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3814 mips_move (code, mips_a0, ins->sreg1);
3815 mips_call (code, mips_t9, addr);
3816 mips_break (code, 0xfb);
3819 case OP_START_HANDLER: {
3821 * The START_HANDLER instruction marks the beginning of
3822 * a handler block. It is called using a call
3823 * instruction, so mips_ra contains the return address.
3824 * Since the handler executes in the same stack frame
3825 * as the method itself, we can't use save/restore to
3826 * save the return address. Instead, we save it into
3827 * a dedicated variable.
3829 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3830 g_assert (spvar->inst_basereg != mips_sp);
3831 code = emit_reserve_param_area (cfg, code);
3833 if (mips_is_imm16 (spvar->inst_offset)) {
3834 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3836 mips_load_const (code, mips_at, spvar->inst_offset);
3837 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3838 mips_sw (code, mips_ra, mips_at, 0);
3842 case OP_ENDFILTER: {
3843 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3844 g_assert (spvar->inst_basereg != mips_sp);
3845 code = emit_unreserve_param_area (cfg, code);
3847 if (ins->sreg1 != mips_v0)
3848 MIPS_MOVE (code, mips_v0, ins->sreg1);
3849 if (mips_is_imm16 (spvar->inst_offset)) {
3850 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3852 mips_load_const (code, mips_at, spvar->inst_offset);
3853 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3854 mips_lw (code, mips_ra, mips_at, 0);
3856 mips_jr (code, mips_ra);
3860 case OP_ENDFINALLY: {
3861 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3862 g_assert (spvar->inst_basereg != mips_sp);
3863 code = emit_unreserve_param_area (cfg, code);
3864 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3865 mips_jalr (code, mips_t9, mips_ra);
3869 case OP_CALL_HANDLER:
3870 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3871 mips_lui (code, mips_t9, mips_zero, 0);
3872 mips_addiu (code, mips_t9, mips_t9, 0);
3873 mips_jalr (code, mips_t9, mips_ra);
3875 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3876 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3879 ins->inst_c0 = code - cfg->native_code;
3882 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3883 if (cfg->arch.long_branch) {
3884 mips_lui (code, mips_at, mips_zero, 0);
3885 mips_addiu (code, mips_at, mips_at, 0);
3886 mips_jr (code, mips_at);
3890 mips_beq (code, mips_zero, mips_zero, 0);
3895 mips_jr (code, ins->sreg1);
3901 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3902 if (offset > (cfg->code_size - max_len - 16)) {
3903 cfg->code_size += max_len;
3904 cfg->code_size *= 2;
3905 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3906 code = cfg->native_code + offset;
3908 g_assert (ins->sreg1 != -1);
3909 mips_sll (code, mips_at, ins->sreg1, 2);
3910 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3911 MIPS_MOVE (code, mips_t8, mips_ra);
3912 mips_bgezal (code, mips_zero, 1); /* bal */
3914 mips_addu (code, mips_t9, mips_ra, mips_at);
3915 /* Table is 16 or 20 bytes from target of bal above */
3916 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3917 MIPS_MOVE (code, mips_ra, mips_t8);
3918 mips_lw (code, mips_t9, mips_t9, 20);
3921 mips_lw (code, mips_t9, mips_t9, 16);
3922 mips_jalr (code, mips_t9, mips_t8);
3924 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3925 mips_emit32 (code, 0xfefefefe);
3930 mips_addiu (code, ins->dreg, mips_zero, 1);
3931 mips_beq (code, mips_at, mips_zero, 2);
3933 MIPS_MOVE (code, ins->dreg, mips_zero);
3939 mips_addiu (code, ins->dreg, mips_zero, 1);
3940 mips_bltz (code, mips_at, 2);
3942 MIPS_MOVE (code, ins->dreg, mips_zero);
3948 mips_addiu (code, ins->dreg, mips_zero, 1);
3949 mips_bgtz (code, mips_at, 2);
3951 MIPS_MOVE (code, ins->dreg, mips_zero);
3954 case OP_MIPS_COND_EXC_EQ:
3955 case OP_MIPS_COND_EXC_GE:
3956 case OP_MIPS_COND_EXC_GT:
3957 case OP_MIPS_COND_EXC_LE:
3958 case OP_MIPS_COND_EXC_LT:
3959 case OP_MIPS_COND_EXC_NE_UN:
3960 case OP_MIPS_COND_EXC_GE_UN:
3961 case OP_MIPS_COND_EXC_GT_UN:
3962 case OP_MIPS_COND_EXC_LE_UN:
3963 case OP_MIPS_COND_EXC_LT_UN:
3965 case OP_MIPS_COND_EXC_OV:
3966 case OP_MIPS_COND_EXC_NO:
3967 case OP_MIPS_COND_EXC_C:
3968 case OP_MIPS_COND_EXC_NC:
3970 case OP_MIPS_COND_EXC_IEQ:
3971 case OP_MIPS_COND_EXC_IGE:
3972 case OP_MIPS_COND_EXC_IGT:
3973 case OP_MIPS_COND_EXC_ILE:
3974 case OP_MIPS_COND_EXC_ILT:
3975 case OP_MIPS_COND_EXC_INE_UN:
3976 case OP_MIPS_COND_EXC_IGE_UN:
3977 case OP_MIPS_COND_EXC_IGT_UN:
3978 case OP_MIPS_COND_EXC_ILE_UN:
3979 case OP_MIPS_COND_EXC_ILT_UN:
3981 case OP_MIPS_COND_EXC_IOV:
3982 case OP_MIPS_COND_EXC_INO:
3983 case OP_MIPS_COND_EXC_IC:
3984 case OP_MIPS_COND_EXC_INC: {
3988 /* If the condition is true, raise the exception */
3990 /* need to reverse test to skip around exception raising */
3992 /* For the moment, branch around a branch to avoid reversing
3995 /* Remember, an unpatched branch to 0 branches to the delay slot */
3996 switch (ins->opcode) {
3997 case OP_MIPS_COND_EXC_EQ:
3998 throw = (guint32 *)(void *)code;
3999 mips_beq (code, ins->sreg1, ins->sreg2, 0);
4003 case OP_MIPS_COND_EXC_NE_UN:
4004 throw = (guint32 *)(void *)code;
4005 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4009 case OP_MIPS_COND_EXC_LE_UN:
4010 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4011 throw = (guint32 *)(void *)code;
4012 mips_beq (code, mips_at, mips_zero, 0);
4016 case OP_MIPS_COND_EXC_GT:
4017 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4018 throw = (guint32 *)(void *)code;
4019 mips_bne (code, mips_at, mips_zero, 0);
4023 case OP_MIPS_COND_EXC_GT_UN:
4024 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4025 throw = (guint32 *)(void *)code;
4026 mips_bne (code, mips_at, mips_zero, 0);
4030 case OP_MIPS_COND_EXC_LT:
4031 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4032 throw = (guint32 *)(void *)code;
4033 mips_bne (code, mips_at, mips_zero, 0);
4037 case OP_MIPS_COND_EXC_LT_UN:
4038 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4039 throw = (guint32 *)(void *)code;
4040 mips_bne (code, mips_at, mips_zero, 0);
4045 /* Not yet implemented */
4046 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4047 g_assert_not_reached ();
4049 skip = (guint32 *)(void *)code;
4050 mips_beq (code, mips_zero, mips_zero, 0);
4052 mips_patch (throw, (guint32)code);
4053 code = mips_emit_exc_by_name (code, ins->inst_p1);
4054 mips_patch (skip, (guint32)code);
4055 cfg->bb_exit->max_offset += 24;
4064 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4067 /* floating point opcodes */
4070 if (((guint32)ins->inst_p0) & (1 << 15))
4071 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4073 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4074 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4076 mips_load_const (code, mips_at, ins->inst_p0);
4077 mips_lwc1 (code, ins->dreg, mips_at, 4);
4078 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4082 if (((guint32)ins->inst_p0) & (1 << 15))
4083 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4085 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4086 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4087 #if PROMOTE_R4_TO_R8
4088 mips_cvtds (code, ins->dreg, ins->dreg);
4091 case OP_STORER8_MEMBASE_REG:
4092 if (mips_is_imm16 (ins->inst_offset)) {
4093 #if _MIPS_SIM == _ABIO32
4094 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
4095 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
4096 #elif _MIPS_SIM == _ABIN32
4097 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4100 mips_load_const (code, mips_at, ins->inst_offset);
4101 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4102 mips_swc1 (code, ins->sreg1, mips_at, 4);
4103 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
4106 case OP_LOADR8_MEMBASE:
4107 if (mips_is_imm16 (ins->inst_offset)) {
4108 #if _MIPS_SIM == _ABIO32
4109 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
4110 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
4111 #elif _MIPS_SIM == _ABIN32
4112 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4115 mips_load_const (code, mips_at, ins->inst_offset);
4116 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4117 mips_lwc1 (code, ins->dreg, mips_at, 4);
4118 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4121 case OP_STORER4_MEMBASE_REG:
4122 g_assert (mips_is_imm16 (ins->inst_offset));
4123 #if PROMOTE_R4_TO_R8
4124 /* Need to convert ins->sreg1 to single-precision first */
4125 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4126 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4128 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4132 g_assert (mips_is_imm16 (ins->inst_offset));
4133 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4135 case OP_LOADR4_MEMBASE:
4136 g_assert (mips_is_imm16 (ins->inst_offset));
4137 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4138 #if PROMOTE_R4_TO_R8
4139 /* Convert to double precision in place */
4140 mips_cvtds (code, ins->dreg, ins->dreg);
4143 case OP_LOADR4_MEMINDEX:
4144 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4145 mips_lwc1 (code, ins->dreg, mips_at, 0);
4147 case OP_LOADR8_MEMINDEX:
4148 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4149 #if _MIPS_SIM == _ABIO32
4150 mips_lwc1 (code, ins->dreg, mips_at, 0);
4151 mips_lwc1 (code, ins->dreg+1, mips_at, 4);
4152 #elif _MIPS_SIM == _ABIN32
4153 mips_ldc1 (code, ins->dreg, mips_at, 0);
4156 case OP_STORER4_MEMINDEX:
4157 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4158 #if PROMOTE_R4_TO_R8
4159 /* Need to convert ins->sreg1 to single-precision first */
4160 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4161 mips_swc1 (code, mips_ftemp, mips_at, 0);
4163 mips_swc1 (code, ins->sreg1, mips_at, 0);
4166 case OP_STORER8_MEMINDEX:
4167 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4168 #if _MIPS_SIM == _ABIO32
4169 mips_swc1 (code, ins->sreg1, mips_at, 0);
4170 mips_swc1 (code, ins->sreg1+1, mips_at, 4);
4171 #elif _MIPS_SIM == _ABIN32
4172 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4175 case OP_ICONV_TO_R_UN: {
4176 static const guint64 adjust_val = 0x41F0000000000000ULL;
4178 /* convert unsigned int to double */
4179 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4180 mips_bgez (code, ins->sreg1, 5);
4181 mips_cvtdw (code, ins->dreg, mips_ftemp);
4183 mips_load (code, mips_at, (guint32) &adjust_val);
4184 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4185 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4186 /* target is here */
4189 case OP_ICONV_TO_R4:
4190 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4191 mips_cvtsw (code, ins->dreg, mips_ftemp);
4192 mips_cvtds (code, ins->dreg, ins->dreg);
4194 case OP_ICONV_TO_R8:
4195 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4196 mips_cvtdw (code, ins->dreg, mips_ftemp);
4198 case OP_FCONV_TO_I1:
4199 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4201 case OP_FCONV_TO_U1:
4202 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4204 case OP_FCONV_TO_I2:
4205 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4207 case OP_FCONV_TO_U2:
4208 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4210 case OP_FCONV_TO_I4:
4212 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4214 case OP_FCONV_TO_U4:
4216 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4219 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4222 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4225 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4228 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4231 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4234 mips_fnegd (code, ins->dreg, ins->sreg1);
4237 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4238 mips_addiu (code, ins->dreg, mips_zero, 1);
4239 mips_fbtrue (code, 2);
4241 MIPS_MOVE (code, ins->dreg, mips_zero);
4244 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4245 mips_addiu (code, ins->dreg, mips_zero, 1);
4246 mips_fbtrue (code, 2);
4248 MIPS_MOVE (code, ins->dreg, mips_zero);
4251 /* Less than, or Unordered */
4252 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4253 mips_addiu (code, ins->dreg, mips_zero, 1);
4254 mips_fbtrue (code, 2);
4256 MIPS_MOVE (code, ins->dreg, mips_zero);
4259 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4260 MIPS_MOVE (code, ins->dreg, mips_zero);
4261 mips_fbtrue (code, 2);
4263 mips_addiu (code, ins->dreg, mips_zero, 1);
4266 /* Greater than, or Unordered */
4267 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4268 MIPS_MOVE (code, ins->dreg, mips_zero);
4269 mips_fbtrue (code, 2);
4271 mips_addiu (code, ins->dreg, mips_zero, 1);
4274 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4276 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4277 mips_fbtrue (code, 0);
4281 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4283 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4284 mips_fbfalse (code, 0);
4288 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4290 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4291 mips_fbtrue (code, 0);
4294 case OP_MIPS_FBLT_UN:
4295 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4297 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4298 mips_fbtrue (code, 0);
4302 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
4304 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4305 mips_fbfalse (code, 0);
4308 case OP_MIPS_FBGT_UN:
4309 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4311 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4312 mips_fbfalse (code, 0);
4316 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4318 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4319 mips_fbfalse (code, 0);
4322 case OP_MIPS_FBGE_UN:
4323 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
4325 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4326 mips_fbfalse (code, 0);
4330 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4332 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4333 mips_fbtrue (code, 0);
4336 case OP_MIPS_FBLE_UN:
4337 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4339 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4340 mips_fbtrue (code, 0);
4344 guint32 *branch_patch;
4346 mips_mfc1 (code, mips_at, ins->sreg1+1);
4347 mips_srl (code, mips_at, mips_at, 16+4);
4348 mips_andi (code, mips_at, mips_at, 2047);
4349 mips_addiu (code, mips_at, mips_at, -2047);
4351 branch_patch = (guint32 *)(void *)code;
4352 mips_bne (code, mips_at, mips_zero, 0);
4355 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4356 mips_patch (branch_patch, (guint32)code);
4357 mips_fmovd (code, ins->dreg, ins->sreg1);
4361 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4362 mips_load (code, ins->dreg, 0x0f0f0f0f);
4367 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4368 g_assert_not_reached ();
4371 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4372 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4373 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4374 g_assert_not_reached ();
4380 last_offset = offset;
4383 cfg->code_len = code - cfg->native_code;
4387 mono_arch_register_lowlevel_calls (void)
4392 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
4394 MonoJumpInfo *patch_info;
4396 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4397 unsigned char *ip = patch_info->ip.i + code;
4398 const unsigned char *target = NULL;
4400 switch (patch_info->type) {
4401 case MONO_PATCH_INFO_IP:
4402 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4404 case MONO_PATCH_INFO_SWITCH: {
4405 gpointer *table = (gpointer *)patch_info->data.table->table;
4408 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4410 for (i = 0; i < patch_info->data.table->table_size; i++) {
4411 table [i] = (int)patch_info->data.table->table [i] + code;
4415 case MONO_PATCH_INFO_METHODCONST:
4416 case MONO_PATCH_INFO_CLASS:
4417 case MONO_PATCH_INFO_IMAGE:
4418 case MONO_PATCH_INFO_FIELD:
4419 case MONO_PATCH_INFO_VTABLE:
4420 case MONO_PATCH_INFO_IID:
4421 case MONO_PATCH_INFO_SFLDA:
4422 case MONO_PATCH_INFO_LDSTR:
4423 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4424 case MONO_PATCH_INFO_LDTOKEN:
4425 case MONO_PATCH_INFO_R4:
4426 case MONO_PATCH_INFO_R8:
4427 /* from OP_AOTCONST : lui + addiu */
4428 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4429 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4432 case MONO_PATCH_INFO_EXC_NAME:
4433 g_assert_not_reached ();
4434 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4437 case MONO_PATCH_INFO_NONE:
4438 /* everything is dealt with at epilog output time */
4441 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4442 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4451 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4457 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4463 * Allow tracing to work with this interface (with an optional argument)
4465 * This code is expected to be inserted just after the 'real' prolog code,
4466 * and before the first basic block. We need to allocate a 2nd, temporary
4467 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4471 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4474 int offset = cfg->arch.tracing_offset;
4480 /* For N32, need to know for each stack slot if it's an integer
4481 * or float argument, and save/restore the appropriate register
4483 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4484 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4485 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4486 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4487 #if _MIPS_SIM == _ABIN32
4488 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4489 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4490 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4491 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4494 mips_load_const (code, mips_a0, cfg->method);
4495 mips_addiu (code, mips_a1, mips_sp, offset);
4496 mips_call (code, mips_t9, func);
4498 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4499 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4500 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4501 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4502 #if _MIPS_SIM == _ABIN32
4503 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4504 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4505 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4506 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4516 mips_adjust_stackframe(MonoCompile *cfg)
4519 int delta, threshold, i;
4520 MonoMethodSignature *sig;
4523 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4526 /* adjust cfg->stack_offset for account for down-spilling */
4527 cfg->stack_offset += SIZEOF_REGISTER;
4529 /* re-align cfg->stack_offset if needed (due to var spilling) */
4530 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4531 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4532 if (cfg->verbose_level > 2) {
4533 g_print ("mips_adjust_stackframe:\n");
4534 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4536 threshold = cfg->arch.local_alloc_offset;
4537 ra_offset = cfg->stack_offset - sizeof(gpointer);
4538 if (cfg->verbose_level > 2) {
4539 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4542 sig = mono_method_signature (cfg->method);
4543 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4544 cfg->vret_addr->inst_offset += delta;
4546 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4547 MonoInst *inst = cfg->args [i];
4549 inst->inst_offset += delta;
4553 * loads and stores based off the frame reg that (used to) lie
4554 * above the spill var area need to be increased by 'delta'
4555 * to make room for the spill vars.
4557 /* Need to find loads and stores to adjust that
4558 * are above where the spillvars were inserted, but
4559 * which are not the spillvar references themselves.
4561 * Idea - since all offsets from fp are positive, make
4562 * spillvar offsets negative to begin with so we can spot
4567 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4571 if (cfg->verbose_level > 2) {
4572 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4574 MONO_BB_FOR_EACH_INS (bb, ins) {
4578 if (cfg->verbose_level > 2) {
4579 mono_print_ins_index (ins_cnt, ins);
4581 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp))
4583 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))
4585 /* The following two catch FP spills */
4586 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_sp))
4588 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_sp))
4590 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4593 if (ins->inst_c0 >= threshold) {
4594 ins->inst_c0 += delta;
4595 if (cfg->verbose_level > 2) {
4597 mono_print_ins_index (ins_cnt, ins);
4600 else if (ins->inst_c0 < 0) {
4601 ins->inst_c0 = - ins->inst_c0 - 4;
4602 if (cfg->verbose_level > 2) {
4604 mono_print_ins_index (ins_cnt, ins);
4607 g_assert (ins->inst_c0 != ra_offset);
4610 if (ins->inst_imm >= threshold) {
4611 ins->inst_imm += delta;
4612 if (cfg->verbose_level > 2) {
4614 mono_print_ins_index (ins_cnt, ins);
4617 g_assert (ins->inst_c0 != ra_offset);
4627 * Stack frame layout:
4629 * ------------------- sp + cfg->stack_usage + cfg->param_area
4630 * param area incoming
4631 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4633 * ------------------- sp + cfg->stack_usage
4635 * ------------------- sp + cfg->stack_usage-4
4637 * ------------------- sp +
4638 * MonoLMF structure optional
4639 * ------------------- sp + cfg->arch.lmf_offset
4640 * saved registers s0-s8
4641 * ------------------- sp + cfg->arch.iregs_offset
4643 * ------------------- sp + cfg->param_area
4644 * param area outgoing
4645 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4647 * ------------------- sp
4651 mono_arch_emit_prolog (MonoCompile *cfg)
4653 MonoMethod *method = cfg->method;
4654 MonoMethodSignature *sig;
4656 int alloc_size, pos, i;
4657 int alloc2_size = 0;
4661 guint32 iregs_to_save = 0;
4663 guint32 fregs_to_save = 0;
4666 /* lmf_offset is the offset of the LMF from our stack pointer. */
4667 guint32 lmf_offset = cfg->arch.lmf_offset;
4670 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4674 cfg->flags |= MONO_CFG_HAS_CALLS;
4676 sig = mono_method_signature (method);
4677 cfg->code_size = 768 + sig->param_count * 20;
4678 code = cfg->native_code = g_malloc (cfg->code_size);
4681 #if _MIPS_SIM == _ABIO32
4682 cfg->arch.tracing_offset = cfg->stack_offset;
4683 #elif _MIPS_SIM == _ABIN32
4684 /* no stack slots by default for argument regs, reserve a special block */
4685 cfg->arch.tracing_offset = cfg->stack_offset;
4686 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4690 /* adjust stackframe assignments for spillvars if needed */
4691 mips_adjust_stackframe (cfg);
4693 /* stack_offset should not be changed here. */
4694 alloc_size = cfg->stack_offset;
4695 cfg->stack_usage = alloc_size;
4698 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4700 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4704 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4706 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4707 fregs_to_save |= (fregs_to_save << 1);
4710 /* If the stack size is too big, save 1024 bytes to start with
4711 * so the prologue can use imm16(reg) addressing, then allocate
4712 * the rest of the frame.
4714 if (alloc_size > ((1 << 15) - 1024)) {
4715 alloc2_size = alloc_size - 1024;
4719 g_assert (mips_is_imm16 (-alloc_size));
4720 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4723 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4724 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4725 if (mips_is_imm16(offset))
4726 mips_sw (code, mips_ra, mips_sp, offset);
4728 g_assert_not_reached ();
4732 /* XXX - optimize this later to not save all regs if LMF constructed */
4733 pos = cfg->arch.iregs_offset - alloc2_size;
4735 if (iregs_to_save) {
4736 /* save used registers in own stack frame (at pos) */
4737 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4738 if (iregs_to_save & (1 << i)) {
4739 g_assert (pos < cfg->stack_usage - sizeof(gpointer));
4740 g_assert (mips_is_imm16(pos));
4741 MIPS_SW (code, i, mips_sp, pos);
4742 pos += SIZEOF_REGISTER;
4747 if (method->save_lmf) {
4748 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4749 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4750 g_assert (mips_is_imm16(offset));
4751 MIPS_SW (code, i, mips_sp, offset);
4757 /* Save float registers */
4758 if (fregs_to_save) {
4759 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4760 if (fregs_to_save & (1 << i)) {
4761 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4762 g_assert (mips_is_imm16(pos));
4763 mips_swc1 (code, i, mips_sp, pos);
4764 pos += sizeof (gulong);
4769 if (method->save_lmf) {
4770 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4771 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4772 g_assert (mips_is_imm16(offset));
4773 mips_swc1 (code, i, mips_sp, offset);
4778 if (cfg->frame_reg != mips_sp) {
4779 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4781 if (method->save_lmf) {
4782 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4783 g_assert (mips_is_imm16(offset));
4784 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4789 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4790 * to the t* registers, which would be clobbered by the instrumentation calls.
4793 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4797 /* load arguments allocated to register from the stack */
4800 cinfo = calculate_sizes (sig, sig->pinvoke);
4802 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4803 ArgInfo *ainfo = &cinfo->ret;
4804 inst = cfg->vret_addr;
4805 if (inst->opcode == OP_REGVAR)
4806 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4807 else if (mips_is_imm16 (inst->inst_offset)) {
4808 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4810 mips_load_const (code, mips_at, inst->inst_offset);
4811 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4812 mips_sw (code, ainfo->reg, mips_at, 0);
4815 /* Keep this in sync with emit_load_volatile_arguments */
4816 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4817 ArgInfo *ainfo = cinfo->args + i;
4818 inst = cfg->args [pos];
4820 if (cfg->verbose_level > 2)
4821 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4822 if (inst->opcode == OP_REGVAR) {
4823 /* Argument ends up in a register */
4824 if (ainfo->regtype == RegTypeGeneral)
4825 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4826 else if (ainfo->regtype == RegTypeFP) {
4827 g_assert_not_reached();
4829 ppc_fmr (code, inst->dreg, ainfo->reg);
4832 else if (ainfo->regtype == RegTypeBase) {
4833 int offset = cfg->stack_usage + ainfo->offset;
4834 g_assert (mips_is_imm16(offset));
4835 mips_lw (code, inst->dreg, mips_sp, offset);
4837 g_assert_not_reached ();
4839 if (cfg->verbose_level > 2)
4840 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4842 /* Argument ends up on the stack */
4843 if (ainfo->regtype == RegTypeGeneral) {
4844 /* Incoming parameters should be above this frame */
4845 if (cfg->verbose_level > 2)
4846 g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
4847 /* g_assert (inst->inst_offset >= alloc_size); */
4848 g_assert (mips_is_imm16 (inst->inst_offset));
4849 switch (ainfo->size) {
4851 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4854 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4858 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4861 #if (SIZEOF_REGISTER == 4)
4862 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4863 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4864 #elif (SIZEOF_REGISTER == 8)
4865 mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4869 g_assert_not_reached ();
4872 } else if (ainfo->regtype == RegTypeBase) {
4874 * Argument comes in on the stack, and ends up on the stack
4875 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4876 * 8 and 16 bit quantities. Shorten them in place.
4878 g_assert (mips_is_imm16 (inst->inst_offset));
4879 switch (ainfo->size) {
4881 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4882 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4885 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4886 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4893 g_assert_not_reached ();
4895 } else if (ainfo->regtype == RegTypeFP) {
4896 g_assert (mips_is_imm16 (inst->inst_offset));
4897 g_assert (mips_is_imm16 (inst->inst_offset+4));
4898 if (ainfo->size == 8) {
4899 #if _MIPS_SIM == _ABIO32
4900 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4901 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4902 #elif _MIPS_SIM == _ABIN32
4903 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4906 else if (ainfo->size == 4)
4907 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4909 g_assert_not_reached ();
4910 } else if (ainfo->regtype == RegTypeStructByVal) {
4912 int doffset = inst->inst_offset;
4914 g_assert (mips_is_imm16 (inst->inst_offset));
4915 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4916 /* Push the argument registers into their stack slots */
4917 for (i = 0; i < ainfo->size; ++i) {
4918 g_assert (mips_is_imm16(doffset));
4919 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
4920 doffset += SIZEOF_REGISTER;
4922 } else if (ainfo->regtype == RegTypeStructByAddr) {
4923 g_assert (mips_is_imm16 (inst->inst_offset));
4924 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4925 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4927 g_assert_not_reached ();
4932 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4933 mips_load_const (code, mips_a0, cfg->domain);
4934 mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
4938 if (method->save_lmf) {
4939 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4940 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4942 if (lmf_pthread_key != -1) {
4943 g_assert_not_reached();
4945 emit_tls_access (code, mips_temp, lmf_pthread_key);
4947 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
4948 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
4949 g_assert (mips_is_imm16(offset));
4950 mips_addiu (code, mips_a0, mips_temp, offset);
4953 /* This can/will clobber the a0-a3 registers */
4954 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
4957 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4958 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
4959 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4960 /* new_lmf->previous_lmf = *lmf_addr */
4961 mips_lw (code, mips_at, mips_v0, 0);
4962 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
4963 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4964 /* *(lmf_addr) = sp + lmf_offset */
4965 g_assert (mips_is_imm16(lmf_offset));
4966 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4967 mips_sw (code, mips_at, mips_v0, 0);
4969 /* save method info */
4970 mips_load_const (code, mips_at, method);
4971 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
4972 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4973 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
4974 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4976 /* save the current IP */
4977 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4978 mips_load_const (code, mips_at, 0x01010101);
4979 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
4983 if (mips_is_imm16 (-alloc2_size)) {
4984 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
4987 mips_load_const (code, mips_at, -alloc2_size);
4988 mips_addu (code, mips_sp, mips_sp, mips_at);
4990 if (cfg->frame_reg != mips_sp)
4991 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4992 alloc_size += alloc2_size;
4995 cfg->code_len = code - cfg->native_code;
4996 g_assert (cfg->code_len < cfg->code_size);
5011 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5014 int save_mode = SAVE_NONE;
5016 MonoMethod *method = cfg->method;
5017 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5018 int save_offset = MIPS_STACK_PARAM_OFFSET;
5020 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5022 offset = code - cfg->native_code;
5023 /* we need about 16 instructions */
5024 if (offset > (cfg->code_size - 16 * 4)) {
5025 cfg->code_size *= 2;
5026 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5027 code = cfg->native_code + offset;
5032 case MONO_TYPE_VOID:
5033 /* special case string .ctor icall */
5034 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5035 save_mode = SAVE_ONE;
5037 save_mode = SAVE_NONE;
5041 save_mode = SAVE_FP;
5043 case MONO_TYPE_VALUETYPE:
5044 save_mode = SAVE_STRUCT;
5048 #if SIZEOF_REGISTER == 4
5049 save_mode = SAVE_TWO;
5050 #elif SIZEOF_REGISTER == 8
5051 save_mode = SAVE_ONE;
5055 save_mode = SAVE_ONE;
5059 mips_addiu (code, mips_sp, mips_sp, -32);
5060 g_assert (mips_is_imm16(save_offset));
5061 switch (save_mode) {
5063 mips_sw (code, mips_v0, mips_sp, save_offset);
5064 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5065 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5066 if (enable_arguments) {
5067 MIPS_MOVE (code, mips_a1, mips_v0);
5068 MIPS_MOVE (code, mips_a2, mips_v1);
5072 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5073 if (enable_arguments) {
5074 MIPS_MOVE (code, mips_a1, mips_v0);
5078 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5079 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5080 mips_lw (code, mips_a0, mips_sp, save_offset);
5081 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5082 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5089 mips_load_const (code, mips_a0, cfg->method);
5090 mips_call (code, mips_t9, func);
5092 switch (save_mode) {
5094 mips_lw (code, mips_v0, mips_sp, save_offset);
5095 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5096 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5099 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5102 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5109 mips_addiu (code, mips_sp, mips_sp, 32);
5116 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5118 MonoMethod *method = cfg->method;
5120 int max_epilog_size = 16 + 20*4;
5121 int alloc2_size = 0;
5122 guint32 iregs_to_restore;
5124 guint32 fregs_to_restore;
5128 if (cfg->method->save_lmf)
5129 max_epilog_size += 128;
5132 if (mono_jit_trace_calls != NULL)
5133 max_epilog_size += 50;
5135 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5136 max_epilog_size += 50;
5139 pos = code - cfg->native_code;
5140 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5141 cfg->code_size *= 2;
5142 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5143 mono_jit_stats.code_reallocs++;
5147 * Keep in sync with OP_JMP
5150 code = cfg->native_code + pos;
5152 code = cfg->native_code + cfg->code_len;
5154 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5155 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5157 if (cfg->frame_reg != mips_sp) {
5158 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5160 /* If the stack frame is really large, deconstruct it in two steps */
5161 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5162 alloc2_size = cfg->stack_usage - 1024;
5163 /* partially deconstruct the stack */
5164 mips_load_const (code, mips_at, alloc2_size);
5165 mips_addu (code, mips_sp, mips_sp, mips_at);
5167 pos = cfg->arch.iregs_offset - alloc2_size;
5169 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5171 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5173 if (iregs_to_restore) {
5174 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5175 if (iregs_to_restore & (1 << i)) {
5176 g_assert (mips_is_imm16(pos));
5177 MIPS_LW (code, i, mips_sp, pos);
5178 pos += SIZEOF_REGISTER;
5185 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5187 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5188 fregs_to_restore |= (fregs_to_restore << 1);
5190 if (fregs_to_restore) {
5191 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5192 if (fregs_to_restore & (1 << i)) {
5193 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5194 g_assert (mips_is_imm16(pos));
5195 mips_lwc1 (code, i, mips_sp, pos);
5202 /* Unlink the LMF if necessary */
5203 if (method->save_lmf) {
5204 int lmf_offset = cfg->arch.lmf_offset;
5206 /* t0 = current_lmf->previous_lmf */
5207 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5208 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5210 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5211 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5212 /* (*lmf_addr) = previous_lmf */
5213 mips_sw (code, mips_temp, mips_t1, 0);
5217 /* Restore the fp */
5218 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5221 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5222 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5223 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5225 /* Restore the stack pointer */
5226 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5227 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5229 /* Caller will emit either return or tail-call sequence */
5231 cfg->code_len = code - cfg->native_code;
5233 g_assert (cfg->code_len < cfg->code_size);
5238 mono_arch_emit_epilog (MonoCompile *cfg)
5242 code = mono_arch_emit_epilog_sub (cfg, NULL);
5244 mips_jr (code, mips_ra);
5247 cfg->code_len = code - cfg->native_code;
5249 g_assert (cfg->code_len < cfg->code_size);
5252 /* remove once throw_exception_by_name is eliminated */
5255 exception_id_by_name (const char *name)
5257 if (strcmp (name, "IndexOutOfRangeException") == 0)
5258 return MONO_EXC_INDEX_OUT_OF_RANGE;
5259 if (strcmp (name, "OverflowException") == 0)
5260 return MONO_EXC_OVERFLOW;
5261 if (strcmp (name, "ArithmeticException") == 0)
5262 return MONO_EXC_ARITHMETIC;
5263 if (strcmp (name, "DivideByZeroException") == 0)
5264 return MONO_EXC_DIVIDE_BY_ZERO;
5265 if (strcmp (name, "InvalidCastException") == 0)
5266 return MONO_EXC_INVALID_CAST;
5267 if (strcmp (name, "NullReferenceException") == 0)
5268 return MONO_EXC_NULL_REF;
5269 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5270 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5271 if (strcmp (name, "ArgumentException") == 0)
5272 return MONO_EXC_ARGUMENT;
5273 g_error ("Unknown intrinsic exception %s\n", name);
5279 mono_arch_emit_exceptions (MonoCompile *cfg)
5282 MonoJumpInfo *patch_info;
5285 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5286 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5287 int max_epilog_size = 50;
5289 /* count the number of exception infos */
5292 * make sure we have enough space for exceptions
5293 * 24 is the simulated call to throw_exception_by_name
5295 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5297 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5298 i = exception_id_by_name (patch_info->data.target);
5299 g_assert (i < MONO_EXC_INTRINS_NUM);
5300 if (!exc_throw_found [i]) {
5301 max_epilog_size += 12;
5302 exc_throw_found [i] = TRUE;
5308 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5309 cfg->code_size *= 2;
5310 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5311 mono_jit_stats.code_reallocs++;
5314 code = cfg->native_code + cfg->code_len;
5316 /* add code to raise exceptions */
5317 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5318 switch (patch_info->type) {
5319 case MONO_PATCH_INFO_EXC: {
5321 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5323 i = exception_id_by_name (patch_info->data.target);
5324 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5325 if (!exc_throw_pos [i]) {
5328 exc_throw_pos [i] = code;
5329 //g_print ("exc: writing stub at %p\n", code);
5330 mips_load_const (code, mips_a0, patch_info->data.target);
5331 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5332 mips_load_const (code, mips_t9, addr);
5333 mips_jr (code, mips_t9);
5336 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5338 /* Turn into a Relative patch, pointing at code stub */
5339 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5340 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5342 g_assert_not_reached();
5352 cfg->code_len = code - cfg->native_code;
5354 g_assert (cfg->code_len < cfg->code_size);
5359 * Thread local storage support
5362 setup_tls_access (void)
5365 //guint32 *ins, *code;
5367 if (tls_mode == TLS_MODE_FAILED)
5370 if (g_getenv ("MONO_NO_TLS")) {
5371 tls_mode = TLS_MODE_FAILED;
5375 if (tls_mode == TLS_MODE_DETECT) {
5377 tls_mode = TLS_MODE_FAILED;
5381 ins = (guint32*)pthread_getspecific;
5382 /* uncond branch to the real method */
5383 if ((*ins >> 26) == 18) {
5385 val = (*ins & ~3) << 6;
5389 ins = (guint32*)val;
5391 ins = (guint32*) ((char*)ins + val);
5394 code = &cmplwi_1023;
5395 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5397 ppc_li (code, ppc_r4, 0x48);
5400 if (*ins == cmplwi_1023) {
5401 int found_lwz_284 = 0;
5402 for (ptk = 0; ptk < 20; ++ptk) {
5404 if (!*ins || *ins == blr_ins)
5406 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5411 if (!found_lwz_284) {
5412 tls_mode = TLS_MODE_FAILED;
5415 tls_mode = TLS_MODE_LTHREADS;
5416 } else if (*ins == li_0x48) {
5418 /* uncond branch to the real method */
5419 if ((*ins >> 26) == 18) {
5421 val = (*ins & ~3) << 6;
5425 ins = (guint32*)val;
5427 ins = (guint32*) ((char*)ins + val);
5430 ppc_li (code, ppc_r0, 0x7FF2);
5431 if (ins [1] == val) {
5432 /* Darwin on G4, implement */
5433 tls_mode = TLS_MODE_FAILED;
5437 ppc_mfspr (code, ppc_r3, 104);
5438 if (ins [1] != val) {
5439 tls_mode = TLS_MODE_FAILED;
5442 tls_mode = TLS_MODE_DARWIN_G5;
5445 tls_mode = TLS_MODE_FAILED;
5449 tls_mode = TLS_MODE_FAILED;
5454 if (monodomain_key == -1) {
5455 ptk = mono_domain_get_tls_key ();
5457 ptk = mono_pthread_key_for_tls (ptk);
5459 monodomain_key = ptk;
5463 if (lmf_pthread_key == -1) {
5464 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5466 /*g_print ("MonoLMF at: %d\n", ptk);*/
5467 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5468 init_tls_failed = 1;
5471 lmf_pthread_key = ptk;
5474 if (monothread_key == -1) {
5475 ptk = mono_thread_get_tls_key ();
5477 ptk = mono_pthread_key_for_tls (ptk);
5479 monothread_key = ptk;
5480 /*g_print ("thread inited: %d\n", ptk);*/
5483 /*g_print ("thread not inited yet %d\n", ptk);*/
5489 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5491 setup_tls_access ();
5495 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5500 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5502 int this_dreg = mips_a0;
5505 this_dreg = mips_a1;
5507 /* add the this argument */
5508 if (this_reg != -1) {
5510 MONO_INST_NEW (cfg, this, OP_MOVE);
5511 this->type = this_type;
5512 this->sreg1 = this_reg;
5513 this->dreg = mono_alloc_ireg (cfg);
5514 mono_bblock_add_inst (cfg->cbb, this);
5515 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5520 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5521 vtarg->type = STACK_MP;
5522 vtarg->sreg1 = vt_reg;
5523 vtarg->dreg = mono_alloc_ireg (cfg);
5524 mono_bblock_add_inst (cfg->cbb, vtarg);
5525 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5530 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5532 MonoInst *ins = NULL;
5538 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5544 mono_arch_print_tree (MonoInst *tree, int arity)
5549 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5553 setup_tls_access ();
5554 if (monodomain_key == -1)
5557 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5558 ins->inst_offset = monodomain_key;
5563 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5565 /* FIXME: implement */
5566 g_assert_not_reached ();
5569 #ifdef MONO_ARCH_HAVE_IMT
5571 #define ENABLE_WRONG_METHOD_CHECK 0
5573 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5574 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5576 #define LOADSTORE_SIZE 4
5577 #define JUMP_IMM_SIZE 16
5578 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5579 #define LOAD_CONST_SIZE 8
5580 #define JUMP_JR_SIZE 8
5583 * LOCKING: called with the domain lock held
5586 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5587 gpointer fail_tramp)
5591 guint8 *code, *start, *patch;
5593 for (i = 0; i < count; ++i) {
5594 MonoIMTCheckItem *item = imt_entries [i];
5596 item->chunk_size += LOAD_CONST_SIZE;
5597 if (item->is_equals) {
5598 if (item->check_target_idx) {
5599 item->chunk_size += BR_SIZE + LOAD_CONST_SIZE + JUMP_JR_SIZE;
5602 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE * 2;
5603 if (!item->has_target_code)
5604 item->chunk_size += LOADSTORE_SIZE;
5606 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5607 #if ENABLE_WRONG_METHOD_CHECK
5608 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5613 item->chunk_size += BR_SIZE;
5614 imt_entries [item->check_target_idx]->compare_done = TRUE;
5616 size += item->chunk_size;
5618 /* the initial load of the vtable address */
5619 size += MIPS_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5621 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5623 code = mono_domain_code_reserve (domain, size);
5629 * We need to save and restore r11 because it might be
5630 * used by the caller as the vtable register, so
5631 * clobbering it will trip up the magic trampoline.
5633 * FIXME: Get rid of this by making sure that r11 is
5634 * not used as the vtable register in interface calls.
5636 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5637 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5639 /* t7 points to the vtable */
5640 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5642 for (i = 0; i < count; ++i) {
5643 MonoIMTCheckItem *item = imt_entries [i];
5645 item->code_target = code;
5646 if (item->is_equals) {
5647 if (item->check_target_idx) {
5648 mips_load_const (code, mips_temp, (gsize)item->key);
5649 item->jmp_code = code;
5650 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5652 if (item->has_target_code) {
5653 mips_load_const (code, mips_t9,
5654 item->value.target_code);
5657 mips_lw (code, mips_t9, mips_t7,
5658 (sizeof (gpointer) * item->value.vtable_slot));
5660 mips_jr (code, mips_t9);
5664 mips_load_const (code, mips_temp, (gsize)item->key);
5666 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5668 if (item->has_target_code) {
5669 mips_load_const (code, mips_t9,
5670 item->value.target_code);
5673 mips_load_const (code, mips_at,
5674 & (vtable->vtable [item->value.vtable_slot]));
5675 mips_lw (code, mips_t9, mips_at, 0);
5677 mips_jr (code, mips_t9);
5679 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5680 mips_load_const (code, mips_at, fail_tramp);
5681 mips_lw (code, mips_t9, mips_at, 0);
5682 mips_jr (code, mips_t9);
5685 /* enable the commented code to assert on wrong method */
5686 #if ENABLE_WRONG_METHOD_CHECK
5687 ppc_load (code, ppc_r0, (guint32)item->key);
5688 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5690 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5692 mips_lw (code, mips_t9, mips_t7,
5693 (sizeof (gpointer) * item->value.vtable_slot));
5694 mips_jr (code, mips_t9);
5697 #if ENABLE_WRONG_METHOD_CHECK
5698 ppc_patch (patch, code);
5704 mips_load_const (code, mips_temp, (gulong)item->key);
5705 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5707 item->jmp_code = code;
5708 mips_beq (code, mips_temp, mips_zero, 0);
5712 /* patch the branches to get to the target items */
5713 for (i = 0; i < count; ++i) {
5714 MonoIMTCheckItem *item = imt_entries [i];
5715 if (item->jmp_code && item->check_target_idx) {
5716 mips_patch ((guint32 *)item->jmp_code,
5717 (guint32)imt_entries [item->check_target_idx]->code_target);
5722 mono_stats.imt_thunks_size += code - start;
5723 g_assert (code - start <= size);
5724 mono_arch_flush_icache (start, size);
5729 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5731 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5736 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5739 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];