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 *divisor_is_zero;
3428 mips_addiu (code, mips_at, mips_zero, 0xffff);
3429 divisor_is_m1 = (guint32 *)(void *)code;
3430 mips_bne (code, ins->sreg2, mips_at, 0);
3433 /* Divide by -1 -- throw exception */
3434 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
3436 mips_patch (divisor_is_m1, (guint32)code);
3438 /* Put divide in branch delay slot (NOT YET) */
3439 divisor_is_zero = (guint32 *)(void *)code;
3440 mips_bne (code, ins->sreg2, mips_zero, 0);
3443 /* Divide by zero -- throw exception */
3444 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3446 mips_patch (divisor_is_zero, (guint32)code);
3447 mips_div (code, ins->sreg1, ins->sreg2);
3448 if (ins->opcode == OP_IDIV)
3449 mips_mflo (code, ins->dreg);
3451 mips_mfhi (code, ins->dreg);
3456 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3458 /* Put divide in branch delay slot (NOT YET) */
3459 mips_bne (code, ins->sreg2, mips_zero, 0);
3462 /* Divide by zero -- throw exception */
3463 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3465 mips_patch (divisor_is_zero, (guint32)code);
3466 mips_divu (code, ins->sreg1, ins->sreg2);
3467 if (ins->opcode == OP_IDIV_UN)
3468 mips_mflo (code, ins->dreg);
3470 mips_mfhi (code, ins->dreg);
3474 g_assert_not_reached ();
3476 ppc_load (code, ppc_r11, ins->inst_imm);
3477 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3478 ppc_mfspr (code, ppc_r0, ppc_xer);
3479 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3480 /* FIXME: use OverflowException for 0x80000000/-1 */
3481 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3483 g_assert_not_reached();
3486 g_assert_not_reached ();
3488 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3492 g_assert (!(ins->inst_imm & 0xffff0000));
3493 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3496 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3500 /* unsigned 16-bit immediate */
3501 g_assert (!(ins->inst_imm & 0xffff0000));
3502 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3505 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3509 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3512 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3515 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3519 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3522 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3525 case OP_ISHR_UN_IMM:
3526 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3528 case OP_LSHR_UN_IMM:
3529 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3532 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3535 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3539 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3542 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3545 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3549 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3551 mips_mult (code, ins->sreg1, ins->sreg2);
3552 mips_mflo (code, ins->dreg);
3557 #if SIZEOF_REGISTER == 8
3559 mips_dmult (code, ins->sreg1, ins->sreg2);
3560 mips_mflo (code, ins->dreg);
3565 mips_mult (code, ins->sreg1, ins->sreg2);
3566 mips_mflo (code, ins->dreg);
3567 mips_mfhi (code, mips_at);
3570 mips_sra (code, mips_temp, ins->dreg, 31);
3571 patch = (guint32 *)(void *)code;
3572 mips_beq (code, mips_temp, mips_at, 0);
3574 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3575 mips_patch (patch, (guint32)code);
3578 case OP_IMUL_OVF_UN: {
3580 mips_mult (code, ins->sreg1, ins->sreg2);
3581 mips_mflo (code, ins->dreg);
3582 mips_mfhi (code, mips_at);
3585 patch = (guint32 *)(void *)code;
3586 mips_beq (code, mips_at, mips_zero, 0);
3588 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3589 mips_patch (patch, (guint32)code);
3593 mips_load_const (code, ins->dreg, ins->inst_c0);
3595 #if SIZEOF_REGISTER == 8
3597 mips_load_const (code, ins->dreg, ins->inst_c0);
3601 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3602 mips_load (code, ins->dreg, 0);
3606 mips_mtc1 (code, ins->dreg, ins->sreg1);
3608 case OP_MIPS_MTC1S_2:
3609 mips_mtc1 (code, ins->dreg, ins->sreg1);
3610 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3613 mips_mfc1 (code, ins->dreg, ins->sreg1);
3616 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3620 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3622 mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3623 mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3627 case OP_ICONV_TO_I4:
3628 case OP_ICONV_TO_U4:
3630 if (ins->dreg != ins->sreg1)
3631 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3633 #if SIZEOF_REGISTER == 8
3635 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3636 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3639 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3640 mips_dsra (code, ins->dreg, ins->dreg, 32);
3644 /* Get sreg1 into v1, sreg2 into v0 */
3646 if (ins->sreg1 == mips_v0) {
3647 if (ins->sreg1 != mips_at)
3648 MIPS_MOVE (code, mips_at, ins->sreg1);
3649 if (ins->sreg2 != mips_v0)
3650 MIPS_MOVE (code, mips_v0, ins->sreg2);
3651 MIPS_MOVE (code, mips_v1, mips_at);
3654 if (ins->sreg2 != mips_v0)
3655 MIPS_MOVE (code, mips_v0, ins->sreg2);
3656 if (ins->sreg1 != mips_v1)
3657 MIPS_MOVE (code, mips_v1, ins->sreg1);
3661 if (ins->dreg != ins->sreg1) {
3662 mips_fmovd (code, ins->dreg, ins->sreg1);
3666 /* Convert from double to float and leave it there */
3667 mips_cvtsd (code, ins->dreg, ins->sreg1);
3669 case OP_FCONV_TO_R4:
3671 mips_cvtsd (code, ins->dreg, ins->sreg1);
3673 /* Just a move, no precision change */
3674 if (ins->dreg != ins->sreg1) {
3675 mips_fmovd (code, ins->dreg, ins->sreg1);
3680 code = emit_load_volatile_arguments(cfg, code);
3683 * Pop our stack, then jump to specified method (tail-call)
3684 * Keep in sync with mono_arch_emit_epilog
3686 code = mono_arch_emit_epilog_sub (cfg, code);
3688 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3689 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3690 if (cfg->arch.long_branch) {
3691 mips_lui (code, mips_t9, mips_zero, 0);
3692 mips_addiu (code, mips_t9, mips_t9, 0);
3693 mips_jr (code, mips_t9);
3697 mips_beq (code, mips_zero, mips_zero, 0);
3702 /* ensure ins->sreg1 is not NULL */
3703 mips_lw (code, mips_zero, ins->sreg1, 0);
3706 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3707 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3709 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3710 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3712 mips_sw (code, mips_at, ins->sreg1, 0);
3725 case OP_VOIDCALL_REG:
3727 case OP_FCALL_MEMBASE:
3728 case OP_LCALL_MEMBASE:
3729 case OP_VCALL_MEMBASE:
3730 case OP_VCALL2_MEMBASE:
3731 case OP_VOIDCALL_MEMBASE:
3732 case OP_CALL_MEMBASE:
3733 call = (MonoCallInst*)ins;
3734 switch (ins->opcode) {
3741 if (ins->flags & MONO_INST_HAS_METHOD) {
3742 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3743 mips_call (code, mips_t9, call->method);
3746 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3747 mips_call (code, mips_t9, call->fptr);
3754 case OP_VOIDCALL_REG:
3756 MIPS_MOVE (code, mips_t9, ins->sreg1);
3757 mips_jalr (code, mips_t9, mips_ra);
3760 case OP_FCALL_MEMBASE:
3761 case OP_LCALL_MEMBASE:
3762 case OP_VCALL_MEMBASE:
3763 case OP_VCALL2_MEMBASE:
3764 case OP_VOIDCALL_MEMBASE:
3765 case OP_CALL_MEMBASE:
3766 mips_lw (code, mips_t9, ins->sreg1, ins->inst_offset);
3767 mips_jalr (code, mips_t9, mips_ra);
3771 #if PROMOTE_R4_TO_R8
3772 /* returned an FP R4 (single), promote to R8 (double) in place */
3773 if ((ins->opcode == OP_FCALL ||
3774 ins->opcode == OP_FCALL_REG) &&
3775 call->signature->ret->type == MONO_TYPE_R4) {
3776 mips_cvtds (code, mips_f0, mips_f0);
3781 int area_offset = cfg->param_area;
3783 /* Round up ins->sreg1, mips_at ends up holding size */
3784 mips_addiu (code, mips_at, ins->sreg1, 31);
3785 mips_addiu (code, mips_temp, mips_zero, ~31);
3786 mips_and (code, mips_at, mips_at, mips_temp);
3788 mips_subu (code, mips_sp, mips_sp, mips_at);
3789 g_assert (mips_is_imm16 (area_offset));
3790 mips_addiu (code, ins->dreg, mips_sp, area_offset);
3792 if (ins->flags & MONO_INST_INIT) {
3793 mips_move (code, mips_temp, ins->dreg);
3794 mips_sb (code, mips_zero, mips_temp, 0);
3795 mips_addiu (code, mips_at, mips_at, -1);
3796 mips_bne (code, mips_at, mips_zero, -3);
3797 mips_addiu (code, mips_temp, mips_temp, 1);
3802 gpointer addr = mono_arch_get_throw_exception(NULL, FALSE);
3803 mips_move (code, mips_a0, ins->sreg1);
3804 mips_call (code, mips_t9, addr);
3805 mips_break (code, 0xfc);
3809 gpointer addr = mono_arch_get_rethrow_exception(NULL, FALSE);
3810 mips_move (code, mips_a0, ins->sreg1);
3811 mips_call (code, mips_t9, addr);
3812 mips_break (code, 0xfb);
3815 case OP_START_HANDLER: {
3817 * The START_HANDLER instruction marks the beginning of
3818 * a handler block. It is called using a call
3819 * instruction, so mips_ra contains the return address.
3820 * Since the handler executes in the same stack frame
3821 * as the method itself, we can't use save/restore to
3822 * save the return address. Instead, we save it into
3823 * a dedicated variable.
3825 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3826 g_assert (spvar->inst_basereg != mips_sp);
3827 code = emit_reserve_param_area (cfg, code);
3829 if (mips_is_imm16 (spvar->inst_offset)) {
3830 mips_sw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3832 mips_load_const (code, mips_at, spvar->inst_offset);
3833 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3834 mips_sw (code, mips_ra, mips_at, 0);
3838 case OP_ENDFILTER: {
3839 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3840 g_assert (spvar->inst_basereg != mips_sp);
3841 code = emit_unreserve_param_area (cfg, code);
3843 if (ins->sreg1 != mips_v0)
3844 MIPS_MOVE (code, mips_v0, ins->sreg1);
3845 if (mips_is_imm16 (spvar->inst_offset)) {
3846 mips_lw (code, mips_ra, spvar->inst_basereg, spvar->inst_offset);
3848 mips_load_const (code, mips_at, spvar->inst_offset);
3849 mips_addu (code, mips_at, mips_at, spvar->inst_basereg);
3850 mips_lw (code, mips_ra, mips_at, 0);
3852 mips_jr (code, mips_ra);
3856 case OP_ENDFINALLY: {
3857 MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3858 g_assert (spvar->inst_basereg != mips_sp);
3859 code = emit_unreserve_param_area (cfg, code);
3860 mips_lw (code, mips_t9, spvar->inst_basereg, spvar->inst_offset);
3861 mips_jalr (code, mips_t9, mips_ra);
3865 case OP_CALL_HANDLER:
3866 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3867 mips_lui (code, mips_t9, mips_zero, 0);
3868 mips_addiu (code, mips_t9, mips_t9, 0);
3869 mips_jalr (code, mips_t9, mips_ra);
3871 /*FIXME should it be before the NOP or not? Does MIPS has a delay slot like sparc?*/
3872 mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3875 ins->inst_c0 = code - cfg->native_code;
3878 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3879 if (cfg->arch.long_branch) {
3880 mips_lui (code, mips_at, mips_zero, 0);
3881 mips_addiu (code, mips_at, mips_at, 0);
3882 mips_jr (code, mips_at);
3886 mips_beq (code, mips_zero, mips_zero, 0);
3891 mips_jr (code, ins->sreg1);
3897 max_len += 4 * GPOINTER_TO_INT (ins->klass);
3898 if (offset > (cfg->code_size - max_len - 16)) {
3899 cfg->code_size += max_len;
3900 cfg->code_size *= 2;
3901 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3902 code = cfg->native_code + offset;
3904 g_assert (ins->sreg1 != -1);
3905 mips_sll (code, mips_at, ins->sreg1, 2);
3906 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS))
3907 MIPS_MOVE (code, mips_t8, mips_ra);
3908 mips_bgezal (code, mips_zero, 1); /* bal */
3910 mips_addu (code, mips_t9, mips_ra, mips_at);
3911 /* Table is 16 or 20 bytes from target of bal above */
3912 if (1 || !(cfg->flags & MONO_CFG_HAS_CALLS)) {
3913 MIPS_MOVE (code, mips_ra, mips_t8);
3914 mips_lw (code, mips_t9, mips_t9, 20);
3917 mips_lw (code, mips_t9, mips_t9, 16);
3918 mips_jalr (code, mips_t9, mips_t8);
3920 for (i = 0; i < GPOINTER_TO_INT (ins->klass); ++i)
3921 mips_emit32 (code, 0xfefefefe);
3926 mips_addiu (code, ins->dreg, mips_zero, 1);
3927 mips_beq (code, mips_at, mips_zero, 2);
3929 MIPS_MOVE (code, ins->dreg, mips_zero);
3935 mips_addiu (code, ins->dreg, mips_zero, 1);
3936 mips_bltz (code, mips_at, 2);
3938 MIPS_MOVE (code, ins->dreg, mips_zero);
3944 mips_addiu (code, ins->dreg, mips_zero, 1);
3945 mips_bgtz (code, mips_at, 2);
3947 MIPS_MOVE (code, ins->dreg, mips_zero);
3950 case OP_MIPS_COND_EXC_EQ:
3951 case OP_MIPS_COND_EXC_GE:
3952 case OP_MIPS_COND_EXC_GT:
3953 case OP_MIPS_COND_EXC_LE:
3954 case OP_MIPS_COND_EXC_LT:
3955 case OP_MIPS_COND_EXC_NE_UN:
3956 case OP_MIPS_COND_EXC_GE_UN:
3957 case OP_MIPS_COND_EXC_GT_UN:
3958 case OP_MIPS_COND_EXC_LE_UN:
3959 case OP_MIPS_COND_EXC_LT_UN:
3961 case OP_MIPS_COND_EXC_OV:
3962 case OP_MIPS_COND_EXC_NO:
3963 case OP_MIPS_COND_EXC_C:
3964 case OP_MIPS_COND_EXC_NC:
3966 case OP_MIPS_COND_EXC_IEQ:
3967 case OP_MIPS_COND_EXC_IGE:
3968 case OP_MIPS_COND_EXC_IGT:
3969 case OP_MIPS_COND_EXC_ILE:
3970 case OP_MIPS_COND_EXC_ILT:
3971 case OP_MIPS_COND_EXC_INE_UN:
3972 case OP_MIPS_COND_EXC_IGE_UN:
3973 case OP_MIPS_COND_EXC_IGT_UN:
3974 case OP_MIPS_COND_EXC_ILE_UN:
3975 case OP_MIPS_COND_EXC_ILT_UN:
3977 case OP_MIPS_COND_EXC_IOV:
3978 case OP_MIPS_COND_EXC_INO:
3979 case OP_MIPS_COND_EXC_IC:
3980 case OP_MIPS_COND_EXC_INC: {
3984 /* If the condition is true, raise the exception */
3986 /* need to reverse test to skip around exception raising */
3988 /* For the moment, branch around a branch to avoid reversing
3991 /* Remember, an unpatched branch to 0 branches to the delay slot */
3992 switch (ins->opcode) {
3993 case OP_MIPS_COND_EXC_EQ:
3994 throw = (guint32 *)(void *)code;
3995 mips_beq (code, ins->sreg1, ins->sreg2, 0);
3999 case OP_MIPS_COND_EXC_NE_UN:
4000 throw = (guint32 *)(void *)code;
4001 mips_bne (code, ins->sreg1, ins->sreg2, 0);
4005 case OP_MIPS_COND_EXC_LE_UN:
4006 mips_subu (code, mips_at, ins->sreg1, ins->sreg2);
4007 throw = (guint32 *)(void *)code;
4008 mips_blez (code, mips_at, 0);
4012 case OP_MIPS_COND_EXC_GT:
4013 mips_slt (code, mips_at, ins->sreg2, ins->sreg1);
4014 throw = (guint32 *)(void *)code;
4015 mips_bne (code, mips_at, mips_zero, 0);
4019 case OP_MIPS_COND_EXC_GT_UN:
4020 mips_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4021 throw = (guint32 *)(void *)code;
4022 mips_bne (code, mips_at, mips_zero, 0);
4026 case OP_MIPS_COND_EXC_LT:
4027 mips_slt (code, mips_at, ins->sreg1, ins->sreg2);
4028 throw = (guint32 *)(void *)code;
4029 mips_bne (code, mips_at, mips_zero, 0);
4033 case OP_MIPS_COND_EXC_LT_UN:
4034 mips_sltu (code, mips_at, ins->sreg1, ins->sreg2);
4035 throw = (guint32 *)(void *)code;
4036 mips_bne (code, mips_at, mips_zero, 0);
4041 /* Not yet implemented */
4042 g_warning ("NYI conditional exception %s\n", mono_inst_name (ins->opcode));
4043 g_assert_not_reached ();
4045 skip = (guint32 *)(void *)code;
4046 mips_beq (code, mips_zero, mips_zero, 0);
4048 mips_patch (throw, (guint32)code);
4049 code = mips_emit_exc_by_name (code, ins->inst_p1);
4050 mips_patch (skip, (guint32)code);
4051 cfg->bb_exit->max_offset += 24;
4060 code = mips_emit_cond_branch (cfg, code, ins->opcode, ins);
4063 /* floating point opcodes */
4066 if (((guint32)ins->inst_p0) & (1 << 15))
4067 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4069 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4070 mips_ldc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4072 mips_load_const (code, mips_at, ins->inst_p0);
4073 mips_lwc1 (code, ins->dreg, mips_at, 4);
4074 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4078 if (((guint32)ins->inst_p0) & (1 << 15))
4079 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16)+1);
4081 mips_lui (code, mips_at, mips_zero, (((guint32)ins->inst_p0)>>16));
4082 mips_lwc1 (code, ins->dreg, mips_at, ((guint32)ins->inst_p0) & 0xffff);
4083 #if PROMOTE_R4_TO_R8
4084 mips_cvtds (code, ins->dreg, ins->dreg);
4087 case OP_STORER8_MEMBASE_REG:
4088 if (mips_is_imm16 (ins->inst_offset)) {
4089 #if _MIPS_SIM == _ABIO32
4090 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset+4);
4091 mips_swc1 (code, ins->sreg1+1, ins->inst_destbasereg, ins->inst_offset);
4092 #elif _MIPS_SIM == _ABIN32
4093 mips_sdc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4096 mips_load_const (code, mips_at, ins->inst_offset);
4097 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
4098 mips_swc1 (code, ins->sreg1, mips_at, 4);
4099 mips_swc1 (code, ins->sreg1+1, mips_at, 0);
4102 case OP_LOADR8_MEMBASE:
4103 if (mips_is_imm16 (ins->inst_offset)) {
4104 #if _MIPS_SIM == _ABIO32
4105 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset+4);
4106 mips_lwc1 (code, ins->dreg+1, ins->inst_basereg, ins->inst_offset);
4107 #elif _MIPS_SIM == _ABIN32
4108 mips_ldc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4111 mips_load_const (code, mips_at, ins->inst_offset);
4112 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
4113 mips_lwc1 (code, ins->dreg, mips_at, 4);
4114 mips_lwc1 (code, ins->dreg+1, mips_at, 0);
4117 case OP_STORER4_MEMBASE_REG:
4118 g_assert (mips_is_imm16 (ins->inst_offset));
4119 #if PROMOTE_R4_TO_R8
4120 /* Need to convert ins->sreg1 to single-precision first */
4121 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4122 mips_swc1 (code, mips_ftemp, ins->inst_destbasereg, ins->inst_offset);
4124 mips_swc1 (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4128 g_assert (mips_is_imm16 (ins->inst_offset));
4129 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4131 case OP_LOADR4_MEMBASE:
4132 g_assert (mips_is_imm16 (ins->inst_offset));
4133 mips_lwc1 (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4134 #if PROMOTE_R4_TO_R8
4135 /* Convert to double precision in place */
4136 mips_cvtds (code, ins->dreg, ins->dreg);
4139 case OP_LOADR4_MEMINDEX:
4140 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4141 mips_lwc1 (code, ins->dreg, mips_at, 0);
4143 case OP_LOADR8_MEMINDEX:
4144 mips_addu (code, mips_at, ins->inst_basereg, ins->sreg2);
4145 #if _MIPS_SIM == _ABIO32
4146 mips_lwc1 (code, ins->dreg, mips_at, 0);
4147 mips_lwc1 (code, ins->dreg+1, mips_at, 4);
4148 #elif _MIPS_SIM == _ABIN32
4149 mips_ldc1 (code, ins->dreg, mips_at, 0);
4152 case OP_STORER4_MEMINDEX:
4153 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4154 #if PROMOTE_R4_TO_R8
4155 /* Need to convert ins->sreg1 to single-precision first */
4156 mips_cvtsd (code, mips_ftemp, ins->sreg1);
4157 mips_swc1 (code, mips_ftemp, mips_at, 0);
4159 mips_swc1 (code, ins->sreg1, mips_at, 0);
4162 case OP_STORER8_MEMINDEX:
4163 mips_addu (code, mips_at, ins->inst_destbasereg, ins->sreg2);
4164 #if _MIPS_SIM == _ABIO32
4165 mips_swc1 (code, ins->sreg1, mips_at, 0);
4166 mips_swc1 (code, ins->sreg1+1, mips_at, 4);
4167 #elif _MIPS_SIM == _ABIN32
4168 mips_sdc1 (code, ins->sreg1, mips_at, 0);
4171 case OP_ICONV_TO_R_UN: {
4172 static const guint64 adjust_val = 0x41F0000000000000ULL;
4174 /* convert unsigned int to double */
4175 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4176 mips_bgez (code, ins->sreg1, 5);
4177 mips_cvtdw (code, ins->dreg, mips_ftemp);
4179 mips_load (code, mips_at, (guint32) &adjust_val);
4180 mips_ldc1 (code, mips_ftemp, mips_at, 0);
4181 mips_faddd (code, ins->dreg, ins->dreg, mips_ftemp);
4182 /* target is here */
4185 case OP_ICONV_TO_R4:
4186 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4187 mips_cvtsw (code, ins->dreg, mips_ftemp);
4188 mips_cvtds (code, ins->dreg, ins->dreg);
4190 case OP_ICONV_TO_R8:
4191 mips_mtc1 (code, mips_ftemp, ins->sreg1);
4192 mips_cvtdw (code, ins->dreg, mips_ftemp);
4194 case OP_FCONV_TO_I1:
4195 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4197 case OP_FCONV_TO_U1:
4198 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4200 case OP_FCONV_TO_I2:
4201 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4203 case OP_FCONV_TO_U2:
4204 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4206 case OP_FCONV_TO_I4:
4208 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4210 case OP_FCONV_TO_U4:
4212 code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4215 mips_fsqrtd (code, ins->dreg, ins->sreg1);
4218 mips_faddd (code, ins->dreg, ins->sreg1, ins->sreg2);
4221 mips_fsubd (code, ins->dreg, ins->sreg1, ins->sreg2);
4224 mips_fmuld (code, ins->dreg, ins->sreg1, ins->sreg2);
4227 mips_fdivd (code, ins->dreg, ins->sreg1, ins->sreg2);
4230 mips_fnegd (code, ins->dreg, ins->sreg1);
4233 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4234 mips_addiu (code, ins->dreg, mips_zero, 1);
4235 mips_fbtrue (code, 2);
4237 MIPS_MOVE (code, ins->dreg, mips_zero);
4240 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4241 mips_addiu (code, ins->dreg, mips_zero, 1);
4242 mips_fbtrue (code, 2);
4244 MIPS_MOVE (code, ins->dreg, mips_zero);
4247 /* Less than, or Unordered */
4248 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4249 mips_addiu (code, ins->dreg, mips_zero, 1);
4250 mips_fbtrue (code, 2);
4252 MIPS_MOVE (code, ins->dreg, mips_zero);
4255 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4256 MIPS_MOVE (code, ins->dreg, mips_zero);
4257 mips_fbtrue (code, 2);
4259 mips_addiu (code, ins->dreg, mips_zero, 1);
4262 /* Greater than, or Unordered */
4263 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4264 MIPS_MOVE (code, ins->dreg, mips_zero);
4265 mips_fbtrue (code, 2);
4267 mips_addiu (code, ins->dreg, mips_zero, 1);
4270 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4272 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4273 mips_fbtrue (code, 0);
4277 mips_fcmpd (code, MIPS_FPU_EQ, ins->sreg1, ins->sreg2);
4279 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4280 mips_fbfalse (code, 0);
4284 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4286 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4287 mips_fbtrue (code, 0);
4290 case OP_MIPS_FBLT_UN:
4291 mips_fcmpd (code, MIPS_FPU_ULT, ins->sreg1, ins->sreg2);
4293 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4294 mips_fbtrue (code, 0);
4298 mips_fcmpd (code, MIPS_FPU_LE, ins->sreg1, ins->sreg2);
4300 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4301 mips_fbfalse (code, 0);
4304 case OP_MIPS_FBGT_UN:
4305 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4307 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4308 mips_fbfalse (code, 0);
4312 mips_fcmpd (code, MIPS_FPU_LT, ins->sreg1, ins->sreg2);
4314 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4315 mips_fbfalse (code, 0);
4318 case OP_MIPS_FBGE_UN:
4319 mips_fcmpd (code, MIPS_FPU_OLT, ins->sreg1, ins->sreg2);
4321 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4322 mips_fbfalse (code, 0);
4326 mips_fcmpd (code, MIPS_FPU_OLE, ins->sreg1, ins->sreg2);
4328 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4329 mips_fbtrue (code, 0);
4332 case OP_MIPS_FBLE_UN:
4333 mips_fcmpd (code, MIPS_FPU_ULE, ins->sreg1, ins->sreg2);
4335 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb);
4336 mips_fbtrue (code, 0);
4340 guint32 *branch_patch;
4342 mips_mfc1 (code, mips_at, ins->sreg1+1);
4343 mips_srl (code, mips_at, mips_at, 16+4);
4344 mips_andi (code, mips_at, mips_at, 2047);
4345 mips_addiu (code, mips_at, mips_at, -2047);
4347 branch_patch = (guint32 *)(void *)code;
4348 mips_bne (code, mips_at, mips_zero, 0);
4351 EMIT_SYSTEM_EXCEPTION_NAME("ArithmeticException");
4352 mips_patch (branch_patch, (guint32)code);
4353 mips_fmovd (code, ins->dreg, ins->sreg1);
4357 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
4358 mips_load (code, ins->dreg, 0x0f0f0f0f);
4363 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4364 g_assert_not_reached ();
4367 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4368 g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4369 mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4370 g_assert_not_reached ();
4376 last_offset = offset;
4379 cfg->code_len = code - cfg->native_code;
4383 mono_arch_register_lowlevel_calls (void)
4388 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4390 MonoJumpInfo *patch_info;
4392 for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4393 unsigned char *ip = patch_info->ip.i + code;
4394 const unsigned char *target = NULL;
4396 switch (patch_info->type) {
4397 case MONO_PATCH_INFO_IP:
4398 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)ip);
4400 case MONO_PATCH_INFO_SWITCH: {
4401 gpointer *table = (gpointer *)patch_info->data.table->table;
4404 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)table);
4406 for (i = 0; i < patch_info->data.table->table_size; i++) {
4407 table [i] = (int)patch_info->data.table->table [i] + code;
4411 case MONO_PATCH_INFO_METHODCONST:
4412 case MONO_PATCH_INFO_CLASS:
4413 case MONO_PATCH_INFO_IMAGE:
4414 case MONO_PATCH_INFO_FIELD:
4415 case MONO_PATCH_INFO_VTABLE:
4416 case MONO_PATCH_INFO_IID:
4417 case MONO_PATCH_INFO_SFLDA:
4418 case MONO_PATCH_INFO_LDSTR:
4419 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4420 case MONO_PATCH_INFO_LDTOKEN:
4421 case MONO_PATCH_INFO_R4:
4422 case MONO_PATCH_INFO_R8:
4423 /* from OP_AOTCONST : lui + addiu */
4424 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4425 patch_lui_addiu ((guint32 *)(void *)ip, (guint32)target);
4428 case MONO_PATCH_INFO_EXC_NAME:
4429 g_assert_not_reached ();
4430 *((gconstpointer *)(void *)(ip + 1)) = patch_info->data.name;
4433 case MONO_PATCH_INFO_NONE:
4434 /* everything is dealt with at epilog output time */
4437 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4438 mips_patch ((guint32 *)(void *)ip, (guint32)target);
4447 mono_trace_lmf_prolog (MonoLMF *new_lmf)
4453 mono_trace_lmf_epilog (MonoLMF *old_lmf)
4459 * Allow tracing to work with this interface (with an optional argument)
4461 * This code is expected to be inserted just after the 'real' prolog code,
4462 * and before the first basic block. We need to allocate a 2nd, temporary
4463 * stack frame so that we can preserve f12-f15 as well as a0-a3.
4467 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
4470 int offset = cfg->arch.tracing_offset;
4476 /* For N32, need to know for each stack slot if it's an integer
4477 * or float argument, and save/restore the appropriate register
4479 MIPS_SW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4480 MIPS_SW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4481 MIPS_SW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4482 MIPS_SW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4483 #if _MIPS_SIM == _ABIN32
4484 MIPS_SW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4485 MIPS_SW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4486 MIPS_SW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4487 MIPS_SW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4490 mips_load_const (code, mips_a0, cfg->method);
4491 mips_addiu (code, mips_a1, mips_sp, offset);
4492 mips_call (code, mips_t9, func);
4494 MIPS_LW (code, mips_a0, mips_sp, offset + 0*SIZEOF_REGISTER);
4495 MIPS_LW (code, mips_a1, mips_sp, offset + 1*SIZEOF_REGISTER);
4496 MIPS_LW (code, mips_a2, mips_sp, offset + 2*SIZEOF_REGISTER);
4497 MIPS_LW (code, mips_a3, mips_sp, offset + 3*SIZEOF_REGISTER);
4498 #if _MIPS_SIM == _ABIN32
4499 MIPS_LW (code, mips_a4, mips_sp, offset + 4*SIZEOF_REGISTER);
4500 MIPS_LW (code, mips_a5, mips_sp, offset + 5*SIZEOF_REGISTER);
4501 MIPS_LW (code, mips_a6, mips_sp, offset + 6*SIZEOF_REGISTER);
4502 MIPS_LW (code, mips_a7, mips_sp, offset + 7*SIZEOF_REGISTER);
4512 mips_adjust_stackframe(MonoCompile *cfg)
4515 int delta, threshold, i;
4516 MonoMethodSignature *sig;
4519 if (cfg->stack_offset == cfg->arch.local_alloc_offset)
4522 /* adjust cfg->stack_offset for account for down-spilling */
4523 cfg->stack_offset += SIZEOF_REGISTER;
4525 /* re-align cfg->stack_offset if needed (due to var spilling) */
4526 cfg->stack_offset = (cfg->stack_offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
4527 delta = cfg->stack_offset - cfg->arch.local_alloc_offset;
4528 if (cfg->verbose_level > 2) {
4529 g_print ("mips_adjust_stackframe:\n");
4530 g_print ("\tspillvars allocated 0x%x -> 0x%x\n", cfg->arch.local_alloc_offset, cfg->stack_offset);
4532 threshold = cfg->arch.local_alloc_offset;
4533 ra_offset = cfg->stack_offset - sizeof(gpointer);
4534 if (cfg->verbose_level > 2) {
4535 g_print ("\tra_offset %d/0x%x delta %d/0x%x\n", ra_offset, ra_offset, delta, delta);
4538 sig = mono_method_signature (cfg->method);
4539 if (sig && sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
4540 cfg->vret_addr->inst_offset += delta;
4542 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4543 MonoInst *inst = cfg->args [i];
4545 inst->inst_offset += delta;
4549 * loads and stores based off the frame reg that (used to) lie
4550 * above the spill var area need to be increased by 'delta'
4551 * to make room for the spill vars.
4553 /* Need to find loads and stores to adjust that
4554 * are above where the spillvars were inserted, but
4555 * which are not the spillvar references themselves.
4557 * Idea - since all offsets from fp are positive, make
4558 * spillvar offsets negative to begin with so we can spot
4563 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4567 if (cfg->verbose_level > 2) {
4568 g_print ("BASIC BLOCK %d:\n", bb->block_num);
4570 MONO_BB_FOR_EACH_INS (bb, ins) {
4574 if (cfg->verbose_level > 2) {
4575 mono_print_ins_index (ins_cnt, ins);
4577 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_fp))
4579 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_fp))
4581 /* The following two catch FP spills */
4582 if (MONO_IS_LOAD_MEMBASE(ins) && (ins->inst_basereg == mips_sp))
4584 if (MONO_IS_STORE_MEMBASE(ins) && (ins->dreg == mips_sp))
4586 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4589 if (ins->inst_c0 >= threshold) {
4590 ins->inst_c0 += delta;
4591 if (cfg->verbose_level > 2) {
4593 mono_print_ins_index (ins_cnt, ins);
4596 else if (ins->inst_c0 < 0) {
4597 ins->inst_c0 = - ins->inst_c0 - 4;
4598 if (cfg->verbose_level > 2) {
4600 mono_print_ins_index (ins_cnt, ins);
4603 g_assert (ins->inst_c0 != ra_offset);
4606 if (ins->inst_imm >= threshold) {
4607 ins->inst_imm += delta;
4608 if (cfg->verbose_level > 2) {
4610 mono_print_ins_index (ins_cnt, ins);
4613 g_assert (ins->inst_c0 != ra_offset);
4623 * Stack frame layout:
4625 * ------------------- sp + cfg->stack_usage + cfg->param_area
4626 * param area incoming
4627 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4629 * ------------------- sp + cfg->stack_usage
4631 * ------------------- sp + cfg->stack_usage-4
4633 * ------------------- sp +
4634 * MonoLMF structure optional
4635 * ------------------- sp + cfg->arch.lmf_offset
4636 * saved registers s0-s8
4637 * ------------------- sp + cfg->arch.iregs_offset
4639 * ------------------- sp + cfg->param_area
4640 * param area outgoing
4641 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4643 * ------------------- sp
4647 mono_arch_emit_prolog (MonoCompile *cfg)
4649 MonoMethod *method = cfg->method;
4650 MonoMethodSignature *sig;
4652 int alloc_size, pos, i;
4653 int alloc2_size = 0;
4657 guint32 iregs_to_save = 0;
4659 guint32 fregs_to_save = 0;
4662 /* lmf_offset is the offset of the LMF from our stack pointer. */
4663 guint32 lmf_offset = cfg->arch.lmf_offset;
4666 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4670 cfg->flags |= MONO_CFG_HAS_CALLS;
4672 sig = mono_method_signature (method);
4673 cfg->code_size = 768 + sig->param_count * 20;
4674 code = cfg->native_code = g_malloc (cfg->code_size);
4677 #if _MIPS_SIM == _ABIO32
4678 cfg->arch.tracing_offset = cfg->stack_offset;
4679 #elif _MIPS_SIM == _ABIN32
4680 /* no stack slots by default for argument regs, reserve a special block */
4681 cfg->arch.tracing_offset = cfg->stack_offset;
4682 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4686 /* adjust stackframe assignments for spillvars if needed */
4687 mips_adjust_stackframe (cfg);
4689 /* stack_offset should not be changed here. */
4690 alloc_size = cfg->stack_offset;
4691 cfg->stack_usage = alloc_size;
4694 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4696 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4700 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4702 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4703 fregs_to_save |= (fregs_to_save << 1);
4706 /* If the stack size is too big, save 1024 bytes to start with
4707 * so the prologue can use imm16(reg) addressing, then allocate
4708 * the rest of the frame.
4710 if (alloc_size > ((1 << 15) - 1024)) {
4711 alloc2_size = alloc_size - 1024;
4715 g_assert (mips_is_imm16 (-alloc_size));
4716 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4719 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4720 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4721 if (mips_is_imm16(offset))
4722 mips_sw (code, mips_ra, mips_sp, offset);
4724 g_assert_not_reached ();
4728 /* XXX - optimize this later to not save all regs if LMF constructed */
4729 pos = cfg->arch.iregs_offset - alloc2_size;
4731 if (iregs_to_save) {
4732 /* save used registers in own stack frame (at pos) */
4733 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4734 if (iregs_to_save & (1 << i)) {
4735 g_assert (pos < cfg->stack_usage - sizeof(gpointer));
4736 g_assert (mips_is_imm16(pos));
4737 MIPS_SW (code, i, mips_sp, pos);
4738 pos += SIZEOF_REGISTER;
4743 if (method->save_lmf) {
4744 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4745 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4746 g_assert (mips_is_imm16(offset));
4747 MIPS_SW (code, i, mips_sp, offset);
4753 /* Save float registers */
4754 if (fregs_to_save) {
4755 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4756 if (fregs_to_save & (1 << i)) {
4757 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4758 g_assert (mips_is_imm16(pos));
4759 mips_swc1 (code, i, mips_sp, pos);
4760 pos += sizeof (gulong);
4765 if (method->save_lmf) {
4766 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4767 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4768 g_assert (mips_is_imm16(offset));
4769 mips_swc1 (code, i, mips_sp, offset);
4774 if (cfg->frame_reg != mips_sp) {
4775 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4777 if (method->save_lmf) {
4778 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4779 g_assert (mips_is_imm16(offset));
4780 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4785 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4786 * to the t* registers, which would be clobbered by the instrumentation calls.
4789 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4793 /* load arguments allocated to register from the stack */
4796 cinfo = calculate_sizes (sig, sig->pinvoke);
4798 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4799 ArgInfo *ainfo = &cinfo->ret;
4800 inst = cfg->vret_addr;
4801 if (inst->opcode == OP_REGVAR)
4802 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4803 else if (mips_is_imm16 (inst->inst_offset)) {
4804 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4806 mips_load_const (code, mips_at, inst->inst_offset);
4807 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4808 mips_sw (code, ainfo->reg, mips_at, 0);
4811 /* Keep this in sync with emit_load_volatile_arguments */
4812 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4813 ArgInfo *ainfo = cinfo->args + i;
4814 inst = cfg->args [pos];
4816 if (cfg->verbose_level > 2)
4817 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4818 if (inst->opcode == OP_REGVAR) {
4819 /* Argument ends up in a register */
4820 if (ainfo->regtype == RegTypeGeneral)
4821 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4822 else if (ainfo->regtype == RegTypeFP) {
4823 g_assert_not_reached();
4825 ppc_fmr (code, inst->dreg, ainfo->reg);
4828 else if (ainfo->regtype == RegTypeBase) {
4829 int offset = cfg->stack_usage + ainfo->offset;
4830 g_assert (mips_is_imm16(offset));
4831 mips_lw (code, inst->dreg, mips_sp, offset);
4833 g_assert_not_reached ();
4835 if (cfg->verbose_level > 2)
4836 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4838 /* Argument ends up on the stack */
4839 if (ainfo->regtype == RegTypeGeneral) {
4840 /* Incoming parameters should be above this frame */
4841 if (cfg->verbose_level > 2)
4842 g_print ("stack slot at %d of %d\n", inst->inst_offset, alloc_size);
4843 /* g_assert (inst->inst_offset >= alloc_size); */
4844 g_assert (mips_is_imm16 (inst->inst_offset));
4845 switch (ainfo->size) {
4847 mips_sb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4850 mips_sh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4854 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4857 #if (SIZEOF_REGISTER == 4)
4858 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4859 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4860 #elif (SIZEOF_REGISTER == 8)
4861 mips_sd (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4865 g_assert_not_reached ();
4868 } else if (ainfo->regtype == RegTypeBase) {
4870 * Argument comes in on the stack, and ends up on the stack
4871 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4872 * 8 and 16 bit quantities. Shorten them in place.
4874 g_assert (mips_is_imm16 (inst->inst_offset));
4875 switch (ainfo->size) {
4877 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4878 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4881 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4882 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4889 g_assert_not_reached ();
4891 } else if (ainfo->regtype == RegTypeFP) {
4892 g_assert (mips_is_imm16 (inst->inst_offset));
4893 g_assert (mips_is_imm16 (inst->inst_offset+4));
4894 if (ainfo->size == 8) {
4895 #if _MIPS_SIM == _ABIO32
4896 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4897 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4898 #elif _MIPS_SIM == _ABIN32
4899 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4902 else if (ainfo->size == 4)
4903 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4905 g_assert_not_reached ();
4906 } else if (ainfo->regtype == RegTypeStructByVal) {
4908 int doffset = inst->inst_offset;
4910 g_assert (mips_is_imm16 (inst->inst_offset));
4911 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4912 /* Push the argument registers into their stack slots */
4913 for (i = 0; i < ainfo->size; ++i) {
4914 g_assert (mips_is_imm16(doffset));
4915 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
4916 doffset += SIZEOF_REGISTER;
4918 } else if (ainfo->regtype == RegTypeStructByAddr) {
4919 g_assert (mips_is_imm16 (inst->inst_offset));
4920 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4921 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4923 g_assert_not_reached ();
4928 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4929 mips_load_const (code, mips_a0, cfg->domain);
4930 mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
4934 if (method->save_lmf) {
4935 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4936 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4938 if (lmf_pthread_key != -1) {
4939 g_assert_not_reached();
4941 emit_tls_access (code, mips_temp, lmf_pthread_key);
4943 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
4944 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
4945 g_assert (mips_is_imm16(offset));
4946 mips_addiu (code, mips_a0, mips_temp, offset);
4949 /* This can/will clobber the a0-a3 registers */
4950 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
4953 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4954 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
4955 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4956 /* new_lmf->previous_lmf = *lmf_addr */
4957 mips_lw (code, mips_at, mips_v0, 0);
4958 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
4959 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4960 /* *(lmf_addr) = sp + lmf_offset */
4961 g_assert (mips_is_imm16(lmf_offset));
4962 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4963 mips_sw (code, mips_at, mips_v0, 0);
4965 /* save method info */
4966 mips_load_const (code, mips_at, method);
4967 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
4968 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4969 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
4970 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4972 /* save the current IP */
4973 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4974 mips_load_const (code, mips_at, 0x01010101);
4975 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
4979 if (mips_is_imm16 (-alloc2_size)) {
4980 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
4983 mips_load_const (code, mips_at, -alloc2_size);
4984 mips_addu (code, mips_sp, mips_sp, mips_at);
4986 if (cfg->frame_reg != mips_sp)
4987 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4988 alloc_size += alloc2_size;
4991 cfg->code_len = code - cfg->native_code;
4992 g_assert (cfg->code_len < cfg->code_size);
5007 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5010 int save_mode = SAVE_NONE;
5012 MonoMethod *method = cfg->method;
5013 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5014 int save_offset = MIPS_STACK_PARAM_OFFSET;
5016 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5018 offset = code - cfg->native_code;
5019 /* we need about 16 instructions */
5020 if (offset > (cfg->code_size - 16 * 4)) {
5021 cfg->code_size *= 2;
5022 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5023 code = cfg->native_code + offset;
5028 case MONO_TYPE_VOID:
5029 /* special case string .ctor icall */
5030 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5031 save_mode = SAVE_ONE;
5033 save_mode = SAVE_NONE;
5037 save_mode = SAVE_FP;
5039 case MONO_TYPE_VALUETYPE:
5040 save_mode = SAVE_STRUCT;
5044 #if SIZEOF_REGISTER == 4
5045 save_mode = SAVE_TWO;
5046 #elif SIZEOF_REGISTER == 8
5047 save_mode = SAVE_ONE;
5051 save_mode = SAVE_ONE;
5055 mips_addiu (code, mips_sp, mips_sp, -32);
5056 g_assert (mips_is_imm16(save_offset));
5057 switch (save_mode) {
5059 mips_sw (code, mips_v0, mips_sp, save_offset);
5060 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5061 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5062 if (enable_arguments) {
5063 MIPS_MOVE (code, mips_a1, mips_v0);
5064 MIPS_MOVE (code, mips_a2, mips_v1);
5068 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5069 if (enable_arguments) {
5070 MIPS_MOVE (code, mips_a1, mips_v0);
5074 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5075 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5076 mips_lw (code, mips_a0, mips_sp, save_offset);
5077 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5078 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5085 mips_load_const (code, mips_a0, cfg->method);
5086 mips_call (code, mips_t9, func);
5088 switch (save_mode) {
5090 mips_lw (code, mips_v0, mips_sp, save_offset);
5091 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5092 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5095 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5098 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5105 mips_addiu (code, mips_sp, mips_sp, 32);
5112 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5114 MonoMethod *method = cfg->method;
5116 int max_epilog_size = 16 + 20*4;
5117 int alloc2_size = 0;
5118 guint32 iregs_to_restore;
5120 guint32 fregs_to_restore;
5124 if (cfg->method->save_lmf)
5125 max_epilog_size += 128;
5128 if (mono_jit_trace_calls != NULL)
5129 max_epilog_size += 50;
5131 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5132 max_epilog_size += 50;
5135 pos = code - cfg->native_code;
5136 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5137 cfg->code_size *= 2;
5138 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5139 mono_jit_stats.code_reallocs++;
5143 * Keep in sync with OP_JMP
5146 code = cfg->native_code + pos;
5148 code = cfg->native_code + cfg->code_len;
5150 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5151 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5153 if (cfg->frame_reg != mips_sp) {
5154 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5156 /* If the stack frame is really large, deconstruct it in two steps */
5157 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5158 alloc2_size = cfg->stack_usage - 1024;
5159 /* partially deconstruct the stack */
5160 mips_load_const (code, mips_at, alloc2_size);
5161 mips_addu (code, mips_sp, mips_sp, mips_at);
5163 pos = cfg->arch.iregs_offset - alloc2_size;
5165 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5167 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5169 if (iregs_to_restore) {
5170 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5171 if (iregs_to_restore & (1 << i)) {
5172 g_assert (mips_is_imm16(pos));
5173 MIPS_LW (code, i, mips_sp, pos);
5174 pos += SIZEOF_REGISTER;
5181 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5183 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5184 fregs_to_restore |= (fregs_to_restore << 1);
5186 if (fregs_to_restore) {
5187 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5188 if (fregs_to_restore & (1 << i)) {
5189 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5190 g_assert (mips_is_imm16(pos));
5191 mips_lwc1 (code, i, mips_sp, pos);
5198 /* Unlink the LMF if necessary */
5199 if (method->save_lmf) {
5200 int lmf_offset = cfg->arch.lmf_offset;
5202 /* t0 = current_lmf->previous_lmf */
5203 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5204 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5206 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5207 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5208 /* (*lmf_addr) = previous_lmf */
5209 mips_sw (code, mips_temp, mips_t1, 0);
5213 /* Restore the fp */
5214 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5217 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5218 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5219 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5221 /* Restore the stack pointer */
5222 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5223 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5225 /* Caller will emit either return or tail-call sequence */
5227 cfg->code_len = code - cfg->native_code;
5229 g_assert (cfg->code_len < cfg->code_size);
5234 mono_arch_emit_epilog (MonoCompile *cfg)
5238 code = mono_arch_emit_epilog_sub (cfg, NULL);
5240 mips_jr (code, mips_ra);
5243 cfg->code_len = code - cfg->native_code;
5245 g_assert (cfg->code_len < cfg->code_size);
5248 /* remove once throw_exception_by_name is eliminated */
5251 exception_id_by_name (const char *name)
5253 if (strcmp (name, "IndexOutOfRangeException") == 0)
5254 return MONO_EXC_INDEX_OUT_OF_RANGE;
5255 if (strcmp (name, "OverflowException") == 0)
5256 return MONO_EXC_OVERFLOW;
5257 if (strcmp (name, "ArithmeticException") == 0)
5258 return MONO_EXC_ARITHMETIC;
5259 if (strcmp (name, "DivideByZeroException") == 0)
5260 return MONO_EXC_DIVIDE_BY_ZERO;
5261 if (strcmp (name, "InvalidCastException") == 0)
5262 return MONO_EXC_INVALID_CAST;
5263 if (strcmp (name, "NullReferenceException") == 0)
5264 return MONO_EXC_NULL_REF;
5265 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5266 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5267 if (strcmp (name, "ArgumentException") == 0)
5268 return MONO_EXC_ARGUMENT;
5269 g_error ("Unknown intrinsic exception %s\n", name);
5275 mono_arch_emit_exceptions (MonoCompile *cfg)
5278 MonoJumpInfo *patch_info;
5281 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5282 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5283 int max_epilog_size = 50;
5285 /* count the number of exception infos */
5288 * make sure we have enough space for exceptions
5289 * 24 is the simulated call to throw_exception_by_name
5291 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5293 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5294 i = exception_id_by_name (patch_info->data.target);
5295 g_assert (i < MONO_EXC_INTRINS_NUM);
5296 if (!exc_throw_found [i]) {
5297 max_epilog_size += 12;
5298 exc_throw_found [i] = TRUE;
5304 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5305 cfg->code_size *= 2;
5306 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5307 mono_jit_stats.code_reallocs++;
5310 code = cfg->native_code + cfg->code_len;
5312 /* add code to raise exceptions */
5313 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5314 switch (patch_info->type) {
5315 case MONO_PATCH_INFO_EXC: {
5317 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5319 i = exception_id_by_name (patch_info->data.target);
5320 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5321 if (!exc_throw_pos [i]) {
5324 exc_throw_pos [i] = code;
5325 //g_print ("exc: writing stub at %p\n", code);
5326 mips_load_const (code, mips_a0, patch_info->data.target);
5327 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5328 mips_load_const (code, mips_t9, addr);
5329 mips_jr (code, mips_t9);
5332 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5334 /* Turn into a Relative patch, pointing at code stub */
5335 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5336 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5338 g_assert_not_reached();
5348 cfg->code_len = code - cfg->native_code;
5350 g_assert (cfg->code_len < cfg->code_size);
5355 * Thread local storage support
5358 setup_tls_access (void)
5361 //guint32 *ins, *code;
5363 if (tls_mode == TLS_MODE_FAILED)
5366 if (g_getenv ("MONO_NO_TLS")) {
5367 tls_mode = TLS_MODE_FAILED;
5371 if (tls_mode == TLS_MODE_DETECT) {
5373 tls_mode = TLS_MODE_FAILED;
5377 ins = (guint32*)pthread_getspecific;
5378 /* uncond branch to the real method */
5379 if ((*ins >> 26) == 18) {
5381 val = (*ins & ~3) << 6;
5385 ins = (guint32*)val;
5387 ins = (guint32*) ((char*)ins + val);
5390 code = &cmplwi_1023;
5391 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5393 ppc_li (code, ppc_r4, 0x48);
5396 if (*ins == cmplwi_1023) {
5397 int found_lwz_284 = 0;
5398 for (ptk = 0; ptk < 20; ++ptk) {
5400 if (!*ins || *ins == blr_ins)
5402 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5407 if (!found_lwz_284) {
5408 tls_mode = TLS_MODE_FAILED;
5411 tls_mode = TLS_MODE_LTHREADS;
5412 } else if (*ins == li_0x48) {
5414 /* uncond branch to the real method */
5415 if ((*ins >> 26) == 18) {
5417 val = (*ins & ~3) << 6;
5421 ins = (guint32*)val;
5423 ins = (guint32*) ((char*)ins + val);
5426 ppc_li (code, ppc_r0, 0x7FF2);
5427 if (ins [1] == val) {
5428 /* Darwin on G4, implement */
5429 tls_mode = TLS_MODE_FAILED;
5433 ppc_mfspr (code, ppc_r3, 104);
5434 if (ins [1] != val) {
5435 tls_mode = TLS_MODE_FAILED;
5438 tls_mode = TLS_MODE_DARWIN_G5;
5441 tls_mode = TLS_MODE_FAILED;
5445 tls_mode = TLS_MODE_FAILED;
5450 if (monodomain_key == -1) {
5451 ptk = mono_domain_get_tls_key ();
5453 ptk = mono_pthread_key_for_tls (ptk);
5455 monodomain_key = ptk;
5459 if (lmf_pthread_key == -1) {
5460 ptk = mono_pthread_key_for_tls (mono_jit_tls_id);
5462 /*g_print ("MonoLMF at: %d\n", ptk);*/
5463 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5464 init_tls_failed = 1;
5467 lmf_pthread_key = ptk;
5470 if (monothread_key == -1) {
5471 ptk = mono_thread_get_tls_key ();
5473 ptk = mono_pthread_key_for_tls (ptk);
5475 monothread_key = ptk;
5476 /*g_print ("thread inited: %d\n", ptk);*/
5479 /*g_print ("thread not inited yet %d\n", ptk);*/
5485 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5487 setup_tls_access ();
5491 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5496 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5498 int this_dreg = mips_a0;
5501 this_dreg = mips_a1;
5503 /* add the this argument */
5504 if (this_reg != -1) {
5506 MONO_INST_NEW (cfg, this, OP_MOVE);
5507 this->type = this_type;
5508 this->sreg1 = this_reg;
5509 this->dreg = mono_alloc_ireg (cfg);
5510 mono_bblock_add_inst (cfg->cbb, this);
5511 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5516 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5517 vtarg->type = STACK_MP;
5518 vtarg->sreg1 = vt_reg;
5519 vtarg->dreg = mono_alloc_ireg (cfg);
5520 mono_bblock_add_inst (cfg->cbb, vtarg);
5521 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5526 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5528 MonoInst *ins = NULL;
5534 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5540 mono_arch_print_tree (MonoInst *tree, int arity)
5545 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5549 setup_tls_access ();
5550 if (monodomain_key == -1)
5553 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5554 ins->inst_offset = monodomain_key;
5559 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5561 /* FIXME: implement */
5562 g_assert_not_reached ();
5565 #ifdef MONO_ARCH_HAVE_IMT
5567 #define ENABLE_WRONG_METHOD_CHECK 0
5569 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5570 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5572 #define LOADSTORE_SIZE 4
5573 #define JUMP_IMM_SIZE 16
5574 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5575 #define LOAD_CONST_SIZE 8
5576 #define JUMP_JR_SIZE 8
5579 * LOCKING: called with the domain lock held
5582 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5583 gpointer fail_tramp)
5587 guint8 *code, *start, *patch;
5589 for (i = 0; i < count; ++i) {
5590 MonoIMTCheckItem *item = imt_entries [i];
5592 item->chunk_size += LOAD_CONST_SIZE;
5593 if (item->is_equals) {
5594 if (item->check_target_idx) {
5595 item->chunk_size += BR_SIZE + LOAD_CONST_SIZE + JUMP_JR_SIZE;
5598 item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE * 2;
5599 if (!item->has_target_code)
5600 item->chunk_size += LOADSTORE_SIZE;
5602 item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
5603 #if ENABLE_WRONG_METHOD_CHECK
5604 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5609 item->chunk_size += BR_SIZE;
5610 imt_entries [item->check_target_idx]->compare_done = TRUE;
5612 size += item->chunk_size;
5614 /* the initial load of the vtable address */
5615 size += MIPS_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
5617 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5619 code = mono_domain_code_reserve (domain, size);
5625 * We need to save and restore r11 because it might be
5626 * used by the caller as the vtable register, so
5627 * clobbering it will trip up the magic trampoline.
5629 * FIXME: Get rid of this by making sure that r11 is
5630 * not used as the vtable register in interface calls.
5632 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5633 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5635 /* t7 points to the vtable */
5636 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5638 for (i = 0; i < count; ++i) {
5639 MonoIMTCheckItem *item = imt_entries [i];
5641 item->code_target = code;
5642 mips_load_const (code, mips_temp, (gsize)item->key);
5643 if (item->is_equals) {
5644 if (item->check_target_idx) {
5645 item->jmp_code = code;
5646 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5648 if (item->has_target_code) {
5649 mips_load_const (code, mips_t9,
5650 item->value.target_code);
5653 mips_lw (code, mips_t9, mips_t7,
5654 (sizeof (gpointer) * item->value.vtable_slot));
5656 mips_jr (code, mips_t9);
5661 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5663 if (item->has_target_code) {
5664 mips_load_const (code, mips_t9,
5665 item->value.target_code);
5668 mips_load_const (code, mips_at,
5669 & (vtable->vtable [item->value.vtable_slot]));
5670 mips_lw (code, mips_t9, mips_at, 0);
5672 mips_jr (code, mips_t9);
5674 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5675 mips_load_const (code, mips_at, fail_tramp);
5676 mips_lw (code, mips_t9, mips_at, 0);
5677 mips_jr (code, mips_t9);
5680 /* enable the commented code to assert on wrong method */
5681 #if ENABLE_WRONG_METHOD_CHECK
5682 ppc_load (code, ppc_r0, (guint32)item->key);
5683 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5685 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5687 mips_lw (code, mips_t9, mips_t7,
5688 (sizeof (gpointer) * item->value.vtable_slot));
5689 mips_jr (code, mips_t9);
5692 #if ENABLE_WRONG_METHOD_CHECK
5693 ppc_patch (patch, code);
5699 mips_load_const (code, mips_temp, (gulong)item->key);
5700 mips_slt (code, mips_temp, mips_temp, MONO_ARCH_IMT_REG);
5702 item->jmp_code = code;
5703 mips_bne (code, mips_temp, mips_zero, 0);
5707 /* patch the branches to get to the target items */
5708 for (i = 0; i < count; ++i) {
5709 MonoIMTCheckItem *item = imt_entries [i];
5710 if (item->jmp_code && item->check_target_idx) {
5711 mips_patch ((guint32 *)item->jmp_code,
5712 (guint32)imt_entries [item->check_target_idx]->code_target);
5717 mono_stats.imt_thunks_size += code - start;
5718 g_assert (code - start <= size);
5719 mono_arch_flush_icache (start, size);
5724 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5726 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5731 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5734 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];