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 g_assert ((code[1] >> 26) == 0x9);
381 patch_lui_addiu (code, target);
382 mono_arch_flush_icache ((guint8 *)code, 8);
386 printf ("unknown op 0x%02x (0x%08x) @ %p\n", op, ins, code);
387 g_assert_not_reached ();
393 offsets_from_pthread_key (guint32 key, int *offset2)
397 *offset2 = idx2 * sizeof (gpointer);
398 return 284 + idx1 * sizeof (gpointer);
403 mono_arch_regname (int reg) {
404 #if _MIPS_SIM == _ABIO32
405 static const char * rnames[] = {
406 "zero", "at", "v0", "v1",
407 "a0", "a1", "a2", "a3",
408 "t0", "t1", "t2", "t3",
409 "t4", "t5", "t6", "t7",
410 "s0", "s1", "s2", "s3",
411 "s4", "s5", "s6", "s7",
412 "t8", "t9", "k0", "k1",
413 "gp", "sp", "fp", "ra"
415 #elif _MIPS_SIM == _ABIN32
416 static const char * rnames[] = {
417 "zero", "at", "v0", "v1",
418 "a0", "a1", "a2", "a3",
419 "a4", "a5", "a6", "a7",
420 "t0", "t1", "t2", "t3",
421 "s0", "s1", "s2", "s3",
422 "s4", "s5", "s6", "s7",
423 "t8", "t9", "k0", "k1",
424 "gp", "sp", "fp", "ra"
427 if (reg >= 0 && reg < 32)
433 mono_arch_fregname (int reg) {
434 static const char * rnames[] = {
435 "f0", "f1", "f2", "f3",
436 "f4", "f5", "f6", "f7",
437 "f8", "f9", "f10", "f11",
438 "f12", "f13", "f14", "f15",
439 "f16", "f17", "f18", "f19",
440 "f20", "f21", "f22", "f23",
441 "f24", "f25", "f26", "f27",
442 "f28", "f29", "f30", "f31"
444 if (reg >= 0 && reg < 32)
449 /* this function overwrites at */
451 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
453 /* XXX write a loop, not an unrolled loop */
455 mips_lw (code, mips_at, sreg, soffset);
456 mips_sw (code, mips_at, dreg, doffset);
465 * mono_arch_get_argument_info:
466 * @csig: a method signature
467 * @param_count: the number of parameters to consider
468 * @arg_info: an array to store the result infos
470 * Gathers information on parameters such as size, alignment and
471 * padding. arg_info should be large enought to hold param_count + 1 entries.
473 * Returns the size of the activation frame.
476 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
478 int k, frame_size = 0;
479 guint32 size, align, pad;
482 if (MONO_TYPE_ISSTRUCT (csig->ret)) {
483 frame_size += sizeof (gpointer);
487 arg_info [0].offset = offset;
490 frame_size += sizeof (gpointer);
494 arg_info [0].size = frame_size;
496 for (k = 0; k < param_count; k++) {
497 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
499 /* ignore alignment for now */
502 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
503 arg_info [k].pad = pad;
505 arg_info [k + 1].pad = 0;
506 arg_info [k + 1].size = size;
508 arg_info [k + 1].offset = offset;
512 align = MONO_ARCH_FRAME_ALIGNMENT;
513 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
514 arg_info [k].pad = pad;
521 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
524 return (gpointer)regs [mips_a0];
528 * Initialize the cpu to execute managed code.
531 mono_arch_cpu_init (void)
536 * Initialize architecture specific code.
539 mono_arch_init (void)
541 InitializeCriticalSection (&mini_arch_mutex);
545 * Cleanup architecture specific code.
548 mono_arch_cleanup (void)
550 DeleteCriticalSection (&mini_arch_mutex);
554 * This function returns the optimizations supported on this cpu.
557 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
561 /* no mips-specific optimizations yet */
567 is_regsize_var (MonoType *t) {
570 t = mono_type_get_underlying_type (t);
574 #if (SIZEOF_REGISTER == 8)
581 case MONO_TYPE_FNPTR:
583 case MONO_TYPE_OBJECT:
584 case MONO_TYPE_STRING:
585 case MONO_TYPE_CLASS:
586 case MONO_TYPE_SZARRAY:
587 case MONO_TYPE_ARRAY:
589 case MONO_TYPE_GENERICINST:
590 if (!mono_type_generic_inst_is_valuetype (t))
593 case MONO_TYPE_VALUETYPE:
600 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
605 for (i = 0; i < cfg->num_varinfo; i++) {
606 MonoInst *ins = cfg->varinfo [i];
607 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
610 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
613 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
616 /* we can only allocate 32 bit values */
617 if (is_regsize_var (ins->inst_vtype)) {
618 g_assert (MONO_VARINFO (cfg, i)->reg == -1);
619 g_assert (i == vmv->idx);
620 vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
628 mono_arch_get_global_int_regs (MonoCompile *cfg)
632 regs = g_list_prepend (regs, (gpointer)mips_s0);
633 regs = g_list_prepend (regs, (gpointer)mips_s1);
634 regs = g_list_prepend (regs, (gpointer)mips_s2);
635 regs = g_list_prepend (regs, (gpointer)mips_s3);
636 regs = g_list_prepend (regs, (gpointer)mips_s4);
637 //regs = g_list_prepend (regs, (gpointer)mips_s5);
638 regs = g_list_prepend (regs, (gpointer)mips_s6);
639 regs = g_list_prepend (regs, (gpointer)mips_s7);
645 * mono_arch_regalloc_cost:
647 * Return the cost, in number of memory references, of the action of
648 * allocating the variable VMV into a register during global register
652 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
659 args_onto_stack (CallInfo *info)
661 g_assert (!info->on_stack);
662 g_assert (info->stack_size <= MIPS_STACK_PARAM_OFFSET);
663 info->on_stack = TRUE;
664 info->stack_size = MIPS_STACK_PARAM_OFFSET;
667 #if _MIPS_SIM == _ABIO32
669 * O32 calling convention version
673 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
674 /* First, see if we need to drop onto the stack */
675 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
676 args_onto_stack (info);
678 /* Now, place the argument */
679 if (info->on_stack) {
680 ainfo->regtype = RegTypeBase;
681 ainfo->reg = mips_sp; /* in the caller */
682 ainfo->offset = info->stack_size;
685 ainfo->regtype = RegTypeGeneral;
686 ainfo->reg = info->gr;
688 info->gr_passed = TRUE;
690 info->stack_size += 4;
694 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
695 /* First, see if we need to drop onto the stack */
696 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
697 args_onto_stack (info);
699 /* Now, place the argument */
700 if (info->on_stack) {
701 g_assert (info->stack_size % 4 == 0);
702 info->stack_size += (info->stack_size % 8);
704 ainfo->regtype = RegTypeBase;
705 ainfo->reg = mips_sp; /* in the caller */
706 ainfo->offset = info->stack_size;
709 // info->gr must be a0 or a2
710 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
711 g_assert(info->gr <= MIPS_LAST_ARG_REG);
713 ainfo->regtype = RegTypeGeneral;
714 ainfo->reg = info->gr;
716 info->gr_passed = TRUE;
718 info->stack_size += 8;
722 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
723 /* First, see if we need to drop onto the stack */
724 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
725 args_onto_stack (info);
727 /* Now, place the argument */
728 if (info->on_stack) {
729 ainfo->regtype = RegTypeBase;
730 ainfo->reg = mips_sp; /* in the caller */
731 ainfo->offset = info->stack_size;
734 /* Only use FP regs for args if no int args passed yet */
735 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
736 ainfo->regtype = RegTypeFP;
737 ainfo->reg = info->fr;
738 /* Even though it's a single-precision float, it takes up two FP regs */
740 /* FP and GP slots do not overlap */
744 /* Passing single-precision float arg in a GP register
745 * such as: func (0, 1.0, 2, 3);
746 * In this case, only one 'gr' register is consumed.
748 ainfo->regtype = RegTypeGeneral;
749 ainfo->reg = info->gr;
752 info->gr_passed = TRUE;
755 info->stack_size += 4;
759 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
760 /* First, see if we need to drop onto the stack */
761 if (!info->on_stack && info->gr+1 > MIPS_LAST_ARG_REG)
762 args_onto_stack (info);
764 /* Now, place the argument */
765 if (info->on_stack) {
766 g_assert(info->stack_size % 4 == 0);
767 info->stack_size += (info->stack_size % 8);
769 ainfo->regtype = RegTypeBase;
770 ainfo->reg = mips_sp; /* in the caller */
771 ainfo->offset = info->stack_size;
774 /* Only use FP regs for args if no int args passed yet */
775 if (!info->gr_passed && info->fr <= MIPS_LAST_FPARG_REG) {
776 ainfo->regtype = RegTypeFP;
777 ainfo->reg = info->fr;
779 /* FP and GP slots do not overlap */
783 // info->gr must be a0 or a2
784 info->gr += (info->gr - MIPS_FIRST_ARG_REG) % 2;
785 g_assert(info->gr <= MIPS_LAST_ARG_REG);
787 ainfo->regtype = RegTypeGeneral;
788 ainfo->reg = info->gr;
790 info->gr_passed = TRUE;
793 info->stack_size += 8;
795 #elif _MIPS_SIM == _ABIN32
797 * N32 calling convention version
801 add_int32_arg (CallInfo *info, ArgInfo *ainfo) {
802 /* First, see if we need to drop onto the stack */
803 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
804 args_onto_stack (info);
806 /* Now, place the argument */
807 if (info->on_stack) {
808 ainfo->regtype = RegTypeBase;
809 ainfo->reg = mips_sp; /* in the caller */
810 ainfo->offset = info->stack_size;
811 info->stack_size += SIZEOF_REGISTER;
814 ainfo->regtype = RegTypeGeneral;
815 ainfo->reg = info->gr;
817 info->gr_passed = TRUE;
822 add_int64_arg (CallInfo *info, ArgInfo *ainfo) {
823 /* First, see if we need to drop onto the stack */
824 if (!info->on_stack && info->gr > MIPS_LAST_ARG_REG)
825 args_onto_stack (info);
827 /* Now, place the argument */
828 if (info->on_stack) {
829 g_assert (info->stack_size % 4 == 0);
830 info->stack_size += (info->stack_size % 8);
832 ainfo->regtype = RegTypeBase;
833 ainfo->reg = mips_sp; /* in the caller */
834 ainfo->offset = info->stack_size;
835 info->stack_size += SIZEOF_REGISTER;
838 g_assert (info->gr <= MIPS_LAST_ARG_REG);
840 ainfo->regtype = RegTypeGeneral;
841 ainfo->reg = info->gr;
843 info->gr_passed = TRUE;
848 add_float32_arg (CallInfo *info, ArgInfo *ainfo) {
849 /* First, see if we need to drop onto the stack */
850 if (!info->on_stack) {
851 if (info->gr > MIPS_LAST_ARG_REG)
852 args_onto_stack (info);
853 else if (info->fr > MIPS_LAST_FPARG_REG)
854 args_onto_stack (info);
857 /* Now, place the argument */
858 if (info->on_stack) {
859 ainfo->regtype = RegTypeBase;
860 ainfo->reg = mips_sp; /* in the caller */
861 ainfo->offset = info->stack_size;
862 info->stack_size += FREG_SIZE;
865 ainfo->regtype = RegTypeFP;
866 ainfo->reg = info->fr;
868 /* FP and GP slots do not overlap */
874 add_float64_arg (CallInfo *info, ArgInfo *ainfo) {
875 /* First, see if we need to drop onto the stack */
876 if (!info->on_stack) {
877 if (info->gr > MIPS_LAST_ARG_REG)
878 args_onto_stack (info);
879 else if (info->fr > MIPS_LAST_FPARG_REG)
880 args_onto_stack (info);
883 /* Now, place the argument */
884 if (info->on_stack) {
885 g_assert(info->stack_size % 4 == 0);
886 info->stack_size += (info->stack_size % 8);
888 ainfo->regtype = RegTypeBase;
889 ainfo->reg = mips_sp; /* in the caller */
890 ainfo->offset = info->stack_size;
891 info->stack_size += FREG_SIZE;
894 ainfo->regtype = RegTypeFP;
895 ainfo->reg = info->fr;
897 /* FP and GP slots do not overlap */
904 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
907 int n = sig->hasthis + sig->param_count;
909 MonoType* simpletype;
910 CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
912 cinfo->fr = MIPS_FIRST_FPARG_REG;
913 cinfo->gr = MIPS_FIRST_ARG_REG;
914 cinfo->stack_size = 0;
916 DEBUG(printf("calculate_sizes\n"));
918 cinfo->vtype_retaddr = MONO_TYPE_ISSTRUCT (sig->ret) ? TRUE : FALSE;
922 /* handle returning a struct */
923 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
924 cinfo->struct_ret = cinfo->gr;
925 add_int32_arg (cinfo, &cinfo->ret);
929 add_int32_arg (cinfo, cinfo->args + n);
934 * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
935 * the first argument, allowing 'this' to be always passed in the first arg reg.
936 * Also do this if the first argument is a reference type, since virtual calls
937 * are sometimes made using calli without sig->hasthis set, like in the delegate
940 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]))))) {
942 add_int32_arg (cinfo, cinfo->args + n);
945 add_int32_arg (cinfo, cinfo->args + sig->hasthis);
949 add_int32_arg (cinfo, &cinfo->ret);
950 cinfo->struct_ret = cinfo->ret.reg;
954 add_int32_arg (cinfo, cinfo->args + n);
958 if (cinfo->vtype_retaddr) {
959 add_int32_arg (cinfo, &cinfo->ret);
960 cinfo->struct_ret = cinfo->ret.reg;
965 DEBUG(printf("params: %d\n", sig->param_count));
966 for (i = pstart; i < sig->param_count; ++i) {
967 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
968 /* Prevent implicit arguments and sig_cookie from
969 being passed in registers */
970 args_onto_stack (cinfo);
971 /* Emit the signature cookie just before the implicit arguments */
972 add_int32_arg (cinfo, &cinfo->sig_cookie);
974 DEBUG(printf("param %d: ", i));
975 if (sig->params [i]->byref) {
976 DEBUG(printf("byref\n"));
977 add_int32_arg (cinfo, &cinfo->args[n]);
981 simpletype = mono_type_get_underlying_type (sig->params [i]);
982 switch (simpletype->type) {
983 case MONO_TYPE_BOOLEAN:
986 DEBUG(printf("1 byte\n"));
987 cinfo->args [n].size = 1;
988 add_int32_arg (cinfo, &cinfo->args[n]);
994 DEBUG(printf("2 bytes\n"));
995 cinfo->args [n].size = 2;
996 add_int32_arg (cinfo, &cinfo->args[n]);
1001 DEBUG(printf("4 bytes\n"));
1002 cinfo->args [n].size = 4;
1003 add_int32_arg (cinfo, &cinfo->args[n]);
1009 case MONO_TYPE_FNPTR:
1010 case MONO_TYPE_CLASS:
1011 case MONO_TYPE_OBJECT:
1012 case MONO_TYPE_STRING:
1013 case MONO_TYPE_SZARRAY:
1014 case MONO_TYPE_ARRAY:
1015 cinfo->args [n].size = sizeof (gpointer);
1016 add_int32_arg (cinfo, &cinfo->args[n]);
1019 case MONO_TYPE_GENERICINST:
1020 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1021 cinfo->args [n].size = sizeof (gpointer);
1022 add_int32_arg (cinfo, &cinfo->args[n]);
1027 case MONO_TYPE_VALUETYPE: {
1030 int has_offset = FALSE;
1032 gint size, alignment;
1035 klass = mono_class_from_mono_type (sig->params [i]);
1037 size = mono_class_native_size (klass, NULL);
1039 size = mono_class_value_size (klass, NULL);
1040 alignment = mono_class_min_align (klass);
1041 #if MIPS_PASS_STRUCTS_BY_VALUE
1042 /* Need to do alignment if struct contains long or double */
1043 if (alignment > 4) {
1044 /* Drop onto stack *before* looking at
1045 stack_size, if required. */
1046 if (!cinfo->on_stack && cinfo->gr > MIPS_LAST_ARG_REG)
1047 args_onto_stack (cinfo);
1048 if (cinfo->stack_size & (alignment - 1)) {
1049 add_int32_arg (cinfo, &dummy_arg);
1051 g_assert (!(cinfo->stack_size & (alignment - 1)));
1055 g_printf ("valuetype struct size=%d offset=%d align=%d\n",
1056 mono_class_native_size (sig->params [i]->data.klass, NULL),
1057 cinfo->stack_size, alignment);
1059 nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1060 g_assert (cinfo->args [n].size == 0);
1061 g_assert (cinfo->args [n].vtsize == 0);
1062 for (j = 0; j < nwords; ++j) {
1064 add_int32_arg (cinfo, &cinfo->args [n]);
1065 if (cinfo->on_stack)
1068 add_int32_arg (cinfo, &dummy_arg);
1069 if (!has_offset && cinfo->on_stack) {
1070 cinfo->args [n].offset = dummy_arg.offset;
1074 if (cinfo->on_stack)
1075 cinfo->args [n].vtsize += 1;
1077 cinfo->args [n].size += 1;
1079 //g_printf ("\tstack_size=%d vtsize=%d\n", cinfo->args [n].size, cinfo->args[n].vtsize);
1080 cinfo->args [n].regtype = RegTypeStructByVal;
1082 add_int32_arg (cinfo, &cinfo->args[n]);
1083 cinfo->args [n].regtype = RegTypeStructByAddr;
1088 case MONO_TYPE_TYPEDBYREF: {
1089 /* keep in sync or merge with the valuetype case */
1090 #if MIPS_PASS_STRUCTS_BY_VALUE
1092 int size = sizeof (MonoTypedRef);
1093 int nwords = (size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1094 cinfo->args [n].regtype = RegTypeStructByVal;
1095 if (!cinfo->on_stack && cinfo->gr <= MIPS_LAST_ARG_REG) {
1096 int rest = MIPS_LAST_ARG_REG - cinfo->gr + 1;
1097 int n_in_regs = rest >= nwords? nwords: rest;
1098 cinfo->args [n].size = n_in_regs;
1099 cinfo->args [n].vtsize = nwords - n_in_regs;
1100 cinfo->args [n].reg = cinfo->gr;
1101 cinfo->gr += n_in_regs;
1102 cinfo->gr_passed = TRUE;
1104 cinfo->args [n].size = 0;
1105 cinfo->args [n].vtsize = nwords;
1107 if (cinfo->args [n].vtsize > 0) {
1108 if (!cinfo->on_stack)
1109 args_onto_stack (cinfo);
1110 g_assert(cinfo->on_stack);
1111 cinfo->args [n].offset = cinfo->stack_size;
1112 g_print ("offset for arg %d at %d\n", n, cinfo->args [n].offset);
1113 cinfo->stack_size += cinfo->args [n].vtsize * sizeof (gpointer);
1117 add_int32_arg (cinfo, &cinfo->args[n]);
1118 cinfo->args [n].regtype = RegTypeStructByAddr;
1125 DEBUG(printf("8 bytes\n"));
1126 cinfo->args [n].size = 8;
1127 add_int64_arg (cinfo, &cinfo->args[n]);
1131 DEBUG(printf("R4\n"));
1132 cinfo->args [n].size = 4;
1133 add_float32_arg (cinfo, &cinfo->args[n]);
1137 DEBUG(printf("R8\n"));
1138 cinfo->args [n].size = 8;
1139 add_float64_arg (cinfo, &cinfo->args[n]);
1143 g_error ("Can't trampoline 0x%x", sig->params [i]->type);
1148 simpletype = mono_type_get_underlying_type (sig->ret);
1149 switch (simpletype->type) {
1150 case MONO_TYPE_BOOLEAN:
1155 case MONO_TYPE_CHAR:
1161 case MONO_TYPE_FNPTR:
1162 case MONO_TYPE_CLASS:
1163 case MONO_TYPE_OBJECT:
1164 case MONO_TYPE_SZARRAY:
1165 case MONO_TYPE_ARRAY:
1166 case MONO_TYPE_STRING:
1167 cinfo->ret.reg = mips_v0;
1171 cinfo->ret.reg = mips_v0;
1175 cinfo->ret.reg = mips_f0;
1176 cinfo->ret.regtype = RegTypeFP;
1178 case MONO_TYPE_GENERICINST:
1179 if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1180 cinfo->ret.reg = mips_v0;
1184 case MONO_TYPE_VALUETYPE:
1186 case MONO_TYPE_TYPEDBYREF:
1187 case MONO_TYPE_VOID:
1190 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1194 /* align stack size to 16 */
1195 cinfo->stack_size = (cinfo->stack_size + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1197 cinfo->stack_usage = cinfo->stack_size;
1203 * Set var information according to the calling convention. mips version.
1204 * The locals var stuff should most likely be split in another method.
1207 mono_arch_allocate_vars (MonoCompile *cfg)
1209 MonoMethodSignature *sig;
1210 MonoMethodHeader *header;
1212 int i, offset, size, align, curinst;
1213 int frame_reg = mips_sp;
1214 guint32 iregs_to_save = 0;
1216 guint32 fregs_to_restore;
1219 /* spill down, we'll fix it in a separate pass */
1220 // cfg->flags |= MONO_CFG_HAS_SPILLUP;
1222 /* allow room for the vararg method args: void* and long/double */
1223 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1224 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1226 /* this is bug #60332: remove when #59509 is fixed, so no weird vararg
1227 * call convs needs to be handled this way.
1229 if (cfg->flags & MONO_CFG_HAS_VARARGS)
1230 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1232 /* gtk-sharp and other broken code will dllimport vararg functions even with
1233 * non-varargs signatures. Since there is little hope people will get this right
1234 * we assume they won't.
1236 if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
1237 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1239 /* a0-a3 always present */
1240 cfg->param_area = MAX (cfg->param_area, MIPS_STACK_PARAM_OFFSET);
1242 header = cfg->header;
1244 sig = mono_method_signature (cfg->method);
1247 * We use the frame register also for any method that has
1248 * exception clauses. This way, when the handlers are called,
1249 * the code will reference local variables using the frame reg instead of
1250 * the stack pointer: if we had to restore the stack pointer, we'd
1251 * corrupt the method frames that are already on the stack (since
1252 * filters get called before stack unwinding happens) when the filter
1253 * code would call any method (this also applies to finally etc.).
1256 if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses || ALWAYS_USE_FP)
1257 frame_reg = mips_fp;
1258 cfg->frame_reg = frame_reg;
1259 if (frame_reg != mips_sp) {
1260 cfg->used_int_regs |= 1 << frame_reg;
1265 if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1266 /* FIXME: handle long and FP values */
1267 switch (mono_type_get_underlying_type (sig->ret)->type) {
1268 case MONO_TYPE_VOID:
1272 cfg->ret->opcode = OP_REGVAR;
1273 cfg->ret->inst_c0 = cfg->ret->dreg = mips_f0;
1276 cfg->ret->opcode = OP_REGVAR;
1277 cfg->ret->inst_c0 = mips_v0;
1281 /* Space for outgoing parameters, including a0-a3 */
1282 offset += cfg->param_area;
1284 /* allow room to save the return value (if it's a struct) */
1285 if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1288 if (sig->call_convention == MONO_CALL_VARARG) {
1289 cfg->sig_cookie = MIPS_STACK_PARAM_OFFSET;
1292 /* Now handle the local variables */
1294 curinst = cfg->locals_start;
1295 for (i = curinst; i < cfg->num_varinfo; ++i) {
1296 inst = cfg->varinfo [i];
1297 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1300 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1301 * pinvoke wrappers when they call functions returning structure
1303 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
1304 size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), (unsigned int *) &align);
1306 size = mono_type_size (inst->inst_vtype, &align);
1308 offset += align - 1;
1309 offset &= ~(align - 1);
1310 inst->inst_offset = offset;
1311 inst->opcode = OP_REGOFFSET;
1312 inst->inst_basereg = frame_reg;
1314 // g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1317 /* Space for LMF (if needed) */
1319 if (cfg->method->save_lmf) {
1320 /* align the offset to 16 bytes */
1321 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1322 cfg->arch.lmf_offset = offset;
1323 offset += sizeof (MonoLMF);
1327 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1328 * args or return vals. Extra stack space avoids this in a lot of cases.
1330 offset += EXTRA_STACK_SPACE;
1331 offset += SIZEOF_REGISTER - 1;
1332 offset &= ~(SIZEOF_REGISTER - 1);
1334 /* Space for saved registers */
1335 cfg->arch.iregs_offset = offset;
1337 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
1339 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
1341 if (iregs_to_save) {
1342 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
1343 if (iregs_to_save & (1 << i)) {
1344 offset += SIZEOF_REGISTER;
1349 /* XXX - Saved S-regs seem to be getting clobbered by some calls with struct
1350 * args or return vals. Extra stack space avoids this in a lot of cases.
1352 offset += EXTRA_STACK_SPACE;
1354 /* saved float registers */
1356 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
1357 if (fregs_to_restore) {
1358 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
1359 if (fregs_to_restore & (1 << i)) {
1360 offset += sizeof(double);
1366 #if _MIPS_SIM == _ABIO32
1367 /* Now add space for saving the ra */
1368 offset += SIZEOF_VOID_P;
1371 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1372 cfg->stack_offset = offset;
1373 cfg->arch.local_alloc_offset = cfg->stack_offset;
1377 * Now allocate stack slots for the int arg regs (a0 - a3)
1378 * On MIPS o32, these are just above the incoming stack pointer
1379 * Even if the arg has been assigned to a regvar, it gets a stack slot
1382 /* Return struct-by-value results in a hidden first argument */
1383 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1384 cfg->vret_addr->opcode = OP_REGOFFSET;
1385 cfg->vret_addr->inst_c0 = mips_a0;
1386 cfg->vret_addr->inst_offset = offset;
1387 cfg->vret_addr->inst_basereg = frame_reg;
1388 offset += SIZEOF_REGISTER;
1391 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1392 inst = cfg->args [i];
1393 if (inst->opcode != OP_REGVAR) {
1396 if (sig->hasthis && (i == 0))
1397 arg_type = &mono_defaults.object_class->byval_arg;
1399 arg_type = sig->params [i - sig->hasthis];
1401 inst->opcode = OP_REGOFFSET;
1402 size = mono_type_size (arg_type, &align);
1404 if (size < SIZEOF_REGISTER) {
1405 size = SIZEOF_REGISTER;
1406 align = SIZEOF_REGISTER;
1408 inst->inst_basereg = frame_reg;
1409 offset = (offset + align - 1) & ~(align - 1);
1410 inst->inst_offset = offset;
1412 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1413 cfg->sig_cookie += size;
1414 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1417 #if _MIPS_SIM == _ABIO32
1418 /* o32: Even a0-a3 get stack slots */
1419 size = SIZEOF_REGISTER;
1420 align = SIZEOF_REGISTER;
1421 inst->inst_basereg = frame_reg;
1422 offset = (offset + align - 1) & ~(align - 1);
1423 inst->inst_offset = offset;
1425 if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos))
1426 cfg->sig_cookie += size;
1427 // g_print ("allocating param %d to %d\n", i, inst->inst_offset);
1431 #if _MIPS_SIM == _ABIN32
1432 /* Now add space for saving the ra */
1433 offset += SIZEOF_VOID_P;
1436 offset = (offset + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1437 cfg->stack_offset = offset;
1438 cfg->arch.local_alloc_offset = cfg->stack_offset;
1443 mono_arch_create_vars (MonoCompile *cfg)
1445 MonoMethodSignature *sig;
1447 sig = mono_method_signature (cfg->method);
1449 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1450 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1451 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1452 printf ("vret_addr = ");
1453 mono_print_ins (cfg->vret_addr);
1458 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
1459 * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info
1463 * take the arguments and generate the arch-specific
1464 * instructions to properly call the function in call.
1465 * This includes pushing, moving arguments to the right register
1467 * Issue: who does the spilling if needed, and when?
1470 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1472 int sig_reg = mono_alloc_ireg (cfg);
1474 MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
1475 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
1476 mips_sp, cinfo->sig_cookie.offset, sig_reg);
1480 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1483 MonoMethodSignature *sig;
1488 sig = call->signature;
1489 n = sig->param_count + sig->hasthis;
1491 cinfo = calculate_sizes (sig, sig->pinvoke);
1492 if (cinfo->struct_ret)
1493 call->used_iregs |= 1 << cinfo->struct_ret;
1495 for (i = 0; i < n; ++i) {
1496 ArgInfo *ainfo = cinfo->args + i;
1499 if (i >= sig->hasthis)
1500 t = sig->params [i - sig->hasthis];
1502 t = &mono_defaults.int_class->byval_arg;
1503 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1505 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos))
1506 emit_sig_cookie (cfg, call, cinfo);
1507 if (is_virtual && i == 0) {
1508 /* the argument will be attached to the call instrucion */
1509 in = call->args [i];
1510 call->used_iregs |= 1 << ainfo->reg;
1513 in = call->args [i];
1514 if (ainfo->regtype == RegTypeGeneral) {
1515 #if SIZEOF_REGISTER == 4
1516 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1517 MONO_INST_NEW (cfg, ins, OP_MOVE);
1518 ins->dreg = mono_alloc_ireg (cfg);
1519 ins->sreg1 = in->dreg + 1;
1520 MONO_ADD_INS (cfg->cbb, ins);
1521 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1523 MONO_INST_NEW (cfg, ins, OP_MOVE);
1524 ins->dreg = mono_alloc_ireg (cfg);
1525 ins->sreg1 = in->dreg + 2;
1526 MONO_ADD_INS (cfg->cbb, ins);
1527 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1530 if (!t->byref && (t->type == MONO_TYPE_R4)) {
1533 #if PROMOTE_R4_TO_R8
1534 /* ??? - convert to single first? */
1535 MONO_INST_NEW (cfg, ins, OP_MIPS_CVTSD);
1536 ins->dreg = mono_alloc_freg (cfg);
1537 ins->sreg1 = in->dreg;
1538 MONO_ADD_INS (cfg->cbb, ins);
1543 /* trying to load float value into int registers */
1544 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1S);
1545 ins->dreg = mono_alloc_ireg (cfg);
1547 MONO_ADD_INS (cfg->cbb, ins);
1548 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1549 } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1550 /* trying to load float value into int registers */
1551 MONO_INST_NEW (cfg, ins, OP_MIPS_MFC1D);
1552 ins->dreg = mono_alloc_ireg (cfg);
1553 ins->sreg1 = in->dreg;
1554 MONO_ADD_INS (cfg->cbb, ins);
1555 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1557 MONO_INST_NEW (cfg, ins, OP_MOVE);
1558 ins->dreg = mono_alloc_ireg (cfg);
1559 ins->sreg1 = in->dreg;
1560 MONO_ADD_INS (cfg->cbb, ins);
1561 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1563 } else if (ainfo->regtype == RegTypeStructByAddr) {
1564 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1565 ins->opcode = OP_OUTARG_VT;
1566 ins->sreg1 = in->dreg;
1567 ins->klass = in->klass;
1568 ins->inst_p0 = call;
1569 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1570 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1571 MONO_ADD_INS (cfg->cbb, ins);
1572 } else if (ainfo->regtype == RegTypeStructByVal) {
1573 /* this is further handled in mono_arch_emit_outarg_vt () */
1574 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1575 ins->opcode = OP_OUTARG_VT;
1576 ins->sreg1 = in->dreg;
1577 ins->klass = in->klass;
1578 ins->inst_p0 = call;
1579 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1580 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1581 MONO_ADD_INS (cfg->cbb, ins);
1582 } else if (ainfo->regtype == RegTypeBase) {
1583 if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1584 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1585 } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1586 if (t->type == MONO_TYPE_R8)
1587 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1589 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1591 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_sp, ainfo->offset, in->dreg);
1593 } else if (ainfo->regtype == RegTypeFP) {
1594 if (t->type == MONO_TYPE_VALUETYPE) {
1595 /* this is further handled in mono_arch_emit_outarg_vt () */
1596 MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1597 ins->opcode = OP_OUTARG_VT;
1598 ins->sreg1 = in->dreg;
1599 ins->klass = in->klass;
1600 ins->inst_p0 = call;
1601 ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1602 memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1603 MONO_ADD_INS (cfg->cbb, ins);
1605 cfg->flags |= MONO_CFG_HAS_FPOUT;
1607 int dreg = mono_alloc_freg (cfg);
1609 if (ainfo->size == 4) {
1610 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, dreg, in->dreg);
1612 MONO_INST_NEW (cfg, ins, OP_FMOVE);
1614 ins->sreg1 = in->dreg;
1615 MONO_ADD_INS (cfg->cbb, ins);
1618 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1619 cfg->flags |= MONO_CFG_HAS_FPOUT;
1622 g_assert_not_reached ();
1626 /* Emit the signature cookie in the case that there is no
1627 additional argument */
1628 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1629 emit_sig_cookie (cfg, call, cinfo);
1631 if (cinfo->struct_ret) {
1634 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1635 vtarg->sreg1 = call->vret_var->dreg;
1636 vtarg->dreg = mono_alloc_preg (cfg);
1637 MONO_ADD_INS (cfg->cbb, vtarg);
1639 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE);
1643 * Reverse the call->out_args list.
1646 MonoInst *prev = NULL, *list = call->out_args, *next;
1653 call->out_args = prev;
1656 call->stack_usage = cinfo->stack_usage;
1657 cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1658 #if _MIPS_SIM == _ABIO32
1659 /* a0-a3 always present */
1660 cfg->param_area = MAX (cfg->param_area, 4 * SIZEOF_REGISTER);
1662 cfg->param_area = (cfg->param_area + MIPS_STACK_ALIGNMENT - 1) & ~(MIPS_STACK_ALIGNMENT - 1);
1663 cfg->flags |= MONO_CFG_HAS_CALLS;
1665 * should set more info in call, such as the stack space
1666 * used by the args that needs to be added back to esp
1673 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1675 MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1676 ArgInfo *ainfo = ins->inst_p1;
1677 int ovf_size = ainfo->vtsize;
1678 int doffset = ainfo->offset;
1679 int i, soffset, dreg;
1681 if (ainfo->regtype == RegTypeStructByVal) {
1683 if (cfg->verbose_level > 0) {
1684 char* nm = mono_method_full_name (cfg->method, TRUE);
1685 g_print ("Method %s outarg_vt struct doffset=%d ainfo->size=%d ovf_size=%d\n",
1686 nm, doffset, ainfo->size, ovf_size);
1692 for (i = 0; i < ainfo->size; ++i) {
1693 dreg = mono_alloc_ireg (cfg);
1694 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1695 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1696 soffset += SIZEOF_REGISTER;
1698 if (ovf_size != 0) {
1699 mini_emit_memcpy (cfg, mips_fp, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1701 } else if (ainfo->regtype == RegTypeFP) {
1702 int tmpr = mono_alloc_freg (cfg);
1704 if (ainfo->size == 4)
1705 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR4_MEMBASE, tmpr, src->dreg, 0);
1707 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmpr, src->dreg, 0);
1708 dreg = mono_alloc_freg (cfg);
1709 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, dreg, tmpr);
1710 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
1712 MonoInst *vtcopy = mono_compile_create_var (cfg, &src->klass->byval_arg, OP_LOCAL);
1716 /* FIXME: alignment? */
1717 if (call->signature->pinvoke) {
1718 size = mono_type_native_stack_size (&src->klass->byval_arg, NULL);
1719 vtcopy->backend.is_pinvoke = 1;
1721 size = mini_type_stack_size (cfg->generic_sharing_context, &src->klass->byval_arg, NULL);
1724 g_assert (ovf_size > 0);
1726 EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype);
1727 mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, size, 0);
1730 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, mips_at, ainfo->offset, load->dreg);
1732 mono_call_inst_add_outarg_reg (cfg, call, load->dreg, ainfo->reg, FALSE);
1737 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1739 MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context,
1740 mono_method_signature (method)->ret);
1743 #if (SIZEOF_REGISTER == 4)
1744 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1747 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1748 ins->sreg1 = val->dreg + 1;
1749 ins->sreg2 = val->dreg + 2;
1750 MONO_ADD_INS (cfg->cbb, ins);
1754 if (ret->type == MONO_TYPE_R8) {
1755 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1758 if (ret->type == MONO_TYPE_R4) {
1759 MONO_EMIT_NEW_UNALU (cfg, OP_MIPS_CVTSD, cfg->ret->dreg, val->dreg);
1763 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1767 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1769 MonoInst *ins, *n, *last_ins = NULL;
1771 if (cfg->verbose_level > 2)
1772 g_print ("Basic block %d peephole pass 1\n", bb->block_num);
1775 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1776 if (cfg->verbose_level > 2)
1777 mono_print_ins_index (0, ins);
1779 switch (ins->opcode) {
1781 case OP_LOAD_MEMBASE:
1782 case OP_LOADI4_MEMBASE:
1784 * OP_IADD reg2, reg1, const1
1785 * OP_LOAD_MEMBASE const2(reg2), reg3
1787 * OP_LOAD_MEMBASE (const1+const2)(reg1), reg3
1789 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)){
1790 int const1 = last_ins->inst_imm;
1791 int const2 = ins->inst_offset;
1793 if (mips_is_imm16 (const1 + const2)) {
1794 ins->inst_basereg = last_ins->sreg1;
1795 ins->inst_offset = const1 + const2;
1805 bb->last_ins = last_ins;
1809 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1811 MonoInst *ins, *n, *last_ins = NULL;
1814 MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1815 MonoInst *last_ins = ins->prev;
1817 switch (ins->opcode) {
1819 /* remove unnecessary multiplication with 1 */
1820 if (ins->inst_imm == 1) {
1821 if (ins->dreg != ins->sreg1) {
1822 ins->opcode = OP_MOVE;
1824 MONO_DELETE_INS (bb, ins);
1828 int power2 = mono_is_power_of_two (ins->inst_imm);
1830 ins->opcode = OP_SHL_IMM;
1831 ins->inst_imm = power2;
1835 case OP_LOAD_MEMBASE:
1836 case OP_LOADI4_MEMBASE:
1838 * OP_STORE_MEMBASE_REG reg, offset(basereg)
1839 * OP_LOAD_MEMBASE offset(basereg), reg
1841 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG
1842 || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1843 ins->inst_basereg == last_ins->inst_destbasereg &&
1844 ins->inst_offset == last_ins->inst_offset) {
1845 if (ins->dreg == last_ins->sreg1) {
1846 MONO_DELETE_INS (bb, ins);
1849 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1850 ins->opcode = OP_MOVE;
1851 ins->sreg1 = last_ins->sreg1;
1856 * Note: reg1 must be different from the basereg in the second load
1857 * OP_LOAD_MEMBASE offset(basereg), reg1
1858 * OP_LOAD_MEMBASE offset(basereg), reg2
1860 * OP_LOAD_MEMBASE offset(basereg), reg1
1861 * OP_MOVE reg1, reg2
1863 if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1864 || last_ins->opcode == OP_LOAD_MEMBASE) &&
1865 ins->inst_basereg != last_ins->dreg &&
1866 ins->inst_basereg == last_ins->inst_basereg &&
1867 ins->inst_offset == last_ins->inst_offset) {
1869 if (ins->dreg == last_ins->dreg) {
1870 MONO_DELETE_INS (bb, ins);
1873 ins->opcode = OP_MOVE;
1874 ins->sreg1 = last_ins->dreg;
1877 //g_assert_not_reached ();
1882 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1883 * OP_LOAD_MEMBASE offset(basereg), reg
1885 * OP_STORE_MEMBASE_IMM imm, offset(basereg)
1886 * OP_ICONST reg, imm
1888 if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1889 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1890 ins->inst_basereg == last_ins->inst_destbasereg &&
1891 ins->inst_offset == last_ins->inst_offset) {
1892 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1893 ins->opcode = OP_ICONST;
1894 ins->inst_c0 = last_ins->inst_imm;
1895 g_assert_not_reached (); // check this rule
1900 case OP_LOADU1_MEMBASE:
1901 case OP_LOADI1_MEMBASE:
1902 if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1903 ins->inst_basereg == last_ins->inst_destbasereg &&
1904 ins->inst_offset == last_ins->inst_offset) {
1905 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1906 ins->sreg1 = last_ins->sreg1;
1909 case OP_LOADU2_MEMBASE:
1910 case OP_LOADI2_MEMBASE:
1911 if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1912 ins->inst_basereg == last_ins->inst_destbasereg &&
1913 ins->inst_offset == last_ins->inst_offset) {
1914 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1915 ins->sreg1 = last_ins->sreg1;
1918 case OP_ICONV_TO_I4:
1919 case OP_ICONV_TO_U4:
1921 ins->opcode = OP_MOVE;
1925 if (ins->dreg == ins->sreg1) {
1926 MONO_DELETE_INS (bb, ins);
1930 * OP_MOVE sreg, dreg
1931 * OP_MOVE dreg, sreg
1933 if (last_ins && last_ins->opcode == OP_MOVE &&
1934 ins->sreg1 == last_ins->dreg &&
1935 ins->dreg == last_ins->sreg1) {
1936 MONO_DELETE_INS (bb, ins);
1944 bb->last_ins = last_ins;
1948 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
1956 switch (ins->opcode) {
1959 case OP_LCOMPARE_IMM:
1960 mono_print_ins (ins);
1961 g_assert_not_reached ();
1964 tmp1 = mono_alloc_ireg (cfg);
1965 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1966 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1967 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1968 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1973 tmp1 = mono_alloc_ireg (cfg);
1974 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1975 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
1976 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IADD_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1977 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->dreg+2, tmp1);
1982 tmp1 = mono_alloc_ireg (cfg);
1983 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
1984 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1985 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
1986 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
1991 tmp1 = mono_alloc_ireg (cfg);
1992 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+1, ins->sreg1+1, ins->inst_ls_word);
1993 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
1994 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, ins->dreg+2, ins->sreg1+2, ins->inst_ms_word);
1995 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2007 mono_print_ins (ins);
2008 g_assert_not_reached ();
2011 tmp1 = mono_alloc_ireg (cfg);
2012 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, mips_zero, ins->sreg1+1);
2013 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, mips_zero, ins->dreg+1);
2014 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, mips_zero, ins->sreg1+2);
2015 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2023 case OP_LCONV_TO_I1:
2024 case OP_LCONV_TO_I2:
2025 case OP_LCONV_TO_I4:
2026 case OP_LCONV_TO_I8:
2027 case OP_LCONV_TO_R4:
2028 case OP_LCONV_TO_R8:
2029 case OP_LCONV_TO_U4:
2030 case OP_LCONV_TO_U8:
2031 case OP_LCONV_TO_U2:
2032 case OP_LCONV_TO_U1:
2034 case OP_LCONV_TO_OVF_I:
2035 case OP_LCONV_TO_OVF_U:
2037 mono_print_ins (ins);
2038 g_assert_not_reached ();
2041 tmp1 = mono_alloc_ireg (cfg);
2042 tmp2 = mono_alloc_ireg (cfg);
2043 tmp3 = mono_alloc_ireg (cfg);
2044 tmp4 = mono_alloc_ireg (cfg);
2045 tmp5 = mono_alloc_ireg (cfg);
2047 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2049 /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
2050 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->dreg+1, ins->sreg1+1);
2052 /* add the high 32-bits, and add in the carry from the low 32-bits */
2053 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2054 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp5, ins->dreg+2);
2056 /* Overflow happens if
2057 * neg + neg = pos or
2059 * XOR of the high bits returns 0 if the signs match
2060 * XOR of that with the high bit of the result return 1 if overflow.
2063 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2064 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2066 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2067 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg+2, ins->sreg2+2);
2068 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp2, tmp2);
2070 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2071 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp3, tmp2, tmp1);
2072 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2074 /* Now, if (tmp4 == 0) then overflow */
2075 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp4, mips_zero, "OverflowException");
2079 case OP_LADD_OVF_UN:
2080 tmp1 = mono_alloc_ireg (cfg);
2081 tmp2 = mono_alloc_ireg (cfg);
2083 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2084 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg+1, ins->sreg1+1);
2085 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2086 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg+2, tmp1, ins->dreg+2);
2087 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->dreg+2, ins->sreg1+2);
2088 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2093 case OP_LMUL_OVF_UN:
2094 mono_print_ins (ins);
2095 g_assert_not_reached ();
2098 tmp1 = mono_alloc_ireg (cfg);
2099 tmp2 = mono_alloc_ireg (cfg);
2100 tmp3 = mono_alloc_ireg (cfg);
2101 tmp4 = mono_alloc_ireg (cfg);
2102 tmp5 = mono_alloc_ireg (cfg);
2104 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2106 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp5, ins->sreg1+1, ins->dreg+1);
2107 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2108 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp5);
2110 /* Overflow happens if
2111 * neg - pos = pos or
2113 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2115 * tmp1 = (lhs ^ rhs)
2116 * tmp2 = (lhs ^ result)
2117 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2120 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1+2, ins->sreg2+2);
2121 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1+2, ins->dreg+2);
2122 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp3, tmp2, tmp1);
2123 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp4, tmp3, 31);
2125 /* Now, if (tmp4 == 1) then overflow */
2126 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp4, mips_zero, "OverflowException");
2130 case OP_LSUB_OVF_UN:
2131 tmp1 = mono_alloc_ireg (cfg);
2132 tmp2 = mono_alloc_ireg (cfg);
2134 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+1, ins->sreg1+1, ins->sreg2+1);
2135 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1+1, ins->dreg+1);
2136 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->sreg1+2, ins->sreg2+2);
2137 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg+2, ins->dreg+2, tmp1);
2139 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp2, ins->sreg1+2, ins->dreg+2);
2140 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp2, mips_zero, "OverflowException");
2144 case OP_LCONV_TO_OVF_I1_UN:
2145 case OP_LCONV_TO_OVF_I2_UN:
2146 case OP_LCONV_TO_OVF_I4_UN:
2147 case OP_LCONV_TO_OVF_I8_UN:
2148 case OP_LCONV_TO_OVF_U1_UN:
2149 case OP_LCONV_TO_OVF_U2_UN:
2150 case OP_LCONV_TO_OVF_U4_UN:
2151 case OP_LCONV_TO_OVF_U8_UN:
2152 case OP_LCONV_TO_OVF_I_UN:
2153 case OP_LCONV_TO_OVF_U_UN:
2154 case OP_LCONV_TO_OVF_I1:
2155 case OP_LCONV_TO_OVF_U1:
2156 case OP_LCONV_TO_OVF_I2:
2157 case OP_LCONV_TO_OVF_U2:
2158 case OP_LCONV_TO_OVF_I4:
2159 case OP_LCONV_TO_OVF_U4:
2160 case OP_LCONV_TO_OVF_I8:
2161 case OP_LCONV_TO_OVF_U8:
2169 case OP_LCONV_TO_R_UN:
2175 case OP_LSHR_UN_IMM:
2177 case OP_LDIV_UN_IMM:
2179 case OP_LREM_UN_IMM:
2190 mono_print_ins (ins);
2191 g_assert_not_reached ();
2193 case OP_LCONV_TO_R8_2:
2194 case OP_LCONV_TO_R4_2:
2195 case OP_LCONV_TO_R_UN_2:
2197 case OP_LCONV_TO_OVF_I4_2:
2198 tmp1 = mono_alloc_ireg (cfg);
2200 /* Overflows if reg2 != sign extension of reg1 */
2201 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp1, ins->sreg1, 31);
2202 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, ins->sreg2, tmp1, "OverflowException");
2203 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
2211 mono_print_ins (ins);
2212 g_assert_not_reached ();
2220 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
2228 switch (ins->opcode) {
2230 tmp1 = mono_alloc_ireg (cfg);
2231 tmp2 = mono_alloc_ireg (cfg);
2232 tmp3 = mono_alloc_ireg (cfg);
2233 tmp4 = mono_alloc_ireg (cfg);
2234 tmp5 = mono_alloc_ireg (cfg);
2236 /* add the operands */
2238 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2240 /* Overflow happens if
2241 * neg + neg = pos or
2244 * (bit31s of operands match) AND (bit31 of operand != bit31 of result)
2245 * XOR of the high bit returns 0 if the signs match
2246 * XOR of that with the high bit of the result return 1 if overflow.
2249 /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
2250 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2252 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2253 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->dreg, ins->sreg2);
2254 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tmp3, tmp2);
2256 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2257 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tmp4, tmp3, tmp1);
2259 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tmp5, tmp4, 31);
2261 /* Now, if (tmp5 == 0) then overflow */
2262 MONO_EMIT_NEW_COMPARE_EXC (cfg, EQ, tmp5, mips_zero, "OverflowException");
2263 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2264 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2268 case OP_IADD_OVF_UN:
2269 tmp1 = mono_alloc_ireg (cfg);
2271 MONO_EMIT_NEW_BIALU (cfg, OP_IADD, ins->dreg, ins->sreg1, ins->sreg2);
2272 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->dreg, ins->sreg1);
2273 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2274 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2275 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2280 tmp1 = mono_alloc_ireg (cfg);
2281 tmp2 = mono_alloc_ireg (cfg);
2282 tmp3 = mono_alloc_ireg (cfg);
2283 tmp4 = mono_alloc_ireg (cfg);
2284 tmp5 = mono_alloc_ireg (cfg);
2286 /* add the operands */
2288 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2290 /* Overflow happens if
2291 * neg - pos = pos or
2293 * XOR of bit31 of the lhs & rhs = 1 if the signs are different
2295 * tmp1 = (lhs ^ rhs)
2296 * tmp2 = (lhs ^ result)
2297 * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
2300 /* tmp3 = 1 if the signs of the two inputs differ */
2301 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp1, ins->sreg1, ins->sreg2);
2302 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tmp2, ins->sreg1, ins->dreg);
2303 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp3, tmp1, 0);
2304 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MIPS_SLTI, tmp4, tmp2, 0);
2305 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tmp5, tmp4, tmp3);
2307 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp5, mips_zero, "OverflowException");
2308 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2309 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2313 case OP_ISUB_OVF_UN:
2314 tmp1 = mono_alloc_ireg (cfg);
2316 MONO_EMIT_NEW_BIALU (cfg, OP_ISUB, ins->dreg, ins->sreg1, ins->sreg2);
2317 MONO_EMIT_NEW_BIALU (cfg, OP_MIPS_SLTU, tmp1, ins->sreg1, ins->dreg);
2318 MONO_EMIT_NEW_COMPARE_EXC (cfg, NE_UN, tmp1, mips_zero, "OverflowException");
2319 /* Make decompse and method-to-ir.c happy, last insn writes dreg */
2320 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->dreg);
2327 map_to_reg_reg_op (int op)
2336 case OP_COMPARE_IMM:
2338 case OP_ICOMPARE_IMM:
2340 case OP_LCOMPARE_IMM:
2356 case OP_LOAD_MEMBASE:
2357 return OP_LOAD_MEMINDEX;
2358 case OP_LOADI4_MEMBASE:
2359 return OP_LOADI4_MEMINDEX;
2360 case OP_LOADU4_MEMBASE:
2361 return OP_LOADU4_MEMINDEX;
2362 case OP_LOADU1_MEMBASE:
2363 return OP_LOADU1_MEMINDEX;
2364 case OP_LOADI2_MEMBASE:
2365 return OP_LOADI2_MEMINDEX;
2366 case OP_LOADU2_MEMBASE:
2367 return OP_LOADU2_MEMINDEX;
2368 case OP_LOADI1_MEMBASE:
2369 return OP_LOADI1_MEMINDEX;
2370 case OP_LOADR4_MEMBASE:
2371 return OP_LOADR4_MEMINDEX;
2372 case OP_LOADR8_MEMBASE:
2373 return OP_LOADR8_MEMINDEX;
2374 case OP_STOREI1_MEMBASE_REG:
2375 return OP_STOREI1_MEMINDEX;
2376 case OP_STOREI2_MEMBASE_REG:
2377 return OP_STOREI2_MEMINDEX;
2378 case OP_STOREI4_MEMBASE_REG:
2379 return OP_STOREI4_MEMINDEX;
2380 case OP_STORE_MEMBASE_REG:
2381 return OP_STORE_MEMINDEX;
2382 case OP_STORER4_MEMBASE_REG:
2383 return OP_STORER4_MEMINDEX;
2384 case OP_STORER8_MEMBASE_REG:
2385 return OP_STORER8_MEMINDEX;
2386 case OP_STORE_MEMBASE_IMM:
2387 return OP_STORE_MEMBASE_REG;
2388 case OP_STOREI1_MEMBASE_IMM:
2389 return OP_STOREI1_MEMBASE_REG;
2390 case OP_STOREI2_MEMBASE_IMM:
2391 return OP_STOREI2_MEMBASE_REG;
2392 case OP_STOREI4_MEMBASE_IMM:
2393 return OP_STOREI4_MEMBASE_REG;
2394 case OP_STOREI8_MEMBASE_IMM:
2395 return OP_STOREI8_MEMBASE_REG;
2397 return mono_op_imm_to_op (op);
2401 map_to_mips_op (int op)
2405 return OP_MIPS_FBEQ;
2407 return OP_MIPS_FBGE;
2409 return OP_MIPS_FBGT;
2411 return OP_MIPS_FBLE;
2413 return OP_MIPS_FBLT;
2415 return OP_MIPS_FBNE;
2417 return OP_MIPS_FBGE_UN;
2419 return OP_MIPS_FBGT_UN;
2421 return OP_MIPS_FBLE_UN;
2423 return OP_MIPS_FBLT_UN;
2431 g_warning ("unknown opcode %s in %s()\n", mono_inst_name (op), __FUNCTION__);
2432 g_assert_not_reached ();
2436 #define NEW_INS(cfg,after,dest,op) do { \
2437 MONO_INST_NEW((cfg), (dest), (op)); \
2438 mono_bblock_insert_after_ins (bb, (after), (dest)); \
2441 #define INS(pos,op,_dreg,_sreg1,_sreg2) do { \
2443 MONO_INST_NEW(cfg, temp, (op)); \
2444 mono_bblock_insert_after_ins (bb, (pos), temp); \
2445 temp->dreg = (_dreg); \
2446 temp->sreg1 = (_sreg1); \
2447 temp->sreg2 = (_sreg2); \
2451 #define INS_IMM(pos,op,_dreg,_sreg1,_imm) do { \
2453 MONO_INST_NEW(cfg, temp, (op)); \
2454 mono_bblock_insert_after_ins (bb, (pos), temp); \
2455 temp->dreg = (_dreg); \
2456 temp->sreg1 = (_sreg1); \
2457 temp->inst_c0 = (_imm); \
2462 * Remove from the instruction list the instructions that can't be
2463 * represented with very simple instructions with no register
2467 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2469 MonoInst *ins, *next, *temp, *last_ins = NULL;
2473 if (cfg->verbose_level > 2) {
2476 g_print ("BASIC BLOCK %d (before lowering)\n", bb->block_num);
2477 MONO_BB_FOR_EACH_INS (bb, ins) {
2478 mono_print_ins_index (idx++, ins);
2484 MONO_BB_FOR_EACH_INS (bb, ins) {
2486 switch (ins->opcode) {
2491 /* Branch opts can eliminate the branch */
2492 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2498 case OP_COMPARE_IMM:
2499 case OP_ICOMPARE_IMM:
2500 case OP_LCOMPARE_IMM:
2502 /* Branch opts can eliminate the branch */
2503 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2507 if (ins->inst_imm) {
2508 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2509 temp->inst_c0 = ins->inst_imm;
2510 temp->dreg = mono_alloc_ireg (cfg);
2511 ins->sreg2 = temp->dreg;
2515 ins->sreg2 = mips_zero;
2517 if (ins->opcode == OP_COMPARE_IMM)
2518 ins->opcode = OP_COMPARE;
2519 else if (ins->opcode == OP_ICOMPARE_IMM)
2520 ins->opcode = OP_ICOMPARE;
2521 else if (ins->opcode == OP_LCOMPARE_IMM)
2522 ins->opcode = OP_LCOMPARE;
2525 case OP_IDIV_UN_IMM:
2528 case OP_IREM_UN_IMM:
2529 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2530 temp->inst_c0 = ins->inst_imm;
2531 temp->dreg = mono_alloc_ireg (cfg);
2532 ins->sreg2 = temp->dreg;
2533 if (ins->opcode == OP_IDIV_IMM)
2534 ins->opcode = OP_IDIV;
2535 else if (ins->opcode == OP_IREM_IMM)
2536 ins->opcode = OP_IREM;
2537 else if (ins->opcode == OP_IDIV_UN_IMM)
2538 ins->opcode = OP_IDIV_UN;
2539 else if (ins->opcode == OP_IREM_UN_IMM)
2540 ins->opcode = OP_IREM_UN;
2542 /* handle rem separately */
2549 if ((ins->inst_imm & 0xffff0000) && (ins->inst_imm & 0xffff)) {
2550 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2551 temp->inst_c0 = ins->inst_imm;
2552 temp->dreg = mono_alloc_ireg (cfg);
2553 ins->sreg2 = temp->dreg;
2554 ins->opcode = map_to_reg_reg_op (ins->opcode);
2564 /* unsigned 16 bit immediate */
2565 if (ins->inst_imm & 0xffff0000) {
2566 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2567 temp->inst_c0 = ins->inst_imm;
2568 temp->dreg = mono_alloc_ireg (cfg);
2569 ins->sreg2 = temp->dreg;
2570 ins->opcode = map_to_reg_reg_op (ins->opcode);
2577 /* signed 16 bit immediate */
2578 if (!mips_is_imm16 (ins->inst_imm)) {
2579 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2580 temp->inst_c0 = ins->inst_imm;
2581 temp->dreg = mono_alloc_ireg (cfg);
2582 ins->sreg2 = temp->dreg;
2583 ins->opcode = map_to_reg_reg_op (ins->opcode);
2589 if (!mips_is_imm16 (-ins->inst_imm)) {
2590 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2591 temp->inst_c0 = ins->inst_imm;
2592 temp->dreg = mono_alloc_ireg (cfg);
2593 ins->sreg2 = temp->dreg;
2594 ins->opcode = map_to_reg_reg_op (ins->opcode);
2600 if (ins->inst_imm == 1) {
2601 ins->opcode = OP_MOVE;
2604 if (ins->inst_imm == 0) {
2605 ins->opcode = OP_ICONST;
2609 imm = mono_is_power_of_two (ins->inst_imm);
2611 ins->opcode = OP_SHL_IMM;
2612 ins->inst_imm = imm;
2615 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2616 temp->inst_c0 = ins->inst_imm;
2617 temp->dreg = mono_alloc_ireg (cfg);
2618 ins->sreg2 = temp->dreg;
2619 ins->opcode = map_to_reg_reg_op (ins->opcode);
2622 case OP_LOCALLOC_IMM:
2623 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2624 temp->inst_c0 = ins->inst_imm;
2625 temp->dreg = mono_alloc_ireg (cfg);
2626 ins->sreg1 = temp->dreg;
2627 ins->opcode = OP_LOCALLOC;
2630 case OP_LOADR4_MEMBASE:
2631 case OP_STORER4_MEMBASE_REG:
2632 /* we can do two things: load the immed in a register
2633 * and use an indexed load, or see if the immed can be
2634 * represented as an ad_imm + a load with a smaller offset
2635 * that fits. We just do the first for now, optimize later.
2637 if (mips_is_imm16 (ins->inst_offset))
2639 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2640 temp->inst_c0 = ins->inst_offset;
2641 temp->dreg = mono_alloc_ireg (cfg);
2642 ins->sreg2 = temp->dreg;
2643 ins->opcode = map_to_reg_reg_op (ins->opcode);
2646 case OP_STORE_MEMBASE_IMM:
2647 case OP_STOREI1_MEMBASE_IMM:
2648 case OP_STOREI2_MEMBASE_IMM:
2649 case OP_STOREI4_MEMBASE_IMM:
2650 case OP_STOREI8_MEMBASE_IMM:
2651 if (!ins->inst_imm) {
2652 ins->sreg1 = mips_zero;
2653 ins->opcode = map_to_reg_reg_op (ins->opcode);
2656 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2657 temp->inst_c0 = ins->inst_imm;
2658 temp->dreg = mono_alloc_ireg (cfg);
2659 ins->sreg1 = temp->dreg;
2660 ins->opcode = map_to_reg_reg_op (ins->opcode);
2662 goto loop_start; /* make it handle the possibly big ins->inst_offset */
2668 /* Branch opts can eliminate the branch */
2669 if (!next || (!(MONO_IS_COND_BRANCH_OP (next) || MONO_IS_COND_EXC (next) || MONO_IS_SETCC (next)))) {
2676 * remap compare/branch and compare/set
2677 * to MIPS specific opcodes.
2679 next->opcode = map_to_mips_op (next->opcode);
2680 next->sreg1 = ins->sreg1;
2681 next->sreg2 = ins->sreg2;
2688 NEW_INS (cfg, last_ins, temp, OP_ICONST);
2689 temp->inst_c0 = (guint32)ins->inst_p0;
2690 temp->dreg = mono_alloc_ireg (cfg);
2691 ins->inst_basereg = temp->dreg;
2692 ins->inst_offset = 0;
2693 ins->opcode = ins->opcode == OP_R4CONST? OP_LOADR4_MEMBASE: OP_LOADR8_MEMBASE;
2695 /* make it handle the possibly big ins->inst_offset
2696 * later optimize to use lis + load_membase
2701 g_assert (ins_is_compare(last_ins));
2702 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->sreg1, last_ins->sreg2);
2703 NULLIFY_INS(last_ins);
2707 g_assert (ins_is_compare(last_ins));
2708 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->sreg1, last_ins->sreg2);
2709 NULLIFY_INS(last_ins);
2713 g_assert (ins_is_compare(last_ins));
2714 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2715 last_ins->dreg = mono_alloc_ireg (cfg);
2716 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2720 g_assert (ins_is_compare(last_ins));
2721 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2722 last_ins->dreg = mono_alloc_ireg (cfg);
2723 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2727 g_assert (ins_is_compare(last_ins));
2728 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2729 last_ins->dreg = mono_alloc_ireg (cfg);
2730 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2734 g_assert (ins_is_compare(last_ins));
2735 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2736 last_ins->dreg = mono_alloc_ireg (cfg);
2737 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2741 g_assert (ins_is_compare(last_ins));
2742 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2743 last_ins->dreg = mono_alloc_ireg (cfg);
2744 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2748 g_assert (ins_is_compare(last_ins));
2749 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2750 last_ins->dreg = mono_alloc_ireg (cfg);
2751 INS_REWRITE(ins, OP_MIPS_BEQ, last_ins->dreg, mips_zero);
2755 g_assert (ins_is_compare(last_ins));
2756 INS_REWRITE(last_ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2757 last_ins->dreg = mono_alloc_ireg (cfg);
2758 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2762 g_assert (ins_is_compare(last_ins));
2763 INS_REWRITE(last_ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2764 last_ins->dreg = mono_alloc_ireg (cfg);
2765 INS_REWRITE(ins, OP_MIPS_BNE, last_ins->dreg, mips_zero);
2770 g_assert (ins_is_compare(last_ins));
2771 last_ins->opcode = OP_IXOR;
2772 last_ins->dreg = mono_alloc_ireg(cfg);
2773 INS_REWRITE_IMM(ins, OP_MIPS_SLTIU, last_ins->dreg, 1);
2778 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg1, last_ins->sreg2);
2779 NULLIFY_INS(last_ins);
2785 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg1, last_ins->sreg2);
2786 NULLIFY_INS(last_ins);
2791 g_assert (ins_is_compare(last_ins));
2792 INS_REWRITE(ins, OP_MIPS_SLT, last_ins->sreg2, last_ins->sreg1);
2793 MONO_DELETE_INS(bb, last_ins);
2798 g_assert (ins_is_compare(last_ins));
2799 INS_REWRITE(ins, OP_MIPS_SLTU, last_ins->sreg2, last_ins->sreg1);
2800 MONO_DELETE_INS(bb, last_ins);
2803 case OP_COND_EXC_EQ:
2804 case OP_COND_EXC_IEQ:
2805 g_assert (ins_is_compare(last_ins));
2806 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, last_ins->sreg1, last_ins->sreg2);
2807 MONO_DELETE_INS(bb, last_ins);
2810 case OP_COND_EXC_GE:
2811 case OP_COND_EXC_IGE:
2812 g_assert (ins_is_compare(last_ins));
2813 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE, last_ins->sreg1, last_ins->sreg2);
2814 MONO_DELETE_INS(bb, last_ins);
2817 case OP_COND_EXC_GT:
2818 case OP_COND_EXC_IGT:
2819 g_assert (ins_is_compare(last_ins));
2820 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT, last_ins->sreg1, last_ins->sreg2);
2821 MONO_DELETE_INS(bb, last_ins);
2824 case OP_COND_EXC_LE:
2825 case OP_COND_EXC_ILE:
2826 g_assert (ins_is_compare(last_ins));
2827 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE, last_ins->sreg1, last_ins->sreg2);
2828 MONO_DELETE_INS(bb, last_ins);
2831 case OP_COND_EXC_LT:
2832 case OP_COND_EXC_ILT:
2833 g_assert (ins_is_compare(last_ins));
2834 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT, last_ins->sreg1, last_ins->sreg2);
2835 MONO_DELETE_INS(bb, last_ins);
2838 case OP_COND_EXC_NE_UN:
2839 case OP_COND_EXC_INE_UN:
2840 g_assert (ins_is_compare(last_ins));
2841 INS_REWRITE(ins, OP_MIPS_COND_EXC_NE_UN, last_ins->sreg1, last_ins->sreg2);
2842 MONO_DELETE_INS(bb, last_ins);
2845 case OP_COND_EXC_GE_UN:
2846 case OP_COND_EXC_IGE_UN:
2847 g_assert (ins_is_compare(last_ins));
2848 INS_REWRITE(ins, OP_MIPS_COND_EXC_GE_UN, last_ins->sreg1, last_ins->sreg2);
2849 MONO_DELETE_INS(bb, last_ins);
2852 case OP_COND_EXC_GT_UN:
2853 case OP_COND_EXC_IGT_UN:
2854 g_assert (ins_is_compare(last_ins));
2855 INS_REWRITE(ins, OP_MIPS_COND_EXC_GT_UN, last_ins->sreg1, last_ins->sreg2);
2856 MONO_DELETE_INS(bb, last_ins);
2859 case OP_COND_EXC_LE_UN:
2860 case OP_COND_EXC_ILE_UN:
2861 g_assert (ins_is_compare(last_ins));
2862 INS_REWRITE(ins, OP_MIPS_COND_EXC_LE_UN, last_ins->sreg1, last_ins->sreg2);
2863 MONO_DELETE_INS(bb, last_ins);
2866 case OP_COND_EXC_LT_UN:
2867 case OP_COND_EXC_ILT_UN:
2868 g_assert (ins_is_compare(last_ins));
2869 INS_REWRITE(ins, OP_MIPS_COND_EXC_LT_UN, last_ins->sreg1, last_ins->sreg2);
2870 MONO_DELETE_INS(bb, last_ins);
2873 case OP_COND_EXC_OV:
2874 case OP_COND_EXC_IOV: {
2875 int tmp1, tmp2, tmp3, tmp4, tmp5;
2876 MonoInst *pos = last_ins;
2878 /* Overflow happens if
2879 * neg + neg = pos or
2882 * (bit31s of operands match) AND (bit31 of operand
2883 * != bit31 of result)
2884 * XOR of the high bit returns 0 if the signs match
2885 * XOR of that with the high bit of the result return 1
2888 g_assert (last_ins->opcode == OP_IADC);
2890 tmp1 = mono_alloc_ireg (cfg);
2891 tmp2 = mono_alloc_ireg (cfg);
2892 tmp3 = mono_alloc_ireg (cfg);
2893 tmp4 = mono_alloc_ireg (cfg);
2894 tmp5 = mono_alloc_ireg (cfg);
2896 /* tmp1 = 0 if the signs of the two inputs match, else 1 */
2897 INS (pos, OP_IXOR, tmp1, last_ins->sreg1, last_ins->sreg2);
2899 /* set tmp2 = 0 if bit31 of results matches is different than the operands */
2900 INS (pos, OP_IXOR, tmp2, last_ins->dreg, last_ins->sreg2);
2901 INS (pos, OP_INOT, tmp3, tmp2, -1);
2903 /* OR(tmp1, tmp2) = 0 if both conditions are true */
2904 INS (pos, OP_IOR, tmp4, tmp3, tmp1);
2905 INS_IMM (pos, OP_SHR_IMM, tmp5, tmp4, 31);
2907 /* Now, if (tmp5 == 0) then overflow */
2908 INS_REWRITE(ins, OP_MIPS_COND_EXC_EQ, tmp5, mips_zero);
2913 case OP_COND_EXC_NO:
2914 case OP_COND_EXC_INO:
2915 g_assert_not_reached ();
2919 case OP_COND_EXC_IC:
2920 g_assert_not_reached ();
2923 case OP_COND_EXC_NC:
2924 case OP_COND_EXC_INC:
2925 g_assert_not_reached ();
2931 bb->last_ins = last_ins;
2932 bb->max_vreg = cfg->next_vreg;
2935 if (cfg->verbose_level > 2) {
2938 g_print ("BASIC BLOCK %d (after lowering)\n", bb->block_num);
2939 MONO_BB_FOR_EACH_INS (bb, ins) {
2940 mono_print_ins_index (idx++, ins);
2949 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2951 /* sreg is a float, dreg is an integer reg. mips_at is used as scratch */
2953 mips_truncwd (code, mips_ftemp, sreg);
2955 mips_cvtwd (code, mips_ftemp, sreg);
2957 mips_mfc1 (code, dreg, mips_ftemp);
2960 mips_andi (code, dreg, dreg, 0xff);
2961 else if (size == 2) {
2962 mips_sll (code, dreg, dreg, 16);
2963 mips_srl (code, dreg, dreg, 16);
2967 mips_sll (code, dreg, dreg, 24);
2968 mips_sra (code, dreg, dreg, 24);
2970 else if (size == 2) {
2971 mips_sll (code, dreg, dreg, 16);
2972 mips_sra (code, dreg, dreg, 16);
2979 * emit_load_volatile_arguments:
2981 * Load volatile arguments from the stack to the original input registers.
2982 * Required before a tail call.
2985 emit_load_volatile_arguments(MonoCompile *cfg, guint8 *code)
2987 MonoMethod *method = cfg->method;
2988 MonoMethodSignature *sig;
2993 sig = mono_method_signature (method);
2994 cinfo = calculate_sizes (sig, sig->pinvoke);
2995 if (cinfo->struct_ret) {
2996 ArgInfo *ainfo = &cinfo->ret;
2997 inst = cfg->vret_addr;
2998 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3001 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3002 ArgInfo *ainfo = cinfo->args + i;
3003 inst = cfg->args [i];
3004 if (inst->opcode == OP_REGVAR) {
3005 if (ainfo->regtype == RegTypeGeneral)
3006 MIPS_MOVE (code, ainfo->reg, inst->dreg);
3007 else if (ainfo->regtype == RegTypeFP)
3008 g_assert_not_reached();
3009 else if (ainfo->regtype == RegTypeBase) {
3012 g_assert_not_reached ();
3014 if (ainfo->regtype == RegTypeGeneral) {
3015 g_assert (mips_is_imm16 (inst->inst_offset));
3016 switch (ainfo->size) {
3018 mips_lb (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3021 mips_lh (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3025 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3028 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3029 mips_lw (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3032 g_assert_not_reached ();
3035 } else if (ainfo->regtype == RegTypeBase) {
3037 } else if (ainfo->regtype == RegTypeFP) {
3038 g_assert (mips_is_imm16 (inst->inst_offset));
3039 if (ainfo->size == 8) {
3040 #if _MIPS_SIM == _ABIO32
3041 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
3042 mips_lwc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
3043 #elif _MIPS_SIM == _ABIN32
3044 mips_ldc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3047 else if (ainfo->size == 4)
3048 mips_lwc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3050 g_assert_not_reached ();
3051 } else if (ainfo->regtype == RegTypeStructByVal) {
3053 int doffset = inst->inst_offset;
3055 g_assert (mips_is_imm16 (inst->inst_offset));
3056 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
3057 for (i = 0; i < ainfo->size; ++i) {
3058 mips_lw (code, ainfo->reg + i, inst->inst_basereg, doffset);
3059 doffset += SIZEOF_REGISTER;
3061 } else if (ainfo->regtype == RegTypeStructByAddr) {
3062 g_assert (mips_is_imm16 (inst->inst_offset));
3063 mips_lw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3065 g_assert_not_reached ();
3075 emit_reserve_param_area (MonoCompile *cfg, guint8 *code)
3077 int size = cfg->param_area;
3079 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3080 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3085 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3086 if (ppc_is_imm16 (-size)) {
3087 ppc_stwu (code, ppc_r0, -size, ppc_sp);
3089 ppc_load (code, ppc_r11, -size);
3090 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3097 emit_unreserve_param_area (MonoCompile *cfg, guint8 *code)
3099 int size = cfg->param_area;
3101 size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3102 size &= -MONO_ARCH_FRAME_ALIGNMENT;
3107 ppc_lwz (code, ppc_r0, 0, ppc_sp);
3108 if (ppc_is_imm16 (size)) {
3109 ppc_stwu (code, ppc_r0, size, ppc_sp);
3111 ppc_load (code, ppc_r11, size);
3112 ppc_stwux (code, ppc_r0, ppc_sp, ppc_r11);
3119 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3124 guint8 *code = cfg->native_code + cfg->code_len;
3125 MonoInst *last_ins = NULL;
3126 guint last_offset = 0;
3130 /* we don't align basic blocks of loops on mips */
3132 if (cfg->verbose_level > 2)
3133 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3135 cpos = bb->max_offset;
3138 if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3139 MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3140 g_assert (!mono_compile_aot);
3143 cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3144 /* this is not thread save, but good enough */
3145 /* fixme: howto handle overflows? */
3146 mips_load_const (code, mips_at, &cov->data [bb->dfn].count);
3147 mips_lw (code, mips_temp, mips_at, 0);
3148 mips_addiu (code, mips_temp, mips_temp, 1);
3149 mips_sw (code, mips_temp, mips_at, 0);
3152 MONO_BB_FOR_EACH_INS (bb, ins) {
3153 offset = code - cfg->native_code;
3155 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3157 if (offset > (cfg->code_size - max_len - 16)) {
3158 cfg->code_size *= 2;
3159 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3160 code = cfg->native_code + offset;
3162 mono_debug_record_line_number (cfg, ins, offset);
3163 if (cfg->verbose_level > 2) {
3164 g_print (" @ 0x%x\t", offset);
3165 mono_print_ins_index (ins_cnt++, ins);
3167 /* Check for virtual regs that snuck by */
3168 g_assert ((ins->dreg >= -1) && (ins->dreg < 32));
3170 switch (ins->opcode) {
3171 case OP_RELAXED_NOP:
3174 case OP_DUMMY_STORE:
3175 case OP_NOT_REACHED:
3179 g_assert_not_reached();
3181 emit_tls_access (code, ins->dreg, ins->inst_offset);
3185 mips_mult (code, ins->sreg1, ins->sreg2);
3186 mips_mflo (code, ins->dreg);
3187 mips_mfhi (code, ins->dreg+1);
3190 mips_multu (code, ins->sreg1, ins->sreg2);
3191 mips_mflo (code, ins->dreg);
3192 mips_mfhi (code, ins->dreg+1);
3194 case OP_MEMORY_BARRIER:
3199 case OP_STOREI1_MEMBASE_IMM:
3200 mips_load_const (code, mips_temp, ins->inst_imm);
3201 if (mips_is_imm16 (ins->inst_offset)) {
3202 mips_sb (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3204 mips_load_const (code, mips_at, ins->inst_offset);
3205 mips_sb (code, mips_temp, mips_at, ins->inst_destbasereg);
3208 case OP_STOREI2_MEMBASE_IMM:
3209 mips_load_const (code, mips_temp, ins->inst_imm);
3210 if (mips_is_imm16 (ins->inst_offset)) {
3211 mips_sh (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3213 mips_load_const (code, mips_at, ins->inst_offset);
3214 mips_sh (code, mips_temp, mips_at, ins->inst_destbasereg);
3217 case OP_STOREI8_MEMBASE_IMM:
3218 mips_load_const (code, mips_temp, ins->inst_imm);
3219 if (mips_is_imm16 (ins->inst_offset)) {
3220 mips_sd (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3222 mips_load_const (code, mips_at, ins->inst_offset);
3223 mips_sd (code, mips_temp, mips_at, ins->inst_destbasereg);
3226 case OP_STORE_MEMBASE_IMM:
3227 case OP_STOREI4_MEMBASE_IMM:
3228 mips_load_const (code, mips_temp, ins->inst_imm);
3229 if (mips_is_imm16 (ins->inst_offset)) {
3230 mips_sw (code, mips_temp, ins->inst_destbasereg, ins->inst_offset);
3232 mips_load_const (code, mips_at, ins->inst_offset);
3233 mips_sw (code, mips_temp, mips_at, ins->inst_destbasereg);
3236 case OP_STOREI1_MEMBASE_REG:
3237 if (mips_is_imm16 (ins->inst_offset)) {
3238 mips_sb (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3240 mips_load_const (code, mips_at, ins->inst_offset);
3241 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3242 mips_sb (code, ins->sreg1, mips_at, 0);
3245 case OP_STOREI2_MEMBASE_REG:
3246 if (mips_is_imm16 (ins->inst_offset)) {
3247 mips_sh (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3249 mips_load_const (code, mips_at, ins->inst_offset);
3250 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3251 mips_sh (code, ins->sreg1, mips_at, 0);
3254 case OP_STORE_MEMBASE_REG:
3255 case OP_STOREI4_MEMBASE_REG:
3256 if (mips_is_imm16 (ins->inst_offset)) {
3257 mips_sw (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3259 mips_load_const (code, mips_at, ins->inst_offset);
3260 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3261 mips_sw (code, ins->sreg1, mips_at, 0);
3264 case OP_STOREI8_MEMBASE_REG:
3265 if (mips_is_imm16 (ins->inst_offset)) {
3266 mips_sd (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3268 mips_load_const (code, mips_at, ins->inst_offset);
3269 mips_addu (code, mips_at, mips_at, ins->inst_destbasereg);
3270 mips_sd (code, ins->sreg1, mips_at, 0);
3274 g_assert_not_reached ();
3275 //x86_mov_reg_imm (code, ins->dreg, ins->inst_p0);
3276 //x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 4);
3278 case OP_LOADI8_MEMBASE:
3279 if (mips_is_imm16 (ins->inst_offset)) {
3280 mips_ld (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3282 mips_load_const (code, mips_at, ins->inst_offset);
3283 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3284 mips_ld (code, ins->dreg, mips_at, 0);
3287 case OP_LOAD_MEMBASE:
3288 case OP_LOADI4_MEMBASE:
3289 case OP_LOADU4_MEMBASE:
3290 g_assert (ins->dreg != -1);
3291 if (mips_is_imm16 (ins->inst_offset)) {
3292 mips_lw (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3294 mips_load_const (code, mips_at, ins->inst_offset);
3295 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3296 mips_lw (code, ins->dreg, mips_at, 0);
3299 case OP_LOADI1_MEMBASE:
3300 if (mips_is_imm16 (ins->inst_offset)) {
3301 mips_lb (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3303 mips_load_const (code, mips_at, ins->inst_offset);
3304 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3305 mips_lb (code, ins->dreg, mips_at, 0);
3308 case OP_LOADU1_MEMBASE:
3309 if (mips_is_imm16 (ins->inst_offset)) {
3310 mips_lbu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3312 mips_load_const (code, mips_at, ins->inst_offset);
3313 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3314 mips_lbu (code, ins->dreg, mips_at, 0);
3317 case OP_LOADI2_MEMBASE:
3318 if (mips_is_imm16 (ins->inst_offset)) {
3319 mips_lh (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3321 mips_load_const (code, mips_at, ins->inst_offset);
3322 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3323 mips_lh (code, ins->dreg, mips_at, 0);
3326 case OP_LOADU2_MEMBASE:
3327 if (mips_is_imm16 (ins->inst_offset)) {
3328 mips_lhu (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3330 mips_load_const (code, mips_at, ins->inst_offset);
3331 mips_addu (code, mips_at, mips_at, ins->inst_basereg);
3332 mips_lhu (code, ins->dreg, mips_at, 0);
3335 case OP_ICONV_TO_I1:
3336 mips_sll (code, mips_at, ins->sreg1, 24);
3337 mips_sra (code, ins->dreg, mips_at, 24);
3339 case OP_ICONV_TO_I2:
3340 mips_sll (code, mips_at, ins->sreg1, 16);
3341 mips_sra (code, ins->dreg, mips_at, 16);
3343 case OP_ICONV_TO_U1:
3344 mips_andi (code, ins->dreg, ins->sreg1, 0xff);
3346 case OP_ICONV_TO_U2:
3347 mips_sll (code, mips_at, ins->sreg1, 16);
3348 mips_srl (code, ins->dreg, mips_at, 16);
3351 mips_slt (code, ins->dreg, ins->sreg1, ins->sreg2);
3354 g_assert (mips_is_imm16 (ins->inst_imm));
3355 mips_slti (code, ins->dreg, ins->sreg1, ins->inst_imm);
3358 mips_sltu (code, ins->dreg, ins->sreg1, ins->sreg2);
3361 g_assert (mips_is_imm16 (ins->inst_imm));
3362 mips_sltiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3365 mips_break (code, 0xfd);
3368 mips_addu (code, ins->dreg, ins->sreg1, ins->sreg2);
3371 mips_daddu (code, ins->dreg, ins->sreg1, ins->sreg2);
3376 g_assert (mips_is_imm16 (ins->inst_imm));
3377 mips_addiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3380 g_assert (mips_is_imm16 (ins->inst_imm));
3381 mips_daddiu (code, ins->dreg, ins->sreg1, ins->inst_imm);
3385 mips_subu (code, ins->dreg, ins->sreg1, ins->sreg2);
3388 mips_dsubu (code, ins->dreg, ins->sreg1, ins->sreg2);
3393 // we add the negated value
3394 g_assert (mips_is_imm16 (-ins->inst_imm));
3395 mips_addiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3399 // we add the negated value
3400 g_assert (mips_is_imm16 (-ins->inst_imm));
3401 mips_daddiu (code, ins->dreg, ins->sreg1, -ins->inst_imm);
3406 mips_and (code, ins->dreg, ins->sreg1, ins->sreg2);
3412 g_assert (!(ins->inst_imm & 0xffff0000));
3413 mips_andi (code, ins->dreg, ins->sreg1, ins->inst_imm);
3418 guint32 *divisor_is_m1;
3419 guint32 *dividend_is_minvalue;
3420 guint32 *divisor_is_zero;
3422 mips_load_const (code, mips_at, -1);
3423 divisor_is_m1 = (guint32 *)(void *)code;
3424 mips_bne (code, ins->sreg2, mips_at, 0);
3425 mips_lui (code, mips_at, mips_zero, 0x8000);
3426 dividend_is_minvalue = (guint32 *)(void *)code;
3427 mips_bne (code, ins->sreg1, mips_at, 0);
3430 /* Divide Int32.MinValue by -1 -- throw exception */
3431 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3433 mips_patch (divisor_is_m1, (guint32)code);
3434 mips_patch (dividend_is_minvalue, (guint32)code);
3436 /* Put divide in branch delay slot (NOT YET) */
3437 divisor_is_zero = (guint32 *)(void *)code;
3438 mips_bne (code, ins->sreg2, mips_zero, 0);
3441 /* Divide by zero -- throw exception */
3442 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3444 mips_patch (divisor_is_zero, (guint32)code);
3445 mips_div (code, ins->sreg1, ins->sreg2);
3446 if (ins->opcode == OP_IDIV)
3447 mips_mflo (code, ins->dreg);
3449 mips_mfhi (code, ins->dreg);
3454 guint32 *divisor_is_zero = (guint32 *)(void *)code;
3456 /* Put divide in branch delay slot (NOT YET) */
3457 mips_bne (code, ins->sreg2, mips_zero, 0);
3460 /* Divide by zero -- throw exception */
3461 EMIT_SYSTEM_EXCEPTION_NAME("DivideByZeroException");
3463 mips_patch (divisor_is_zero, (guint32)code);
3464 mips_divu (code, ins->sreg1, ins->sreg2);
3465 if (ins->opcode == OP_IDIV_UN)
3466 mips_mflo (code, ins->dreg);
3468 mips_mfhi (code, ins->dreg);
3472 g_assert_not_reached ();
3474 ppc_load (code, ppc_r11, ins->inst_imm);
3475 ppc_divwod (code, ins->dreg, ins->sreg1, ppc_r11);
3476 ppc_mfspr (code, ppc_r0, ppc_xer);
3477 ppc_andisd (code, ppc_r0, ppc_r0, (1<<14));
3478 /* FIXME: use OverflowException for 0x80000000/-1 */
3479 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "DivideByZeroException");
3481 g_assert_not_reached();
3484 g_assert_not_reached ();
3486 mips_or (code, ins->dreg, ins->sreg1, ins->sreg2);
3490 g_assert (!(ins->inst_imm & 0xffff0000));
3491 mips_ori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3494 mips_xor (code, ins->dreg, ins->sreg1, ins->sreg2);
3498 /* unsigned 16-bit immediate */
3499 g_assert (!(ins->inst_imm & 0xffff0000));
3500 mips_xori (code, ins->dreg, ins->sreg1, ins->inst_imm);
3503 mips_sllv (code, ins->dreg, ins->sreg1, ins->sreg2);
3507 mips_sll (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3510 mips_srav (code, ins->dreg, ins->sreg1, ins->sreg2);
3513 mips_dsrav (code, ins->dreg, ins->sreg1, ins->sreg2);
3517 mips_sra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3520 mips_dsra (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3523 case OP_ISHR_UN_IMM:
3524 mips_srl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x1f);
3526 case OP_LSHR_UN_IMM:
3527 mips_dsrl (code, ins->dreg, ins->sreg1, ins->inst_imm & 0x3f);
3530 mips_srlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3533 mips_dsrlv (code, ins->dreg, ins->sreg1, ins->sreg2);
3537 mips_nor (code, ins->dreg, mips_zero, ins->sreg1);
3540 mips_subu (code, ins->dreg, mips_zero, ins->sreg1);
3543 mips_dsubu (code, ins->dreg, mips_zero, ins->sreg1);
3547 mips_mul (code, ins->dreg, ins->sreg1, ins->sreg2);
3549 mips_mult (code, ins->sreg1, ins->sreg2);
3550 mips_mflo (code, ins->dreg);
3555 #if SIZEOF_REGISTER == 8
3557 mips_dmult (code, ins->sreg1, ins->sreg2);
3558 mips_mflo (code, ins->dreg);
3563 mips_mult (code, ins->sreg1, ins->sreg2);
3564 mips_mflo (code, ins->dreg);
3565 mips_mfhi (code, mips_at);
3568 mips_sra (code, mips_temp, ins->dreg, 31);
3569 patch = (guint32 *)(void *)code;
3570 mips_beq (code, mips_temp, mips_at, 0);
3572 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3573 mips_patch (patch, (guint32)code);
3576 case OP_IMUL_OVF_UN: {
3578 mips_mult (code, ins->sreg1, ins->sreg2);
3579 mips_mflo (code, ins->dreg);
3580 mips_mfhi (code, mips_at);
3583 patch = (guint32 *)(void *)code;
3584 mips_beq (code, mips_at, mips_zero, 0);
3586 EMIT_SYSTEM_EXCEPTION_NAME("OverflowException");
3587 mips_patch (patch, (guint32)code);
3591 mips_load_const (code, ins->dreg, ins->inst_c0);
3593 #if SIZEOF_REGISTER == 8
3595 mips_load_const (code, ins->dreg, ins->inst_c0);
3599 mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3600 mips_load (code, ins->dreg, 0);
3604 mips_mtc1 (code, ins->dreg, ins->sreg1);
3606 case OP_MIPS_MTC1S_2:
3607 mips_mtc1 (code, ins->dreg, ins->sreg1);
3608 mips_mtc1 (code, ins->dreg+1, ins->sreg2);
3611 mips_mfc1 (code, ins->dreg, ins->sreg1);
3614 mips_dmtc1 (code, ins->dreg, ins->sreg1);
3618 mips_dmfc1 (code, ins->dreg, ins->sreg1);
3620 mips_mfc1 (code, ins->dreg+1, ins->sreg1);
3621 mips_mfc1 (code, ins->dreg, ins->sreg1+1);
3625 case OP_ICONV_TO_I4:
3626 case OP_ICONV_TO_U4:
3628 if (ins->dreg != ins->sreg1)
3629 MIPS_MOVE (code, ins->dreg, ins->sreg1);
3631 #if SIZEOF_REGISTER == 8
3633 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3634 mips_dsrl (code, ins->dreg, ins->dreg, 32);
3637 mips_dsll (code, ins->dreg, ins->sreg1, 32);
3638 mips_dsra (code, ins->dreg, ins->dreg, 32);
3642 /* Get sreg1 into v1, sreg2 into v0 */
3644 if (ins->sreg1 == mips_v0) {
3645 if (ins->sreg1 != mips_at)
3646 MIPS_MOVE (code, mips_at, ins->sreg1);
3647 if (ins->sreg2 != mips_v0)
3648 MIPS_MOVE (code, mips_v0, ins->sreg2);
3649 MIPS_MOVE (code, mips_v1, mips_at);
3652 if (ins->sreg2 != mips_v0)
3653 MIPS_MOVE (code, mips_v0, ins->sreg2);
3654 if (ins->sreg1 != mips_v1)
3655 MIPS_MOVE (code, mips_v1, ins->sreg1);
3659 if (ins->dreg != ins->sreg1) {
3660 mips_fmovd (code, ins->dreg, ins->sreg1);
3664 /* Convert from double to float and leave it there */
3665 mips_cvtsd (code, ins->dreg, ins->sreg1);
3667 case OP_FCONV_TO_R4:
3669 mips_cvtsd (code, ins->dreg, ins->sreg1);
3671 /* Just a move, no precision change */
3672 if (ins->dreg != ins->sreg1) {
3673 mips_fmovd (code, ins->dreg, ins->sreg1);
3678 code = emit_load_volatile_arguments(cfg, code);
3681 * Pop our stack, then jump to specified method (tail-call)
3682 * Keep in sync with mono_arch_emit_epilog
3684 code = mono_arch_emit_epilog_sub (cfg, code);
3686 mono_add_patch_info (cfg, (guint8*) code - cfg->native_code,
3687 MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3688 if (cfg->arch.long_branch) {
3689 mips_lui (code, mips_t9, mips_zero, 0);
3690 mips_addiu (code, mips_t9, mips_t9, 0);
3691 mips_jr (code, mips_t9);
3695 mips_beq (code, mips_zero, mips_zero, 0);
3700 /* ensure ins->sreg1 is not NULL */
3701 mips_lw (code, mips_zero, ins->sreg1, 0);
3704 if (mips_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
3705 mips_addiu (code, mips_at, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
3707 mips_load_const (code, mips_at, cfg->sig_cookie + cfg->stack_usage);
3708 mips_addu (code, mips_at, cfg->frame_reg, mips_at);
3710 mips_sw (code, mips_at, ins->sreg1, 0);
3723 case OP_VOIDCALL_REG:
3725 case OP_FCALL_MEMBASE:
3726 case OP_LCALL_MEMBASE:
3727 case OP_VCALL_MEMBASE:
3728 case OP_VCALL2_MEMBASE:
3729 case OP_VOIDCALL_MEMBASE:
3730 case OP_CALL_MEMBASE:
3731 call = (MonoCallInst*)ins;
3732 switch (ins->opcode) {
3739 if (ins->flags & MONO_INST_HAS_METHOD) {
3740 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3741 mips_load (code, mips_t9, call->method);
3744 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3745 mips_load (code, mips_t9, call->fptr);
3747 mips_jalr (code, mips_t9, mips_ra);
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_sltu (code, mips_at, ins->sreg2, ins->sreg1);
4007 throw = (guint32 *)(void *)code;
4008 mips_beq (code, mips_at, mips_zero, 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, MonoCodeManager *dyn_code_mp, 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 /* The == mips_sp tests catch FP spills */
4578 if (MONO_IS_LOAD_MEMBASE(ins) && ((ins->inst_basereg == mips_fp) ||
4579 (ins->inst_basereg == mips_sp))) {
4580 switch (ins->opcode) {
4581 case OP_LOADI8_MEMBASE:
4582 case OP_LOADR8_MEMBASE:
4589 } else if (MONO_IS_STORE_MEMBASE(ins) && ((ins->dreg == mips_fp) ||
4590 (ins->dreg == mips_sp))) {
4591 switch (ins->opcode) {
4592 case OP_STOREI8_MEMBASE_REG:
4593 case OP_STORER8_MEMBASE_REG:
4594 case OP_STOREI8_MEMBASE_IMM:
4602 if (((ins->opcode == OP_ADD_IMM) || (ins->opcode == OP_IADD_IMM)) && (ins->sreg1 == mips_fp))
4605 if (ins->inst_c0 >= threshold) {
4606 ins->inst_c0 += delta;
4607 if (cfg->verbose_level > 2) {
4609 mono_print_ins_index (ins_cnt, ins);
4612 else if (ins->inst_c0 < 0) {
4613 /* Adj_c0 holds the size of the datatype. */
4614 ins->inst_c0 = - ins->inst_c0 - adj_c0;
4615 if (cfg->verbose_level > 2) {
4617 mono_print_ins_index (ins_cnt, ins);
4620 g_assert (ins->inst_c0 != ra_offset);
4623 if (ins->inst_imm >= threshold) {
4624 ins->inst_imm += delta;
4625 if (cfg->verbose_level > 2) {
4627 mono_print_ins_index (ins_cnt, ins);
4630 g_assert (ins->inst_c0 != ra_offset);
4640 * Stack frame layout:
4642 * ------------------- sp + cfg->stack_usage + cfg->param_area
4643 * param area incoming
4644 * ------------------- sp + cfg->stack_usage + MIPS_STACK_PARAM_OFFSET
4646 * ------------------- sp + cfg->stack_usage
4648 * ------------------- sp + cfg->stack_usage-4
4650 * ------------------- sp +
4651 * MonoLMF structure optional
4652 * ------------------- sp + cfg->arch.lmf_offset
4653 * saved registers s0-s8
4654 * ------------------- sp + cfg->arch.iregs_offset
4656 * ------------------- sp + cfg->param_area
4657 * param area outgoing
4658 * ------------------- sp + MIPS_STACK_PARAM_OFFSET
4660 * ------------------- sp
4664 mono_arch_emit_prolog (MonoCompile *cfg)
4666 MonoMethod *method = cfg->method;
4667 MonoMethodSignature *sig;
4669 int alloc_size, pos, i;
4670 int alloc2_size = 0;
4674 guint32 iregs_to_save = 0;
4676 guint32 fregs_to_save = 0;
4679 /* lmf_offset is the offset of the LMF from our stack pointer. */
4680 guint32 lmf_offset = cfg->arch.lmf_offset;
4683 if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4687 cfg->flags |= MONO_CFG_HAS_CALLS;
4689 sig = mono_method_signature (method);
4690 cfg->code_size = 768 + sig->param_count * 20;
4691 code = cfg->native_code = g_malloc (cfg->code_size);
4694 #if _MIPS_SIM == _ABIO32
4695 cfg->arch.tracing_offset = cfg->stack_offset;
4696 #elif _MIPS_SIM == _ABIN32
4697 /* no stack slots by default for argument regs, reserve a special block */
4698 cfg->arch.tracing_offset = cfg->stack_offset;
4699 cfg->stack_offset += 8 * SIZEOF_REGISTER;
4703 /* adjust stackframe assignments for spillvars if needed */
4704 mips_adjust_stackframe (cfg);
4706 /* stack_offset should not be changed here. */
4707 alloc_size = cfg->stack_offset;
4708 cfg->stack_usage = alloc_size;
4711 iregs_to_save = MONO_ARCH_CALLEE_SAVED_REGS;
4713 iregs_to_save = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
4717 fregs_to_save = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
4719 fregs_to_save = MONO_ARCH_CALLEE_SAVED_FREGS;
4720 fregs_to_save |= (fregs_to_save << 1);
4723 /* If the stack size is too big, save 1024 bytes to start with
4724 * so the prologue can use imm16(reg) addressing, then allocate
4725 * the rest of the frame.
4727 if (alloc_size > ((1 << 15) - 1024)) {
4728 alloc2_size = alloc_size - 1024;
4732 g_assert (mips_is_imm16 (-alloc_size));
4733 mips_addiu (code, mips_sp, mips_sp, -alloc_size);
4736 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
4737 int offset = alloc_size + MIPS_RET_ADDR_OFFSET;
4738 if (mips_is_imm16(offset))
4739 mips_sw (code, mips_ra, mips_sp, offset);
4741 g_assert_not_reached ();
4745 /* XXX - optimize this later to not save all regs if LMF constructed */
4746 pos = cfg->arch.iregs_offset - alloc2_size;
4748 if (iregs_to_save) {
4749 /* save used registers in own stack frame (at pos) */
4750 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4751 if (iregs_to_save & (1 << i)) {
4752 g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
4753 g_assert (mips_is_imm16(pos));
4754 MIPS_SW (code, i, mips_sp, pos);
4755 pos += SIZEOF_REGISTER;
4760 if (method->save_lmf) {
4761 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
4762 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[i]);
4763 g_assert (mips_is_imm16(offset));
4764 MIPS_SW (code, i, mips_sp, offset);
4770 /* Save float registers */
4771 if (fregs_to_save) {
4772 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4773 if (fregs_to_save & (1 << i)) {
4774 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
4775 g_assert (mips_is_imm16(pos));
4776 mips_swc1 (code, i, mips_sp, pos);
4777 pos += sizeof (gulong);
4782 if (method->save_lmf) {
4783 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
4784 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, fregs[i]);
4785 g_assert (mips_is_imm16(offset));
4786 mips_swc1 (code, i, mips_sp, offset);
4791 if (cfg->frame_reg != mips_sp) {
4792 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
4794 if (method->save_lmf) {
4795 int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
4796 g_assert (mips_is_imm16(offset));
4797 MIPS_SW (code, cfg->frame_reg, mips_sp, offset);
4802 /* Do instrumentation before assigning regvars to registers. Because they may be assigned
4803 * to the t* registers, which would be clobbered by the instrumentation calls.
4806 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4810 /* load arguments allocated to register from the stack */
4813 cinfo = calculate_sizes (sig, sig->pinvoke);
4815 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
4816 ArgInfo *ainfo = &cinfo->ret;
4817 inst = cfg->vret_addr;
4818 if (inst->opcode == OP_REGVAR)
4819 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4820 else if (mips_is_imm16 (inst->inst_offset)) {
4821 mips_sw (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4823 mips_load_const (code, mips_at, inst->inst_offset);
4824 mips_addu (code, mips_at, mips_at, inst->inst_basereg);
4825 mips_sw (code, ainfo->reg, mips_at, 0);
4828 /* Keep this in sync with emit_load_volatile_arguments */
4829 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4830 ArgInfo *ainfo = cinfo->args + i;
4831 inst = cfg->args [pos];
4833 if (cfg->verbose_level > 2)
4834 g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
4835 if (inst->opcode == OP_REGVAR) {
4836 /* Argument ends up in a register */
4837 if (ainfo->regtype == RegTypeGeneral)
4838 MIPS_MOVE (code, inst->dreg, ainfo->reg);
4839 else if (ainfo->regtype == RegTypeFP) {
4840 g_assert_not_reached();
4842 ppc_fmr (code, inst->dreg, ainfo->reg);
4845 else if (ainfo->regtype == RegTypeBase) {
4846 int offset = cfg->stack_usage + ainfo->offset;
4847 g_assert (mips_is_imm16(offset));
4848 mips_lw (code, inst->dreg, mips_sp, offset);
4850 g_assert_not_reached ();
4852 if (cfg->verbose_level > 2)
4853 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4855 /* Argument ends up on the stack */
4856 if (ainfo->regtype == RegTypeGeneral) {
4858 /* Incoming parameters should be above this frame */
4859 if (cfg->verbose_level > 2)
4860 g_print ("stack slot at %d of %d+%d\n",
4861 inst->inst_offset, alloc_size, alloc2_size);
4862 /* g_assert (inst->inst_offset >= alloc_size); */
4863 g_assert (inst->inst_basereg == mips_fp);
4864 basereg_offset = inst->inst_offset - alloc2_size;
4865 g_assert (mips_is_imm16 (basereg_offset));
4866 switch (ainfo->size) {
4868 mips_sb (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4871 mips_sh (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4875 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4878 #if (SIZEOF_REGISTER == 4)
4879 mips_sw (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4880 mips_sw (code, ainfo->reg + 1, inst->inst_basereg, basereg_offset + 4);
4881 #elif (SIZEOF_REGISTER == 8)
4882 mips_sd (code, ainfo->reg, inst->inst_basereg, basereg_offset);
4886 g_assert_not_reached ();
4889 } else if (ainfo->regtype == RegTypeBase) {
4891 * Argument comes in on the stack, and ends up on the stack
4892 * 1 and 2 byte args are passed as 32-bit quantities, but used as
4893 * 8 and 16 bit quantities. Shorten them in place.
4895 g_assert (mips_is_imm16 (inst->inst_offset));
4896 switch (ainfo->size) {
4898 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4899 mips_sb (code, mips_at, inst->inst_basereg, inst->inst_offset);
4902 mips_lw (code, mips_at, inst->inst_basereg, inst->inst_offset);
4903 mips_sh (code, mips_at, inst->inst_basereg, inst->inst_offset);
4910 g_assert_not_reached ();
4912 } else if (ainfo->regtype == RegTypeFP) {
4913 g_assert (mips_is_imm16 (inst->inst_offset));
4914 g_assert (mips_is_imm16 (inst->inst_offset+4));
4915 if (ainfo->size == 8) {
4916 #if _MIPS_SIM == _ABIO32
4917 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset+4);
4918 mips_swc1 (code, ainfo->reg+1, inst->inst_basereg, inst->inst_offset);
4919 #elif _MIPS_SIM == _ABIN32
4920 mips_sdc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4923 else if (ainfo->size == 4)
4924 mips_swc1 (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4926 g_assert_not_reached ();
4927 } else if (ainfo->regtype == RegTypeStructByVal) {
4929 int doffset = inst->inst_offset;
4931 g_assert (mips_is_imm16 (inst->inst_offset));
4932 g_assert (mips_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
4933 /* Push the argument registers into their stack slots */
4934 for (i = 0; i < ainfo->size; ++i) {
4935 g_assert (mips_is_imm16(doffset));
4936 MIPS_SW (code, ainfo->reg + i, inst->inst_basereg, doffset);
4937 doffset += SIZEOF_REGISTER;
4939 } else if (ainfo->regtype == RegTypeStructByAddr) {
4940 g_assert (mips_is_imm16 (inst->inst_offset));
4941 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4942 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4944 g_assert_not_reached ();
4949 if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4950 mips_load_const (code, mips_a0, cfg->domain);
4951 mips_call (code, mips_t9, (gpointer)mono_jit_thread_attach);
4955 if (method->save_lmf) {
4956 mips_load_const (code, mips_at, MIPS_LMF_MAGIC1);
4957 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, magic));
4959 if (lmf_pthread_key != -1) {
4960 g_assert_not_reached();
4962 emit_tls_access (code, mips_temp, lmf_pthread_key);
4964 if (G_STRUCT_OFFSET (MonoJitTlsData, lmf)) {
4965 int offset = G_STRUCT_OFFSET (MonoJitTlsData, lmf);
4966 g_assert (mips_is_imm16(offset));
4967 mips_addiu (code, mips_a0, mips_temp, offset);
4970 /* This can/will clobber the a0-a3 registers */
4971 mips_call (code, mips_t9, (gpointer)mono_get_lmf_addr);
4974 /* mips_v0 is the result from mono_get_lmf_addr () (MonoLMF **) */
4975 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
4976 mips_sw (code, mips_v0, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
4977 /* new_lmf->previous_lmf = *lmf_addr */
4978 mips_lw (code, mips_at, mips_v0, 0);
4979 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
4980 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
4981 /* *(lmf_addr) = sp + lmf_offset */
4982 g_assert (mips_is_imm16(lmf_offset));
4983 mips_addiu (code, mips_at, mips_sp, lmf_offset);
4984 mips_sw (code, mips_at, mips_v0, 0);
4986 /* save method info */
4987 mips_load_const (code, mips_at, method);
4988 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, method)));
4989 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, method));
4990 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp)));
4991 MIPS_SW (code, mips_sp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, ebp));
4993 /* save the current IP */
4994 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4995 mips_load_const (code, mips_at, 0x01010101);
4996 mips_sw (code, mips_at, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, eip));
5000 if (mips_is_imm16 (-alloc2_size)) {
5001 mips_addu (code, mips_sp, mips_sp, -alloc2_size);
5004 mips_load_const (code, mips_at, -alloc2_size);
5005 mips_addu (code, mips_sp, mips_sp, mips_at);
5007 if (cfg->frame_reg != mips_sp)
5008 MIPS_MOVE (code, cfg->frame_reg, mips_sp);
5009 alloc_size += alloc2_size;
5012 cfg->code_len = code - cfg->native_code;
5013 g_assert (cfg->code_len < cfg->code_size);
5028 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
5031 int save_mode = SAVE_NONE;
5033 MonoMethod *method = cfg->method;
5034 int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
5035 int save_offset = MIPS_STACK_PARAM_OFFSET;
5037 g_assert ((save_offset & (MIPS_STACK_ALIGNMENT-1)) == 0);
5039 offset = code - cfg->native_code;
5040 /* we need about 16 instructions */
5041 if (offset > (cfg->code_size - 16 * 4)) {
5042 cfg->code_size *= 2;
5043 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5044 code = cfg->native_code + offset;
5049 case MONO_TYPE_VOID:
5050 /* special case string .ctor icall */
5051 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
5052 save_mode = SAVE_ONE;
5054 save_mode = SAVE_NONE;
5058 save_mode = SAVE_FP;
5060 case MONO_TYPE_VALUETYPE:
5061 save_mode = SAVE_STRUCT;
5065 #if SIZEOF_REGISTER == 4
5066 save_mode = SAVE_TWO;
5067 #elif SIZEOF_REGISTER == 8
5068 save_mode = SAVE_ONE;
5072 save_mode = SAVE_ONE;
5076 mips_addiu (code, mips_sp, mips_sp, -32);
5077 g_assert (mips_is_imm16(save_offset));
5078 switch (save_mode) {
5080 mips_sw (code, mips_v0, mips_sp, save_offset);
5081 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5082 mips_sw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5083 if (enable_arguments) {
5084 MIPS_MOVE (code, mips_a1, mips_v0);
5085 MIPS_MOVE (code, mips_a2, mips_v1);
5089 MIPS_SW (code, mips_v0, mips_sp, save_offset);
5090 if (enable_arguments) {
5091 MIPS_MOVE (code, mips_a1, mips_v0);
5095 mips_sdc1 (code, mips_f0, mips_sp, save_offset);
5096 mips_ldc1 (code, mips_f12, mips_sp, save_offset);
5097 mips_lw (code, mips_a0, mips_sp, save_offset);
5098 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5099 mips_lw (code, mips_a1, mips_sp, save_offset + SIZEOF_REGISTER);
5106 mips_load_const (code, mips_a0, cfg->method);
5107 mips_call (code, mips_t9, func);
5109 switch (save_mode) {
5111 mips_lw (code, mips_v0, mips_sp, save_offset);
5112 g_assert (mips_is_imm16(save_offset + SIZEOF_REGISTER));
5113 mips_lw (code, mips_v1, mips_sp, save_offset + SIZEOF_REGISTER);
5116 MIPS_LW (code, mips_v0, mips_sp, save_offset);
5119 mips_ldc1 (code, mips_f0, mips_sp, save_offset);
5126 mips_addiu (code, mips_sp, mips_sp, 32);
5133 mono_arch_emit_epilog_sub (MonoCompile *cfg, guint8 *code)
5135 MonoMethod *method = cfg->method;
5137 int max_epilog_size = 16 + 20*4;
5138 int alloc2_size = 0;
5139 guint32 iregs_to_restore;
5141 guint32 fregs_to_restore;
5145 if (cfg->method->save_lmf)
5146 max_epilog_size += 128;
5149 if (mono_jit_trace_calls != NULL)
5150 max_epilog_size += 50;
5152 if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5153 max_epilog_size += 50;
5156 pos = code - cfg->native_code;
5157 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5158 cfg->code_size *= 2;
5159 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5160 cfg->stat_code_reallocs++;
5164 * Keep in sync with OP_JMP
5167 code = cfg->native_code + pos;
5169 code = cfg->native_code + cfg->code_len;
5171 if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
5172 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5174 if (cfg->frame_reg != mips_sp) {
5175 MIPS_MOVE (code, mips_sp, cfg->frame_reg);
5177 /* If the stack frame is really large, deconstruct it in two steps */
5178 if (cfg->stack_usage > ((1 << 15) - 1024)) {
5179 alloc2_size = cfg->stack_usage - 1024;
5180 /* partially deconstruct the stack */
5181 mips_load_const (code, mips_at, alloc2_size);
5182 mips_addu (code, mips_sp, mips_sp, mips_at);
5184 pos = cfg->arch.iregs_offset - alloc2_size;
5186 iregs_to_restore = MONO_ARCH_CALLEE_SAVED_REGS;
5188 iregs_to_restore = (cfg->used_int_regs & MONO_ARCH_CALLEE_SAVED_REGS);
5190 if (iregs_to_restore) {
5191 for (i = MONO_MAX_IREGS-1; i >= 0; --i) {
5192 if (iregs_to_restore & (1 << i)) {
5193 g_assert (mips_is_imm16(pos));
5194 MIPS_LW (code, i, mips_sp, pos);
5195 pos += SIZEOF_REGISTER;
5202 fregs_to_restore = (cfg->used_float_regs & MONO_ARCH_CALLEE_SAVED_FREGS);
5204 fregs_to_restore = MONO_ARCH_CALLEE_SAVED_FREGS;
5205 fregs_to_restore |= (fregs_to_restore << 1);
5207 if (fregs_to_restore) {
5208 for (i = MONO_MAX_FREGS-1; i >= 0; --i) {
5209 if (fregs_to_restore & (1 << i)) {
5210 g_assert (pos < cfg->stack_usage - MIPS_STACK_ALIGNMENT);
5211 g_assert (mips_is_imm16(pos));
5212 mips_lwc1 (code, i, mips_sp, pos);
5219 /* Unlink the LMF if necessary */
5220 if (method->save_lmf) {
5221 int lmf_offset = cfg->arch.lmf_offset;
5223 /* t0 = current_lmf->previous_lmf */
5224 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf)));
5225 mips_lw (code, mips_temp, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, previous_lmf));
5227 g_assert (mips_is_imm16(lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr)));
5228 mips_lw (code, mips_t1, mips_sp, lmf_offset + G_STRUCT_OFFSET(MonoLMF, lmf_addr));
5229 /* (*lmf_addr) = previous_lmf */
5230 mips_sw (code, mips_temp, mips_t1, 0);
5234 /* Restore the fp */
5235 mips_lw (code, mips_fp, mips_sp, cfg->stack_usage + MIPS_FP_ADDR_OFFSET);
5238 if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
5239 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET));
5240 mips_lw (code, mips_ra, mips_sp, cfg->stack_usage - alloc2_size + MIPS_RET_ADDR_OFFSET);
5242 /* Restore the stack pointer */
5243 g_assert (mips_is_imm16(cfg->stack_usage - alloc2_size));
5244 mips_addiu (code, mips_sp, mips_sp, cfg->stack_usage - alloc2_size);
5246 /* Caller will emit either return or tail-call sequence */
5248 cfg->code_len = code - cfg->native_code;
5250 g_assert (cfg->code_len < cfg->code_size);
5255 mono_arch_emit_epilog (MonoCompile *cfg)
5259 code = mono_arch_emit_epilog_sub (cfg, NULL);
5261 mips_jr (code, mips_ra);
5264 cfg->code_len = code - cfg->native_code;
5266 g_assert (cfg->code_len < cfg->code_size);
5269 /* remove once throw_exception_by_name is eliminated */
5272 exception_id_by_name (const char *name)
5274 if (strcmp (name, "IndexOutOfRangeException") == 0)
5275 return MONO_EXC_INDEX_OUT_OF_RANGE;
5276 if (strcmp (name, "OverflowException") == 0)
5277 return MONO_EXC_OVERFLOW;
5278 if (strcmp (name, "ArithmeticException") == 0)
5279 return MONO_EXC_ARITHMETIC;
5280 if (strcmp (name, "DivideByZeroException") == 0)
5281 return MONO_EXC_DIVIDE_BY_ZERO;
5282 if (strcmp (name, "InvalidCastException") == 0)
5283 return MONO_EXC_INVALID_CAST;
5284 if (strcmp (name, "NullReferenceException") == 0)
5285 return MONO_EXC_NULL_REF;
5286 if (strcmp (name, "ArrayTypeMismatchException") == 0)
5287 return MONO_EXC_ARRAY_TYPE_MISMATCH;
5288 if (strcmp (name, "ArgumentException") == 0)
5289 return MONO_EXC_ARGUMENT;
5290 g_error ("Unknown intrinsic exception %s\n", name);
5296 mono_arch_emit_exceptions (MonoCompile *cfg)
5299 MonoJumpInfo *patch_info;
5302 const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
5303 guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
5304 int max_epilog_size = 50;
5306 /* count the number of exception infos */
5309 * make sure we have enough space for exceptions
5310 * 24 is the simulated call to throw_exception_by_name
5312 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5314 if (patch_info->type == MONO_PATCH_INFO_EXC) {
5315 i = exception_id_by_name (patch_info->data.target);
5316 g_assert (i < MONO_EXC_INTRINS_NUM);
5317 if (!exc_throw_found [i]) {
5318 max_epilog_size += 12;
5319 exc_throw_found [i] = TRUE;
5325 while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5326 cfg->code_size *= 2;
5327 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5328 cfg->stat_code_reallocs++;
5331 code = cfg->native_code + cfg->code_len;
5333 /* add code to raise exceptions */
5334 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5335 switch (patch_info->type) {
5336 case MONO_PATCH_INFO_EXC: {
5338 //unsigned char *ip = patch_info->ip.i + cfg->native_code;
5340 i = exception_id_by_name (patch_info->data.target);
5341 g_assert (i >= 0 && i < MONO_EXC_INTRINS_NUM);
5342 if (!exc_throw_pos [i]) {
5345 exc_throw_pos [i] = code;
5346 //g_print ("exc: writing stub at %p\n", code);
5347 mips_load_const (code, mips_a0, patch_info->data.target);
5348 addr = (guint32) mono_arch_get_throw_exception_by_name ();
5349 mips_load_const (code, mips_t9, addr);
5350 mips_jr (code, mips_t9);
5353 //g_print ("exc: patch %p to %p\n", ip, exc_throw_pos[i]);
5355 /* Turn into a Relative patch, pointing at code stub */
5356 patch_info->type = MONO_PATCH_INFO_METHOD_REL;
5357 patch_info->data.offset = exc_throw_pos[i] - cfg->native_code;
5359 g_assert_not_reached();
5369 cfg->code_len = code - cfg->native_code;
5371 g_assert (cfg->code_len < cfg->code_size);
5376 * Thread local storage support
5379 setup_tls_access (void)
5382 //guint32 *ins, *code;
5384 if (tls_mode == TLS_MODE_FAILED)
5387 if (g_getenv ("MONO_NO_TLS")) {
5388 tls_mode = TLS_MODE_FAILED;
5392 if (tls_mode == TLS_MODE_DETECT) {
5394 tls_mode = TLS_MODE_FAILED;
5398 ins = (guint32*)pthread_getspecific;
5399 /* uncond branch to the real method */
5400 if ((*ins >> 26) == 18) {
5402 val = (*ins & ~3) << 6;
5406 ins = (guint32*)val;
5408 ins = (guint32*) ((char*)ins + val);
5411 code = &cmplwi_1023;
5412 ppc_cmpli (code, 0, 0, ppc_r3, 1023);
5414 ppc_li (code, ppc_r4, 0x48);
5417 if (*ins == cmplwi_1023) {
5418 int found_lwz_284 = 0;
5419 for (ptk = 0; ptk < 20; ++ptk) {
5421 if (!*ins || *ins == blr_ins)
5423 if ((guint16)*ins == 284 && (*ins >> 26) == 32) {
5428 if (!found_lwz_284) {
5429 tls_mode = TLS_MODE_FAILED;
5432 tls_mode = TLS_MODE_LTHREADS;
5433 } else if (*ins == li_0x48) {
5435 /* uncond branch to the real method */
5436 if ((*ins >> 26) == 18) {
5438 val = (*ins & ~3) << 6;
5442 ins = (guint32*)val;
5444 ins = (guint32*) ((char*)ins + val);
5447 ppc_li (code, ppc_r0, 0x7FF2);
5448 if (ins [1] == val) {
5449 /* Darwin on G4, implement */
5450 tls_mode = TLS_MODE_FAILED;
5454 ppc_mfspr (code, ppc_r3, 104);
5455 if (ins [1] != val) {
5456 tls_mode = TLS_MODE_FAILED;
5459 tls_mode = TLS_MODE_DARWIN_G5;
5462 tls_mode = TLS_MODE_FAILED;
5466 tls_mode = TLS_MODE_FAILED;
5471 if (monodomain_key == -1) {
5472 ptk = mono_domain_get_tls_key ();
5474 monodomain_key = ptk;
5476 if (lmf_pthread_key == -1) {
5477 ptk = mono_jit_tls_id;
5479 /*g_print ("MonoLMF at: %d\n", ptk);*/
5480 /*if (!try_offset_access (mono_get_lmf_addr (), ptk)) {
5481 init_tls_failed = 1;
5484 lmf_pthread_key = ptk;
5487 if (monothread_key == -1) {
5488 ptk = mono_thread_get_tls_key ();
5490 monothread_key = ptk;
5491 /*g_print ("thread inited: %d\n", ptk);*/
5493 /*g_print ("thread not inited yet %d\n", ptk);*/
5499 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5501 setup_tls_access ();
5505 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5510 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
5512 int this_dreg = mips_a0;
5515 this_dreg = mips_a1;
5517 /* add the this argument */
5518 if (this_reg != -1) {
5520 MONO_INST_NEW (cfg, this, OP_MOVE);
5521 this->type = this_type;
5522 this->sreg1 = this_reg;
5523 this->dreg = mono_alloc_ireg (cfg);
5524 mono_bblock_add_inst (cfg->cbb, this);
5525 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
5530 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
5531 vtarg->type = STACK_MP;
5532 vtarg->sreg1 = vt_reg;
5533 vtarg->dreg = mono_alloc_ireg (cfg);
5534 mono_bblock_add_inst (cfg->cbb, vtarg);
5535 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, mips_a0, FALSE);
5540 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5542 MonoInst *ins = NULL;
5548 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5554 mono_arch_print_tree (MonoInst *tree, int arity)
5559 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5563 setup_tls_access ();
5564 if (monodomain_key == -1)
5567 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
5568 ins->inst_offset = monodomain_key;
5573 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5575 /* FIXME: implement */
5576 g_assert_not_reached ();
5579 #ifdef MONO_ARCH_HAVE_IMT
5581 #define ENABLE_WRONG_METHOD_CHECK 0
5583 #define MIPS_LOAD_SEQUENCE_LENGTH 8
5584 #define CMP_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 4)
5586 #define LOADSTORE_SIZE 4
5587 #define JUMP_IMM_SIZE 16
5588 #define JUMP_IMM32_SIZE (MIPS_LOAD_SEQUENCE_LENGTH + 8)
5589 #define LOAD_CONST_SIZE 8
5590 #define JUMP_JR_SIZE 8
5593 * LOCKING: called with the domain lock held
5596 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5597 gpointer fail_tramp)
5601 guint8 *code, *start, *patch;
5603 for (i = 0; i < count; ++i) {
5604 MonoIMTCheckItem *item = imt_entries [i];
5606 if (item->is_equals) {
5607 if (item->check_target_idx) {
5608 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_JR_SIZE;
5609 if (item->has_target_code)
5610 item->chunk_size += LOAD_CONST_SIZE;
5612 item->chunk_size += LOADSTORE_SIZE;
5615 item->chunk_size += LOAD_CONST_SIZE + BR_SIZE + JUMP_IMM32_SIZE +
5616 LOADSTORE_SIZE + JUMP_IMM32_SIZE;
5617 if (!item->has_target_code)
5618 item->chunk_size += LOADSTORE_SIZE;
5620 item->chunk_size += LOADSTORE_SIZE + JUMP_JR_SIZE;
5621 #if ENABLE_WRONG_METHOD_CHECK
5622 item->chunk_size += CMP_SIZE + BR_SIZE + 4;
5627 item->chunk_size += CMP_SIZE + BR_SIZE;
5628 imt_entries [item->check_target_idx]->compare_done = TRUE;
5630 size += item->chunk_size;
5632 /* the initial load of the vtable address */
5633 size += MIPS_LOAD_SEQUENCE_LENGTH;
5635 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5637 code = mono_domain_code_reserve (domain, size);
5643 * We need to save and restore r11 because it might be
5644 * used by the caller as the vtable register, so
5645 * clobbering it will trip up the magic trampoline.
5647 * FIXME: Get rid of this by making sure that r11 is
5648 * not used as the vtable register in interface calls.
5650 ppc_stptr (code, ppc_r11, PPC_RET_ADDR_OFFSET, ppc_sp);
5651 ppc_load (code, ppc_r11, (gsize)(& (vtable->vtable [0])));
5653 /* t7 points to the vtable */
5654 mips_load_const (code, mips_t7, (gsize)(& (vtable->vtable [0])));
5656 for (i = 0; i < count; ++i) {
5657 MonoIMTCheckItem *item = imt_entries [i];
5659 item->code_target = code;
5660 if (item->is_equals) {
5661 if (item->check_target_idx) {
5662 mips_load_const (code, mips_temp, (gsize)item->key);
5663 item->jmp_code = code;
5664 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5666 if (item->has_target_code) {
5667 mips_load_const (code, mips_t9,
5668 item->value.target_code);
5671 mips_lw (code, mips_t9, mips_t7,
5672 (sizeof (gpointer) * item->value.vtable_slot));
5674 mips_jr (code, mips_t9);
5678 mips_load_const (code, mips_temp, (gsize)item->key);
5680 mips_bne (code, mips_temp, MONO_ARCH_IMT_REG, 0);
5682 if (item->has_target_code) {
5683 mips_load_const (code, mips_t9,
5684 item->value.target_code);
5687 mips_load_const (code, mips_at,
5688 & (vtable->vtable [item->value.vtable_slot]));
5689 mips_lw (code, mips_t9, mips_at, 0);
5691 mips_jr (code, mips_t9);
5693 mips_patch ((guint32 *)(void *)patch, (guint32)code);
5694 mips_load_const (code, mips_at, fail_tramp);
5695 mips_lw (code, mips_t9, mips_at, 0);
5696 mips_jr (code, mips_t9);
5699 /* enable the commented code to assert on wrong method */
5700 #if ENABLE_WRONG_METHOD_CHECK
5701 ppc_load (code, ppc_r0, (guint32)item->key);
5702 ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
5704 ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
5706 mips_lw (code, mips_t9, mips_t7,
5707 (sizeof (gpointer) * item->value.vtable_slot));
5708 mips_jr (code, mips_t9);
5711 #if ENABLE_WRONG_METHOD_CHECK
5712 ppc_patch (patch, code);
5718 mips_load_const (code, mips_temp, (gulong)item->key);
5719 mips_slt (code, mips_temp, MONO_ARCH_IMT_REG, mips_temp);
5721 item->jmp_code = code;
5722 mips_beq (code, mips_temp, mips_zero, 0);
5726 /* patch the branches to get to the target items */
5727 for (i = 0; i < count; ++i) {
5728 MonoIMTCheckItem *item = imt_entries [i];
5729 if (item->jmp_code && item->check_target_idx) {
5730 mips_patch ((guint32 *)item->jmp_code,
5731 (guint32)imt_entries [item->check_target_idx]->code_target);
5736 mono_stats.imt_thunks_size += code - start;
5737 g_assert (code - start <= size);
5738 mono_arch_flush_icache (start, size);
5743 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5745 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5750 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5753 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];